@lifeaitools/rdc-skills 0.26.6 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rdc",
3
- "version": "0.26.6",
3
+ "version": "0.28.0",
4
4
  "description": "RDC typed-agent dispatch skill suite for Claude Code — plan, build, review, overnight unattended builds with work-item tracking and TDD enforcement.",
5
5
  "author": {
6
6
  "name": "LIFEAI",
@@ -1402,7 +1402,12 @@
1402
1402
  "name": "action",
1403
1403
  "required": false,
1404
1404
  "default": "status",
1405
- "values": ["status", "install", "repair", "update"]
1405
+ "values": [
1406
+ "status",
1407
+ "install",
1408
+ "repair",
1409
+ "update"
1410
+ ]
1406
1411
  }
1407
1412
  ],
1408
1413
  "flags": []
@@ -1424,7 +1429,9 @@
1424
1429
  "GPU crash"
1425
1430
  ],
1426
1431
  "follows": [],
1427
- "leads_to": ["status"],
1432
+ "leads_to": [
1433
+ "status"
1434
+ ],
1428
1435
  "sandbox_aware": false,
1429
1436
  "output_contract": "guides/output-contract.md",
1430
1437
  "enabled_default": true,
@@ -1580,19 +1587,58 @@
1580
1587
  "category": "reporting",
1581
1588
  "usage": "rdc:behavior-audit <report-dir> [--since-days N] [--latest N] [--reprocess]",
1582
1589
  "args": {
1583
- "positional": [{ "name": "report-dir", "required": true, "description": "Bounded directory for the evidence bundle.", "accepts": "path" }],
1590
+ "positional": [
1591
+ {
1592
+ "name": "report-dir",
1593
+ "required": true,
1594
+ "description": "Bounded directory for the evidence bundle.",
1595
+ "accepts": "path"
1596
+ }
1597
+ ],
1584
1598
  "flags": [
1585
- { "name": "--since-days", "type": "number", "default": 7, "description": "Only include transcripts modified within the window." },
1586
- { "name": "--latest", "type": "number", "default": null, "description": "Limit to the newest N sessions per engine." },
1587
- { "name": "--reprocess", "type": "boolean", "default": false, "description": "Intentionally parse completed hashes again without deleting the ledger." }
1599
+ {
1600
+ "name": "--since-days",
1601
+ "type": "number",
1602
+ "default": 7,
1603
+ "description": "Only include transcripts modified within the window."
1604
+ },
1605
+ {
1606
+ "name": "--latest",
1607
+ "type": "number",
1608
+ "default": null,
1609
+ "description": "Limit to the newest N sessions per engine."
1610
+ },
1611
+ {
1612
+ "name": "--reprocess",
1613
+ "type": "boolean",
1614
+ "default": false,
1615
+ "description": "Intentionally parse completed hashes again without deleting the ledger."
1616
+ }
1588
1617
  ]
1589
1618
  },
1590
- "requires": ["codeflow", "work-items-rpc"],
1591
- "produces": ["work_items", ".rdc/reports/"],
1619
+ "requires": [
1620
+ "codeflow",
1621
+ "work-items-rpc"
1622
+ ],
1623
+ "produces": [
1624
+ "work_items",
1625
+ ".rdc/reports/"
1626
+ ],
1592
1627
  "default_model": "inherit",
1593
- "triggers": ["audit transcript calls", "audit codex behavior", "audit claude behavior", "truth gate audit", "review behavior evidence", "why did the agent bypass the gate"],
1594
- "follows": ["workitems"],
1595
- "leads_to": ["review"],
1628
+ "triggers": [
1629
+ "audit transcript calls",
1630
+ "audit codex behavior",
1631
+ "audit claude behavior",
1632
+ "truth gate audit",
1633
+ "review behavior evidence",
1634
+ "why did the agent bypass the gate"
1635
+ ],
1636
+ "follows": [
1637
+ "workitems"
1638
+ ],
1639
+ "leads_to": [
1640
+ "review"
1641
+ ],
1596
1642
  "sandbox_aware": false,
1597
1643
  "output_contract": "guides/output-contract.md",
1598
1644
  "enabled_default": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifeaitools/rdc-skills",
3
- "version": "0.26.6",
3
+ "version": "0.28.0",
4
4
  "description": "RDC typed-agent dispatch skill suite for Claude Code - plan, build, review, overnight builds",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -0,0 +1,179 @@
1
+ # Collaborator Contract — read this if you were dispatched by `rdc:collab`
2
+
3
+ > **You are the responder.** Another agent (Claude Code, Codex, a local LLM, or a
4
+ > claude.ai session) dispatched you under a structured collaboration protocol.
5
+ > This document is *your* half of it. The initiator's half is
6
+ > [`SKILL.md`](./SKILL.md) in this directory.
7
+ >
8
+ > Link to this file in the dispatch itself so the peer can read it. Do not
9
+ > assume it has been read.
10
+
11
+ ---
12
+
13
+ ## Why this exists
14
+
15
+ A collaboration fails in a specific, repeatable way: the initiator says **what to
16
+ discuss** and never **how to answer**, so the responder answers in whatever shape
17
+ is habitual to it — a file write, a plan document, a lesson, a wall of prose. A
18
+ full round is then spent parsing, arguing with, or discarding the reply.
19
+
20
+ Both halves carry a responsibility. The initiator owes you a format, numbered
21
+ points, and a named writer. You owe it a reply in that format, an honest
22
+ `BLOCKED`, and no unilateral writes.
23
+
24
+ ---
25
+
26
+ ## What you can expect FROM the initiator
27
+
28
+ If any of these is missing, say so in your reply — that is a legitimate answer,
29
+ not an evasion.
30
+
31
+ 1. **A response contract** stated *before* the content — the exact format your
32
+ answer must take.
33
+ 2. **Numbered points.** Unnumbered points get answered in aggregate, which
34
+ settles nothing.
35
+ 3. **A named single writer** for the document or code under discussion, decided
36
+ before round one.
37
+ 4. **Settled points never re-sent.** Each round carries only what is still open,
38
+ plus a one-line record of what was settled.
39
+ 5. **A watchdog, not a nag.** If you go silent the initiator diagnoses first —
40
+ process alive, exit code, guard block, session validity — before re-sending.
41
+ It should not re-dispatch on top of a call you are still working.
42
+ 6. **Escalation, not blame,** when you disagree. A stated disagreement with
43
+ evidence is a valid terminal state.
44
+
45
+ ---
46
+
47
+ ## The boundary — you are in a CONVERSATION, not a build
48
+
49
+ **Do not write to the repository during a collab. Not one file.**
50
+
51
+ This is not a restriction on you; it is what a collab *is*. Your deliverable is
52
+ the **reply**. If settling the point requires code, config, or a document change,
53
+ say what should change — the change itself happens afterward, in a session built
54
+ for it (`rdc:build`, an isolated worktree agent, or you working your own lane
55
+ against a work item).
56
+
57
+ **Why it matters to you specifically:** a peer that tries to write mid-conversation
58
+ can end up holding finished, correct work it cannot deliver — refused by a write
59
+ guard, then refused permission to stop by a gate demanding the delivery evidence
60
+ that guard just made impossible. That happened on 2026-08-14 and cost a complete
61
+ negotiation result. **Your reasoning in the reply is always deliverable. A file
62
+ write may not be.**
63
+
64
+ ---
65
+
66
+ ## What you owe BACK — your responsibilities
67
+
68
+ ### 1. Answer in the required format. Nothing outside it.
69
+
70
+ If the dispatch gives you a contract, use it verbatim. Prose around the blocks
71
+ is not helpful — it is what the format exists to remove.
72
+
73
+ **One block per point:**
74
+
75
+ ```
76
+ POINT <n>: AGREE | AGREE-WITH-AMENDMENT | DISAGREE
77
+ EDIT: <the exact section and change that SHOULD be made, or NONE — describe it, do not make it>
78
+ REASON: <one sentence — only if AMENDMENT or DISAGREE>
79
+ ```
80
+
81
+ **For a factual question rather than a proposal:**
82
+
83
+ ```
84
+ FINDING <n>: <the answer, one sentence>
85
+ EVIDENCE: <command run + literal result — exit code, row count, probe status>
86
+ CONFIDENCE: VERIFIED | INFERRED | UNKNOWN
87
+ ```
88
+
89
+ **Always close with:**
90
+
91
+ ```
92
+ OWNER: <who lands the resulting Decision or work item — exactly one agent>
93
+ BLOCKED: <what you cannot do from where you are, or NONE>
94
+ ```
95
+
96
+ ### 2. Declare `BLOCKED` loudly. Silence is the worst answer.
97
+
98
+ If you cannot write, cannot reach a service, or lack the credential — **say it in
99
+ the reply**. A blocked responder that goes quiet is indistinguishable from a dead
100
+ one, and it costs the initiator a full watchdog cycle to discover what you
101
+ already knew.
102
+
103
+ **Your completed reasoning still counts when your write is blocked.** Put the
104
+ answer in the reply body. Do not let it die inside a failed tool call.
105
+
106
+ ### 3. Do not write outside your own lane or scope.
107
+
108
+ - **Codex:** if you were started by `codex exec` (headless), you CANNOT write in any lane — your managed identity was never minted and `-C` does not create it. Report `BLOCKED: headless codex exec has no lane claim` and put your answer in the reply. If you were started by the launcher in a Codex-owned lane (`x-codex-N`, `x-codex-sv`), you can write, but not during a collab.
109
+ A session created in the wrong cwd is poisoned for its whole life — `resume` replays the recorded identity. Writes are refused with
110
+ `CODEX MANAGED LANE: App Local must use an owned managed Codex lane`. That is a
111
+ **dispatch defect, not your failure** — report it as `BLOCKED: poisoned session identity, start a NEW session in
112
+ my lane` — `-C` will NOT repair it. Do not attempt a workaround.
113
+ - **Claude agents:** if you will commit, you must have been given
114
+ `isolation: "worktree"` as a real tool parameter. A sentence in your prompt
115
+ claiming isolation is inert.
116
+ - **Everyone:** never `git stash` in a shared checkout, never force-push, never
117
+ commit onto a branch you were not told to use. If the branch you land on is
118
+ someone else's, say so rather than committing "just this once".
119
+
120
+ ### 4. Do not take ownership you were not given.
121
+
122
+ Exactly one agent writes each artifact. If you were not named the writer, put
123
+ your change in the **reply**, not in the file. Two writers on one surface loses
124
+ work with no error.
125
+
126
+ If the named writer is you and you are blocked, say so — ownership transfers
127
+ explicitly, never by assumption.
128
+
129
+ ### 5. An agreement is a Decision, not an episode.
130
+
131
+ When a negotiation settles, the outcome belongs in the **governing document** —
132
+ the plan, the ARCHITECTURE.md, the rule — where it becomes queryable
133
+ architecture. **Do not file a settled agreement as a lesson.** Lessons are for
134
+ episodes: a root-cause theory that proved wrong, a documented path that did not
135
+ work, a surprising tool behaviour. A settled negotiation filed as a lesson buries
136
+ a constraint in an append-only pile nobody traverses.
137
+
138
+ ### 6. Answer the point that was asked.
139
+
140
+ If you disagree with the framing, say `DISAGREE` and give the reason in one
141
+ sentence — do not silently answer a different, easier question. If a point is
142
+ unanswerable without information you do not have, say that in `REASON` and name
143
+ what would settle it.
144
+
145
+ ### 7. Do not restate what is already settled.
146
+
147
+ The initiator sends only open points. Re-litigating a settled one restarts a
148
+ negotiation that was converging.
149
+
150
+ ---
151
+
152
+ ## Terminal states — any of these is a complete, legitimate answer
153
+
154
+ | State | Meaning |
155
+ |---|---|
156
+ | All points `AGREE` | Converged. The named writer applies the edits. |
157
+ | Some `DISAGREE` with reasons | A real disagreement. Escalates as a packet, not a transcript. |
158
+ | `BLOCKED` on everything | You cannot act from where you are. Name the fix. |
159
+ | A point needs evidence neither side has | Name the measurement that would settle it. |
160
+
161
+ **"I could not do it and here is exactly why" outranks a plausible answer you are
162
+ not confident in.** The initiator can act on a precise blocker immediately; it
163
+ cannot act on a guess it has to verify.
164
+
165
+ ---
166
+
167
+ ## Anti-patterns — these each cost a full round
168
+
169
+ | Anti-pattern | Why |
170
+ |---|---|
171
+ | Answering in prose when a format was given | The initiator has to parse and may misread you |
172
+ | Writing a file instead of replying | Your answer may be guard-blocked and lost |
173
+ | Filing a settled agreement as a lesson | Buries a queryable Decision |
174
+ | Going silent when blocked | Indistinguishable from being dead |
175
+ | Editing a document you do not own | Lost work, no error, no trace |
176
+ | Writing ANY file during a collab | Not your job here — the reply is the deliverable |
177
+ | Committing to whatever branch you happen to be on | The change strands where nobody looks for it |
178
+ | Answering an easier adjacent question | The real point stays open and looks settled |
179
+ | Attempting a workaround for a guard block | The guard is usually right; the dispatch is usually wrong |
@@ -1,239 +1,361 @@
1
1
  ---
2
2
  name: rdc:collab
3
- description: "Usage `rdc:collab --session <session_id>` — Bidirectional relay with a claude.ai session — read inbox, do work, write outbox, loop. Use when coordinating with a parallel claude.ai conversation."
3
+ description: "Usage `rdc:collab <collaborator> [inbound] <topic>` — Structured agent-to-agent CONVERSATION with Codex, a local LLM, a Claude agent, or a claude.ai session. Converges on a decision and never writes to the repo work that needs writing becomes a work item for rdc:build. Every dispatch carries a response contract."
4
4
  ---
5
5
 
6
6
  > **⚠️ OUTPUT CONTRACT (READ FIRST):** `guides/output-contract.md`
7
7
  > Checklist-only output. No tool-call narration. No raw MCP/JSON/log dumps.
8
8
  > One checklist upfront, updated in place, shown again at end with a 1-line verdict.
9
9
 
10
- > **Sandbox contract:** This skill honors `RDC_TEST=1` per `guides/agent-bootstrap.md` § RDC_TEST Sandbox Contract. Destructive external calls short-circuit under the flag. Chitchat relay writes (`chitchat_reply`) and git push are skipped under `RDC_TEST=1`.
10
+ > **Sandbox contract:** This skill honors `RDC_TEST=1` per `guides/agent-bootstrap.md` § RDC_TEST Sandbox Contract. Destructive external calls short-circuit under the flag. Chitchat relay writes (`chitchat_reply`), engine dispatch, and git push are skipped under `RDC_TEST=1`.
11
11
 
12
+ # /rdc:collab — Structured Agent-to-Agent Collaboration
12
13
 
13
- # /rdc:collab Claude Code Collab Session Listener
14
- > Invoked as: `/rdc:collab --session <session_id>`
15
- > You are the build/execute half of a live collab session with claude.ai.
16
- > Transport: chitchat MCP tools (`chitchat_poll` / `chitchat_reply`) + SSE stream
17
- > Dave is watching this terminal and can interject at any time.
14
+ > `rdc:collab <collaborator> [inbound] <topic>`
15
+ > Collaborators: `codex` · `local-llm` · `claude-agent` · `claude-ai`
16
+ > Direction: outbound (default, you dispatch) · `inbound` (claude.ai relay, peer initiates)
18
17
 
19
18
  ---
20
19
 
21
- ## When to Use
22
- - Project lead wants to delegate a task to a claude.ai session
23
- - You need bidirectional relay between this CLI agent and a claude.ai coworker
24
- - An async work handoff is in progress via the chitchat relay
20
+ ## Collab is CONVERSATION. It never writes to the repo.
21
+
22
+ **There is one mode, because there was only ever one.** v0.27.0 shipped a
23
+ `delegate` mode whose contract asked the peer for `CHANGED: <file paths>` — an
24
+ instruction to go mutate the repo and report back. Handing work off is a real
25
+ need; routing it through a *conversation channel* is a category error. Work goes
26
+ to `rdc:build`, to an `Agent` with `isolation: "worktree"` as a real parameter, or
27
+ to a launcher-started session working its own lane against a work item. Those have
28
+ isolation, a work item, review, and landing. A chat channel has none of them.
29
+
30
+ **This is a design boundary, not a workaround for a broken door.** A separate,
31
+ real constraint exists — a headless `codex exec` peer currently cannot write at
32
+ all (see the note under Step 1) — but that constraint is a **bug being fixed**,
33
+ not the reason for this rule. Even once headless Codex can write, work handoff
34
+ still goes through the build path. Do not read the boundary as "collab can't
35
+ write"; read it as "collab isn't where writing belongs."
36
+
37
+ **The boundary:**
38
+
39
+ | Collab does | Collab never does |
40
+ |---|---|
41
+ | Ask, answer, converge, disagree | Edit a file |
42
+ | Produce a **Decision** for the governing document | Commit or push |
43
+ | Produce a **work item** when writing is required | Build, deploy, or land |
44
+ | Return findings, verdicts, evidence *as text* | Claim to have changed anything |
45
+
46
+ **When code must be written, collab is over.** Its output is a work item, and the
47
+ writing happens where writing belongs — `rdc:build`, an `Agent` with
48
+ `isolation: "worktree"` as a real parameter, or the peer working its own lane
49
+ against that item. A conversation channel is not a build channel.
50
+
51
+ **Why this is structural, not a style rule.** Because collab never mutates, a
52
+ collab session is non-mutating *by definition* — there is no mode to select
53
+ wrongly and no flag to leave on. Delivery gates (truth-gate, completion gate,
54
+ CodeFlow preflight) have nothing to gate, and safety guards (credential exposure,
55
+ cross-tree write, push-main, lane identity) remain fully live because nothing
56
+ here goes near them. The peer that tries to write is not blocked by policy; it is
57
+ simply doing something this skill never asks for.
25
58
 
26
- ## Arguments
27
-
28
- - `rdc:collab --session <id>` — start or resume a collab relay with the given session ID
29
-
30
- ## What This Is
59
+ ---
31
60
 
32
- claude.ai writes tasks into your inbox via `chitchat_send`. The clauth daemon
33
- queues them and if you are connected to the SSE stream pushes the event
34
- immediately (zero-latency). You read, act, commit, reply via `chitchat_reply`,
35
- and loop. Dave can watch everything in this terminal and interject by typing —
36
- treat anything Dave types as a high-priority override.
61
+ > **Two halves.** This file is the **initiator's** contract how to dispatch,
62
+ > what to demand, how to bound it. [`COLLABORATOR.md`](./COLLABORATOR.md) is the
63
+ > **responder's** contract what the peer owes back and what it may expect from
64
+ > you. **Link `COLLABORATOR.md` in every dispatch**; a contract only one side has
65
+ > read is a contract only one side keeps.
37
66
 
38
67
  ---
39
68
 
40
- ## Step 1 Parse session ID
69
+ ## The rule this skill exists to enforce
41
70
 
42
- Extract `--session <uuid>` from args.
71
+ **Never dispatch to another agent without a response contract.**
43
72
 
44
- If no `--session`, call `chitchat_list` and show all active sessions.
73
+ An agent asked an open question answers in whatever shape is habitual to it — a
74
+ file write, a plan, a lesson, a wall of prose. It is not being unhelpful; you
75
+ did not tell it how to answer. A dispatch without a contract produces output you
76
+ then have to parse, argue with, or discard, and it costs a full round every time.
77
+
78
+ **Corollary: an agreement is a Decision, not an episode.** When collaboration
79
+ settles a question, the output belongs in the governing document (and therefore
80
+ in AKG) as a decision/constraint/policy — never filed as a lesson. Lessons are
81
+ for *episodes*: something was learned the hard way. A settled negotiation filed
82
+ as a lesson buries a queryable constraint in an append-only pile nobody
83
+ traverses.
45
84
 
46
85
  ---
47
86
 
48
- ## Step 2 Initialize (chitchat-native)
87
+ ## Two clocks: the reply drives, a watchdog bounds
88
+
89
+ Both are required, and they do different jobs. Running either alone is a known
90
+ failure:
91
+
92
+ | | Driver | Watchdog |
93
+ |---|---|---|
94
+ | What it is | the collaborator's reply | a `/loop` or `Monitor`, armed at dispatch |
95
+ | Fires on | completion | **silence past the expected envelope** |
96
+ | Job | advance the negotiation | **diagnose why nothing came back** |
97
+ | Cadence | none — event-driven | ~2–3× the peer's normal reply time |
98
+
99
+ **Driver alone → you wait forever.** A background dispatch with no timeout is
100
+ correct about not guessing a duration and wrong about liveness: if the peer dies,
101
+ is guard-blocked, or its session id has expired, nothing ever wakes you. This is
102
+ the failure the watchdog exists to catch.
103
+
104
+ **Watchdog alone → you fire on top of live calls.** A wall-clock cadence has no
105
+ relationship to the work: if the peer answers in 30s you idle the remainder, if
106
+ it takes 8 minutes you stack a second call onto the first.
107
+
108
+ ### The watchdog does NOT retry. It investigates.
109
+
110
+ Re-dispatching a silent peer is the wrong reflex — it doubles the load on
111
+ something already failing and destroys the evidence of why. On wake, run the
112
+ diagnosis ladder in order and stop at the first hit:
113
+
114
+ 1. **Is the process alive?** Check the background task's status. Still running is
115
+ a legitimate answer — re-arm the watchdog with a longer envelope and stop.
116
+ 2. **Did it exit, and with what?** A non-zero exit or exit 143 (killed) is a
117
+ result, not silence. Read it.
118
+ 3. **Was it guard-blocked?** Grep the output for a `deny`/`Blocked` line. The
119
+ `CODEX MANAGED LANE` block is the common one and is a *dispatch* defect
120
+ (wrong `-C`), not a peer failure — fix and re-dispatch once.
121
+ 4. **Is the session still addressable?** A stale `resume <session-id>`, a stopped
122
+ chitchat session, or a dead local-LLM endpoint all present as silence.
123
+ 5. **Did it answer somewhere you are not reading?** A peer that cannot write its
124
+ intended target often reports into stdout, a log, or an error body instead.
125
+ The answer may already exist.
126
+ 6. **None of the above** → the peer is genuinely stuck. Escalate per Step 6 with
127
+ the ladder's findings attached. Do not silently retry.
128
+
129
+ Arm the watchdog **at dispatch**, disarm it **on reply**. An armed watchdog
130
+ outliving its dispatch is noise, and noise is how a real stall gets ignored.
131
+
132
+ ---
49
133
 
50
- Call `chitchat_list` to verify the session exists in the daemon.
134
+ ## Step 0 Parse arguments
51
135
 
52
- If the session is not found:
53
136
  ```
54
- Session <id> not found in clauth daemon.
55
- Start a session from claude.ai first:
56
- chitchat_start(name: "<session-slug>")
57
- Then pass the returned session_id here.
137
+ rdc:collab <collaborator> [mode] <topic…>
138
+ rdc:collab --session <id> ← legacy form, implies `claude-ai listen`
58
139
  ```
59
140
 
60
- Send the ready signal via MCP:
61
- ```
62
- chitchat_reply(session_id, "Claude Code connected. Ready to receive tasks.\ncwd: <rootPath>")
63
- ```
141
+ - No collaborator list active chitchat sessions and available engines, then stop.
142
+ - `inbound` (or the legacy `--session <id>` form) → the peer initiates; see the
143
+ claude.ai relay section. Same conversation, opposite direction.
144
+ - **If the topic names work to be performed rather than a question to settle, this
145
+ is the wrong skill.** Create the work item and use `rdc:build` / `rdc:fixit`.
64
146
 
65
- Print to terminal:
66
- ```
67
- [rdc:collab] Session <id> active (chitchat transport).
68
- SSE stream: http://127.0.0.1:52437/chitchat/<id>/stream
69
- Waiting for messages from claude.ai... (Ctrl+C to end)
70
- ```
147
+ ---
71
148
 
