@lifeaitools/rdc-skills 0.26.5 → 0.27.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.4",
3
+ "version": "0.27.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.5",
3
+ "version": "0.27.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,160 @@
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
+ ## What you owe BACK — your responsibilities
48
+
49
+ ### 1. Answer in the required format. Nothing outside it.
50
+
51
+ If the dispatch gives you a contract, use it verbatim. Prose around the blocks
52
+ is not helpful — it is what the format exists to remove.
53
+
54
+ **Negotiate — one block per point:**
55
+
56
+ ```
57
+ POINT <n>: AGREE | AGREE-WITH-AMENDMENT | DISAGREE
58
+ EDIT: <the exact section and change you will make, or NONE>
59
+ REASON: <one sentence — only if AMENDMENT or DISAGREE>
60
+ ```
61
+
62
+ **Delegate:**
63
+
64
+ ```
65
+ STATUS: DONE | PARTIAL | BLOCKED
66
+ CHANGED: <file paths, or NONE>
67
+ EVIDENCE: <command run + literal result — exit code, row count, probe status>
68
+ BLOCKED: <what stopped you, or NONE>
69
+ ```
70
+
71
+ **Always close with:**
72
+
73
+ ```
74
+ OWNER: <who writes the change — exactly one agent>
75
+ BLOCKED: <what you cannot do from where you are, or NONE>
76
+ ```
77
+
78
+ ### 2. Declare `BLOCKED` loudly. Silence is the worst answer.
79
+
80
+ If you cannot write, cannot reach a service, or lack the credential — **say it in
81
+ the reply**. A blocked responder that goes quiet is indistinguishable from a dead
82
+ one, and it costs the initiator a full watchdog cycle to discover what you
83
+ already knew.
84
+
85
+ **Your completed reasoning still counts when your write is blocked.** Put the
86
+ answer in the reply body. Do not let it die inside a failed tool call.
87
+
88
+ ### 3. Do not write outside your own lane or scope.
89
+
90
+ - **Codex:** you must be running in a Codex-owned lane (`x-codex-N`, `x-codex-sv`).
91
+ If the initiator invoked you with its own cwd, every write will be refused with
92
+ `CODEX MANAGED LANE: App Local must use an owned managed Codex lane`. That is a
93
+ **dispatch defect, not your failure** — report it as `BLOCKED: wrong lane
94
+ attachment, re-dispatch with -C <my-lane>` and do not attempt a workaround.
95
+ - **Claude agents:** if you will commit, you must have been given
96
+ `isolation: "worktree"` as a real tool parameter. A sentence in your prompt
97
+ claiming isolation is inert.
98
+ - **Everyone:** never `git stash` in a shared checkout, never force-push, never
99
+ commit onto a branch you were not told to use. If the branch you land on is
100
+ someone else's, say so rather than committing "just this once".
101
+
102
+ ### 4. Do not take ownership you were not given.
103
+
104
+ Exactly one agent writes each artifact. If you were not named the writer, put
105
+ your change in the **reply**, not in the file. Two writers on one surface loses
106
+ work with no error.
107
+
108
+ If the named writer is you and you are blocked, say so — ownership transfers
109
+ explicitly, never by assumption.
110
+
111
+ ### 5. An agreement is a Decision, not an episode.
112
+
113
+ When a negotiation settles, the outcome belongs in the **governing document** —
114
+ the plan, the ARCHITECTURE.md, the rule — where it becomes queryable
115
+ architecture. **Do not file a settled agreement as a lesson.** Lessons are for
116
+ episodes: a root-cause theory that proved wrong, a documented path that did not
117
+ work, a surprising tool behaviour. A settled negotiation filed as a lesson buries
118
+ a constraint in an append-only pile nobody traverses.
119
+
120
+ ### 6. Answer the point that was asked.
121
+
122
+ If you disagree with the framing, say `DISAGREE` and give the reason in one
123
+ sentence — do not silently answer a different, easier question. If a point is
124
+ unanswerable without information you do not have, say that in `REASON` and name
125
+ what would settle it.
126
+
127
+ ### 7. Do not restate what is already settled.
128
+
129
+ The initiator sends only open points. Re-litigating a settled one restarts a
130
+ negotiation that was converging.
131
+
132
+ ---
133
+
134
+ ## Terminal states — any of these is a complete, legitimate answer
135
+
136
+ | State | Meaning |
137
+ |---|---|
138
+ | All points `AGREE` | Converged. The named writer applies the edits. |
139
+ | Some `DISAGREE` with reasons | A real disagreement. Escalates as a packet, not a transcript. |
140
+ | `BLOCKED` on everything | You cannot act from where you are. Name the fix. |
141
+ | A point needs evidence neither side has | Name the measurement that would settle it. |
142
+
143
+ **"I could not do it and here is exactly why" outranks a plausible answer you are
144
+ not confident in.** The initiator can act on a precise blocker immediately; it
145
+ cannot act on a guess it has to verify.
146
+
147
+ ---
148
+
149
+ ## Anti-patterns — these each cost a full round
150
+
151
+ | Anti-pattern | Why |
152
+ |---|---|
153
+ | Answering in prose when a format was given | The initiator has to parse and may misread you |
154
+ | Writing a file instead of replying | Your answer may be guard-blocked and lost |
155
+ | Filing a settled agreement as a lesson | Buries a queryable Decision |
156
+ | Going silent when blocked | Indistinguishable from being dead |
157
+ | Editing a document you do not own | Lost work, no error, no trace |
158
+ | Committing to whatever branch you happen to be on | The change strands where nobody looks for it |
159
+ | Answering an easier adjacent question | The real point stays open and looks settled |
160
+ | Attempting a workaround for a guard block | The guard is usually right; the dispatch is usually wrong |
@@ -1,239 +1,296 @@
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> [mode] <topic>` — Structured collaboration with another agent: Codex, a local LLM, a Claude agent, or a claude.ai session. Modes: negotiate (converge on a decision), delegate (hand off work), listen (claude.ai relay). 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> [mode] <topic>`
15
+ > Collaborators: `codex` · `local-llm` · `claude-agent` · `claude-ai`
16
+ > Modes: `negotiate` (default for a decision) · `delegate` · `listen`
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
25
-
26
- ## Arguments
27
-
28
- - `rdc:collab --session <id>` — start or resume a collab relay with the given session ID
29
-
30
- ## What This Is
31
-
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.
20
+ > **Two halves.** This file is the **initiator's** contract — how to dispatch,
21
+ > what to demand, how to bound it. [`COLLABORATOR.md`](./COLLABORATOR.md) is the
22
+ > **responder's** contract what the peer owes back and what it may expect from
23
+ > you. **Link `COLLABORATOR.md` in every dispatch**; a contract only one side has
24
+ > read is a contract only one side keeps.
37
25
 
