aboutsummaryrefslogtreecommitdiff
path: root/docs/design
diff options
context:
space:
mode:
Diffstat (limited to 'docs/design')
-rw-r--r--docs/design/2026-05-28-generic-agent-runtime-spec.org77
1 files changed, 64 insertions, 13 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 bd9d60b..243eac3 100644
--- a/docs/design/2026-05-28-generic-agent-runtime-spec.org
+++ b/docs/design/2026-05-28-generic-agent-runtime-spec.org
@@ -378,20 +378,61 @@ subagent (the Agent tool), use that — no second session exists and nothing
here applies. A helper instance is for interactive, long-lived parallel work
Craig drives himself in a second terminal.
-*** Identity and spawn
+*** Detection: an agent discovers it isn't alone (no operator action)
+
+Third revision (Craig, 2026-06-11): the agent detects concurrency itself, so
+the operator can open a plain terminal, run the agent, and say nothing
+special — no env var, no special opener, no launcher flag required.
+
+The signal is a stateless process scan, verified live on 2026-06-11 with four
+concurrent agents: enumerate running agent processes (=pgrep -x claude=),
+read each one's working directory from =/proc/<pid>/cwd=, keep those whose
+cwd is the project root or inside it, and exclude the scanner's own process
+ancestry (walk parent pids from =/proc/self=). What remains is the set of
+/other/ live agents in this project. A small script, =agent-roster=, wraps
+this and prints the others (pid + cwd), exit 0 when alone.
+
+The check is the *first action of every session* — before any pull, rsync,
+or anchor read, because everything startup does next forks on it:
+
+- /Alone, no anchor:/ fresh session. Normal startup.
+- /Alone, anchor exists:/ the previous session crashed. Recover — exactly
+ today's behavior.
+- /Not alone:/ a live primary (or primary + helpers) exists. Skip startup
+ entirely and execute =helper-mode.org= instead.
+
+This also resolves the standing ambiguity in the singleton check: a live
+anchor used to mean only "crashed session"; with the roster it splits into
+crashed (no live process) vs concurrent (live process).
+
+Known limits, accepted for v1: an agent session not running as a local
+process on this machine (a cloud session against the same checkout) is
+invisible to the scan; and the match is on process cwd, so an agent started
+from outside the project tree wouldn't be seen. Both are edge shapes the
+operator created deliberately and can manage manually.
+
+*** Identity and role files
- The primary keeps the unset-id singleton (=.ai/session-context.org=), per
Phase 1's compatibility rule. Zero friction for the overwhelmingly common
one-agent case, and the asymmetry is harmless: the helper's writes land in
=.ai/session-context.d/=, away from the singleton.
-- The launcher assigns helper identity: =ai --helper [project]= detects a live
- anchor (the singleton exists, or =session-context.d/= is non-empty), exports
- =AI_AGENT_ID=helper-<rand4>= (sanitized by =session-context-path=), and names
- the tmux window =<project>:helper-<rand4>=. Spawning a helper into a project
- with /no/ live anchor still works — it just means the "primary" duties below
- have no owner, so the helper warns and runs as a normal full session instead.
-- =--helper= also sets =AI_HELPER=1= so workflows can branch on role without
- parsing the id.
+- A helper self-assigns its identity when detection fires: pick
+ =helper-<rand4>=, record it as the first line of its own context file at
+ =.ai/session-context.d/<id>.org=, and use that path explicitly for the
+ rest of the session (exporting =AI_AGENT_ID= per Bash call where the
+ =session-context-path= resolver is involved). No launcher cooperation
+ needed.
+- =helper-mode.org= (a template workflow, Craig's "helper.org") is the role
+ contract the detection routes to: self-assignment above, the read/write
+ tiers from this section, the light startup, and the helper wrap-up. It is
+ 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.
*** Read/write contract for shared files
@@ -546,11 +587,21 @@ Rationale:
Independent of the phases 2-6 go/no-go; same-runtime only.
-- =ai --helper= flag: live-anchor detection, =AI_AGENT_ID= + =AI_HELPER=
- export, tmux window naming, no-live-anchor warning path.
+- =agent-roster= script: process-scan detection (cwd match within project
+ root, self-ancestry exclusion), exit 0 alone / 1 not-alone, others listed
+ pid + cwd. Bats-tested with fake =/proc=-style fixtures or spawned sleeper
+ processes.
+- Startup gains the detection as its first action, before Phase A.0's pulls:
+ not-alone routes to =helper-mode.org= and runs nothing else; alone keeps
+ today's crashed-vs-fresh anchor logic.
+- =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.
- The shared-file read/write contract documented where agents will obey it
- (protocols.org, with startup.org and wrap-it-up.org carrying the helper
- branches).
+ (protocols.org pointing at =helper-mode.org=, with startup.org and
+ wrap-it-up.org carrying the helper branches).
- Bats tests: id assignment and sanitization through the launcher, helper vs
primary path resolution, two simultaneous context files (extends the
existing =session-context-path= suite).