72
- Note: File relay at `.rdc/relay/sessions/` is kept for backwards compatibility
73
- but is no longer the primary transport. Chitchat MCP + SSE is the default.
149
+ ## Step 1 Collaborator matrix
150
+
151
+ Resolve the transport BEFORE composing the message. Getting this wrong is the
152
+ most common failure and it fails at the guard layer, not the prompt layer.
153
+
154
+ | Collaborator | Invocation | Isolation requirement | Known failure mode |
155
+ |---|---|---|---|
156
+ | **`codex`** | `codex exec [-C <dir>] "<msg>"` · resume: `codex exec resume <session-id> "<msg>"` | **A headless `codex exec` peer is READ-ONLY. It cannot write to any lane — see below.** Never dispatch it from your own lane. | Its managed identity is fixed at session creation and `-C` does **not** change it. Dispatch from your lane and every write is refused with `CODEX MANAGED LANE: App Local must use an owned managed Codex lane` — permanently, for that session's whole life. |
157
+
158
+ > **`-C` does not establish lane identity — verified 2026-08-14, and an earlier
159
+ > version of this table said the opposite.** Managed identity is an 8-field record
160
+ > (`lane, role, repoIdentity, ownerPid, ownerStartFingerprint, sessionId,
161
+ > leaseEpoch, ownerToken`) built by `buildStartupIdentity()` in
162
+ > [`pool/codex-topology.mjs`](file:///C:/Dev/lifeai-env/pool/codex-topology.mjs)
163
+ > and minted **only by the interactive launcher**, which also claims the lease.
164
+ > `codex exec` has no lane-claim path, so it cannot produce that record — which
165
+ > means **a headless Codex peer cannot write in any lane, including its own**.
166
+ >
167
+ > Two consequences: (1) `resume` replays the session's *recorded* identity, so a
168
+ > session created in the wrong cwd is poisoned for life and `-C` will not repair
169
+ > it — start a new session instead; (2) treat a `codex exec` peer as a
170
+ > conversational participant only. Writing work belongs to a launcher-started
171
+ > Codex session, `rdc:build`, or an isolated-worktree agent.
172
+ >
173
+ > Beware the error text: `App Local denied: <lane> has a foreign live lease` also
174
+ > fires when there is **no lease at all** (`ownerMatchesLease` returns false for a
175
+ > null lease), so it will send you hunting a conflicting owner that does not exist.
176
+
177
+ file:///C:/Dev/lifeai-env/pool/codex-topology.mjs
178
+ | **`local-llm`** | local endpoint per `.claude/context/clauth.md`; credential via `curl -s http://127.0.0.1:52437/v/<service>` | none (no repo attachment) | Small context windows: send the contract and the open points, never the whole document. Link paths instead of pasting files. |
179
+ | **`claude-agent`** | `Agent` tool, or `claude -p --bare` / `claude --bg` | **`isolation: "worktree"` as an actual tool parameter** if it will commit — a prose claim of isolation is inert | Parallel agents on a shared checkout race on `git stash` and `.git/index`. See `.claude/rules/subagent-credentials.md`. |
180
+ | **`claude-ai`** | chitchat MCP (`chitchat_send` / `chitchat_poll` / `chitchat_reply`) + SSE | session-scoped | Messages evaporate when the session stops — export durable decisions to TinTin. |
181
+
182
+ **Dispatch is long-running.** Run engine dispatch as a **background task**, not
183
+ behind a `timeout` guess. A truncated call looks like a failure and is not one.
74
184
 
75
185
  ---
76
186
 
77
- ## Step 3Wait for message (SSE-first, poll-fallback)
187
+ ## Step 2Compose the response contract (mandatory)
78
188
 
79
- ### Primary path SSE (zero-latency)
189
+ Every dispatch carries an explicit answer format. The contract is not politeness —
190
+ it is what makes the reply *checkable*.
80
191
 
81
- Connect to the SSE stream and wait for the daemon to push a message:
192
+ **Every field returns information. No field asks the peer what it changed** — if a
193
+ contract invites `CHANGED: <file paths>`, it has invited the peer to mutate the
194
+ repo mid-conversation, which is the v0.27.0 defect this version removes.
82
195
 
83
- ```bash
84
- curl -s -N --max-time 30 http://127.0.0.1:52437/chitchat/<session_id>/stream
85
- ```
196
+ **The contract — one block per open point:**
86
197
 
87
- The stream emits:
88
- - `event: message` lines with `data: <JSON>` when `chitchat_send` fires from claude.ai
89
- - `: keepalive` comment lines every 15s (ignore these)
198
+ ```
199
+ POINT <n>: AGREE | AGREE-WITH-AMENDMENT | DISAGREE
200
+ EDIT: <the exact section and change that SHOULD be made, or NONE — describe it, do not make it>
201
+ REASON: <one sentence — only if AMENDMENT or DISAGREE>
202
+ ```
90
203
 
91
- **When a `data:` event arrives:** parse the JSON directly it contains the
92
- message. The SSE stream drains the inbox as it delivers; do NOT call
93
- `chitchat_poll` after receiving via SSE. Proceed directly to Step 4 with the
94
- parsed message body.
204
+ **When the point is a factual question rather than a proposal**, the peer answers
205
+ with findings still text, still no repo mutation:
95
206
 
96
- **If 30s elapses with no message event (only keepalives or silence):**
97
- Print `[rdc:collab] Still listening...` and retry SSE immediately. After 10
98
- consecutive 30s timeouts (5 min idle), print a longer heartbeat but keep
99
- looping.
207
+ ```
208
+ FINDING <n>: <the answer, one sentence>
209
+ EVIDENCE: <command run + literal result exit code, row count, probe status>
210
+ CONFIDENCE: VERIFIED | INFERRED | UNKNOWN
211
+ ```
100
212
 
101
- **⛔ curl exit 28 (`--max-time`) is SUCCESS, not failure, on an SSE read.**
102
- `curl --max-time 30` ALWAYS exits 28 at the timeout boundary — that is normal for
103
- a long-lived SSE stream and says nothing about delivery. If a `data:` event was
104
- received in the output, process it and proceed to Step 4 — do NOT treat exit 28 as
105
- a curl failure (lesson 2026-06-08-collab-sse-exit-28-is-success: exit 28 arrived
106
- together with a full `event: message` / `data: {...}` payload, and reading it as a
107
- failure misclassified a zero-latency delivery). Only **connection-refused or a
108
- non-200** is a real curl failure that triggers the polling fallback.
213
+ Rules that make the contract hold:
109
214
 
110
- **If curl fails (daemon restart, connection refused, non-200 NOT a bare exit 28
111
- with a delivered `data:` event):** fall back to polling path below.
215
+ 1. **State the format before the content.** Contract first, then the points.
216
+ 2. **Say what NOT to produce** when the peer has a known default — e.g. *"do not
217
+ write a lesson; this is a Decision and belongs in the plan."*
218
+ 3. **Number the points.** Unnumbered points get answered in aggregate.
219
+ 4. **Name the single writer before round 1** (see Step 4).
220
+ 5. **Ask for `BLOCKED` explicitly.** Without it, a peer that cannot act reports
221
+ success or silence.
112
222
 
113
- ### Fallback path — polling (2s interval)
223
+ ---
114
224
 
115
- Use this path only when SSE is unavailable:
225
+ ## Step 3 Converge
116
226
 
117
227
  ```
118
- loop:
119
- result = chitchat_poll(session_id)
120
- if result.status == "ready":
121
- proceed to Step 4 with result.message
122
- else (status == "idle"):
123
- wait 2 seconds
124
- continue loop
228
+ open_points = [all points]
229
+ round = 0
230
+ while open_points and round < MAX_ROUNDS (default 4):
231
+ round += 1
232
+ dispatch(open_points, contract) ← background task, no timeout guess
233
+ arm_watchdog(envelope = 2-3x expected reply time)
234
+ reply = await completion ← OR watchdog fires first
235
+ if watchdog fired: run the diagnosis ladder; do NOT re-dispatch blindly
236
+ disarm_watchdog()
237
+ if reply does not match the contract:
238
+ re-dispatch ONCE restating the format only — never re-argue the content
239
+ settle: AGREE and accepted AGREE-WITH-AMENDMENT leave open_points
240
+ if open_points did not shrink this round:
241
+ STOP — escalate (Step 6). A non-shrinking round means the disagreement
242
+ is real, and further rounds spend tokens without moving it.
125
243
  ```
126
244
 
127
- **`chitchat_poll` return shapes:**
128
- - `{ status: "idle" }` inbox empty, keep polling
129
- - `{ status: "ready", message: "..." }` — message waiting, consume it
245
+ **Never re-send a settled point.** Each round carries only what is still open,
246
+ plus a one-line record of what was settled. Re-sending settled points is how a
247
+ negotiation becomes a loop that never terminates.
130
248
 
131
- ---
249
+ **Convergence is the termination condition, not a timer.**
132
250
 
133
- ## Step 4 — Process message
134
-
135
- You now have the message body (from SSE `data:` JSON or `chitchat_poll` result).
251
+ ---
136
252
 
137
- Check if the message begins with `type: stop` (literal prefix) or contains a
138
- `type` field equal to `"stop"` in the JSON.
253
+ ## Step 4 Single-writer rule (for the OUTCOME, not the conversation)
139
254
 
140
- **`type: stop`** go to Step 7.
255
+ Nobody writes during a collab. The single-writer rule governs **who lands the
256
+ settled Decision afterward** — name that agent before round 1 and say so in the
257
+ dispatch.
141
258
 
142
- **Anything else (default: task/message):**
259
+ > Two active writers on one surface is forbidden — the same rule the fleet plans
260
+ > state as *"never run two active writers for one effect."*
143
261
 
144
- Print to terminal:
145
- ```
146
- [rdc:collab] Turn <N> from claude.ai:
147
- ──────────────────────────────────────
148
- <message body>
149
- ──────────────────────────────────────
150
- ```
262
+ If the named writer turns out to be **structurally blocked** (wrong lane, no
263
+ credentials, read-only mount), ownership transfers to the other agent *for that
264
+ artifact only*, recorded in the change itself with attribution. A blocked writer
265
+ never means the agreed work is abandoned — the reasoning already exists in the
266
+ reply, which is exactly why the reply, not a file, is the deliverable.
151
267
 
152
268
  ---
153
269
 
154
- ## Step 5 — Do the work
270
+ ## Step 5 — Land the outcome
155
271
 
156
- Act on the message. Full Claude Code capabilities:
157
- - File edits, git commits to `develop`
158
- - Supabase RPC queries
159
- - Type-checks: `npx tsc --noEmit` (never `pnpm build`)
160
- - Run skills: `/rdc:plan`, `/rdc:fixit`, etc.
161
- - Answer questions directly
272
+ An agreement is a **Decision**. Route it by kind:
162
273
 
163
- Follow `.rdc/guides/agent-bootstrap.md` rules throughout.
274
+ | Outcome | Home |
275
+ |---|---|
276
+ | Settled decision, constraint, or policy | The governing document — plan / ARCHITECTURE.md / rule. AKG ingests from there. |
277
+ | Work to perform | `insert_work_item` via RPC, per `.claude/rules/work-items-rpc.md` |
278
+ | A genuine hard-won episode (a wrong theory, a surprising infra behaviour) | `.rdc/lessons/` per `guides/lessons-learned-spec.md` |
279
+ | A stated, unresolved disagreement | Escalate — Step 6 |
164
280
 
165
- For long tasks, stream progress updates mid-work:
166
- ```
167
- chitchat_reply(session_id, "Turn <N> in progress: <what you've done so far>...")
168
- ```
169
- This lets claude.ai see progress immediately rather than waiting for the full
170
- response.
281
+ **Do not file a settled agreement as a lesson.** That is the single most common
282
+ misroute this skill exists to prevent.
171
283
 
172
284
  ---
173
285
 
174
- ## Step 6 — Send response
175
-
176
- When work is done, send the response via MCP:
286
+ ## Step 6 — Escalate (only after convergence fails)
177
287
 
178
- ```
179
- chitchat_reply(session_id, "<response body>")
180
- ```
288
+ Escalation is the last step, never the first. It happens when a round fails to
289
+ shrink the open set, the round cap is hit, or both agents are blocked.
181
290
 
182
- Response body format:
183
- ```
184
- Turn <N> complete.
185
- Commits: <sha1, sha2 or none>
186
-
187
- <what you did, what you found, any questions or decisions needed from claude.ai>
188
- ```
291
+ Escalate as **one packet**, not a transcript:
189
292
 
190
- Print to terminal:
191
293
  ```
192
- [rdc:collab] Turn <N> done. Response sent via chitchat_reply.
193
- Waiting for next message...
294
+ UNRESOLVED: <the point, in one sentence>
295
+ POSITION A (<agent>): <claim + its evidence>
296
+ POSITION B (<agent>): <claim + its evidence>
297
+ WHAT WOULD SETTLE IT: <the measurement, probe, or decision needed>
298
+ COST OF EACH BRANCH: <one line each>
194
299
  ```
195
300
 
196
- Return to Step 3.
301
+ A transcript is not an escalation. If the human has to read the argument to find
302
+ the question, the packet was not written.
197
303
 
198
304
  ---
199
305
 
200
- ## Step 7End session
306
+ ## `listen` modeclaude.ai relay
201
307
 
202
- Received `type: stop` message, or Dave pressed Ctrl+C.
308
+ Legacy behaviour, unchanged and still correct for `claude-ai`. Transport is
309
+ chitchat MCP + SSE; you are the build half of a live session.
203
310
 
204
- Send final summary via MCP:
205
- ```
206
- chitchat_reply(session_id, "Session complete.\nTurns: <N>\nCommits: <list or none>\nOpen items: <anything unresolved>")
207
- ```
311
+ - `chitchat_list` to verify the session; `chitchat_reply` to signal ready.
312
+ - SSE first: `curl -s -N --max-time 30 http://127.0.0.1:52437/chitchat/<id>/stream`.
313
+ **⛔ curl exit 28 is SUCCESS on an SSE read** — `--max-time` always exits 28 at
314
+ the boundary. If a `data:` event arrived, process it. Only connection-refused
315
+ or a non-200 is a real failure (lesson `2026-06-08-collab-sse-exit-28-is-success`).
316
+ - Poll fallback: `chitchat_poll` at 2s — `{status:"idle"}` keep polling,
317
+ `{status:"ready", message}` consume.
318
+ - `type: stop` ends the session; send a final summary, then `chitchat_stop`.
319
+ - Stream progress mid-work with `chitchat_reply` on long tasks.
208
320
 
209
- Then call:
210
- ```
211
- chitchat_stop(session_id)
212
- ```
321
+ ---
213
322
 
214
- Print:
215
- ```
216
- [rdc:collab] Session ended.
217
- ```
323
+ ## Dave interjections
324
+
325
+ Anything Dave types is a high-priority override, in every mode.
326
+
327
+ ⛔ **When an interjection appears to CONTRADICT the task premise, restate your
328
+ understanding in ONE sentence and confirm before branching into a wide
329
+ `AskUserQuestion` menu.** A tight "I read this as X — correct?" reconciles faster
330
+ and avoids acting on a misread premise (lesson
331
+ `2026-06-08-collab-premise-contradicting-interjection`).
218
332
 
219
333
  ---
220
334
 
221
- ## Dave Interjections
335
+ ## Anti-patterns
336
+
337
+ | Anti-pattern | Why it costs a round |
338
+ |---|---|
339
+ | Dispatching prose with no response contract | The peer answers in its habitual shape; you parse or discard it |
340
+ | Filing a settled agreement as a lesson | Buries a queryable Decision in an append-only pile |
341
+ | Driving a negotiation with `/loop` | The clock has no relationship to the reply |
342
+ | Dispatching with no watchdog armed | A dead peer is indistinguishable from a slow one; you wait forever |
343
+ | Watchdog re-dispatches instead of diagnosing | Doubles load on a failing peer and destroys the evidence of why |
344
+ | `codex exec` without `-C <its-lane>` | Codex inherits your lane; every write is guard-blocked |
345
+ | Re-sending settled points each round | The negotiation cannot terminate |
346
+ | Wrapping dispatch in a `timeout` guess | A still-running call reads as a failure |
347
+ | Escalating a transcript | The human has to find the question themselves |
348
+ | Two agents editing one document | Lost work, no error |
349
+ | Writing to the repo during a collab | Your answer may be guard-blocked and stranded; the reply is always deliverable, a write may not be |
350
+ | Using collab to hand off WORK | Wrong skill. Create a work item and use rdc:build or an isolated-worktree agent |
222
351
 
223
- If Dave types in this terminal during a turn:
224
- - Treat it as an override injected into the current task
225
- - Acknowledge it in your `chitchat_reply` response
226
- - If it changes direction mid-task, note what you stopped and why
227
- - ⛔ **When an interjection appears to CONTRADICT the task premise, restate your
228
- understanding in ONE sentence and confirm before branching into a wide
229
- `AskUserQuestion` menu.** A tight "I read this as X — correct?" reconciles faster
230
- than a multiple-choice and avoids acting on a misread premise (lesson
231
- 2026-06-08-collab-premise-contradicting-interjection: "there is no pm2 this
232
- replaces it" was read as "PM2 is abolished as the transport" and triggered a
233
- 3-option transport menu, when it meant "there was no dev *site* yet — push to
234
- the unchanged PM2 path"; the wide menu over-committed to one interpretation and
235
- cost a round).
352
+ ---
236
353
 
237
354
  ## Capture lessons (exit step)
238
355
 
239
- Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — write one `.rdc/lessons/<YYYY-MM-DD>-collab-<short-slug>.md` per lesson using the schema in that spec. Set `scope` (`simple` | `architectural`) and `status` (`open`, or `applied` if you shipped the fix in this same run, with the commit linked). Commit the lesson file(s) on `develop` alongside the run's other commits, and note "N lessons captured" in your verdict/summary. A run that taught nothing writes nothing — absence is the default.
356
+ Before the final verdict line, follow `guides/lessons-learned-spec.md` § Capture
357
+ procedure. Write a lesson only for a genuine **episode** — a first root-cause
358
+ theory that proved wrong, a documented path that did not work, a surprising
359
+ tool/infra behaviour. **A settled agreement is not a lesson** (see Step 5). Set
360
+ `scope` and `status`; commit alongside the run's other commits; note "N lessons
361
+ captured" in the verdict. A run that taught nothing writes nothing.