38
26
  ---
39
27
 
40
- ## Step 1 Parse session ID
28
+ ## The rule this skill exists to enforce
41
29
 
42
- Extract `--session <uuid>` from args.
30
+ **Never dispatch to another agent without a response contract.**
43
31
 
44
- If no `--session`, call `chitchat_list` and show all active sessions.
32
+ An agent asked an open question answers in whatever shape is habitual to it — a
33
+ file write, a plan, a lesson, a wall of prose. It is not being unhelpful; you
34
+ did not tell it how to answer. A dispatch without a contract produces output you
35
+ then have to parse, argue with, or discard, and it costs a full round every time.
45
36
 
46
- ---
37
+ **Corollary: an agreement is a Decision, not an episode.** When collaboration
38
+ settles a question, the output belongs in the governing document (and therefore
39
+ in AKG) as a decision/constraint/policy — never filed as a lesson. Lessons are
40
+ for *episodes*: something was learned the hard way. A settled negotiation filed
41
+ as a lesson buries a queryable constraint in an append-only pile nobody
42
+ traverses.
47
43
 
48
- ## Step 2 — Initialize (chitchat-native)
44
+ ---
49
45
 
50
- Call `chitchat_list` to verify the session exists in the daemon.
46
+ ## Two clocks: the reply drives, a watchdog bounds
47
+
48
+ Both are required, and they do different jobs. Running either alone is a known
49
+ failure:
50
+
51
+ | | Driver | Watchdog |
52
+ |---|---|---|
53
+ | What it is | the collaborator's reply | a `/loop` or `Monitor`, armed at dispatch |
54
+ | Fires on | completion | **silence past the expected envelope** |
55
+ | Job | advance the negotiation | **diagnose why nothing came back** |
56
+ | Cadence | none — event-driven | ~2–3× the peer's normal reply time |
57
+
58
+ **Driver alone → you wait forever.** A background dispatch with no timeout is
59
+ correct about not guessing a duration and wrong about liveness: if the peer dies,
60
+ is guard-blocked, or its session id has expired, nothing ever wakes you. This is
61
+ the failure the watchdog exists to catch.
62
+
63
+ **Watchdog alone → you fire on top of live calls.** A wall-clock cadence has no
64
+ relationship to the work: if the peer answers in 30s you idle the remainder, if
65
+ it takes 8 minutes you stack a second call onto the first.
66
+
67
+ ### The watchdog does NOT retry. It investigates.
68
+
69
+ Re-dispatching a silent peer is the wrong reflex — it doubles the load on
70
+ something already failing and destroys the evidence of why. On wake, run the
71
+ diagnosis ladder in order and stop at the first hit:
72
+
73
+ 1. **Is the process alive?** Check the background task's status. Still running is
74
+ a legitimate answer — re-arm the watchdog with a longer envelope and stop.
75
+ 2. **Did it exit, and with what?** A non-zero exit or exit 143 (killed) is a
76
+ result, not silence. Read it.
77
+ 3. **Was it guard-blocked?** Grep the output for a `deny`/`Blocked` line. The
78
+ `CODEX MANAGED LANE` block is the common one and is a *dispatch* defect
79
+ (wrong `-C`), not a peer failure — fix and re-dispatch once.
80
+ 4. **Is the session still addressable?** A stale `resume <session-id>`, a stopped
81
+ chitchat session, or a dead local-LLM endpoint all present as silence.
82
+ 5. **Did it answer somewhere you are not reading?** A peer that cannot write its
83
+ intended target often reports into stdout, a log, or an error body instead.
84
+ The answer may already exist.
85
+ 6. **None of the above** → the peer is genuinely stuck. Escalate per Step 6 with
86
+ the ladder's findings attached. Do not silently retry.
87
+
88
+ Arm the watchdog **at dispatch**, disarm it **on reply**. An armed watchdog
89
+ outliving its dispatch is noise, and noise is how a real stall gets ignored.
51
90
 
