These instructions are for AI assistants working in this project.
Always open @/openspec/AGENTS.md when the request:
- Mentions planning or proposals (words like proposal, spec, change, plan)
- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work
- Sounds ambiguous and you need the authoritative spec before coding
Use @/openspec/AGENTS.md to learn:
- How to create and apply change proposals
- Spec format and conventions
- Project structure and guidelines
Keep this managed block so 'openspec update' can refresh the instructions.
This file provides essential context for AI assistants working with the dots repository.
Build and run the CLI:
go install ./...
dotsgo install ./... # Build all binaries
revive -set_exit_status ./... # Run linterdots install all # Full system setup
dots install <component> # Install specific component
dots update # Update configuration
dots doctor # Run diagnosticsRoute every spec-worthy change through openspec/ before writing code. Any behavioral change
— new CLI command or component, changed install/update behavior, new skill/custom agent/hook, an
altered convention or invariant — gets a change folder first:
- Create
openspec/changes/<name>/withproposal.md, delta specs underspecs/<capability>/spec.md, andtasks.md. Use a kebab-case, verb-ledchange-id(add-,update-,remove-,refactor-). - Run
openspec validate <name> --strictand get approval before implementing. - Implement against the tasks, keeping deltas in sync as requirements shift.
- Archive within the same PR, before merge — run
openspec archive <name> --yes(or apply it by hand: merge the delta requirements into the base specs underopenspec/specs/<capability>/and move the change folder toopenspec/changes/archive/<YYYY-MM-DD>-<name>/) and commit the result on the change branch. Squash-merge applies the work immediately, so the base-spec update must land atomically with the PR — do NOT leave archiving as a separate post-merge step (that strands the base specs behind shipped code).
Skip the change folder only for genuinely non-behavioral work: docs, comments, formatting, test-only edits, mechanical refactors, non-breaking dependency bumps, config changes. When unsure, write the change.
See @/openspec/AGENTS.md for the full spec format, delta conventions, and CLI reference.
Specs are LOCAL DOCS only (see openspec/project.md → OpenSpec note): nothing in CI, the
build, or the runtime reads them, and that stays true. Never wire openspec validate (or any spec
tooling) into CI. The quality gate is and stays the Pre-Completion Checklist below
(go install ./..., revive, go test ./..., the skill tests, the skill linter, and qlty).
/Users/darrencheng/.dots/
├── main.go # Entry point → cli/commands.Execute()
├── cli/commands/ # All CLI commands (Cobra framework)
│ ├── install.go # Install orchestration
│ └── install/ # Component installers
├── agents/
│ ├── skills/ # Cross-agent skills (SKILL.md per skill)
│ ├── hooks/ # Claude Code hooks (registered via dots install agents)
│ └── custom/ # Custom agent types (.md per agent → ~/.claude/agents/)
├── cmd/ # 25 standalone utilities
└── pkg/ # Shared utilities (log, run, cache, path)
context/ is a durable, cross-session store for project knowledge, checked into git so it
persists across clones:
context/knowledge/index.md— knowledge graph index; one topic file per domain, indexed herecontext/research/— investigation notes and spike resultscontext/plans/— strategic plans and proposals
Read context/knowledge/index.md when you need project history or domain context beyond what's
in this file. Populated and maintained via the /improve skill.
-
Command Execution: Use
pkg/runpackagerun.Verbose()- Show outputrun.Silent()- Hide outputexec()helper in installers for error handling
-
Adding Components:
- Add to
commandsslice incli/commands/install.go - Create method in
cli/commands/install/<component>.go
- Add to
-
Logging: Use
pkg/logfor consistent output -
Testing: All new Go code must include tests
- Pure logic functions must have unit tests (
*_test.goin the same package) - Skill scripts with testable logic should have bash tests in
.github/skill-tests/ - CI runs
go test ./...andbash .github/skill-tests/run_all.sh— both must pass
- Pure logic functions must have unit tests (
| Component | Installs |
|---|---|
| bin | ~/bin utilities |
| git | Git configuration |
| home | Dotfiles in ~/ |
| zsh | ZSH configuration |
| fonts | Developer fonts |
| homebrew | System packages |
| npm | Global NPM packages |
| languages | asdf & runtimes |
| vim | Vim configuration |
| hammerspoon | Window management |
| tools | Devbox, Claude Code, Codex |
| osx | macOS defaults |
| agents | Agent skills, custom agents, hooks, and status lines (symlinks agents/skills → ~/.claude/skills + ~/.agents/skills, agents/custom → ~/.claude/agents, agents/AGENTS.md → ~/.claude/CLAUDE.md, registers Claude hooks and status line in ~/.claude/settings.json, and configures Codex's native status line with model, context remaining, 5-hour usage, and weekly usage in $CODEX_HOME/config.toml or ~/.codex/config.toml) |
| pi | pi.dev coding agent CLI + config (installs pi via curl pi.dev/install.sh, symlinks pi/agent/models.json → ~/.pi/agent/models.json, and seeds defaultProvider/defaultModel for Ollama qwen3:32b in ~/.pi/agent/settings.json; auth.json and sessions/ stay local) |
All skills live in agents/skills/<name>/SKILL.md following the Agent Skills open standard. This directory is symlinked to both ~/.claude/skills/ (for Claude Code) and ~/.agents/skills/ (for Codex) via dots install agents.
Each skill is a directory with a SKILL.md entrypoint. Add supporting files (scripts, templates, examples) alongside the SKILL.md when needed.
The !`command` syntax runs shell commands and injects output as context. Critical restrictions:
- Avoid
$()command substitution inside dynamic context expressions. Use plain commands instead — Claude Code blocks$()in these expansions for security reasons. - Avoid
||and&&operators — use separate commands or pipes instead. Claude Code's permission system treats these as multiple operations and blocks them. - Always pipe through
| head -Nafter2>/dev/null. The2>/dev/nullsuppresses stderr but does not fix the exit code — a non-zero exit code breaks the skill loader. Piping throughheadneutralizes the exit code (pipeline exit code = last command =head= 0). - Never use
origin/HEADin dynamic context — it doesn't exist in repos that weren'tgit clone'd or where the ref wasn't fetched. Detect the base branch withgit branch -r | grep -oE 'origin/(main|master)' | head -1, or provide bothorigin/mainandorigin/mastervariants so one always has output. - Keep output bounded with
| head -Nor| grepto avoid blowing up context. - No agent teams in Conductor. Do not use
TeamCreate,TeamDelete,SendMessage, orCLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS. Use parallelTasktool calls with sub-agents instead.
# BAD — $() blocked by permission system
!`DEFAULT=$(gh repo view ...) && git log origin/$DEFAULT..HEAD`
# BAD — || treated as multiple operations
!`git log origin/main..HEAD --oneline 2>/dev/null || echo "None"`
# BAD — 2>/dev/null alone does not fix exit code, breaks skill loader
!`git log origin/main..HEAD --oneline 2>/dev/null`
# BAD — origin/HEAD doesn't exist in many repos, returns empty context
!`git log origin/HEAD..HEAD --oneline 2>/dev/null | head -50`
# GOOD — detect base branch portably (no custom tools)
- Base ref: !`git branch -r 2>/dev/null | grep -oE 'origin/(main|master)' | head -1`
# GOOD — provide both branches, one will have output
- Commits vs main: !`git log origin/main..HEAD --oneline 2>/dev/null | head -50`
- Commits vs master: !`git log origin/master..HEAD --oneline 2>/dev/null | head -50`
See /write-skill for the full skill-authoring guide.
All skills must follow the Agent Skills specification. Key rules enforced by CI:
namemust match the parent directory name (lowercase, hyphens only, no consecutive hyphens)descriptionmust say what the skill does AND when to use it — include a "Use when..." or "Use for..." clause with trigger keywords for auto-activation- SKILL.md should be under 500 lines — extract detailed reference material to
references/files - File references use relative paths from the skill root, one level deep (e.g.,
references/CHECKLIST.md) - Progressive disclosure: metadata (~100 tokens) loads at startup; full SKILL.md loads on activation;
references/andscripts/load on demand
CI runs agnix for schema validation and .github/lint-skills.sh for best-practice checks (name/dir match, description quality, line count).
Claude Code auto-activates skills by matching keywords in each skill's description field against the user's message. Other agents (Codex, Copilot) do not have this mechanism, so use this routing table instead.
When the user's message matches a phrase below, read and follow the corresponding skill:
| Trigger Phrases | Skill |
|---|---|
| "last screenshot", "see screenshot", "recent screenshot", "show screenshot", "last N screenshots" | agents/skills/screenshot/SKILL.md |
| "investigate CI failures", "find flaky tests", "why is CI failing", "diagnose test flakiness", "flaky CI" | agents/skills/ci-investigate/SKILL.md |
| "create skill", "new skill", "write skill", "add a slash command", "improve skill" | agents/skills/write-skill/SKILL.md |
| "add to PATH", "Bash tool PATH", "command not found in Claude Code", "works in terminal but not Claude Code", "CLAUDE_ENV_FILE", "env.PATH not working" | agents/skills/bash-tool-path/SKILL.md |
| "prioritize", "RICE score", "backlog grooming", "sprint planning", "rank items" | agents/skills/prioritize/SKILL.md |
| "swarm", "parallel agents", "agent team in conductor", "multi-agent", "spawn agents" | agents/skills/swarm/SKILL.md |
| "orchestrate", "fable workflow", "dynamic workflow", "tiered workflow", "model-tiered build", "plan on fable implement with sonnet and opus" | agents/skills/orchestrate/SKILL.md |
| "skill gap analysis", "missing skills", "missing agents", "equip project", "bootstrap skills from spec", "what skills do I need" | agents/skills/equip/SKILL.md |
| "write a plan", "implementation plan", "plan from PRD", "plan from spike", "break down this spec", "planning" | agents/skills/plan/SKILL.md |
"slack", "channel history", "slack search", "slack messages", "find channel", "find user slack", any #channel-name reference (e.g. #app-reviews, #rnd-leadership, #general) |
agents/skills/slack/SKILL.md |
| "email", "gmail", "search email", "read email", "inbox", "email labels" | agents/skills/email/SKILL.md |
| "notion", "read notion", "notion page", "notion database" | agents/skills/notion/SKILL.md |
| "speak to me", "read to me", "read this aloud", "say this", "speak the summary" | agents/skills/tts/SKILL.md |
| "loop", "poll", "recurring", "every N minutes", "babysit", "monitor periodically", "run on interval" | agents/skills/loop/SKILL.md |
| "compare PRs", "combine PRs", "combine these PRs", "cherry-pick between PRs", "competing implementations", "competing PRs" | agents/skills/combine-prs/SKILL.md |
| "open a PR", "address review comments", "address review feedback", "fix CI failures on the PR", "wait for CI", "address PR comments" | agents/skills/pr/SKILL.md |
| "audit pending commits", "check deploy risk", "review what's shipping", "audit deploy risk", "deploy audit" | agents/skills/deploy-audit/SKILL.md |
| "validate a deploy", "check post-deploy health", "confirm production rollout is healthy", "deploy validate", "post-deploy check" | agents/skills/deploy-validate/SKILL.md |
| "just address comments", "only address comments", "resolve review threads", "reply to PR comments", "clear bot comments", "address comments without re-running CI" | agents/skills/address-comments/SKILL.md |
| "improve skills", "capture learnings", "upgrade context", "learn from session" | agents/skills/improve/SKILL.md |
| "amend", "amend commit", "rewrite commit message", "improve commit message", "fix commit message" | agents/skills/amend/SKILL.md |
| "squash", "squash commits", "condense commits", "squash branch", "clean up commits" | agents/skills/squash/SKILL.md |
| "wrapup", "wrap up", "session closeout", "anything else to capture", "end of session", "done for the day", "end of day" | agents/skills/wrapup/SKILL.md |
| "explain like I'm 5", "eli5", "explain simply", "dumb it down", "explain in simple terms" | agents/skills/eli5/SKILL.md |
| "skill usage", "which skills do I use", "unused skills", "skill stats", "skill suggestions" | agents/skills/skill-usage/SKILL.md |
| "dream", "KB hygiene", "knowledge base cleanup", "memory hygiene", "audit KB", "dream consolidation" | agents/skills/dream/SKILL.md |
| "create slides", "build a presentation", "make a deck", "turn talking points into a talk", "HTML slideshow", "presentation deck" | agents/skills/slides/SKILL.md |
| "preview markdown", "render markdown", "how does this README render on GitHub", "GitHub-flavored markdown preview", "check that images render on GitHub", "markdown preview" | agents/skills/markdown-preview/SKILL.md |
This is a public repository. Skills and configuration checked in here must be generic and reusable by anyone.
Never commit to tracked files:
- Email addresses, usernames, account names, or other personal identifiers
- Company names, internal tool names, proprietary patterns, or org-specific conventions
- API keys, tokens, secrets, or credential paths that reveal identity
- Hardcoded account lists or user-specific configuration — use dynamic lookups instead (e.g.,
gmail accountsinstead of a static table)
Put personal or org-specific knowledge in private project-local CLAUDE.md files, ~/.dots/sys/, or gitignored directories instead.
When receiving a handoff for ~/.dots skill changes, apply them to this workspace under agents/skills/. This repo is the source of truth for skills — ~/.claude/skills/ is a symlink to agents/skills/ via dots install agents.
This repo controls the user's global Claude Code instructions: agents/AGENTS.md is the source of
truth, symlinked to ~/.claude/CLAUDE.md via dots install agents (see
cli/commands/install/agents.go). Whenever the user asks to update their global CLAUDE.md, make the
same edit to agents/AGENTS.md here so the repo copy stays in sync — don't only edit the live
~/.claude/CLAUDE.md.
Apply the Public Repo Policy above when syncing: only mirror generic, reusable instructions into
agents/AGENTS.md. If an instruction is personal or org-specific, leave it in the user's local
~/.claude/CLAUDE.md only.
When making changes that affect user-facing features — adding/removing skills, custom agents, CLI commands, components, or utilities — always update README.md to reflect those changes. Keep counts, tables, and the project structure tree accurate.
Configuration lives in .qlty/qlty.toml. CI runs qlty check and qlty smells on every PR.
Before finishing any change, run:
qlty fmt # Auto-format
qlty check --fix --level=low # Fix lint findings
qlty smells --all --no-snippets # Inspect maintainability (duplication, complexity, deep nesting)
qlty metrics --all --sort complexity --limit 10 # HotspotsFilter to changed files only by replacing --all with --upstream=origin/master. When fixing a maintainability finding, prefer extracting a helper over disabling the rule. See https://docs.qlty.sh/cli/coding-with-ai-agents.
If qlty panics with failed to create initial log file ... PermissionDenied under a sandboxed agent, redirect its log dir by overriding HOME: HOME=/tmp/qlty-home qlty smells --all. The Claude Code sandbox blocks writes to ~/.qlty/logs even though the user owns the directory (com.apple.provenance xattr from a different process).
If instead you get command not found: qlty in the Bash tool despite qlty working in a normal terminal, its install dir (~/.qlty/bin) isn't on the Bash tool's PATH — invoke it by full path (~/.qlty/bin/qlty) or see /bash-tool-path to fix PATH for the session.
Before considering any task complete, run the full test suite:
go install ./... # Build all binaries
revive -set_exit_status ./... # Run linter
go test ./... # Run Go tests
bash .github/skill-tests/run_all.sh # Run skill script tests
bash .github/lint-skills.sh # Run skill linter
qlty check --all --no-fix --level=high # Quality gate (same as CI)
qlty smells --all --no-snippets # Maintainability scan (same as CI)Do not skip any of these steps. If any command fails, fix the issue before finishing. This applies to all tasks — feature work, bug fixes, skill changes, and documentation updates.
If go install/go test/go vet fails with failed to initialize build cache ... mkdir ... operation not permitted under a sandboxed agent, redirect the build cache: export GOCACHE=/tmp/gocache-<worktree> before running the Go commands. The Claude Code sandbox can block writes to the default ~/.argus/cache/go-build, the same class of issue as the qlty HOME workaround above.
- Installation is destructive (no backups)
- Requires macOS, Homebrew, Go 1.15+
- Uses map-based dispatch for dynamic component installation
- CI runs on GitHub Actions (macOS, Go 1.24.10)