Appearance
Project Orchestration Handbook
The encyclopedic guide to running projects with BoB (Big ol' Brain). For humans and agents.
This handbook is the human-facing how-to. For under-the-hood architecture and internals, see project-management-reference.md. For deep dives on individual subsystems, see the See Also section.
1. The Big Picture
What BoB is
BoB (Big ol' Brain) is a global Claude Code tooling framework. Skills, agents, slash commands, hooks, scripts, and templates live in a single source-of-truth git repo and get distributed to every project via deploy + symlink.
When someone says Bob, BoB, big brain, or big ol' brain, they mean this framework. See bob-identity.md for the full identity definition.
Source of truth → runtime
BOB_SOURCE (~/projects/bigbrain) <- Source of truth (git repo)
│
│ scripts/deploy.sh (sync)
▼
BOB_HOME (~/.claude/) <- Runtime (Claude Code reads here)
│
│ cdi (per-project init: symlinks)
▼
.claude/ (in each project) <- Project-level entry points| Layer | Location | Purpose |
|---|---|---|
| BOB_SOURCE | ~/projects/bigbrain | Edit here. One git repo. Single source of truth. |
| BOB_HOME | ~/.claude | Where Claude Code reads at runtime. Synced from src. |
| Project | <repo>/.claude/ | Per-project symlinks to BOB_HOME items + local items |
The Prime Directive
Everything BoB manages must be declarative, version-controlled, reproducible, idempotent, and observable — with every piece of state owned by exactly one source of truth.
Full text and approved patterns: prime-directive.md.
Work tracking lives in GitHub Issues
Every project's vision lives in docs/vision.md. Everything below the vision lives in GitHub Issues — capabilities, requirements, bugs, decisions, lessons, session summaries, and TODOs. There are no REQ-*.md, BUG-*.md, SOL-*.md, or PM index files. If someone tries to create one, stop them.
Component types at a glance
| Type | Source path | Loading model |
|---|---|---|
| Universal skill | BOB_SOURCE/skills/ | Auto-loaded everywhere by Claude Code |
| Universal command | BOB_SOURCE/commands/ | Symlinked into each project's .claude/commands/ by cdi |
| Universal agent | BOB_SOURCE/agents/ | Symlinked into each project's .claude/agents/ by cdi |
| Universal runbook | BOB_SOURCE/runbooks/ | Referenced by absolute path; not symlinked |
| Registry skill | BOB_SOURCE/registry/skills/ | Provisioned per-project via manifest (provisions/<project>.json) |
| Registry command | BOB_SOURCE/registry/commands/ | Same — opt-in per project |
| Registry agent | BOB_SOURCE/registry/agents/ | Same — opt-in per project |
| Hook | BOB_SOURCE/hooks/ | Wired up in ~/.claude/settings.json by event |
| Script | BOB_SOURCE/scripts/ | Invoked by absolute path from skills, commands, hooks, or shell |
| Template | BOB_SOURCE/templates/ | Copied (not symlinked) into projects, then customized |
| Provision manifest | BOB_SOURCE/provisions/ | Declares which registry items a project gets |
2. Quick Start
Moved to a tutorial — see Getting Started.
3. Setup & Lifecycle
3.1 First-time install on a machine
Moved — see Getting Started.
3.2 Deploying changes from BOB_SOURCE → BOB_HOME
deploy.sh is the only sanctioned way to update ~/.claude/. Direct edits to ~/.claude/ are anti-pattern — you'd lose them on the next deploy.
bash
scripts/deploy.sh --dry-run # Preview what would change
scripts/deploy.sh # Apply
scripts/deploy.sh --first-run # First-deploy mode (cleans up legacy .git/ in BOB_HOME)
scripts/deploy.sh --force # Skip confirmation promptsMachine-specific files are protected and never overwritten:
~/.claude/settings.json~/.claude/settings.local.json~/.claude/CLAUDE.local.md
3.3 Per-project initialization (cdi)
bash
cd <project>
cdi # Idempotent — safe to re-runCreates <project>/.claude/ with symlinks to:
commands/from~/.claude/commands/agents/from~/.claude/agents/hooks/referenced insettings.json- Templates (copied, not symlinked)
Skills are not symlinked — they're auto-loaded globally from ~/.claude/skills/.
3.4 Provisioning registry items (cdprov + /provision)
Each project has a manifest at BOB_SOURCE/provisions/<project>.json declaring which registry skills, commands, and agents it uses (in addition to the universal set).
bash
cdprov # Apply manifest — create symlinks to match
cdprov --status # What's in manifest vs. what's actually linked
cdprov --diff # Dry run — show planned changes
cdprov --refresh # Re-sync symlinks (drop stale, add missing)Inside Claude (/provision):
/provision status
/provision add skill cloudflare-dev
/provision add command deploy
/provision add agent code-reviewer
/provision remove skill seo-auditing
/provision diff
/provision init # Bootstrap a manifest for a new projectManifest shape (provisions/<project>.json):
json
{
"_meta": { "project": "myproj", "stack": ["cloudflare-workers", "d1"] },
"skills": ["cloudflare-dev", "d1-expert"],
"commands": ["deploy", "research"],
"agents": ["code-reviewer", "code-debugger"],
"runbooks": []
}Validate against schemas/manifest.schema.json.
3.4a Universal vs registry — and how to promote between tiers
Every command, skill, and agent lives in exactly one of two tiers. This is the single most important distinction to internalise — most "why isn't my command showing up?" confusion comes from not knowing which tier an item is in.
| Tier | Source folder | Who gets it | How it lands in a project |
|---|---|---|---|
| Universal | commands/, skills/, agents/, runbooks/ | Every project, automatically | cdi symlinks commands/agents in; skills auto-load globally |
| Registry | registry/commands/, registry/skills/, … | Only projects that opt in | Listed in provisions/<project>.json, then cdprov links it |
Registry is an à-la-carte menu: with 30+ registry skills and ~17 registry commands, you don't want cloudflare-dev loaded into a non-Cloudflare project. So registry items are opt-in, declared per-project. Universal items carry a context cost in every project, so default new items to registry and promote only the ones that are genuinely needed everywhere.
The end-to-end flow — what links what:
edit in BOB_SOURCE → deploy.sh (sync to ~/.claude) → cdi (universal symlinks)
→ cdprov (registry symlinks, per manifest)deploy.sh copies files into the runtime dir but links nothing into projects. cdi links the universal set. cdprov links the registry items a project's manifest names. A registry item that no manifest references is linked into no project — even after deploy.
Promote registry → universal (the item should be in every project):
bash
cd ~/projects/bigbrain
git mv registry/commands/<name>.md commands/<name>.md # the tier IS the folder
scripts/deploy.sh # sync to ~/.claude
# then re-run `cdi` in each existing project to pick up the new symlink;
# new projects get it automatically. Remove the item from any provisions/*.json
# that listed it — it's now universal, so an explicit opt-in is redundant.Demote universal → registry (the item is only needed by some projects): reverse the move (git mv commands/<name>.md registry/<name>.md), deploy.sh, then add the item to the manifest of each project that still needs it and cdprov --refresh. Projects not naming it lose the symlink on their next cdi/refresh.
The tier of an item is defined entirely by which folder holds it — promotion and demotion are just a git mv plus a re-link. There is no separate registration step.
3.5 Updating BoB
bash
cd ~/projects/bigbrain
git pull # Get upstream changes
scripts/deploy.sh --dry-run # Always preview first
scripts/deploy.sh # Apply
make check # Verify nothing broke3.6 Local overrides (gitignored)
<project>/.claude/CLAUDE.local.md— project notes that don't get checked in.~/.claude/CLAUDE.local.md— global notes that don't sync.
These are loaded into context but never deployed or committed.
3.7 Verification (Makefile)
make is the IaC verification layer. Run any of these from BOB_SOURCE:
| Target | What it checks |
|---|---|
make check | All of: deps + schemas + symlinks + hooks + provisions |
make check-deps | node, jq, git, make versions |
make check-schemas | All *.json configs against JSON Schema definitions |
make check-symlinks | Every symlink across registered projects resolves |
make check-hooks | Every hook script in settings.json exists and is executable |
make check-provisions | Each project's actual symlink state matches its manifest |
make test | Schema validator unit tests + warp-drive state machine tests + integration |
make ci | check + test (what GitHub Actions runs) |
make doctor | Diagnostic dump for triaging weirdness |
make help | Print all targets |
Current test counts (run make test for the live numbers):
- Schema validator: 34 unit tests
- Warp-drive state machine: 99 transition tests
- Integration tests for all check scripts: 13
make ci is what GitHub Actions runs on push and PR to master. CI skips check-symlinks and check-provisions because those scan local project directories that don't exist on the runner.
Doc-link sweep: the doc-keeper auditor's broken_relative_link rule (scripts/doc-keeper/audit.js, run via make docs-check) validates every relative .md/.txt link across README.md, CLAUDE.md, and docs/**/*.md (excluding docs/archive/**, which is frozen historical content). It supersedes the former standalone check-doc-links.sh, removed in #462 as dead tooling.
4. The Product Hierarchy
Vision & Strategy (docs/vision.md) /vision
└── Business case (GitHub Issue, business-case) /business-case — justify investment (above cap)
└── Capability (GitHub Issue, label: cap) /capability
└── Requirement (GitHub Issue, req) /requirement
└── Warp-drive chunks automatic — individual commits
Use case (GitHub Issue, label: use-case) /use-case — a scenario; Realizes → cap/req
└── → Capability (broad) or Requirement (narrow)| Level | Format | Command | Contains |
|---|---|---|---|
| Vision | docs/vision.md | /vision | Why, who, where, principles, non-goals, roadmap. Living doc. |
| Business case | GitHub Issue (business-case) | /business-case | Problem, options, cost/benefit, risk, recommendation, success metrics |
| Capability | GitHub Issue (cap) | /capability | User stories, success metrics, requirements checklist |
| Requirement | GitHub Issue (req) | /requirement | Description, acceptance criteria (checkboxes), priority, notes |
| Use case | GitHub Issue (use-case) | /use-case | Actor, goal, scenario, success criteria; decomposes to cap/req |
| Bug | GitHub Issue (bug) | gh issue create --label bug | Bug reports |
| TODO | GitHub Issue (todo) | auto-created by warp-drive timeout | Human action items |
Justification and scenario nodes
Two issue types bracket the capability spine without being part of the linear cap → req decomposition:
- Business case (
business-case,/business-case) sits above capability — it justifies investment before capabilities are spawned. Its recommended option is realized by one or more capabilities, each carryingPart of #NN(whereNNis the business case) in its Notes, exactly as a requirement links to its capability. The vision-doc fold-in of an approved recommendation is deferred to grooming;/business-casenever editsdocs/vision.md. - Use case (
use-case,/use-case) captures a concrete scenario (actor, goal, main/alternate flows, success criteria) and decomposes into the work that realizes it — a capability (broad: multiple actors/steps) or requirement(s) (narrow: one actor/goal). Each realizing issue carriesRealizes #NN(whereNNis the use case) in its Notes, and inherits the use case'sarea:<slug>so the whole scenario tree is one warp-drivable workstream.
Query the traceability with gh issue list --label use-case, gh issue list --label business-case, and gh issue list --search "Realizes #NN".
Labels
| Label | Meaning |
|---|---|
business-case | Business case — investment justification above capability |
cap | Capability |
req | Requirement |
use-case | Use case — a scenario that decomposes into cap/req |
bug | Bug report |
todo | Human action item |
approved | Ready to work — picked up by /warp-drive |
in-progress | Being worked on |
blocked | Waiting on something |
implemented | Code done, awaiting verification |
serial-only | Excluded from cdfork --from-issues (pinch points) |
area:<slug> | Workstream tag — batches issues for one module/feature/capability (see Area labels) |
decision | Architecture decision (created by /journal decision) |
lesson | Lesson learned (created by /journal lesson) |
session-summary | Session summary (created by /session-summary) |
p1-critical / p2-high / p3-medium / p4-low | Priority |
The approval workflow
/capabilitycreates an issue (labelcap).- Break it into requirements with
/requirement(labelreq, withPart of #NNlinking back to the capability). - Add
approvedwhen a requirement is ready to work. /warp-drivepicks the highest-priorityreq+approvedissue not in progress.- When done, warp-drive flags it
implementedand moves on.
Area labels (batching by workstream)
Within a single repo, issues for distinct workstreams — a new module, a feature, a capability rollout — are intermixed. An area:<slug> label tags every issue belonging to one workstream so the whole cluster can be listed and warp-driven as a unit without hand-picking issue numbers (#260).
Convention. Slugs are kebab-case workstream names:
area:billing,area:baz,area:seebod. Labels use a reserved colour (#5319E7) and anArea: <Name>description so the namespace is visually distinct and observable. Scope is within a single repo — each project tracks its own issues on its own repo.Hierarchy fit. A capability owns its
area:<slug>(derived from its title); its child requirements inherit the same label so the Capability → Requirement tree is warp-drivable as one unit.Idempotent provisioning (Prime Directive). Create/reconcile a label on demand with the helper — it never duplicates or clobbers:
bash~/.claude/scripts/area-labels.sh ensure billing # create/refresh area:billing (accepts a name too) ~/.claude/scripts/area-labels.sh list # list existing area:* labels ~/.claude/scripts/area-labels.sh slugify "Billing & Invoicing" # -> billing-invoicingStatus overview per workstream (the
gh issue listrecipe):bash~/.claude/scripts/area-labels.sh issues billing # open issues in the area ~/.claude/scripts/area-labels.sh issues billing --state all # equivalent raw form: gh issue list --label "area:billing" --state openWarp-drive batching.
/warp-drive --area <slug>narrows discovery toreq + approved + area:<slug>— see the warp-drive guide.Expectation & drift check (#527). Every open
capandreqshould carry anarea:<slug>label (other issue types — bugs, todos — take one when a workstream is meaningful, but it is not required)./capabilityand/requirementassign one at creation; to catch anything that slipped through, run the audit (also wired into/what-nextStep 5):bash~/.claude/scripts/area-labels.sh audit # lists open cap/req missing area:* (exit 3 on drift)
What NOT to create
The following filename patterns are forbidden. They predate the GitHub Issues migration. Do not regenerate them:
REQ-*.md,SOL-*.md,BUG-*.md,RISK-*.md,INC-*.md,CR-*.md,UXR-*.md,STATUS-*.mdREQUIREMENTS-INDEX.md,SOLUTIONS-INDEX.md,backlog.md,traceability-matrix.md.claude/project-management/,.claude/requirements/,.claude/journal/decisions/(orlessons/,sessions/)
If a tool emits any of these, treat it as a bug and fix the tool.
Pinch points (mark serial-only)
Some work cannot be parallelized. Mark these requirements serial-only so cdfork --from-issues skips them:
- Config / settings sync
- Lockfile bumps
- DB migrations
- Compiled-asset rebuilds
- Deploy steps
5. Dev Environment Lifecycle
Every project can declare its dev environment in dev.json. The /dev-up command (and bin/dev-up from a terminal) reads it and brings the environment to a fully testable state — server, migrations, seed data, test users, health check.
Full reference: dev-lifecycle.md.
5.1 The dev.json manifest
Lives at the project root. Sample at templates/dev.json. Schema at schemas/dev.schema.json.
json
{
"server": { "command": "npm run dev", "port": 5173, "health": "/api/health" },
"migrations": { "command": "npm run migrate:dev", "auto_run": true },
"seed": { "directory": "seed/", "runner": "node", "order": "alphabetical" },
"auth": { "adapter": "d1", "users_file": "seed/users.json" },
"access": { "localhost": "http://localhost:5173" }
}5.1a Port allocation (#197)
cdi allocates every project a deterministic 10-port band so multiple dev servers coexist without collisions. Two-tier, single source of truth:
- Ledger (authoritative):
BOB_SOURCE/provisions/ports.json, version-controlled, managed byscripts/port-ledger.js.base = 5200 + slot*10;slotfrom an FNV-1a hash of the project name. Sub-offsets:+0vite,+1wrangler,+2cds dashboard,+3..9reserved. - Projection (derived):
cdiwrites a marked, regeneratable block intodev.json(_bob_ports+server.port) and the vite/wrangler configs — never hand-edited; lossless and idempotent.
Name-hash is the default proposal; the ledger only records and arbitrates collisions (deterministic next free band). Explicit non-default pins (e.g. nanaawards 5180) are retrofit-backfilled and preserved. The legacy cds~/.claude/dashboard-ports.json registry is folded into the ledger and retired. Inspect with cdb --ports / cds --ports. Full reference: dev-lifecycle.md → Port Allocation.
Fleet backfill (#198). Projects provisioned before #197 have no band yet. make port-migrate (or node scripts/port-fleet-migrate.js) is a one-shot, idempotent migration that walks every provisioned project (provisions/*.json), allocates each its band via the same allocator as cdi, writes the ledger, and regenerates the marked projection blocks. It backfills only un-allocated projects, never reassigns an existing band, aborts loudly before any write on a pin collision, and is a verified no-op on a second run. Always review make port-migrate-dry first. deploy.sh runs it idempotently (honouring --dry-run) and non-fatally on each deploy.
5.2 /dev-up and friends
| Command | Purpose |
|---|---|
/dev-up | Full lifecycle (server + migrations + seed + users + health) |
/dev-up --check | Health probe only |
/dev-up --skip-seed / --skip-users / --skip-server | Partial run |
/dev-up --regen-seed | Discard cached seed and regenerate |
bin/dev-up | Same, from a regular terminal |
bin/dev-health | Shortcut for dev-up --check |
5.3 Seed convention
- Seed scripts live in
seed/— alphabetical execution order. - Seed data must cover all lifecycle states the domain defines (not just fresh records).
- New features include their seed updates in the same commit.
- Seed coverage gate:
scripts/dev-lifecycle/check-seed-coverage.sh.
5.4 Standardized test users
seed/users.json declares test users, provisioned via pluggable auth adapters.
| Adapter | Use when… |
|---|---|
d1 | Cloudflare D1 (SQLite) |
sqlite | Local SQLite |
supabase | Supabase auth |
script | Custom provisioning script |
custom | Inline command in provision_command |
The superuser is consistent across every project: admin@test.local / admin123.
5.5 Integration with warp-drive
When dev.json exists, warp-drive automatically:
- Calls
dev-upbefore the first chunk - Verifies health between chunks
- Auto-recovers on dev failure
- Treats dev health failure as a blockable event
6. Manual Workflow
The day-to-day cycle when you're at the keyboard.
/start-work → branch off
… code …
/commit → create a commit
/journal → optional: capture a decision/lesson
/pr → optional: open a PR
/finish-work → merge + cleanup
/session-summary → close the session as a GitHub Issue/start-work
Creates a new branch with a sensible name. Argument: feature | fix | docs | refactor | tooling | chore.
/commit
Stages and commits with a generated message. The commit skill enforces:
- No commits to
master/main(use/start-workfirst) - Pre-commit hooks run (don't bypass with
--no-verify) - Commit message reflects the why, not just the what
/pr
Pushes branch and opens a PR with requirement traceability — links back to the GitHub Issue(s) the branch addresses.
Subactions: /pr create, /pr template, /pr link.
/finish-work
Merges current branch to master (Level 3) or opens a PR (Level 2), runs cleanup, deletes the local branch.
/journal
Create a journal entry as a GitHub Issue. Three types:
| Subcommand | Label |
|---|---|
/journal decision <name> | decision |
/journal lesson <name> | lesson |
/journal session <name> | session-summary |
/session-summary
End-of-session writeup as a GitHub Issue. Captures what shipped, what's next, decisions, lessons.
Built-in Claude Code commands you'll use alongside
| Command | Purpose |
|---|---|
/review | Code review of pending changes |
/security-review | Security review of pending changes |
/init | Initialize a CLAUDE.md from existing codebase |
/clean_gone | Clean up local branches that are gone on the remote |
/commit-push-pr | Commit, push, and open PR in one go (built-in plugin) |
/loop | Run a slash command on a recurring interval |
/schedule | Cron-style scheduling for recurring agents |
7. Autonomous Workflow (Warp Drive)
7.1 Automation levels
| Level | Name | Start with | Default behavior |
|---|---|---|---|
| 1 | Supervised | claude / -a1 | Confirm every tool that can change state |
| 2 | Trusted Dev | claude -a2 | Auto-approve safe ops; PRs instead of direct merges |
| 3 | Autonomous | claude -a3 | Minimize prompts; merge directly to master |
Switch mid-session with /automation level <N>. See profiles/{supervised,trusted,autonomous}.json for the exact permission profiles.
7.2 /warp-drive — the autonomous development loop
This replaces /auto-loop. /auto-loop is legacy and will be removed.
/warp-drive # Discover next approved requirement, work it
/warp-drive 42 # Work on issue #42 specifically
/stop-warp-drive # Graceful stopWhat it does each cycle:
- Discover work (
gh issue list --label approved --label req) - Plan implementation
- Code (chunked: max 3 acceptance criteria per commit)
- Test
- Update issue (flip ACs, add labels)
- Commit + journal
- Merge (L3) or open PR (L2)
- Ask "continue?" → loop or stop
Full deep-dive: warp-drive.md.
7.3 The warp CLI (terminal observation)
Run from any shell — no Claude session needed:
bash
warp status # Phase, current chunk, recent activity
warp stop # Abort the loop from outside
warp config # Show _workflow settings (incl. session_merge)
warp help # All commandsIntegration-branch streams (#268). Accumulate several requirements onto one branch and ship them once, instead of a merge per requirement:
bash
warp session start integration/feature-x # create + check out the session branch
# ...run /warp-drive over the cluster; each requirement merges into the session branch...
warp session status # show resolved branch config
warp finalize --dry-run # preview the ship
warp finalize # L2: one consolidated PR / L3: rebase+merge to main
warp session end # clear the session branch (git branch left intact)The merging phase switches to local-accumulate automatically when a session branch is set and _workflow.session_merge is local (the default); set it to pr to keep per-requirement PRs. See the warp-drive guide.
7.4 /what-next — discover work without committing
Reads project state and proposes the next sensible work item. Use it when you're not sure where to pick up.
/what-next7.5 /stop-warp-drive
Inside Claude — graceful stop with proper cleanup. Don't kill the session with Ctrl-C; let the skill flush state cleanly.
7.6 Remote Decision Bridge (/rdb)
When you're away from the keyboard, RDB routes all decisions to Telegram via ask_remote/notify_remote.
/rdb on # Decisions go to Telegram
/rdb off # Back to terminal prompts
/rdb status # Current stateGoing AFK? Saying "I'm stepping away" is treated as /rdb on automatically.
7.7 Warp-drive launch checklist
- [ ]
claude -a3 -rdb(or-a2 -rdb) - [ ]
/warp-drivestarted - [ ] Phone has Telegram open
- [ ] Laptop plugged in and won't sleep
- [ ] At least one
req+approvedissue exists
7.8 Error handling
- Warp-drive does 3 strikes on failed fixes before escalating.
- Failures escalate to a Telegram prompt (RDB) or terminal (no RDB).
- "Type 'skip'" or "do whatever you think is best" are valid responses.
- Repeated escalations create a
todo-labeled issue for human follow-up.
7.9 Declarative loop primitive (generic "do X until Y")
Warp-drive is a loop hardcoded to the dev cycle. For any other iterate-until-done loop — fix-until-tests-pass, refactor-until-lint-clean, or "keep running this agent against this check until it passes" — use the declarative loop primitive (#424): a manifest (goal + agent + evaluator + stop_condition + guardrails) run by a single reusable runner.
bash
node ~/.claude/scripts/loop/run.js ~/.claude/templates/loops/fix-until-tests-pass.jsonGuardrails are mandatory (max_iterations at minimum) and breaches halt as blockable events, reusing warp-drive's budget_exceeded semantics. Cost telemetry reuses the warp-drive token/cost model. Provision it as the skills/loop-primitive registry item. Full reference: loop-primitive.md.
8. Parallel Work (cdfork)
cdfork fans out N parallel /warp-drive sessions, one per branch, in isolated git worktrees + tmux windows. Tmux + git are the state — no daemon, no DB. If the orchestrator dies, your worktrees and commits survive.
Full reference: cdfork.md.
8.1 Subcommands
| Command | Purpose |
|---|---|
cdfork fork <branch>... | Spawn one warp-drive per named branch |
cdfork fork --from-issues [N] | Auto-pick N approved requirements; fan out |
cdfork status [--json] | List worktrees + tmux + warp-drive state |
cdfork drop <branch> [--force] | Tear down a worktree + tmux window |
cdfork drop --all [--force] | Tear down every cdfork worktree for this repo |
cdfork pair --contract <p> --backend <r> --frontend <r> --branch <n> | Cross-repo contract-driven mode |
cdfork-pair ... | Standalone shape of cdfork pair |
cdfork help | Show command summary |
8.2 Worktree layout
For a repo at /path/to/<repo>/:
/path/to/<repo>.worktrees/<branch>/Sibling, not nested — keeps Composer, Bundler, npm, etc. from getting confused.
8.3 When to use cdfork vs. a single warp-drive
| Use cdfork when… | Use single /warp-drive when… |
|---|---|
Multiple independent issues are approved | Single issue or tightly-coupled work |
| Work clusters don't touch the same files | Issues touch shared config/migrations |
| You want to maximize throughput while AFK | Linear progression matters |
| You have CPU + RAM to spare | Single-threaded resource constraint |
8.4 What cdfork --from-issues actually does
- Runs
gh issue list --label approved --label req(excludingserial-only) - Picks the top N (default 3) by priority + age
- Derives a branch name per issue (e.g.
req-42-add-auth) - Spawns one worktree + tmux window + warp-drive per branch
8.5 cdfork pair (cross-repo)
Designed for headless splits where backend + frontend share a contract. Anchor use case: nanawall.com Drupal-headless migration.
bash
cdfork pair \
--contract ~/contracts/api-spec.yaml \
--backend ~/Sites/nanawall-api \
--frontend ~/Sites/nanawall-web \
--branch feat/product-listingTwo worktrees, two tmux windows, both warp-drives anchored to the same contract path.
8.6 Prerequisites
| Tool | Why | Install |
|---|---|---|
git | Worktrees | brew install git |
tmux | Window management | brew install tmux (NOT installed by default) |
claude | Spawned in each window | Claude Code CLI |
gh | --from-issues | brew install gh |
jq | Status JSON, issue filtering | brew install jq |
Preflight runs before any worktree is touched and fails fast on missing deps.
9. Reporting & Continuous Improvement
9.1 Per-event reporting (GitHub Issues)
| What | Command | Label |
|---|---|---|
| Architecture decision | /journal decision <name> | decision |
| Lesson learned | /journal lesson <name> | lesson |
| Session writeup | /session-summary or /journal session <name> | session-summary |
| Bug report | gh issue create --label bug | bug |
| Human action item | auto-created by warp-drive timeout | todo |
9.2 /rebob — full state reconciliation
Think git fsck for project management. Examines ground truth (git log, file system, codebase) and reconciles all PM artifacts against it.
/rebobUse it after long absences, before/after major refactors, or when state feels off.
9.3 /trace-mining — outer improvement loop
Analyzes past session journals to extract failure patterns, identify recurring harness gaps, and propose targeted improvements.
/trace-miningOutput feeds back into BoB — surfacing missing skills, broken hooks, or workflow friction. Pair with gh issue list --label lesson to mine accumulated learnings.
9.4 Registry-only continuous-improvement commands
Provision and use as needed (not universal — opt-in per project):
/research— Manage research projects (questions, sources, findings, decisions). Also available as a universal skill (research)./retrospective— Standard / start-stop-continue / 4Ls retros./standup— Daily standup format./status— Status reports at quick / weekly / monthly cadence.
9.5 Automatic self-healing (warp-drive session end)
At session_ending, warp-drive runs scripts/warp-drive/trace-mine-session.sh to close the improvement loop without manual effort. Since #295 it mines the warp-drive state history, not the issues you filed:
- What counts as a finding — genuine execution friction recorded by the state machine:
tests_failed/merge_failed/push_failedevents,retry_count, more than one coding↔testing cycle (coding_cycles),no_work, and phase stalls (longest inter-transition gap overmax_phase_minutes). Each finding is tagged with an action bucket: coding reliability (root-cause), merge/process (config), harness/capability (stall), or process. - No friction → no issue. A clean session is skipped silently (
{"skipped":true,...}) — the common case. This is the key difference from the old behavior, which always emitted an issue that merely re-listed the chunk reports/decisions filed during the session. - Context, not findings. Issues filed during the session (
decision,risk,lesson,bug-deferred) and the session summary are listed under a Context section for cross-reference — they are no longer presented as findings. - When friction is found, the miner files a
warp-drive-labelled issue on the BoB repo titledself-healing: session friction from <project> #<req>.
This complements the on-demand /trace-mining (§9.3): the automatic miner flags per-session friction; /trace-mining analyses patterns across many sessions.
9.6 Model tiering in multi-agent workflows
When you orchestrate work with the Workflow tool (agent() / parallel() / pipeline()), make asymmetric model tiering the default: spend a cheap, fast model on wide exploration and reserve a strong model for selective judgment. This is a convention, not a new capability — agent(prompt, {model, effort}) already accepts per-call overrides. Source: the "Self-Improving Loop" external-validation lesson (#264) — cheap breadth, expensive judgment.
The convention.
| Stage role | Examples | Default tier |
|---|---|---|
| Finder / explorer / sweep — wide, shallow, parallel, disposable | find bugs, grep logs, enumerate call-sites, map a subsystem | cheap: model: 'haiku' or low effort |
| Verify / judge / critic / synthesize — narrow, deep, decisive | adversarially refute a finding, score competing designs, write the final answer | strong: model: 'opus' (or omit to inherit) + high effort |
Economic rationale. Finders run in bulk and most of what they surface is noise — paying premium per-token to generate candidates is wasteful. Judgment runs on the small filtered set where correctness actually matters, so that is where the strong model earns its cost. A pool of cheap finders feeding a few expensive verifiers gets most of the quality of an all-strong fleet at a fraction of the spend.
Inheritance caveat. When you pass no model/effort, the agent inherits the session model (the resolved main-loop model) and session effort — which is almost always the right default. Only override when you're confident a different tier fits the stage: drop finders to haiku/low, lift the hardest verify/judge stages to high effort. Don't set model "just because"; an unnecessary override is how you accidentally run a 200-agent sweep on the expensive tier.
Canonical example — find → verify with explicit per-stage tiers:
js
// Cheap, parallel finders sweep each dimension; each finding is then verified
// by an expensive, skeptical judge. The pipeline runs verify-as-soon-as-found.
const results = await pipeline(
DIMENSIONS,
// FIND (cheap breadth): wide net, low cost, tolerant of false positives
d => agent(d.prompt, {
label: `find:${d.key}`, phase: 'Find',
model: 'haiku', effort: 'low', // <-- cheap tier
schema: FINDINGS_SCHEMA,
}),
// VERIFY (expensive judgment): adversarially refute each candidate
review => parallel(review.findings.map(f => () =>
agent(`Adversarially verify — try to REFUTE: ${f.title}`, {
label: `verify:${f.file}`, phase: 'Verify',
model: 'opus', effort: 'high', // <-- strong tier
schema: VERDICT_SCHEMA,
}).then(v => ({ ...f, verdict: v }))
))
)
const confirmed = results.flat().filter(Boolean).filter(f => f.verdict?.isReal)The same shape applies to judge panels (cheap candidate generation → strong scoring), loop-until-dry discovery (cheap finders → strong dedup/synthesis), and multi-modal sweeps (cheap per-modality search → strong completeness critic). Keep the breadth cheap; keep the gate strong.
10. Skill Glossary
Moved to reference — see Glossary.
11. Agent Glossary
Moved to reference — see Glossary.
12. Slash Command Glossary
Moved to reference — see Glossary.
13. Shell Command Glossary
Moved to reference — see Glossary.
14. Hooks Reference
Moved to reference — see Hooks Reference.
15. Files & Layout
15.1 BOB_SOURCE structure
BOB_SOURCE/
├── skills/ # Universal skills (auto-loaded)
├── commands/ # Universal slash commands
├── agents/ # Universal subagents
├── runbooks/ # Universal runbooks
├── registry/
│ ├── skills/ # Opt-in skills
│ ├── commands/ # Opt-in commands
│ ├── agents/ # Opt-in agents
│ └── runbooks/ # Opt-in runbooks
├── provisions/ # Per-project manifests (one JSON per project)
├── hooks/ # All hooks; wired in settings.json
├── scripts/ # CLI scripts, helpers, engines
├── bin/ # PATH-friendly entrypoints
├── templates/ # Copied (not symlinked) into projects
├── schemas/ # JSON Schema for manifest, projects, settings
├── profiles/ # Permission profiles per automation level
├── docs/ # Guides (this file lives here)
├── tests/ # `make test` targets
├── claude-init.sh # cdi
├── claude-dashboard.sh # cdb
├── claude-promote.sh # cdp
├── claude-link.sh # cdl
├── settings.json # Default settings shipped to BOB_HOME
├── CLAUDE.md # Default project instructions
├── README.md
├── Makefile
└── bob-identity.md15.2 Project-level structure
A typical project has:
my-project/
├── .claude/ # Created by cdi — symlinks into BOB_HOME
│ ├── commands/ # Symlinks
│ ├── agents/ # Symlinks
│ ├── settings.json # Project-specific overrides (optional)
│ └── settings.local.json # Machine-specific, gitignored
├── CLAUDE.md # Project instructions (committed)
├── CLAUDE.local.md # Local notes (gitignored)
├── docs/
│ └── vision.md # The living vision doc
├── dev.json # Dev environment manifest
├── seed/ # Seed scripts + users.json
└── ...15.3 Forbidden patterns
Do not create these — they predate the GitHub Issues migration:
.claude/project-management/ ✗
.claude/requirements/ ✗
.claude/journal/decisions/ ✗ (use /journal decision)
.claude/journal/lessons/ ✗ (use /journal lesson)
.claude/journal/sessions/ ✗ (use /journal session)
REQ-*.md SOL-*.md BUG-*.md ✗
RISK-*.md INC-*.md CR-*.md ✗
UXR-*.md STATUS-*.md ✗
REQUIREMENTS-INDEX.md ✗
SOLUTIONS-INDEX.md ✗
backlog.md ✗
traceability-matrix.md ✗15.4 BOB_HOME (~/.claude/) — runtime only
Synced from BOB_SOURCE by deploy.sh. Don't edit directly. Files protected from overwrite:
~/.claude/settings.json~/.claude/settings.local.json~/.claude/CLAUDE.local.md
15.5 Documentation filename conventions (docs/)
Files under docs/ follow one mechanical naming rule so the directory greps and globs predictably, the docs site renders stable URLs, and contributors (and warp-drive) never have to guess casing.
| Rule | Decision |
|---|---|
| Case | lowercase only |
| Word separator | - (kebab-case) |
| Character set | [a-z0-9-] only — no underscores, spaces, accents, em-dashes |
| Extension | .md for prose, .json for data. .txt / .markdown are not allowed |
| Date stamps | ISO 8601 suffix: <topic>-YYYY-MM-DD.md (e.g. doc-audit-2026-05-07.md) |
| Acronyms | lowercased — pm-cheatsheet, iac-audit, bob-identity |
| Subdirectories | lowercase, plural where applicable: audits/, archive/, research/ |
| Suffix patterns | *-guide.md for "explain X", *-reference.md for reference docs |
Frontmatter title | independent of the filename — the docs-site engine uses title for display, the slug for the URL |
Reserved names (exempt): README.md, index.md, _index.md, CHANGELOG.md, CONTRIBUTING.md, LICENSE. These follow conventional uppercase and are skipped by the linter.
Canonical regex (basename minus extension): ^[a-z0-9]+(-[a-z0-9]+)*$ with extension in {md, json}.
Why:
- Slug collapse — under flat serving
PM-CHEATSHEET.mdandpm-cheatsheet.mdcan produce the same URL (and engines like Starlight lowercase slugs); lowercasing eliminates the collision and keeps links engine-portable. - Case-insensitive filesystems — macOS APFS treats
Foo.mdandfoo.mdas the same file. A single casing rule avoids silentgit mvno-ops and cross-machine drift. (When renaming,git mv -fthrough a temp name clears the no-op hurdle.) - Greppability — one rule means callers can link and search without second-guessing casing.
Not part of the convention: numbered ordering prefixes (01-foo.md) — use the docs-site engine's nav-ordering config (e.g. Starlight's sidebar.order frontmatter) instead; mixing the two is the worst outcome. There is no filename-length budget — long descriptive names like project-orchestration-handbook.md are fine.
Scope & enforcement: This convention covers docs/ (excluding docs/archive/**, which is frozen historical record). It is enforced two ways:
make check-doc-naming(script:scripts/checks/check-doc-naming.sh) — wired intomake check; fails CI on any non-reserveddocs/**file outside the rule.- The doc-keeper auditor emits a
filename-violationdrift category so violations also surface in/doc-auditreports.
The same lowercase-kebab rule is applied to the code-side item directories (agents/, registry/{skills,agents,commands}/, runbooks/, provisions/) by the sibling linter make check-filename-conventions (scripts/checks/check-filename-conventions.sh, #238-241), with framework-reserved carve-outs (SKILL.md, _default.json, …). Skill bundle assets (LICENSE.txt, *.pdf, scripts inside a skill dir) are not policed — only item/dir names are.
15.6 Test & inspection artifacts (.bob-artifacts/)
Ephemeral test/inspection output — Playwright screenshots, DOM snapshots, scratch captures — goes in a single per-project directory: .bob-artifacts/. Never the repo root or scattered /tmp paths (#253).
cdiidempotently adds.bob-artifacts/and.playwright-mcp/(the Playwright MCP default output dir) to the project's root.gitignore, so these artifacts never get accidentally committed.- The
webapp-testingskill writes screenshots there;verify/runflows should follow the same convention. - Backfill an existing project (or clean stray root screenshots) with
scripts/clean-artifacts.sh <project>— idempotent: it relocates loose root-level screenshots into.bob-artifacts/and ensures the.gitignoreentries.
16. Troubleshooting
16.1 Diagnostic commands
| Symptom | Run this |
|---|---|
| "Is BoB healthy?" | make check |
| "Are my project's symlinks ok?" | cdb then cdb --check <project> |
| "What is provisioned in this project?" | cdprov --status |
| "Does the manifest match reality?" | cdprov --diff |
| "Why is warp-drive stuck?" | warp status |
| "Is the dev env healthy?" | bin/dev-health or /dev-up --check |
| "Hook script missing?" | make check-hooks |
| "JSON config invalid?" | make check-schemas |
| "Stale state across the system?" | /rebob |
| "Lessons accumulating? Patterns?" | /trace-mining |
16.2 State files
| File | Owner | Notes |
|---|---|---|
<project>/.warp-drive-state.json | warp-drive engine | Current chunk, phase, history |
<project>/.autoloop-state.json | (legacy) auto-loop | Will be removed |
~/.claude/settings.local.json | machine | _rdb.enabled lives here |
16.3 Common problems
| Problem | Fix |
|---|---|
| Hooks aren't firing | make check-hooks; verify ~/.claude/settings.json references existing scripts |
| Symlinks point to nowhere | cdprov --refresh (re-link) or cdprov --prune (drop dangling/cross-machine; dry-run first); fleet-wide: make repair-fleet then make check-fleet (#303) |
| Warp-drive won't start | Check warp status; ensure at least one req + approved issue exists |
| Telegram silent (RDB on) | Check ~/.claude/settings.local.json for _rdb.enabled: true; type something in terminal |
/auto-loop did weird things | Stop using /auto-loop — switch to /warp-drive |
Got prompt to create REQ-NNNN.md | Stop. That's a regression. File a bug — work tracking is GitHub Issues |
| Tests stuck in fix loop | Warp-drive 3-strikes-out automatically; let it escalate |
cdfork worktree won't drop | cdfork drop <branch> --force; if that fails, manually git worktree prune |
| Deploy refuses to overwrite something | That's by design — settings.json, settings.local.json, CLAUDE.local.md are protected |
17. Automated Versioning
Every BoB-managed project can be automatically versioned — conventional-commit-driven semver bumps, git tags, CHANGELOG.md, and GitHub Releases — provisioned from one source of truth rather than hand-copied CI (capability #275).
Tool: commit-and-tag-version (maintained fork of standard-version). release-please was considered and deferred (see the versioning guide).
Enable it — versioning is an opt-in manifest capability (like gh_project); it copies template files rather than symlinking:
jsonc
// provisions/<project>.json
"versioning": { "enabled": true, "main_branch": "main" }bash
cdprov refresh # copies auto-release.yml + .versionrc.json + commitlint config,
# merges package.json (release script + devDependency)The orchestrator recommends versioning by default for every project and picks a push trigger-path filter per project type (docroot/** for cms, the full source surface for framework, src/**+package.json for apps/libraries, no filter for research/mixed). An existing versioning block is always preserved on re-run, so enabled:false opt-outs and customizations survive.
A merge to the main branch then bumps the version, rewrites the changelog, tags vX.Y.Z, and publishes a GitHub Release — loop-guarded against the chore(release) commit. Conventional-commit enforcement ships as config (#278).
Heads-up: the workflow pushes the release commit/tag directly to the main branch via
GITHUB_TOKEN; enabling branch protection without a bot exception breaks it. Full detail, bump rules, and the per-type path table: versioning.md.
18. See Also
- bob-identity.md — What "BoB" means
- prime-directive.md — IaC principles, approved patterns, anti-patterns
- warp-drive.md — Full warp-drive deep-dive
- cdfork.md — Full cdfork deep-dive
- dev-lifecycle.md — Full dev env lifecycle reference (also covers the docs-site lifecycle, #153)
- orchestrator.md — Registry metadata contract, recommendation engine, interview question bank (#157 family)
- gh-projects.md — GitHub Projects v2 integration: the
cdprojCLI, profiles, canonical fields, manifest opt-in, warp-drive/command integration, backfill (#210 family) - versioning.md — Automated semantic versioning:
commit-and-tag-version, theversioningmanifest block, per-project-type trigger paths, provisioning, branch-protection caveat (#275 family) - vision.md — BoB's own vision document
- project-management-reference.md — Under-the-hood architecture (note: predates GitHub Issues migration; due for its own audit)
- branch-config.md — Branch detection / configuration
- automation-behavior.md — How automation levels behave
- backup-recovery.md — Backup & recovery
- new-machine-setup.md — Setup on a fresh machine
- verification-system.md —
make checkdeep-dive - token-monitoring.md — Token usage observability
- pm-conventions.md — PM conventions (redirect stub; original archived 2026-05-07)
- doc-audit-2026-05-07.md — Documentation audit methodology and gap list (use as a template for the next reconciliation cycle)
- archive/ — Frozen historical PM docs (
2026-02-pm/,2026-05-pm/). Each archive subdir is dated and immutable; superseded docs leave a redirect stub at the original path. Excluded from the published docs site; browse on GitHub.
Last updated: 2026-05-07 — reconciled with doc audit (#144). Changelog: disambiguated cdr (Claude Disaster Recovery, not legacy reqs-index) in §13.1; surfaced live test counts and the doc-link sweep script in §3.7; added doc audit and archive subtree to §17 See Also.