52
- If the session is not found:
53
- ```
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.
58
- ```
91
+ ---
59
92
 
60
- Send the ready signal via MCP:
61
- ```
62
- chitchat_reply(session_id, "Claude Code connected. Ready to receive tasks.\ncwd: <rootPath>")
63
- ```
93
+ ## Step 0 Parse arguments
64
94
 
65
- Print to terminal:
66
95
  ```
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)
96
+ rdc:collab <collaborator> [mode] <topic…>
97
+ rdc:collab --session <id> ← legacy form, implies `claude-ai listen`
70
98
  ```
71
99
 
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.
100
+ - No collaborator list active chitchat sessions and available engines, then stop.
101
+ - No mode `negotiate` if the topic names a document, decision, plan, or review;
102
+ `delegate` if it names work to perform; `listen` for `claude-ai` with `--session`.
74
103
 
75
104
  ---
76
105
 
77
- ## Step 3Wait for message (SSE-first, poll-fallback)
106
+ ## Step 1Collaborator matrix
78
107
 
79
- ### Primary path SSE (zero-latency)
108
+ Resolve the transport BEFORE composing the message. Getting this wrong is the
109
+ most common failure and it fails at the guard layer, not the prompt layer.
80
110
 
81
- Connect to the SSE stream and wait for the daemon to push a message:
111
+ | Collaborator | Invocation | Isolation requirement | Known failure mode |
112
+ |---|---|---|---|
113
+ | **`codex`** | `codex exec -C <its-lane> "<msg>"` · resume: `codex exec -C <its-lane> resume <session-id> "<msg>"` | **MUST run with `-C` pointing at a Codex-owned lane** (`x-codex-N` or `x-codex-sv`) | Inheriting your cwd attaches Codex to *your* lane; `managedAppAttachmentDecision()` refuses every write with `CODEX MANAGED LANE: App Local must use an owned managed Codex lane`. The guard is correct — fix the `-C`, never the guard. |
114
+ | **`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. |
115
+ | **`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`. |
116
+ | **`claude-ai`** | chitchat MCP (`chitchat_send` / `chitchat_poll` / `chitchat_reply`) + SSE | session-scoped | Messages evaporate when the session stops — export durable decisions to TinTin. |
82
117
 
83
- ```bash
84
- curl -s -N --max-time 30 http://127.0.0.1:52437/chitchat/<session_id>/stream
85
- ```
86
-
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)
118
+ **Dispatch is long-running.** Run engine dispatch as a **background task**, not
119
+ behind a `timeout` guess. A truncated call looks like a failure and is not one.
90
120
 
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.
121
+ ---
95
122
 
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.
123
+ ## Step 2 Compose the response contract (mandatory)
100
124
 
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.
125
+ Every dispatch in `negotiate` or `delegate` mode carries an explicit answer
126
+ format. The contract is not politeness it is what makes the reply *checkable*.
109
127
 
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.
128
+ **Negotiate contractone block per open point:**
112
129
 
113
- ### Fallback path — polling (2s interval)
130
+ ```
131
+ POINT <n>: AGREE | AGREE-WITH-AMENDMENT | DISAGREE
132
+ EDIT: <the exact section and change you will make, or NONE>
133
+ REASON: <one sentence — only if AMENDMENT or DISAGREE>
134
+ ```
114
135
 
115
- Use this path only when SSE is unavailable:
136
+ Plus one closing block, always:
116
137
 
117
138
  ```
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
139
+ OWNER: <who writes the change — exactly one agent>
140
+ BLOCKED: <what you cannot do from where you are, or NONE>
125
141
  ```
126
142
 
127
- **`chitchat_poll` return shapes:**
128
- - `{ status: "idle" }` — inbox empty, keep polling
129
- - `{ status: "ready", message: "..." }` — message waiting, consume it
143
+ **Delegate contract:**
130
144
 
131
- ---
132
-
133
- ## Step 4 Process message
145
+ ```
146
+ STATUS: DONE | PARTIAL | BLOCKED
147
+ CHANGED: <file paths, or NONE>
148
+ EVIDENCE: <command run + literal result — exit code, row count, probe status>
149
+ BLOCKED: <what stopped you, or NONE>
150
+ ```
134
151
 
135
- You now have the message body (from SSE `data:` JSON or `chitchat_poll` result).
152
+ Rules that make the contract hold:
136
153
 
137
- Check if the message begins with `type: stop` (literal prefix) or contains a
138
- `type` field equal to `"stop"` in the JSON.
154
+ 1. **State the format before the content.** Contract first, then the points.
155
+ 2. **Say what NOT to produce** when the peer has a known default — e.g. *"do not
156
+ write a lesson; this is a Decision and belongs in the plan."*
157
+ 3. **Number the points.** Unnumbered points get answered in aggregate.
158
+ 4. **Name the single writer before round 1** (see Step 4).
159
+ 5. **Ask for `BLOCKED` explicitly.** Without it, a peer that cannot act reports
160
+ success or silence.
139
161
 
140
- **`type: stop`** → go to Step 7.
162
+ ---
141
163
 
142
- **Anything else (default: task/message):**
164
+ ## Step 3 — Converge (negotiate mode)
143
165
 
144
- Print to terminal:
145
166
  ```
