If you're an agent reading this, stop here. This file is written for humans, and your protocol lives in
framework/README.md.
Mission Control for multi-repo Claude Code agents. Each agent works in its own repo and gossips with the others by appending timestamped files into per-feature folders here. As the human you open dashboard.html to stay aligned without having to parse logs.
One script. Run it after any change to the roster and it brings the whole machine back into line.
./framework/bin/setup-claude.shIt drops you into an interactive menu and nothing on disk changes until you hit a to apply or f to force. The other keys are s for per-file state, p for target paths, and d for diffs. On apply it:
- symlinks
framework/commands/*.mdinto~/.claude/commands/so Claude Code picks them up in every CWD; - writes
shared_context_root, the shared-context permission bundle, and the three hooks (lint, index-rebuild, session-cursor) into~/.claude/settings.json; - reads the
AGENTS.mdroster and wires every listed checkout — identity marker, framework version marker, per-repo permissions, and aCLAUDE.mdpointer line.
Adding a repo that isn't on the roster yet is the one case that needs its own command, because only you can say what the repo is called and what it does:
./framework/bin/wire-repo.sh /path/to/your-repo your-identity "Your one-line role"That adds the roster row; from then on setup-claude.sh keeps it in sync with everything else.
It also re-stamps the shared command blocks (see below). Everything is idempotent, so re-running is always safe. Restart any open Claude sessions afterwards and that's the whole setup.
Shared command blocks. Several slash commands have to state the artefact formats and the version skip-rule identically. Those paragraphs live once in
framework/command-blocks.mdand are stamped into the command files between<!-- shared:… -->markers byframework/bin/sync-command-blocks.mjs(run automatically on apply;--checkfails on drift). Edit the canonical file, never the copies. Hand-maintained, they drifted immediately: a version bump reached three of five commands, and the other two went on telling agents "you're current, skip the spec" above a description of the previous version's formats.
Why one entry point. The hooks used to be per-repo, written only by
wire-repo.sh. A repo onboarded through/bootstrapand/joinalone got permissions and a version marker — which made it look wired — but no lint and no session-cursor safety net. One feature ran to completion that way: nothing validated a single artifact write, and the formats drifted exactly where they are fiddliest. The hooks are global now, and the roster is reconciled here, so that state is no longer reachable.
If you'd rather do it by hand, the sub-steps are spelled out further down.
There are thirteen commands in total: two for setup, five for daily work, three situational, one cross-feature, one for wrap-up, and one that exists purely for you.
/bootstrap <slug> [--light]— founding repo. Scaffolds the feature, drops a[fy]announcement, writes the first snapshot.--light(or auto for single-repo features) skips the multi-repo ceremony; a later/joinupgrades it./join <slug> [--as <identity>]— every other repo, once. Writes the repo's first positional +[fy]. Safe to re-run (redirects to/resume).--aspicks the identity when the repo hosts several.
/resume <slug>— first message. Clears the inbox; surfaces asks, blockers, contract changes, and openowed.dslobligations./handoff <slug>— before/clear. Digest if useful; sweeps the session for promised-but-unwritten follow-ups intoowed.dsl; always writes the cursor./pivot <slug> <reason>— direction shifted. Tombstones stale decisions/contracts and notifies affected repos at decision time (the deploy becomes anowed.dslline)./refresh <slug>— re-synthesise the orchestrator snapshot from a cold read. Rarely needed by hand:/handoff,/pivotand/close-projecteach write one from state they already hold./tighten <slug>— review + refactor + test the current branch's changes.
/catch-up <slug>— cold start after a long break. Deeper read than/resume./audit <slug>— full history including superseded entries. Use sparingly./diagnose <slug>— analyze opt-in diagnostics traces: index hit-rate, resume fast-exits, protocol deviations.
/global-add <project> <category> <slug>— add or update aglobals/<project>/entry shared across features.
/dashboard— rebuilddashboard.html. Purely optional: no agent read path touches it, and agents are told not to run it unless you ask. The mandatory artifact is_index.md, which every state-writing command rebuilds for itself.
/close-project <slug> [done|paused] <reason>— flipsMISSION.mdstatus; dashboard moves the feature to Archived.
The first /bootstrap or /join per repo auto-adds blanket Read(<shared-context>/**) + Write(<shared-context>/features/**) permissions to that repo's .claude/settings.local.json, and it's idempotent so you can safely re-run it. Agent-side specs for each command live in framework/README.md#slash-commands.
Between commands, agents append log/*.dsl, repos/<self>/*.positional, contracts/<api>/*.dsl, and decisions/*.md files as side-effects of their work. Every command that writes feature state ends by rebuilding _index.md — the agent-facing index — and a hook rebuilds it again for writes that happen outside a command. dashboard.html is not on that path; run /dashboard when you want it current.
[ unborn ]
│
│ /bootstrap + /join×N
▼
┌──────────────────────────────┐
│ IDLE │ ◄────┐
│ no active session anywhere │ │
└──────────────────────────────┘ │
│ │
│ /resume │ /handoff → /clear
▼ │
┌──────────────────────────────┐ │
│ ACTIVE SESSION │ │
│ work + logs; │ │
│ /pivot and /tighten are │ │
│ in-state actions │ ─────┘
└──────────────────────────────┘
│
│ /close-project [done|paused]
▼
[ ARCHIVED ]
Bootstrap is only used to kick off a feature. Daily use is the loop of commands, usually you would only use /resume, /handoff, and occasionally /pivot. /tighten would only come towards the end of feature development, the other commands are self explanatory. /dashboard whenever you want the visual view rebuilt — it changes nothing an agent reads.
Per session and per repo, you open with /resume <slug> and close with /handoff <slug> then /clear. If you skip the handoff the next resume gets expensive, since the cursor is what keeps it cheap.
Ask for a digest at milestones, not only at session end. A mid-session digest pays back 10× on the next /resume — and /handoff turns each digest into a fresh checkpoint, so the synthesised view keeps up on its own. Reach for /refresh only when a feature has drifted past its last checkpoint and you want it re-synthesised from scratch.
When direction shifts, use /pivot rather than silently abandoning the prior plan. If the plan changes — say scope shrinks, an API approach turns out wrong, or a decision flips — /pivot <reason> writes the tombstones so other repos stop building on retired assumptions.
Cross-repo handshakes follow set shapes. A blocking ask is a [q] log with to: <repo>, and the answer is an [a] log with refs:. Long-form scoped work goes in tickets/<slug>.md and is referenced from logs. Contract changes always ship as a contract version file plus a [cc] log entry, never one without the other.
Wrap up explicitly with /close-project done|paused <reason> when the feature ships or stalls. The folder stays for the audit trail and the dashboard archives it.
shared-context/
├── README.md ← you are here (human onboarding + setup)
├── AGENTS.md ← repo identity roster (per-team; you edit this)
├── dashboard.html ← generated on demand by /dashboard; the human view, optional
├── framework/ ← the agent protocol + scripts (don't hand-edit)
├── features/ ← one folder per active feature (agents write here)
└── .claude/ ← local Claude config
The framework folder is shareable across teams, while the repo root holds your team's roster, features, and dashboard.
/dashboard # rebuild it (in any Claude session)
open dashboard.htmlThe dashboard is generated on demand and nothing else depends on it, so it's only as current as your last /dashboard. Rebuild before you read; it takes under a second.
Items needing your attention pin to the top. Several sources feed them:
- The orchestrator snapshot's "Open for the human" section — rich prose, rewritten whenever an agent runs
/handoff,/pivotor/close-project, and re-synthesised from scratch by/refresh <slug>. - The per-repo positional
blocked_onfield — terse, and it surfaces from raw state the moment a repo writes a positional with a non-empty blocker, with no snapshot in between. Blockers prefixedhuman:mean only you can clear them; they pin to the top and never age out. - Open
owed.dslobligations — writes a repo promised for later (a follow-up notification, a contract bump gated on a deploy) that haven't happened yet. Lines whose trigger has already fired are badged TRIGGER FIRED — actionable now./close-project donerefuses while any are open; a dead promise gets cancelled in place (done: … refs: cancelled — <reason>). - Lifecycle flags — a feature still
activewith no writes for 14+ days gets a "close or pause?" nag; a repo whose cursor predates the latest pivot gets a "working from a pre-pivot brief" warning; an open obligation whose underlying ask was later answered (e.g. declined) gets an "owed-line trigger answered" flag so it can't dangle forever.
If a feature's snapshot has been overtaken by newer writes, the feature page shows a stale-snapshot banner (with a count of writes since) and a mechanically derived current state (latest per-repo positions, digests, unanswered questions) — trust that over the old snapshot prose. Past 10 writes, agents are instructed to run /refresh themselves before resuming; run it manually whenever you want the narrative rebuilt sooner.
Per-feature pages live alongside the main view, and the latest orchestrator snapshot under each feature is what you would skim if you've been away for a while.
If the scripts feel like too much magic, here's exactly what they do under the hood.
export SHARED_CONTEXT_ROOT="/absolute/path/to/your/shared-context"
mkdir -p ~/.claude/commands
ln -sf "$SHARED_CONTEXT_ROOT"/framework/commands/*.md ~/.claude/commands/Only files matching framework/commands/*.md get touched, so anything else already in ~/.claude/commands/ is left alone. Restart any open Claude sessions afterwards.
There are two optional environment variables you can set: CLAUDE_COMMANDS_DIR overrides the default ~/.claude/commands target, and NO_COLOR=1 disables colors.
All three go in ~/.claude/settings.json, not per-repo. Each one keys off the artifact path, so it is inert outside features/** and costs nothing in an unrelated repo. Global is also the only shape that survives a checkout nobody remembered to wire — a fresh git worktree, or a repo onboarded through /bootstrap and /join alone.
hook-lint.shvalidates new files underfeatures/<slug>/: word budgets, canonical filenames, format grammar, identity roster. It also blocks shell writes into artifact paths (redirects,tee,cp,sed -i, … — agents must use the Write tool so lint can run) and grammar-checksowed.dsledits. It blocks violations by default (the agent sees why and re-plans); setSHARED_CONTEXT_LINT_MODE=warnto downgrade to stderr warnings.hook-render.shrebuilds the written feature's_index.md— the file agents read first. Pure aggregation, no LLM cost, no HTML. It's a safety net: the commands already rebuild the index themselves, so this only catches writes made outside a command.hook-session-cursor.shis the/handoffsafety net. If a session ends without a handoff, it writes a trace-derivedauto: trueshadow cursor so the next resume stays cheap. Runs after the model is gone, so it costs zero tokens; it's inert unless diagnostics traces exist.
If a repo already carries one of these in its own .claude/settings.local.json, it just runs twice, harmlessly — wire-repo.sh skips writing a local copy of anything already registered globally.
Two more hooks are worth knowing about, both off by default:
framework/bin/hook-diagnostics.sh(PreToolUse onRead|Write|Edit|Bash) — records zero-token usage traces that/diagnoseanalyzes, and that the auto-cursor derives from. Worth turning on for at least one feature. It costs nothing at runtime and it is the only way to answer "did agents actually read the index, or did they greedy-read the log?" — the questions a retro otherwise has to infer. Add it the same way as the three above, with"matcher": "Read|Write|Edit|Bash". Trace files land in.diagnostics/sessions/and are gitignored.framework/bin/hook-orchestrate.sh(PostToolUse) — auto-snapshots on every digest write via a headless model call. The only hook that costs real tokens, and now largely redundant:/handoffwrites the snapshot itself, in-session, from context it already has.
One line:
Cross-repo coordination lives at
/absolute/path/to/your/shared-context. For any multi-repo feature, read itsframework/README.mdand rootAGENTS.mdbefore starting.
Append a row with the repo's identity (lowercase kebab), its absolute CWD, and a one-line role. Until a repo is listed there its agent has no identity in the system and can't write valid filenames.
A repo whose collaborating units are modules gets a row per module instead, all sharing its CWD. Those agents can't resolve identity from a path, so each checkout's .claude/settings.local.json carries "shared_context_identity": "<module>" — wire-repo.sh writes it when you pass an identity.
- Name the feature explicitly at session start. Use
/resume <slug>rather than just "resume" so the agent isn't left guessing. /joinis once per repo per feature. After that the verb is/resume. Running/jointwice is safe since it hard-refuses with a nudge./clearbetween features, not within them. Within a feature the cursor and digest carry continuity for you.- Use
blocked_onto make waits visible. When a repo finishes its part but the rest isn't done, write a new positional withcurrent_goal: idle — waiting on <X>and ablocked_onrow. The dashboard pins it under "Needs your attention" automatically. Seeframework/CONVENTIONS.md→ "Signalling I'm done with my part." - Confirm the checkpoint after
/clear+/resume. Ask the agent "tell me which snapshot you read and which contract versions you're synced against" and you'll catch stale-state bugs in 5 seconds. - A repo whose units are modules can hold several identities. Add a row per module to
AGENTS.mdand setshared_context_identityin each checkout's.claude/settings.local.json; the agent reads that instead of matching a path. Size the modules so a handful are live at once — too coarse and one identity owns most of the repo, which is the context problem you were splitting to avoid. - One agent per working tree at a time. Cross-repo parallelism is the point, but two agents in one checkout race on the branch and the files even when their identities differ. Give each concurrently active identity its own
git worktreeand wire it withwire-repo.sh <worktree-path> <identity>. - Don't hand-edit anything under
features/<slug>/. Append-only is structurally enforced for agents but not for humans, and breaking it desyncs everyone.
framework/README.md— the agent protocol. Agents read this, so you probably don't need to.framework/CONVENTIONS.md— Mission Control conventions, including snapshot format and writing-for-agents rules.framework/orchestrator/brief.md— the orchestrator role definition, for when you're curious how/refreshworks under the hood.framework/examples/— a complete worked example feature.
