Skip to content

docs(rules): claim acquire before worktree work (split-brain prevention for multi-Otto)#3032

Merged
AceHack merged 5 commits into
mainfrom
otto-claim-acquire-before-worktree-work-rule-2026-05-13
May 13, 2026
Merged

docs(rules): claim acquire before worktree work (split-brain prevention for multi-Otto)#3032
AceHack merged 5 commits into
mainfrom
otto-claim-acquire-before-worktree-work-rule-2026-05-13

Conversation

@AceHack
Copy link
Copy Markdown
Member

@AceHack AceHack commented May 13, 2026

Auto-load rule mandating before any worktree-creating backlog work. Prevents Otto-CLI vs Otto-Desktop split-brain by requiring atomic claim via the existing B-0400 slice 3 + 5 infrastructure (PRs #2939 + #2959 already shipped). Discipline-level fix today; substrate-level pre-commit hook is future work.

Per Aaron 2026-05-13: "probalby want to figure out how not to split brain with yourself bot any idea?" — this rule is the operationally-honest answer.

🤖 Generated with Claude Code

…it-brain prevention for multi-Otto)

Aaron 2026-05-13 set up Otto on Claude Desktop alongside Otto-CLI,
creating a real multi-foreground-surface split-brain risk. Both Ottos
share git + bus on one machine and could pick the same backlog row
simultaneously.

The claim-coordinator (tools/bus/claim.ts, B-0400 slice 3) was built
for this — atomic check/acquire/release with PID-liveness + 24h TTL.
PR #2939 shipped it; PR #2959 added the gate integration. The
infrastructure exists; this rule is the discipline-level mechanization
that auto-loads at cold-boot so both Ottos read it + use it before
worktree-creating backlog work.

Applies to: starting work on a B-NNNN row, creating feature branch +
worktree, opening a backlog-advancing PR.

Does NOT apply to: CI fixes on already-claimed PRs, ad-hoc memory-
file writes, conversation-driven substrate, hot fixes.

