diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-11 20:05:16 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-11 20:05:16 -0500 |
| commit | 65b99e86d570e489bcd91f377b71193cd7eaba44 (patch) | |
| tree | 346bce8950cb0832f14041ef4d3ab955960607fd | |
| parent | 00fc6f10d132e61adde26613372cf845a5abe776 (diff) | |
| download | rulesets-65b99e86d570e489bcd91f377b71193cd7eaba44.tar.gz rulesets-65b99e86d570e489bcd91f377b71193cd7eaba44.zip | |
docs(spec): deterministic helper spawn and session-end ordering rules
The launcher becomes the spawn mechanism: a shell script runs the roster check, assigns the id, and launches with the helper instructions in order, where a model-followed startup instruction can skip a step. The in-session roster check stays as the safety net for raw launches and still splits a live anchor into crashed versus concurrent.
Session-end ordering was unhandled: a helper outliving the primary stranded a dirty worktree, since the helper may not commit and the agent allowed to is gone. The git ban on helpers is concurrency-scoped, so it lifts when the helper finds itself alone at wrap-up and the last agent out closes the door with the full wrap-up. The mirror case pauses too: a primary wrapping with live helpers stops at the commit and asks whether to sweep the helper's in-flight work, wait, or leave closing to the helper.
| -rw-r--r-- | docs/design/2026-05-28-generic-agent-runtime-spec.org | 63 | ||||
| -rw-r--r-- | todo.org | 3 |
2 files changed, 52 insertions, 14 deletions
diff --git a/docs/design/2026-05-28-generic-agent-runtime-spec.org b/docs/design/2026-05-28-generic-agent-runtime-spec.org index 243eac3..2b451cc 100644 --- a/docs/design/2026-05-28-generic-agent-runtime-spec.org +++ b/docs/design/2026-05-28-generic-agent-runtime-spec.org @@ -429,10 +429,21 @@ operator created deliberately and can manage manually. not operator-triggerable by phrase; startup's detection is its entry point, plus an explicit "you are a helper" instruction as the manual fallback. -- =ai --helper= remains as a convenience (exports =AI_AGENT_ID= and - =AI_HELPER=1=, names the tmux window =<project>:helper-<id>=), but it is - no longer the mechanism — detection is. The flag's value is a clearer - tmux roster and skipping the self-assignment step. +- The launcher is the deterministic spawn path (Craig, 2026-06-11, fourth + revision): a shell script can't skip a step the way a model-followed + instruction can. =ai --helper [project]= does three things in order — + (a) runs =agent-roster= for the target directory, (b) assigns and exports + the id (=AI_AGENT_ID=helper-<rand4>=, =AI_HELPER=1=) when the roster shows + a live agent, and (c) launches the agent in that directory with the + helper opening instruction (read and follow =helper-mode.org=) already in + the prompt. Window named =<project>:helper-<id>=. Roster empty → it warns + and launches a normal primary session instead. +- The in-session startup check (previous subsection) stays as the safety + net, not the mechanism: it catches agents started raw (=claude= in a + terminal, no launcher) and is still what splits a live anchor into + crashed-vs-concurrent. Belt and suspenders: the launcher makes the common + path deterministic; the startup roster keeps the uncommon path safe. + Both call the same =agent-roster= script. *** Read/write contract for shared files @@ -520,13 +531,34 @@ Helper startup is deliberately light: resolve the context path, read its Session Log — the context-contamination rule above), and start working. No pulls, no rsync, no inbox processing, no staleness nudges. -Helper wrap-up: archive its own file to -=.ai/sessions/YYYY-MM-DD-HH-MM-<id>-<desc>.org= (existing rule), skip the -hygiene passes and the commit/push steps, and surface any uncommitted tree -changes it left so the primary or Craig picks them up. A helper that dies -uncleanly leaves its file in =session-context.d/= — the next startup's -existence check surfaces it as an interrupted agent, same as the singleton -today. +Helper wrap-up forks on the roster, because session-end /ordering/ is not +guaranteed — the primary may wrap and leave while helpers keep working +(Craig, 2026-06-11): + +- /Others still live:/ archive its own file to + =.ai/sessions/YYYY-MM-DD-HH-MM-<id>-<desc>.org=, skip the hygiene passes + and the commit/push steps, and surface any uncommitted tree changes so + the remaining agents or Craig pick them up. Today's helper contract. +- /Alone (orphaned helper — the primary already wrapped):/ last agent out + closes the door. Without this, the helper's edits would strand as a dirty + worktree with nobody allowed to commit them. The git ban on helpers + exists for /concurrency/ (index-lock contention, interleaved staging), + and an orphaned helper has no concurrency — so the ban lifts, and the + helper assumes closing duties: the full wrap-up, including hygiene passes + (it is alone; the gate is satisfied), commit through the normal + review/voice flow, and push. + +The mirror case — the /primary/ wrapping while helpers still live — extends +the hygiene gate to the wrap-up commit itself: a wrap-up commit sweeps the +whole tree, including a helper's in-progress edits. With live helpers on the +roster, the primary's wrap-up pauses and asks Craig: commit the helper's +work-in-progress along with its own (the helper's log-before-write journal +shows what was in flight), wait for the helper to finish, or wrap without +the shared-file hygiene and leave the helper to close the door as above. + +A helper that dies uncleanly leaves its file in =session-context.d/= — the +next session's roster-aware startup surfaces it as an interrupted agent, +same as the singleton today. ** Hook and validation strategy @@ -597,8 +629,13 @@ Independent of the phases 2-6 go/no-go; same-runtime only. - =helper-mode.org= template workflow — the role contract: identity self-assignment, the read/write tiers, light start, helper wrap-up. INDEX entry marked auto-routed (no operator trigger phrase). -- =ai --helper= flag as the optional convenience: =AI_AGENT_ID= + =AI_HELPER= - export, tmux window naming. +- =ai --helper= as the deterministic spawn path: roster check, id + assignment + export, launch with the helper-mode opening instruction, + tmux window naming, warn-and-run-primary when the roster is empty. +- Wrap-up ordering rules: helper wrap-up re-runs the roster and assumes + full closing duties (hygiene + commit + push) when orphaned; primary + wrap-up with live helpers pauses at the commit and asks (commit helper + WIP / wait / leave closing to the helper). - The shared-file read/write contract documented where agents will obey it (protocols.org pointing at =helper-mode.org=, with startup.org and wrap-it-up.org carrying the helper branches). @@ -50,7 +50,8 @@ Implement Phase 1.5 of the generic-agent-runtime spec ([[file:docs/design/2026-0 - =agent-roster= detection script (the load-bearing piece, replaces operator action entirely): pgrep + /proc cwd match within project root + self-ancestry exclusion; verified live 2026-06-11 with 4 concurrent agents. Bats coverage. - Startup detection-first: the roster check runs before Phase A.0's pulls; not-alone routes to the new =helper-mode.org= role contract and runs nothing else; alone keeps crashed-vs-fresh anchor logic (the roster also disambiguates crashed primary from live primary). - =helper-mode.org= template workflow: identity self-assignment (helper-<rand4>, recorded in its own .d/ context file), the read/write tiers, light start, helper wrap-up. Auto-routed, no trigger phrase. -- =ai --helper= flag demoted to convenience: AI_AGENT_ID + AI_HELPER export, tmux window naming. +- =ai --helper= as the deterministic spawn path (Craig's shell-script point: a script can't skip the check): roster → id export → launch with the helper-mode opener; warn-and-run-primary on empty roster. The startup roster check stays as the safety net for raw launches. +- Wrap-up ordering: helper wrap-up re-runs the roster — orphaned helper (primary already gone) assumes full closing duties incl. commit+push (the git ban is concurrency-scoped and lifts when alone; otherwise its edits strand as a dirty tree); primary wrap-up with live helpers pauses at the commit and asks (commit helper WIP / wait / leave closing to the helper). - Shared-file read/write contract into protocols.org pointing at helper-mode.org (helper: scoped single-heading org edits only; file-wide passes, inbox processing, and all git mutation stay primary-only); helper branches in startup.org (light path, no pulls/rsync) and wrap-it-up.org (archive own file, skip hygiene + commit). - Bats: launcher id assignment/sanitization, helper-vs-primary resolution, two simultaneous context files. - Data-integrity items (spec second pass, 2026-06-11): live-helper gate before any file-wide hygiene pass (todo-cleanup/lint-org/wrap-org-table check session-context.d/, pause + ask on live files, surface stale ones); todo-cleanup.el brought up to the backup-to-/tmp invariant (lint-org and wrap-org-table already conform — verified); log-before-write journaling for helper shared-file edits; memory writes primary-only (MEMORY.md has no heading anchors — helpers log candidates instead); agent id in helper-originated inbox-send slugs (minute-resolution filenames can collide). |