146
- [rdc:collab] Turn <N> from claude.ai:
147
- ──────────────────────────────────────
148
- <message body>
149
- ──────────────────────────────────────
167
+ open_points = [all points]
168
+ round = 0
169
+ while open_points and round < MAX_ROUNDS (default 4):
170
+ round += 1
171
+ dispatch(open_points, contract) ← background task, no timeout guess
172
+ arm_watchdog(envelope = 2-3x expected reply time)
173
+ reply = await completion ← OR watchdog fires first
174
+ if watchdog fired: run the diagnosis ladder; do NOT re-dispatch blindly
175
+ disarm_watchdog()
176
+ if reply does not match the contract:
177
+ re-dispatch ONCE restating the format only — never re-argue the content
178
+ settle: AGREE and accepted AGREE-WITH-AMENDMENT leave open_points
179
+ if open_points did not shrink this round:
180
+ STOP — escalate (Step 6). A non-shrinking round means the disagreement
181
+ is real, and further rounds spend tokens without moving it.
150
182
  ```
151
183
 
184
+ **Never re-send a settled point.** Each round carries only what is still open,
185
+ plus a one-line record of what was settled. Re-sending settled points is how a
186
+ negotiation becomes a loop that never terminates.
187
+
188
+ **Convergence is the termination condition, not a timer.**
189
+
152
190
  ---
153
191
 
154
- ## Step 5Do the work
192
+ ## Step 4Single-writer rule
155
193
 
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
194
+ Before round 1, name **one** agent as the writer of the document or code under
195
+ discussion, and say so in the dispatch.
162
196
 
163
- Follow `.rdc/guides/agent-bootstrap.md` rules throughout.
197
+ > Two active writers on one surface is forbidden — the same rule the fleet plans
198
+ > state as *"never run two active writers for one effect."*
164
199
 
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.
200
+ If the named writer turns out to be **structurally blocked** (wrong lane, no
201
+ credentials, read-only mount), ownership transfers to the other agent *for that
202
+ artifact only*, and the transfer is recorded in the change itself with
203
+ attribution. A blocked writer does not mean the agreed work is abandoned.
171
204
 
172
205
  ---
173
206
 
174
- ## Step 6Send response
207
+ ## Step 5Land the outcome
175
208
 
176
- When work is done, send the response via MCP:
209
+ An agreement is a **Decision**. Route it by kind:
177
210
 
178
- ```
179
- chitchat_reply(session_id, "<response body>")
180
- ```
211
+ | Outcome | Home |
212
+ |---|---|
213
+ | Settled decision, constraint, or policy | The governing document — plan / ARCHITECTURE.md / rule. AKG ingests from there. |
214
+ | Work to perform | `insert_work_item` via RPC, per `.claude/rules/work-items-rpc.md` |
215
+ | A genuine hard-won episode (a wrong theory, a surprising infra behaviour) | `.rdc/lessons/` per `guides/lessons-learned-spec.md` |
216
+ | A stated, unresolved disagreement | Escalate — Step 6 |
181
217
 
182
- Response body format:
183
- ```
184
- Turn <N> complete.
185
- Commits: <sha1, sha2 or none>
218
+ **Do not file a settled agreement as a lesson.** That is the single most common
219
+ misroute this skill exists to prevent.
186
220
 
187
- <what you did, what you found, any questions or decisions needed from claude.ai>
188
- ```
221
+ ---
222
+
223
+ ## Step 6 — Escalate (only after convergence fails)
224
+
225
+ Escalation is the last step, never the first. It happens when a round fails to
226
+ shrink the open set, the round cap is hit, or both agents are blocked.
227
+
228
+ Escalate as **one packet**, not a transcript:
189
229
 
190
- Print to terminal:
191
230
  ```
192
- [rdc:collab] Turn <N> done. Response sent via chitchat_reply.
193
- Waiting for next message...
231
+ UNRESOLVED: <the point, in one sentence>
232
+ POSITION A (<agent>): <claim + its evidence>
233
+ POSITION B (<agent>): <claim + its evidence>
234
+ WHAT WOULD SETTLE IT: <the measurement, probe, or decision needed>
235
+ COST OF EACH BRANCH: <one line each>
194
236
  ```
195
237
 
196
- Return to Step 3.
238
+ A transcript is not an escalation. If the human has to read the argument to find
239
+ the question, the packet was not written.
197
240
 
198
241
  ---
199
242
 
200
- ## Step 7End session
243
+ ## `listen` modeclaude.ai relay
201
244
 
202
- Received `type: stop` message, or Dave pressed Ctrl+C.
245
+ Legacy behaviour, unchanged and still correct for `claude-ai`. Transport is
246
+ chitchat MCP + SSE; you are the build half of a live session.
203
247
 
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
- ```
248
+ - `chitchat_list` to verify the session; `chitchat_reply` to signal ready.
249
+ - SSE first: `curl -s -N --max-time 30 http://127.0.0.1:52437/chitchat/<id>/stream`.
250
+ **⛔ curl exit 28 is SUCCESS on an SSE read** — `--max-time` always exits 28 at
251
+ the boundary. If a `data:` event arrived, process it. Only connection-refused
252
+ or a non-200 is a real failure (lesson `2026-06-08-collab-sse-exit-28-is-success`).
253
+ - Poll fallback: `chitchat_poll` at 2s — `{status:"idle"}` keep polling,
254
+ `{status:"ready", message}` consume.
255
+ - `type: stop` ends the session; send a final summary, then `chitchat_stop`.
256
+ - Stream progress mid-work with `chitchat_reply` on long tasks.
208
257
 
209
- Then call:
210
- ```
211
- chitchat_stop(session_id)
212
- ```
258
+ ---
213
259
 
214
- Print:
215
- ```
216
- [rdc:collab] Session ended.
217
- ```
260
+ ## Dave interjections
261
+
262
+ Anything Dave types is a high-priority override, in every mode.
263
+
264
+ ⛔ **When an interjection appears to CONTRADICT the task premise, restate your
265
+ understanding in ONE sentence and confirm before branching into a wide
266
+ `AskUserQuestion` menu.** A tight "I read this as X — correct?" reconciles faster
267
+ and avoids acting on a misread premise (lesson
268
+ `2026-06-08-collab-premise-contradicting-interjection`).
218
269
 
219
270
  ---
220
271
 
221
- ## Dave Interjections
272
+ ## Anti-patterns
273
+
274
+ | Anti-pattern | Why it costs a round |
275
+ |---|---|
276
+ | Dispatching prose with no response contract | The peer answers in its habitual shape; you parse or discard it |
277
+ | Filing a settled agreement as a lesson | Buries a queryable Decision in an append-only pile |
278
+ | Driving a negotiation with `/loop` | The clock has no relationship to the reply |
279
+ | Dispatching with no watchdog armed | A dead peer is indistinguishable from a slow one; you wait forever |
280
+ | Watchdog re-dispatches instead of diagnosing | Doubles load on a failing peer and destroys the evidence of why |
281
+ | `codex exec` without `-C <its-lane>` | Codex inherits your lane; every write is guard-blocked |
282
+ | Re-sending settled points each round | The negotiation cannot terminate |
283
+ | Wrapping dispatch in a `timeout` guess | A still-running call reads as a failure |
284
+ | Escalating a transcript | The human has to find the question themselves |
285
+ | Two agents editing one document | Lost work, no error |
222
286
 
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).
287
+ ---
236
288
 
237
289
  ## Capture lessons (exit step)
238
290
 
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.
291
+ Before the final verdict line, follow `guides/lessons-learned-spec.md` § Capture
292
+ procedure. Write a lesson only for a genuine **episode** — a first root-cause
293
+ theory that proved wrong, a documented path that did not work, a surprising
294
+ tool/infra behaviour. **A settled agreement is not a lesson** (see Step 5). Set
295
+ `scope` and `status`; commit alongside the run's other commits; note "N lessons
296
+ captured" in the verdict. A run that taught nothing writes nothing.