Composes with:
- backlog-item-start-gate.md (this rule adds zero-th step)
- dont-ask-permission.md (acquire exit 0 IS the substrate permission)
- never-be-idle.md (if acquire fails, pick another row)
- B-0400 + slice 3 + slice 5 infrastructure
- Otto Claude Desktop bootstream (PR #3030)
- fetch-before-push memory (sibling coordination pattern at git scope)

Future substrate-level mechanization: pre-commit hook that auto-calls
'claim check' and fails on no-held-claim. Today's rule is the
discipline-level fix.

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 13, 2026 21:21
@AceHack AceHack enabled auto-merge (squash) May 13, 2026 21:21
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 98df00a8b9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .claude/rules/claim-acquire-before-worktree-work.md Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new agent-rule doc that mandates calling the existing bus claim coordinator (tools/bus/claim.ts acquire) before starting worktree-creating backlog work, to prevent split-brain between concurrent agent instances (Otto-CLI vs Otto-Desktop). This is a discipline-level rule that auto-loads at cold-boot; substrate-level enforcement (pre-commit hook) is explicitly deferred.

Changes:

  • New rule file .claude/rules/claim-acquire-before-worktree-work.md with carved sentence, applicability scope, examples, and composition notes
  • Documents when the rule applies (backlog work) vs. does not (CI fixes, hotfixes, conversation-driven memory writes)
  • Cross-references B-0400 slices 3 + 5 (PRs #2939, #2959) as the substrate this rule operationalizes

…shed by same --from value (Vera P1)

Vera caught (PR #3032 review): the original Example 2 showed two Ottos
calling 'acquire --from otto' and the second exiting 1. That's WRONG
per claim.ts line ~270 — same --from is filtered out as self-re-
acquire (idempotent). Both calls succeed; split-brain not prevented.

Fix:
- Example 2 renamed to "KNOWN GAP" — shows actual behavior (both
  succeed) + names the architectural cause (SENDER_IDS doesn't
  distinguish multi-surface instances)
- Added workarounds: lane-based convention, branch-prefix discipline,
  schema extension (otto-cli / otto-desktop)
- New Example 3 shows TARGET behavior with schema fix (--from otto-cli
  vs --from otto-desktop)
- Example 3 renamed to Example 4 (crash recovery)

The architectural gap is a real follow-up: extending SENDER_IDS to
support multi-surface instances of the same logical agent. Future
work, not this PR.

Operational consequence today: use the lane-based + branch-prefix
workarounds. Claim-coordinator is INSUFFICIENT for multi-Otto without
the schema extension.

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d437b9eb22

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .claude/rules/claim-acquire-before-worktree-work.md Outdated
Comment thread .claude/rules/claim-acquire-before-worktree-work.md Outdated
P1 (PRRT_kwDOSF9kNM6B5VwU): carved sentence claimed split-brain
is  but claim.ts filters by c.from !== sender, soprevented
same-sender instances both exit 0. Updated to state --from must
differ and document the known gap explicitly.

P2 (PRRT_kwDOSF9kNM6B5VwX): example 4 claimed PID-liveness can
reclaim a claim mid- no such mechanism exists. Only TTLTTL
expiry or explicit release ends a claim. Corrected comment.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 13, 2026 21:30
AceHack added a commit that referenced this pull request May 13, 2026
…nfirmation 2026-05-13 (#3035)

Aaron 2026-05-13 activated Otto on Claude Desktop alongside Otto-CLI,
running the multi-foreground-surface architecture from PR #3030 for
the first time. Preserves operational discoveries:

1. Claude Desktop Routines are GIT-TRACKED (durable across sessions)
   vs Claude Code CronCreate session-only — supersedes 'every session
   MUST CronList' mechanism at Desktop scope

2. Two cadence layers in Desktop: Loop (minute, session-bounded) +
   Routine (configurable, git-tracked). Both fire simultaneously.

3. CRITICAL ARCHITECTURAL GAP: SENDER_IDS in tools/bus/types.ts
   doesn't distinguish multi-surface instances. claim.ts treats
   --from otto from CLI and Desktop as IDENTICAL — split-brain
   prevention fails without schema extension. Vera caught this on
   PR #3032 review. Workarounds: lane-based + branch-prefix +
   future schema extension.

4. Approval friction profile shapes lane split natively:
   - Otto-CLI: better at .claude/rules/ edits (auto-accept covers)
   - Otto-Desktop: better at substrate + conversation + routines
   - The lane split emerges from approval costs, not convention —
     more robust because friction enforces it

Generalizable principle: multi-foreground-surface works because
surfaces have DIFFERENT cost profiles, not because they're redundant
clones. Future multi-instance work should match work to lowest-
friction surface for that work shape.

Composes with:
- Otto canonical bootstream (full canonical + tight)
- .claude/rules/tick-must-never-stop.md (CLI cron caveat)
- .claude/rules/claim-acquire-before-worktree-work.md (the rule
  with the architectural gap named)
- .claude/rules/holding-without-named-dependency-is-standing-by-failure.md
- B-0400 slice 3 (PR #2939) + slice 5 (PR #2959)
- fetch-before-push memory (sibling discipline at git scope)

Co-authored-by: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 840c30254d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .claude/rules/claim-acquire-before-worktree-work.md Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

…aught it doesn't work)

Vera caught: branch-prefix doesn't prevent split-brain because
claim.ts only filters by 'from', not by 'branch'. Two Ottos with
same --from otto but different --branch both succeed (both exit 0).
The branch field is post-hoc metadata, not a coordination key.

Real workarounds reduce to:
1. Lane-based convention (zero-code; ONLY real prevention today)
2. Schema extension (future SENDER_IDS additions)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 030513fb1b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .claude/rules/claim-acquire-before-worktree-work.md Outdated
…orkarounds (Vera P2)

The body of the rule was already corrected (commit 030513f) to remove
branch-prefix as a workaround. The carved sentence wasn't updated.
Vera caught the inconsistency.

Now carved sentence + body both say: lane-based convention is the
ONLY real split-brain workaround today.

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@AceHack AceHack merged commit 5935e76 into main May 13, 2026
25 checks passed
@AceHack AceHack deleted the otto-claim-acquire-before-worktree-work-rule-2026-05-13 branch May 13, 2026 21:40
AceHack added a commit that referenced this pull request May 13, 2026
Real-time observation: Otto-CLI hijacked the primary worktree branch context
while Otto-Desktop was working there, in the SAME session that Otto-CLI
authored PR #3032's claim-acquire-before-worktree rule. The rule was
speculative when proposed; this observation is its first empirical validation.

Files:
- memory/feedback_split_brain_real_time_otto_cli_otto_desktop_primary_worktree_branch_hijack_pr_3032_claim_acquire_rule_validation_2026_05_13.md
- docs/hygiene-history/ticks/2026/05/13/2140Z.md

The memory extends PR #3032's rule operationally — adds 3 clauses beyond
"claim acquire before worktree work":

1. Each Otto gets ONE dedicated worktree (never share primary)
2. Never git checkout on a worktree another Otto is using
3. Bus claim envelope should include 'worktree' field

Composes with PR #3032 (validates), substrate-or-it-didn't-happen
(rules in flight don't apply to behavior in flight),
glass-halo-bidirectional (observation enabled diagnosis).

Co-Authored-By: Claude <noreply@anthropic.com>
AceHack added a commit that referenced this pull request May 13, 2026
…trate-level split-brain fix) (#3037)

* feat(bus): extend SENDER_IDS schema with multi-surface variants (substrate-level fix for split-brain)

Substrate-level mechanization of the split-brain prevention Vera caught
on PR #3032: SENDER_IDS previously only had identity-level names
(otto, alexa, riven, vera, lior), so multi-foreground-surface
instances of the SAME agent looked identical to claim.ts's
`c.from !== sender` filter.

Adds surface-tagged variants while preserving back-compat for the
unsuffixed names:

- otto-cli / otto-desktop (Otto's two active surfaces today)
- alexa-cli / alexa-kiro
- riven-cli / riven-cursor
- lior-antigravity / lior-gemini
- vera-codex

Now `bun tools/bus/claim.ts acquire --from otto-cli --item B-NNNN`
and `--from otto-desktop --item B-NNNN` are DISTINCT claims — the
second exits 1 if the first holds.

All 64 existing bus tests pass — TypeScript's discriminated union
enforces type safety at compile time; runtime SENDER_IDS array
matches.

Composes with:
- .claude/rules/claim-acquire-before-worktree-work.md (PR #3032 merged)
- memory/feedback_aaron_otto_identity_stays_unified_across_surfaces_*
  (PR #3036 merged — identity stays unified; this is the schema fix)
- memory/feedback_aaron_multi_foreground_surface_otto_activation_*
  (PR #3035 merged — operational evidence)
- B-0400 slice 3 (claim-coordinator; this extends its sender space)

Future work: agents should opt in to surface-tagged variants
(otto-cli vs otto). Unsuffixed names still work but don't
distinguish surfaces. Eventually the unsuffixed names can be
deprecated, but back-compat preserved for today.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(rules): SENDER_IDS schema extension landed (PR #3037) — update rule references (Copilot P1)

Copilot caught: rule still said 'schema fix is future work' but the
PR being landed (#3037) ships the extension. Both the carved
sentence and the workarounds-list now reflect the LANDED state.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(bus): claim.ts coverage for multi-surface sender IDs (Copilot P1)

Adds 8 new tests proving the SENDER_IDS schema extension actually
works:

- acquire accepts otto-cli + otto-desktop (surface-tagged)
- CRITICAL: otto-cli and otto-desktop are DISTINCT senders on same
  item — second acquire correctly exits 1 when first holds claim
- alexa-kiro / riven-cursor / lior-antigravity / vera-codex accepted
- Back-compat: identity-level otto still works

Tests: 41 pass / 0 fail / 80 expect() calls (was 33 / ~60).

The split-brain prevention now has empirical test coverage that
proves the schema extension delivers the operational behavior the
rule promises.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(bus/rules): resolve Copilot review threads on PR #3037

- Rename misleading test: "different acquires both succeed" → "same-item
  claim by second surface is rejected" (the test asserted rejection, not
  success — name was inverted from the behavior under test)
- Add missing acceptance tests for alexa-cli, riven-cli, lior-gemini
  (three of the new SENDER_IDS had no per-surface coverage); also add
  cross-surface blocking test for alexa-cli vs alexa-kiro to match the
  otto-cli/otto-desktop pattern
- Update claim-acquire-before-worktree-work.md: remove contradictions
  that framed the schema fix as still "future work" / "KNOWN GAP" after
  PR #3037 landed it; Example 2 now shows the fixed surface-tagged flow,
  Example 3 caption updated to reflect current operational behavior

All 45 claim.test.ts assertions pass.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
AceHack added a commit that referenced this pull request May 13, 2026
… registration (#3034)

* feat(routines): git-tracked Claude Desktop routines substrate + autonomous-loop registration

Aaron asked for a power-user / scripting / version-control path for Claude
Desktop scheduled tasks (the "Routines" sidebar panel), composed with the
existing CLI <<autonomous-loop>> cron substrate. This introduces
tools/routines/ as canonical-source-of-truth for Desktop routines and
registers the first one (autonomous-loop) as a Desktop-side every-2-hour
fallback for the CLI every-minute tick.

Two-layer architecture:

  tools/routines/<id>/       — git-tracked canonical (SKILL.md + schedule.json)
  ~/.claude/scheduled-tasks/ — runtime location, generated from canonical
  tools/routines/install.ts  — idempotent Bun TS installer (rule-0 compliant)

The scheduled-tasks MCP server is cross-host — same server wired into both
CLI Claude Code and Claude Desktop. Both surfaces read/write the same disk
store. This PR makes the prompt-body authoring path git-canonical so
routines are diffable, PR-reviewable, and shareable across maintainer
machines.

Three-layer catch-43 defence now in place:

  1. CLI session cron      — every minute, cheap re-prompt, dies on exit
  2. Desktop routine       — every 2 hours, persistent cold-boot, survives restart
  3. tools/routines/ repo  — git canonical, survives runtime corruption

Composes with:
- .claude/rules/tick-must-never-stop.md (catch-43 substrate)
- .claude/rules/rule-0-no-sh-files.md (TS installer, not bash)
- .claude/rules/holding-without-named-dependency-is-standing-by-failure.md (PR #3029)
- .claude/rules/dv2-data-split-discipline-activated.md (canonical vs runtime change-rate split)
- docs/AUTONOMOUS-LOOP.md (canonical tick procedure)

Tick shard: docs/hygiene-history/ticks/2026/05/13/2125Z.md

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(routines): address PR #3034 reviewer feedback — tsc + portability + testability

Bundles all 7 review findings from PR #3034 into one commit:

install.ts
- Fix tsc exactOptionalPropertyTypes violations (was the BLOCKING required check failure)
- Eliminate TOCTOU races: replace existsSync+readFileSync pairs with try/catch around readFileSync via readFileOrUndefined helper (addresses CodeQL alert)
- Surface invalid schedule.json instead of silently swallowing parse failures: new scheduleParseError field + console.error + parseErrors summary count (Codex P2)
- Export listRoutines/readSchedule/syncRoutine/main with directory parameters so tests can drive deterministically without touching real homedir() or import.meta.dir (Copilot test-coverage suggestion; actual test suite is a follow-up)
- Gate main() under if (import.meta.main) — aligns with other tools/** scripts that use the importable/testable pattern (Copilot)

autonomous-loop/SKILL.md
- Remove hardcoded /Users/acehack/Documents/src/repos/Zeta path from routine prompt (Codex P1, Copilot duplicate). Now portable across maintainer machines via "typically ~/Documents/src/repos/Zeta" guidance + project-metadata fallback. Installer will sync the new prompt to the live runtime SKILL.md on next run; the next routine fire (22:07Z) picks up the portable version.

README.md
- Fix Rule 0 wording: was "only `.sh` allowed there" (implied tools/setup/ is .sh-only); now ".sh files are restricted to under tools/setup/; other formats also live there" (matches .claude/rules/rule-0-no-sh-files.md) (Copilot)

docs/hygiene-history/ticks/2026/05/13/2125Z.md
- Update pr: TBD → pr: 3034 (Copilot — placeholder breaks consumers that parse frontmatter)

Verify trace:
1. npx tsc --noEmit on routines files: clean ✓
2. bun tools/routines/install.ts: [updated] autonomous-loop, parseErrors=0 ✓
3. Runtime SKILL.md at ~/.claude/scheduled-tasks/autonomous-loop/SKILL.md now portable

Follow-up (not in this commit): add bun:test test suite for install.ts (Copilot suggestion; refactor for testability landed here so the suite can land cleanly).

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(lint): markdownlint MD037/MD032 in routines SKILL.md and tick shard

- SKILL.md:16 — wrap cron expression in backtick span to avoid MD037
  (asterisks in "* * * * *" were parsed as emphasis markers)
- 2125Z.md:43 — add blank line before list to satisfy MD032
  (markdownlint requires blank lines surrounding lists)

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(memory): land split-brain empirical observation + tick shard 2140Z

Real-time observation: Otto-CLI hijacked the primary worktree branch context
while Otto-Desktop was working there, in the SAME session that Otto-CLI
authored PR #3032's claim-acquire-before-worktree rule. The rule was
speculative when proposed; this observation is its first empirical validation.

Files:
- memory/feedback_split_brain_real_time_otto_cli_otto_desktop_primary_worktree_branch_hijack_pr_3032_claim_acquire_rule_validation_2026_05_13.md
- docs/hygiene-history/ticks/2026/05/13/2140Z.md

The memory extends PR #3032's rule operationally — adds 3 clauses beyond
"claim acquire before worktree work":

1. Each Otto gets ONE dedicated worktree (never share primary)
2. Never git checkout on a worktree another Otto is using
3. Bus claim envelope should include 'worktree' field

Composes with PR #3032 (validates), substrate-or-it-didn't-happen
(rules in flight don't apply to behavior in flight),
glass-halo-bidirectional (observation enabled diagnosis).

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(memory): add required frontmatter to split-brain observation memory

The non-required CI check "check memory file frontmatter completeness"
flagged the file. Added YAML frontmatter (name/description/type) matching
the convention used by other memory/feedback_*.md files.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(routines): surface missing cronExpression + always emit registration hint

P1: registration hint was gated on action=created|updated, so a
schedule-only change (SKILL.md unchanged) silently skipped the
create_scheduled_task reminder. Remove the action  emitfilter
the hint whenever cronExpression is present, regardless of action.

P2: readSchedule returned { missing: false } with no parseError
when schedule.json parsed but lacked cronExpression, producing a
silent misconfiguration. Now surfaces a descriptive parseError so
the caller prints the malformed-schedule warning.

Addresses chatgpt-codex-connector review threads on PR #3034.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(routines): remove persona-name attribution + clarify schedule.json optionality

Two Copilot review threads on PR #3034:

install.ts (Copilot — BP "No name attribution in code"):
- Doc comment said "ask Otto (or call directly) to run create_scheduled_task"
- Console output said "(in a Claude session, ask Otto to run create_scheduled_task for each)"
- Both replaced with persona-agnostic phrasing:
  "invoke create_scheduled_task from an interactive Claude session (or via direct MCP API call)"

README.md (Copilot — internal consistency):
- Top-level routine description said each routine has SKILL.md + schedule.json without noting schedule.json is optional
- But installer explicitly supports missing schedule.json (ad-hoc routines)
- Now: SKILL.md marked **required**, schedule.json marked **optional** with the ad-hoc clarification both in the bullet list and in the Authoring section

Verify trace:
- bun tools/routines/install.ts → [skipped-unchanged] (idempotent confirmed)
- npx tsc --noEmit → clean on routines files

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(routines): validate cronExpression type + non-zero exit on parse errors (Codex P2 x2)

Two P2 findings from Codex on PR #3034:

1. Reject non-string cronExpression values (PRRT_kwDOSF9kNM6B5oEP):
   readSchedule now narrows parsed.cronExpression via typeof === "string"
   before accepting it. Non-string values (number, null, object) return a
   parseError with the offending type. Defends against schedule.json files
   that happen to round-trip through JSON but have semantically wrong types.

2. Fail installer when schedule parsing reports errors (PRRT_kwDOSF9kNM6B5oEU):
   main() now returns an exit code (0 on success, 1 if parseErrors > 0).
   The if (import.meta.main) entrypoint calls process.exit(main()) so CI
   catches malformed schedule.json files instead of silently counting them
   in the summary and exiting 0.

Verify trace:
- bun tools/routines/install.ts (clean run): exits 0, parseErrors=0 ✓
- npx tsc --noEmit: clean on routines files ✓

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(tick): 2150Z shard — PR #3034 thread sweep + Computer-Use framing correction

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(memory): add missing created field to split-brain observation frontmatter

The memory-index-integrity CI gate requires all four frontmatter
fields: name, description, type, created. The prior fix commit
(459a511) added the other three fields but omitted created.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(routines): more reviewer fixes — persona refs, read-error surfacing, empty cron rejection

Four threads addressed (3 P1 + 2 P2 from Codex/Copilot on PR #3034):

install.ts:
- readFileOrUndefined now distinguishes ENOENT (returns undefined → "missing file") from other errors (re-throws → installer fails loudly). Permission errors, IO failures no longer silently treated as missing. (Codex P2, Copilot P1)
- readSchedule now rejects empty cronExpression strings with parseError "cronExpression must be a non-empty string". (Codex P2)

autonomous-loop/SKILL.md + README.md:
- Remove remaining "Otto" persona attribution per BP "No name attribution in code" on current-state surfaces under tools/. SKILL.md description + first paragraph now use "Autonomous-loop tick" without persona claim. README.md "Ask Otto" rephrased to direct MCP invocation; "Otto bootstream" rephrased to "canonical bootstream" with note that the literal filename is historical-surface substrate. (Copilot P1)

Identity-stays-unified substrate (PR #3036) is preserved — the fresh-session that fires this routine identifies as Otto via the bootstream's Part 1, not via the routine prompt itself. Routine prompt is functional description; identity is established at cold-boot.

Deferred to follow-up row: bun:test coverage for install.ts (Copilot P1 thread 5). Refactor for testability already shipped (exported pure functions accept directory params); actual test suite is its own task — will file as a separate backlog row.

Verify trace:
- bun tools/routines/install.ts: exits 0, parseErrors=0 ✓
- npx tsc --noEmit: clean on routines files ✓

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(routines): listRoutines + missing-SKILL.md surface failures (Codex P1 + P2)

Same silent-failure-prevention pattern as readFileOrUndefined:

1. listRoutines now distinguishes ENOENT (returns empty array — the no

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
AceHack added a commit that referenced this pull request May 13, 2026
…rd + memory (#3041)

* docs(rules): Otto inter-surface communication channels — reference card + memory

Aaron 2026-05-13 asked Otto on both surfaces independently "do yall have a good
way of communicating you should make sure and save it for future versions to
remember." Two complementary observers landed independent partial lists; this
PR synthesizes them as 8 channels in 2 classes (ambient vs explicit) and lands
the substrate as both auto-loaded rule + detailed memory.

Files:
- .claude/rules/otto-channels-reference-card.md (auto-loaded; reference card)
- memory/feedback_otto_inter_surface_communication_channels_8_channels_ambient_vs_explicit_aaron_2026_05_13.md (substantive empirical evidence)

Ambient channels (state-of-the-world; both Ottos read continuously):
  Git, .claude/rules/ auto-load, Bootstream, Tick shards, Memory files, PR review threads

Explicit channels (active signaling; meant to be observed by peer):
  Bus envelopes, Claim coordinator, Routines schedule, Aaron as ferry

Per Otto on CLI 2026-05-13: "the bus is the explicit channel; git is the ambient one."

Empirically validated: today's session exercised all 8 channels — 6 commits on
PR #3034 across both processes (zero conflicts via rebase-on-pull), 3 memory
files landed, PR #3032 rule auto-loaded for future, 9 bus envelopes scanned,
multiple Aaron-as-ferry paste-relays, cross-lane PR thread resolution.

Composes with PR #3032 (claim-acquire), PR #3036 (identity-stays-unified),
PR #3037 (SENDER_IDS schema), B-0444 (bus envelope worktree field), and
the existing wake-time-substrate / glass-halo-bidirectional / substrate-or-it-didn't-happen
rules.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(rules): correct channel count (8→10) + commit count (6→9) consistency

Codex P2 + Copilot P1 findings on PR #3041:
- Carved sentence + 'all 8 channels' references inconsistent with enumerated list (actually 10: 6 ambient + 4 explicit)
- 'Empirical evidence' section claimed 6 commits but commit table lists 9

Both factual inaccuracies. Aligned references throughout:
- '8 channels' → '10 channels' in carved sentence + empirical-evidence header + memory description
- '6 commits' → '9 commits (6 by Otto on Desktop + 3 by Otto on CLI surface)' in empirical evidence
- 'all 8 channels exercised' → 'all 10 channels exercised'

The 'Otto on CLI surfaced 6' / 'Otto on Desktop surfaced 8' counts in the
inter-observer comparison are correct as-is — those refer to standalone
observation counts per surface, not the combined synthesis (= 10).

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants