Personal Claude Code configuration for forks: subagents, slash commands, skills, and dispatch scripts with a stable installer.
This repository is designed for a single maintainer working on their own adaptation. It is source-available for reading and forking, while remaining explicitly private-maintainer scoped for this operational track.
Start here
- Getting started — install, verify, first
/pmrun - Core concepts — the orchestration model and why it is shaped this way
Reference
- Platform support — per-OS install model (symlink / copy mode)
- Executor contract —
full/minimalprofile + PM handoff abstraction - Dispatch brief schema — required brief fields +
self_verifymacros - Model tier policy — sonnet-default, Opus escalation rules
- Memory system — memory persistence layer: on-disk layout and recall lifecycle
- Context retrieval — repo index + prior-art scan before dispatching
- Task lifecycle —
pmctl tasksubcommands (claim/dispatch/status/review) - Review model — four-layer rigor model (pre-impl → pr-gate → machine verify)
- pr-gate handover schema — deprecated
pr-gate-handover_v1block format
Primary working language is Mandarin Chinese. Commit messages and code identifiers are English. Issue threads may be bilingual; non-Mandarin contributors are welcome and should expect bilingual responses.
Examples use ${PM_DISPATCH_REPO} to refer to your local clone root. If unset, scripts/install-guards.sh derives it automatically from the git toplevel with:
repo_root="${PM_DISPATCH_REPO:-$(cd "$(dirname "$0")/.." && pwd)}"
agents/ → ~/.claude/agents/ subagents callable via the Agent tool
commands/ → ~/.claude/commands/ /slash commands
scripts/ hook wrappers (called by absolute path) + usage tracking scripts
→ ~/.claude/scripts/ token-usage.sh and log-usage.sh are symlinked here by install.sh
pm/ → ~/.claude/.pm/ cross-repo PM schema, scripts, templates
settings/ settings fragments to merge into ~/.claude/settings.json by hand
docs/ guides, schemas, and policy documents
Cross-repo project-management schema and tooling consumed by project-pm and BACKLOG.md / DECISIONS.md authoring across the user's repos. install.sh symlinks ~/.claude/.pm/ to this directory so canonical path references (e.g., the rollup.sh --out default, prose mentions in memory) keep working.
Contents:
schema.md— pm-schema v1.2 definition.templates/{BACKLOG,DECISIONS}.md— bootstrap templates.scripts/rollup.sh,scripts/validate.sh— portable shell tooling (pure stdlib).scripts/test/— fixture-driven test suite for the scripts above.
Runtime artifacts (.agent-trace/, rollup/PORTFOLIO.md) are gitignored.
The canonical PM path is now ~/.claude/.pm/, installed as a symlink to pm-dispatch/pm/.
bash ~/github/pm-dispatch/install.sh— Expected:link $HOME/.claude/.pm -> .../pm-dispatch/pm. Exit code 0.readlink ~/.claude/.pm— Should print the path underpm-dispatch/pm/. If it doesn't, stop; do not use rollup.sh / validate.sh until the symlink is confirmed.
Legacy PM directories or symlinks under the old github checkout location are not used by the installer. If one is present, install.sh leaves it untouched and emits no warning about it; inspect and remove it manually only after confirming all active references use ~/.claude/.pm.
Prerequisite: jq must be on $PATH. Install: Linux/WSL2 sudo apt install jq, macOS brew install jq, Windows winget install jqlang.jq.
./install.sh --dry-run # preview
./install.sh # apply (auto-detect profile)
./install.sh --profile minimal # skip adapter bash guards
./install.sh --profile full # wire all hooks (no adapter ships a bash guard today)
CLAUDE_HOME=/tmp/sandbox ./install.sh # install into an alternate dir (sandbox/testing)The install destination defaults to ~/.claude; set CLAUDE_HOME to install (and later uninstall.sh) into an alternate directory without touching your real config — useful for rehearsing install changes. install.sh and uninstall.sh must use the same CLAUDE_HOME.
Idempotent — re-run safely after adding files. Per-file symlinks so other tools' agents in ~/.claude/agents/ are not clobbered. If a destination already exists and is not our symlink, it is skipped with a CONFLICT warning.
Supported platforms (core-development phase): Linux and WSL2 only (WSL2 is treated as Linux). Native Windows Git Bash is not officially supported right now — platform-hardening is deferred until the core stabilizes (CC-370); run under WSL2 instead. See
docs/platform-support.md.
On platforms without symlink support (e.g. native Windows Git Bash, best-effort only), the installer falls back to copy mode: managed directories are created as directory junctions and helper scripts are copied — re-run install.sh after git pull to refresh changed copies. See docs/platform-support.md for the per-platform install model.
install.sh also makes the pmctl CLI discoverable. On Linux, macOS, and WSL2
it creates a symlink from ${PMCTL_BIN_DIR:-$HOME/.local/bin}/pmctl to
cli/pmctl and prints an export PATH=... note if that bin directory is not
already on $PATH. On Windows Git Bash it does not copy pmctl; add
<repo>/cli to $PATH manually so pmctl runs in place and can resolve its
repo-local libraries.
Profile: selects whether to wire adapter bash guards (adapters/<name>/bash-guard.sh, manifest-driven via needs_bash_guard). No adapter ships a bash guard today (codex's was retired with the codex-executor agent), so full and minimal currently wire the same hook set; the flag is retained for forward compatibility with future adapters that declare one. Auto-detect runs command -v codex — if found, full; otherwise minimal. See docs/executor-contract.md for the executor profile model.
After installing, verify the environment is healthy:
bash scripts/doctor.shdoctor.sh checks that claude, jq, and pmctl are on $PATH, hooks are wired into ~/.claude/settings.json, the memory directory exists, scripts are executable, and frontmatter passes lint — each failing check prints a concrete remediation command.
bash scripts/run-all-tests.sh # run all suites (test-codex-dispatch auto-skips when Codex is absent)
bash scripts/run-all-tests.sh --list # show registered suites without running
bash scripts/run-all-tests.sh --skip test-codex-dispatch # skip one suiteRequires a complete developer checkout — any registered suite that is missing or
not executable causes the aggregator to exit non-zero. Use --skip <name> to
opt out of environment-specific suites (e.g., test-codex-dispatch if the Codex
CLI is not installed).
install.sh --verify delegates to this script.
Orchestration
- project-pm — PM across
~/github/repos. Triages requests, decomposes work, writes briefs (main thread dispatches), synthesizes PR-gate reviews, maintains per-project memory at~/.claude/projects/<claude-project-id>/memory/project_<repo>.md.
Executors (codex, claude, opencode) are not subagents — the main thread dispatches each as an independent CLI subprocess via pmctl dispatch run --adapter <name>, then verifies via git diff and dispatch-post-verify.sh.
Reviewers (advisors — PM may override with reasoning)
- critic — Adversarial review of plan / diff. Scope creep, incompleteness, convention drift.
- architecture-reviewer — Layer / coupling / abstraction fit. Does the change respect the existing design.
Reviewers (HARD GATES — only the user can override a block)
- security-reviewer — OWASP-style security review for any implementation change. Auth, injection, secrets, deps, deserialization, etc.
- risk-reviewer — Blast radius, reversibility, migration safety, fail mode, observability. Distinct from security.
- qa-tester — Owns the testing phase. Loads
${QA_RULES_DIR}/${QA_RULES_ENTRY:-AGENT.md}as Tier 1 source of truth for test categories, layer choice, and anti-patterns. Red-line violations are blocking. Any QA rules directory with a Tier 1 entry point works; setQA_RULES_DIRand optionallyQA_RULES_ENTRYto use your own.
Project ID in memory paths is derived from the sanitized absolute path of your working directory. Run
ls ~/.claude/projects/to find the directory name on your machine.
- /pm
<request>— Routes a free-form request to theproject-pmagent. - /pr-gate
[context]— Explicitly runs the full review pipeline before opening a PR.
All reviewer agent spawns use model: "sonnet" by default. Opus is only used
when all three escalation conditions hold (full tier + diff > 1000 lines +
sensitive path). See docs/model-tier-policy.md
for the full decision rules, implementation-task guidance, and token tracking
usage.
- QA rules directory (
$QA_RULES_DIR, default~/github/qa-testing-rules/). Any directory with anAGENT.mdTier 1 entry point works — theqa-testing-rulesrepo is the reference implementation, but you can substitute your own. SetQA_RULES_ENTRYto override the entry point filename if your rules repo uses a different convention.
- cli/pmctl — Runtime CLI spine.
install.shsymlinks it into${PMCTL_BIN_DIR:-$HOME/.local/bin}on Linux/macOS/WSL; Windows users should add<repo>/clito$PATHmanually because a copiedpmctlcannot resolve repo-local libraries. Key sub-commands:pmctl dispatch run --adapter <codex|claude> --brief-file <path>(preferred dispatch path);pmctl task create/show/list/update/claim/dispatch/status/review(task CRUD + lifecycle; seedocs/pmctl-task.md);pmctl decision add;pmctl trace tail(readsevents.jsonl+ archives with--kind/--task/--since/--until/--jsonfilters);pmctl context index/update/query/pack/reuse-scan(repo index + prior-art scan; seedocs/context-retrieval.md);pmctl validate brief;pmctl gate run;pmctl guard check --role <pm|executor|reviewer> --runtime <codex|claude>;pmctl safe bash;pmctl adapter generate <name>(scaffoldsadapters/<name>/adapter.yamland support files).adapter.yamlis the source of truth and must stay out ofgenerated_files; regenerate only the files listed there. - pm-prep-snapshot.sh — Captures branch/PR/backlog/tooling state before PM-agent spawn and writes a typed snapshot for PM consumption.
- codex-watch.sh — Tails
.agent-trace/latest.jsonland prints a one-line human summary per event ([turn.started],[cmd] exit=0 …,[msg] …,[turn.completed] tokens: …). Run from another terminal during a long dispatch to see real-time progress. - guard-pm-write.sh —
PreToolUsehook (matcherEdit|Write). Blocksproject-pmfrom editing/writing outside~/.claude/projects/<claude-project-id>/memory/. Asserts absolute paths and normalizes... No-op for any other agent or the main thread. Bypass (logged):PM_GUARD_PM_WRITE=off. Requiresjqandrealpath. - guard-executor-write.sh — the unified executor write-guard, surfaced via
pmctl guard check --role executor(cli-only — no livePreToolUsehook, since the brief is authored by trusted main-thread code). It derives the runtime fromagent_typeand enforces that runtime'swrite_guard_mode. Bypass (logged):PM_GUARD_<RUNTIME>_WRITE=off. Requiresjqandrealpath. - guard-save-rate-limits.sh —
StatusLinehook that saves Claude rate-limit payloads to~/.claude/rate-limits.jsonfortoken-usage.sh --remaining. If a previousstatusLine.commandexisted during install, it is saved to~/.claude/statusline-chain.confand invoked after the rate-limit file is updated. - install-guards.sh / uninstall-guards.sh — Idempotent
jq-based splice into~/.claude/settings.json.--dry-runshows the diff without applying. Each apply backs upsettings.jsontosettings.json.bak.<timestamp>. - test-guards.sh — Regression suite for the managed hook scripts (~200+ cases: happy paths, boundary, per-metachar isolated coverage, quote /
../ glob / read-root / git -C /--flag=pathbypass attempts, destructive git, stash subverbs, audit-log content assertions, env-var bypass, type-confusion, and StatusLine rate-limit capture). Exit 0 on all pass.VERBOSE=1prints every case. Run byinstall.shand isolates audit logs viaPM_GUARD_LOG_DIR. - lint-scripts.sh — Hygiene check for
scripts/*.sh: executable bit, shebang,bash -nparses, has aset -...line. Run byinstall.sh. - lint-frontmatter.sh — Validates YAML frontmatter in
agents/,commands/, andskills/against PyYAML flow-collection semantics (dq-escape whitelist, adjacent-quote, tab-indent, and empty-entry detection across all four collection paths). Run by CI anddoctor.sh. - run-all-tests.sh — Standalone test aggregator: runs every registered suite and prints one pass/fail summary.
install.sh --verifyruns it as a preflight;--listand--skip <name>are available. - doctor.sh — Environment health check: verifies
claude/jq/pmctlare on$PATH, hooks are wired into~/.claude/settings.json, the memory directory exists, scripts are executable, and frontmatter passes lint.--profile minimal|full|autoscopes which hook checks apply. Each failing check prints a concrete remediation command. - token-usage.sh — Multi-pool token usage estimator (Claude / Codex / Spark). Reads
~/.claude/usage-tracker.jsonl. Symlinked to~/.claude/scripts/token-usage.shbyinstall.sh. Usage:bash ~/.claude/scripts/token-usage.sh [--today|--all].--remaining(no arg) auto-reads~/.claude/rate-limits.jsonif the StatusLine hook is installed;--remaining Naccepts manual dashboard value. - log-usage.sh — Appends one entry to
~/.claude/usage-tracker.jsonl. Symlinked to~/.claude/scripts/log-usage.shbyinstall.sh. Usage:bash ~/.claude/scripts/log-usage.sh <type> <tokens> [note]. Call after any significant agent operation; standard types in the script header. - usage-weekly.sh — Weekly Markdown report from
~/.claude/stats-cache.json(Claude internal cache) and Codex session JSONL files. Read-only. Run manually or from a cron job.
Dependencies (runtime): jq and realpath (coreutils) must be on $PATH. Hooks fail closed (exit 2) if either is missing — they log to stderr and Claude Code surfaces the message.
Audit log: every hook firing that targets the matched subagent appends one line to $PM_GUARD_LOG_DIR/hooks.log (default ~/.claude/logs/hooks.log). No-ops for other agents are not logged. Format: <ISO8601> <hook-name> agent=<type> tool=<name> decision=<allow|deny|bypass> reason=<...> target=<path-or-cmd>. reason and target are printf %q-escaped so the log is safely re-parseable. The PM_GUARD_LOG_DIR env var lets the test suite redirect to a sandbox dir without polluting the live log.
Rollback: to disable hooks system-wide, run scripts/uninstall-guards.sh (creates a backup, splices out PreToolUse entries pointing at this repo). To restore a specific prior settings file, copy from ~/.claude/settings.json.bak.<timestamp>. The hook scripts in this repo are inert without the settings.json wiring.
- Subagents cannot spawn subagents. Claude Code intentionally restricts nested
Agenttool calls regardless of frontmatter declaration (Agent SDK docs). The main thread orchestrates: it spawns subagents (PM, reviewers) and relays outputs between them, and dispatches executors as CLI subprocesses. PM produces briefs and synthesizes verdicts; it does not dispatch. Reviewers run in parallel from the main thread, not from PM. Never includeAgentin any subagent'stools:frontmatter —scripts/lint-agents.shenforces this. - Hooks enforce hard rules; prose alone leaks. CLAUDE.md compliance for "never do X" rules sits around 70% in the public research, so structural enforcement matters for invariants. The live
PreToolUsehook in~/.claude/settings.jsonisguard-pm-write.sh(project-pm can only Edit/Write inside the memory dir). Executor write policy is enforced by the unifiedguard-executor-write.shviapmctl guard check(cli-only — the brief is authored by trusted main-thread code, so no live write hook is needed). All guards no-op for the main thread and other subagents.- Threat model: defends against accidental misuse and prompt-injected misuse by the targeted subagent. Specifically not a defense against the user's main thread, which has full tool access by design.
- Failure mode: fail-closed on missing
jq/realpath, malformed input JSON, or empty/non-absolute paths. Fail-open (no-op) only when the firing agent is not the targeted subagent, or when the bypass env var is the literal stringoff(anything else, including empty string and case variants, does not bypass — bypasses are logged). - Bypass:
PM_GUARD_PM_WRITE=off/PM_GUARD_<RUNTIME>_WRITE=off(e.g.PM_GUARD_CODEX_WRITE=off). Each bypass appends a line to~/.claude/logs/hooks.log. - Tests:
scripts/test-guards.shexercises ~150+ cases including per-metacharacter isolation, quoted-path /..-traversal /git -C/--flag=PATH/ bundled-short-flag (-rf/path,-n5/path) bypass attempts, destructive-git forms, and audit-log content assertions. Run byinstall.shwith audit logs sandboxed viaPM_GUARD_LOG_DIR. - Known overrestriction: short-flag-attached values containing
/after letter/digit chars are treated as paths and validated against read roots — sogrep -ipath/to/regexis denied even whenpath/to/regexis intended as a regex pattern, not a file. Workaround: pass the pattern as a separate token (grep -i path/to/regex file) or use-e/ positional form. Same for paths with embedded/that legitimately need to escape the read root: use the bypass env var.
- PM thinks, Codex implements.
project-pmwrites the brief; the codex executor (a CLI subprocess) implements it, it does not design. Architecture, scope, and acceptance criteria stay with the PM. - Definitions in repo, state on disk. Agent and command definitions are version-controlled here. Per-project state (memory, traces) lives in
~/.claude/and stays out of this repo. - Decoupled from agent-playbook-template. The playbook is a methodology framework; this repo is a personal config. They evolve independently.
MIT. See LICENSE.
- New agent: drop a
name.md(with frontmatter) intoagents/, re-runinstall.sh. Don't includeAgentintools:—scripts/lint-agents.shwill reject the install. - New command: drop a
name.mdintocommands/, re-runinstall.sh. - New guard: drop a
scripts/guard-<name>.shand add a correspondingPreToolUseentry by re-runningscripts/install-guards.sh(extend the splice if it's a new pair); don't hand-editsettings.jsonif it can be avoided. Add test cases toscripts/test-guards.sh— security-relevant scripts ship with regression coverage. - Settings allowlist additions: edit
~/.claude/settings.jsondirectly; don't try to symlink settings.
Schema and reusable self-verify macros: docs/dispatch-brief.md. All briefs dispatched to executor adapters must include working_dir, goal, files, and acceptance; executors reject briefs missing those fields.
self_verify— required for file-writing briefs (any brief whosefiles:block contains an entry taggedwrite:ornew:, or any entry without an explicitread:tag; when in doubt, treat as file-writing). Optional only for read-only briefs where everyfiles:entry is explicitly taggedread:. Seedocs/dispatch-brief.mdfor the canonical definition.
Codex briefs that touch many files can run 10–30 minutes. The background dispatch keeps running while you watch its trace. Two patterns:
-
External tail (any session, no Claude Code involvement). From another terminal:
~/github/pm-dispatch/scripts/codex-watch.sh --cd /path/to/projectPrints one line per codex event as it streams. Works whether the dispatcher was launched from Claude Code, the CLI, or a CI job.
-
Background dispatch from main thread. The canonical route already runs
pmctl dispatch runas a background Bash command (run_in_background: true), so the main thread stays responsive.Monitor(or periodicallyBashwithtail -n 5 .agent-trace/latest.jsonl) the trace file for progress, then checkgit diffand the post-verify verdict when the completion notification arrives.
If a dispatch exits 124, codex hit the timeout — almost always a silent startup hang. The wrapper banner + closing line in .agent-trace/latest.stderr is the post-mortem: re-dispatching usually clears the hang. Extend --timeout (or $CODEX_DISPATCH_TIMEOUT) only when codex is genuinely doing more work than the default 20 minutes.
Claude Code is a product of Anthropic. This project is an independent personal configuration for Claude Code and is not affiliated with, sponsored by, or endorsed by Anthropic. "Claude" and "Claude Code" are trademarks of Anthropic; references in this repository are descriptive use only.
Similarly, Codex CLI is a product of OpenAI; this project integrates with it but is not affiliated with OpenAI.