Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions .claude/rules/claim-acquire-before-worktree-work.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Always `claim acquire` before worktree-creating backlog work

Carved sentence:

> When multiple instances of the same agent (e.g., Otto-CLI + Otto-Desktop)
> share git + bus on one machine, split-brain is prevented by the
> claim-coordinator (`tools/bus/claim.ts`, B-0400 slice 3). Use it. Before
> starting work on any backlog row, `claim acquire` first. If already
Comment thread
AceHack marked this conversation as resolved.
Outdated
> claimed, pick a different row.

## Operational content

The bus claim-coordinator already exists (PR #2939, merged 2026-05-09):

```bash
# Before any worktree-creating backlog work:
bun tools/bus/claim.ts acquire --from <agent> --item <B-NNNN> [--branch <ref>]
# Exit 0 = claim acquired; proceed
# Exit 1 = already claimed by another agent; pick a different row

# After PR merges or work abandoned:
bun tools/bus/claim.ts release --from <agent> --item <B-NNNN>
```

The claim envelope (`topic: "claim", action: "claim"`) lives on the bus with
24h TTL by default. It is visible to all agents reading
`/tmp/zeta-bus/` and to all factory surfaces (Otto-CLI, Otto-Desktop,
Vera-Codex, Riven-Cursor, Lior-Antigravity, Alexa-Kiro).

## When this rule applies

**APPLIES** to:

- Starting work on a `docs/backlog/P*/B-*.md` row (any slice)
- Creating a feature branch + worktree for that row
- Opening a PR that closes / advances a backlog row

**DOES NOT APPLY** to:

- Fixing CI failures on an already-claimed PR
- Resolving review threads on an already-claimed PR
- Ad-hoc memory-file writes / substrate-honest disclosure responses to
Aaron's messages (these are conversation-driven, not backlog-driven)
- Hot fixes to broken main / rollback PRs (urgency > coordination)

## Composes with other rules

- `.claude/rules/backlog-item-start-gate.md` β€” already mandates prior-art
search + dependency check; this rule adds `claim acquire` as the
zero-th step before those checks
- `.claude/rules/dont-ask-permission.md` β€” within authority scope, ship;
`claim acquire` exit 0 IS the substrate-level permission grant
- `.claude/rules/never-be-idle.md` β€” if claim acquire fails, pick a
different row from the same priority tier (don't go idle)
- `.claude/rules/honor-those-that-came-before.md` β€” claim acquire
preserves the work the holder is doing

## Operational examples

### Example 1: Otto-CLI picks B-0444 (which exists)

```bash
$ bun tools/bus/claim.ts acquire --from otto --item B-0444 --branch otto/b0444-impl-2026-05-13
$ echo $?
0
# Proceeded with worktree creation + impl
```

### Example 2: Otto-CLI and Otto-Desktop race

```bash
# Otto-CLI publishes claim first:
$ bun tools/bus/claim.ts acquire --from otto --item B-0444
$ echo $?
0

# Otto-Desktop tries to claim same row a second later:
$ bun tools/bus/claim.ts acquire --from otto --item B-0444
$ echo $?
1
Comment thread
AceHack marked this conversation as resolved.
Outdated
# Otto-Desktop picks B-0445 instead.
```

### Example 3: Otto-CLI crashes mid-work

```bash
# Otto-CLI process dies. Claim stays on bus with 24h TTL.
# Otto-Desktop checks:
$ bun tools/bus/claim.ts check --item B-0444
# Output: claimed by otto (TTL expires in 23h 59m)

# After 24h or after Otto-CLI process is confirmed dead (PID-liveness),
# the claim auto-releases or can be reclaimed.
Comment thread
AceHack marked this conversation as resolved.
Outdated
```

## Why this rule exists (operational evidence)

Aaron 2026-05-13 set up Otto on Claude Desktop alongside Otto-CLI. The
two-foreground-surface architecture creates a real split-brain risk:
both Ottos might pick the same backlog row simultaneously, leading to
duplicate work, race conditions, or worse β€” both committing to the
same branch with conflicts.

The claim-coordinator (B-0400 slice 3, PR #2939) was built for exactly
this. Without a rule enforcing its use, both Ottos might forget to
acquire claims and the split-brain happens. The substrate-honest fix
is mechanizing the discipline via this rule.

Per `.claude/rules/encoding-rules-without-mechanizing.md`: this rule
auto-loads at cold-boot so future-Otto reads it before any backlog
work.

## Composes with substrate

- B-0400 (bus protocol β€” the schema this rule uses)
- B-0400 slice 3 (PR #2939 β€” claim-coordinator implementation)
- B-0400 slice 5 (PR #2959 β€” `--with-bus-claims` gate integration)
- PR #3017 (B-0440.4 β€” bus publish pattern; same protocol)
- `docs/research/2026-05-12-otto-canonical-bootstream-multi-foreground-surface-orchestrator-ifs-format.md`
(the multi-foreground-surface design this rule operationalizes)
- `docs/launch/2026-05-13-otto-claude-desktop-bootstream-tight.md`
(PR #3030 β€” Claude Desktop variant; second Otto surface)
- `memory/feedback_aaron_good_failure_mode_git_fetch_before_push_catches_multi_agent_duplicate_work_2026_05_13.md`
(sibling fetch-before-push discipline; same coordination pattern at
git scope)

## Substrate-honest framing

This rule is not a strict requirement at the code level β€” the
claim-coordinator returns a useful exit code, but no automated hook
enforces calling it. The discipline relies on agent-side compliance
at cold-boot.

A future slice could add a pre-commit / pre-worktree hook that calls
`claim check` automatically and fails if no claim is held. That's
substrate-level mechanization. Today's rule is the discipline-level
mechanization.

## Full reasoning

PR #2939 (B-0400 slice 3 β€” claim-coordinator implementation)
PR #2959 (B-0400 slice 5 β€” bus-gate integration)
PR #3017 (B-0440.4 β€” bus publish pattern)
PR #3030 (Otto Claude Desktop tight bootstream β€” second Otto surface)

Aaron 2026-05-13 verbatim: *"probalby want to figure out how not to
split brain with yourself bot any idea?"* β€” substrate-honest naming
of the split-brain risk; this rule is the operationally-honest
answer.
Loading