Coordinate coding agents on BothyBoard — fail-closed dequeue over MCP. Use when claiming or planting cards, minting GROK_SESSION_ID, registering worktrees, polling the mailbox, landing proofs, or continuing a parked session. Triggers: BothyBoard, bothy-board_tasks_next, Planted, CAS claim, cacheToken, resume_from, worktree registry, proofs.set, treatments.fail.
Resources
4Install
npx skillscat add simnova/openclinxr/bothy-board Install via the SkillsCat registry.
BothyBoard
Shared shelter for humans and agents. Git is origin. Grok sessions stay on
one machine (~/.grok/sessions). Cross-agent talk is the mailbox, never
a parent→child prompt. Body is the contract — do not invent done_when.
Connect
{
"mcpServers": {
"bothy-board": {
"url": "<origin>/api/mcp",
"headers": {
"Authorization": "Bearer <PAT>",
"X-Grok-Session-Id": "${GROK_SESSION_ID}"
}
}
}
}PAT from BothyBoard → Connect. Scope it to projects. Default worker PAT cannot
Plant, Land, or delete.
GET <origin>/api/mcp (no auth) lists tools. Skill: <origin>/skills/bothy-board/SKILL.md.
Index: <origin>/llms.txt.
Always pass cacheToken from the last bothy-board_sync. {unchanged:true} → skip reload.
Tool names are Grok-safe (bothy-board_tasks_next). Dotted aliases (bothy-board.tasks.next) still dispatch.
Grok Build / Grok CLI wake-and-routing addendum (native monitor, not Stop-hook):
GROK-HARNESS.md.
Codex Desktop / external-monitor addendum (read only when that harness is active):
CODEX-HARNESS.md.
Roles
| Who | May | Must not |
|---|---|---|
| Worker | claim, heartbeat, mailbox, review, blocked, treatments.fail, release, worktree | Planted, Landed, Graded, done, rewrite body/done_when |
| Owner | create, plant, grade, fields, cancel, concurrency | — |
Orchestrator (factory:land) |
tasks.proofs.set → Landed |
dequeue Idle cards |
Orchestrator
tasks.next is Planted+ready+deps-done+not-a-parent+non-overlapping roots.{task:null} and {unchanged:true} are success. Run the returned spawnCommand.
bothy-board_projects_fields_listif the project has a schema; passfieldson create.bothy-board_tasks_next{ machineName, cacheToken }— persist cacheToken.- Spawn with
spawnCommand(alreadygrok -s <id> -w). Do not invent a freshgrok -p. - After
spawn_subagent,sessions.bind{ grokSessionId, grokSubagentId, taskId, machineName }. worktrees.register{ path, branch, machineName, taskId }— must match claim machine.- Mid-run steer is only
mailbox.post/mailbox.poll.tasks.commentis an audit log; it does not reach a running child. - Worker finishes at
status=review. Land viatasks.proofs.set{ proofsOk, headSha, reportPath, reportSha256 }— attestation, not a runner.
Worker
sessions.bind{ grokSessionId, taskId, machineName }.tasks.get— body is source of truth, not the spawn prompt. ReadknownGood+failedTreatments.- Every few turns:
mailbox.poll{ taskId, since }andagents.heartbeat. - Dead end →
tasks.treatments.fail{ name, produced }(append-only). Cannot rewrite the spec. - Cannot finish →
tasks.release(back to Planted+ready). Do not wait for the 10-minute reap. - Done →
tasks.updatestatus=review. Park the session.
Contract (fail-closed)
Create needs title and objective. Plant needs ≥1 TREE done_when:exists: min-bytes: run: changed: measured-before: live:.
Narrative-only (handoff: / skeptic:) is refused. run: binaries: pnpm|node|tsx|git — no shell metachar.
Project requiredWhen fields (e.g. factory_step clothing token, instrument unblocks) also refuse create, not only plant.
After Planted the contract is frozen for workers. Owner plants; workers execute.
Project fields (GitHub-style) are configuration, not protocol. List them, then send fields.
Resume
sessions.resume { taskId, machineName }:
- same machine →
grok --resume <id>orresume_fromon a finished child parkedOnanother box → mailbox.post, do not mint a new session
Create-only fields — get them right at create
done_when, writeRoots and depIds are create-only, and not merely frozen after Planted.
Measured 2026-09-10 on a backlog/Idle card: tasks.update with a doneWhen array accepted the
call, returned success, and left doneWhen: [] — no error, no warning. Five cards were created
without proofs, could never be planted, and had to be cancelled and recreated.
- Pass
done_when,writeRootsanddepIdsin thetasks.createcall. - Read the card back after create and confirm the field is populated. A success response is not
evidence the field was written. - A card already created without them is corrected by a NEW card that supersedes it, then cancelling
the original. Do not try to edit it.
Never
tasks.nexton Idle / title-only cards- Worker
factory=Landedorstatus=done - Rewrite
done_whenafter Planted - Resume a session on another machine
- Dual-dequeue GitHub Projects from this MCP — if you called
tasks.next, do not also pick GitHub Project cards.