greprag 0.9.1 → 0.11.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.
@@ -12,7 +12,7 @@ description: |
12
12
  "what's been happening in this project", "session context".
13
13
  metadata:
14
14
  author: travsteward
15
- version: "3.5.0"
15
+ version: "3.7.0"
16
16
  repository: https://github.com/travsteward/greprag
17
17
  license: MIT
18
18
  ---
@@ -21,6 +21,12 @@ license: MIT
21
21
 
22
22
  The agent drives all setup and runs the briefing. Single source of truth: `greprag status --json`.
23
23
 
24
+ ### OpenCode vs Claude Code
25
+
26
+ - **Claude Code**: hooks in `~/.claude/settings.json` + advisor skill — follow steps 1-6 below.
27
+ - **OpenCode**: plugin at `~/.config/opencode/plugins/greprag-memory.ts` runs silently (injects recap via system prompt, stores turns automatically). The `/greprag` skill works on-demand in both. Run `greprag init --opencode` once to install.
28
+ - Both share the same anchor (`.claude/project.json` or `.opencode/project.json`) and the same API key.
29
+
24
30
  ## Step 1 — Get the status
25
31
 
26
32
  ```bash
@@ -30,9 +36,23 @@ greprag status --json
30
36
  Parse the JSON. The keys to check, in this order:
31
37
 
32
38
  1. `auth.api_key_present`
33
- 2. `hooks.session_start_recap`, `hooks.stop_store`, `hooks.user_prompt_submit_notify`
34
- 3. `project.anchor_found`
35
- 4. `project.memory_capture`, `project.session_start_recap`, `project.inbox_notify`
39
+ 2. `project.anchor_found`
40
+ 3. `project.memory_capture`, `project.session_start_recap`, `project.inbox_notify`
41
+
42
+ For Claude Code, also check `hooks.session_start_recap`, `hooks.stop_store`, `hooks.user_prompt_submit_notify`.
43
+
44
+ Also check the chip-coordination convention is installed in global CLAUDE.md (Step 3b):
45
+ ```bash
46
+ if grep -q "greprag-conventions:start v3" ~/.claude/CLAUDE.md; then echo CONV_V3
47
+ elif grep -q "greprag-conventions:start v2" ~/.claude/CLAUDE.md; then echo CONV_V2_NEEDS_UPGRADE
48
+ elif grep -q "greprag-conventions:start v1" ~/.claude/CLAUDE.md; then echo CONV_V1_NEEDS_UPGRADE
49
+ else echo CONV_MISSING; fi
50
+ ```
51
+
52
+ Also check the permission allowlist (Step 3c):
53
+ ```bash
54
+ node -e "const s=JSON.parse(require('fs').readFileSync(require('os').homedir()+'/.claude/settings.json','utf8'));const a=(s.permissions&&s.permissions.allow)||[];console.log(a.includes('Monitor')?'MON_OK':'MON_MISSING')"
55
+ ```
36
56
 
37
57
  For each gap, walk the user through the fix. When everything is configured, skip to Step 6 (briefing).
38
58
 
@@ -83,6 +103,122 @@ Edit `~/.claude/settings.json` to add the missing hook(s):
83
103
 
84
104
  Append the missing entries to the existing arrays (create the arrays if absent). Don't overwrite existing hooks from other tools.
85
105
 
106
+ ## Step 3b — Convention install (only if marker missing or out-of-date)
107
+
108
+ The chip-spawning + agent-coordination convention is a one-time install into the user's global CLAUDE.md. Every project session reads it; without it, chips spawn without worktree isolation, inbox report-back, or reply-listening. Detect first:
109
+
110
+ ```bash
111
+ if grep -q "greprag-conventions:start v3" ~/.claude/CLAUDE.md; then echo V3
112
+ elif grep -q "greprag-conventions:start v2" ~/.claude/CLAUDE.md; then echo V2_UPGRADE
113
+ elif grep -q "greprag-conventions:start v1" ~/.claude/CLAUDE.md; then echo V1_UPGRADE
114
+ else echo MISSING; fi
115
+ test -f ~/.claude/docs/agent-coordination.md && echo DOC_OK || echo DOC_MISSING
116
+ ```
117
+
118
+ **If `MISSING`**, insert the v3 block into `~/.claude/CLAUDE.md` immediately after the `## Inbox` section (use the Edit tool, marker comments verbatim):
119
+
120
+ ```markdown
121
+ <!-- greprag-conventions:start v3 -->
122
+ ## Chip Spawning & Agent Coordination
123
+
124
+ Delegating work — `spawn_task` chip vs `Agent` tool, two chip modes, the worktree-first + inbox-report + reply-listening convention. Full spec: `~/.claude/docs/agent-coordination.md`.
125
+
126
+ **Two chip modes** — pick deliberately:
127
+ - **Mode A (default) — ship chip.** Lands in a worktree, ships code, user-in-loop optional. The workhorse. A chip that dispatches its own `Agent` sub-tasks mid-work is still Mode A — that's a behavior, not a peer mode.
128
+ - **Mode B — discussion chip.** Lands as a context-rich conversation partner. Reads code, proposes, iterates. Ships nothing without explicit go-ahead. Output is a decision or a scoped follow-up chip. Reach for B the moment you notice you're proposing architecture from partial grep reads.
129
+
130
+ **Spawn primitives** (not modes — pick by what fits the work):
131
+ - `spawn_task` — Mode A or B chip. Worktree, chip UI, persistence, optional cross-project via `cwd:`.
132
+ - `Agent` — one-shot delegation, returns once to caller. No chip lifecycle. Pass `subagent_type` (Explore / Plan / general-purpose / code-reviewer) when a specialized shape fits.
133
+
134
+ **Non-negotiables for every `spawn_task` chip prompt:** (0.5) project facts pulled from `greprag fact`, (1) worktree-first setup, (2) `greprag send` report-back, (3) `Monitor` on own inbox for follow-ups. Without them the chip pollutes the main checkout, has no return channel, or dies after one report. Copy the boilerplate verbatim from the deep doc.
135
+
136
+ **Reply listening (any session, not just chips).** Any time you `greprag send` a message that could draw a directive in response, arm a `Monitor` watcher on your own inbox in the same turn. Use the bash-wrapper form so the watcher auto-restarts if the inner SSE process dies (network blip, supervisor bug, Cygwin fork failure):
137
+
138
+ ```bash
139
+ while true; do greprag inbox watch --session <own-session-id> --json; echo "[wrapper] watcher exited, restarting in 1s" >&2; sleep 1; done
140
+ ```
141
+
142
+ Run under `Monitor` with `persistent: true`. Fall back to `--project <own-project>` instead of `--session` when no session identity is available. The Stop hook only fires between user prompts; without Monitor, mid-task replies are invisible until the next stop boundary.
143
+
144
+ For real-time chip reports, the parent arms the same wrapped watcher (`--session <parent-session-id>` preferred, `--project <parent-project>` for multi-chip campaigns) under `Monitor` BEFORE spawning. Each stdout line = one notification. Do NOT use `Bash(run_in_background)` — it only fires on process completion, not per line; a watcher never exits, so the parent gets zero events. Do NOT use the bare `greprag inbox watch` without the `while true` wrapper — if the inner watcher dies you go silently deaf with no restart.
145
+ <!-- greprag-conventions:end v3 -->
146
+ ```
147
+
148
+ **If `V2_UPGRADE`**, replace the entire `<!-- greprag-conventions:start v2 -->` … `<!-- greprag-conventions:end v2 -->` block (inclusive of markers) with the v3 block above. Tell the user "Upgrading greprag-conventions v2 → v3 (collapses Mode B mission-commander into Mode A behavior; renames Mode C to Mode B = discussion chip)." Don't preserve any v2 content — v3 supersedes.
149
+
150
+ **If `V1_UPGRADE`**, replace the entire `<!-- greprag-conventions:start v1 -->` … `<!-- greprag-conventions:end v1 -->` block (inclusive of markers) with the v3 block above. Tell the user "Upgrading greprag-conventions v1 → v3 (adds Block 3 reply-listening; reframes modes as ship chip + discussion chip)." Don't preserve any v1 content — v3 supersedes.
151
+
152
+ **If `DOC_MISSING`**, copy the canonical content from the template shipped with this skill:
153
+ ```bash
154
+ mkdir -p ~/.claude/docs && cp ~/.claude/skills/greprag/templates/agent-coordination.md ~/.claude/docs/agent-coordination.md
155
+ ```
156
+
157
+ If `DOC_OK` but you just upgraded from v1 or v2, overwrite the doc too (the v3 template carries the new mode framing + operating guidelines + detection signals):
158
+ ```bash
159
+ cp ~/.claude/skills/greprag/templates/agent-coordination.md ~/.claude/docs/agent-coordination.md
160
+ ```
161
+
162
+ The deep doc covers Block 0.5 (project-facts pull), Block 1 (worktree-first), Block 2 (inbox report-back), Block 3 (reply-listening), parent-side watcher, Mode A operating guidelines + sub-Agent dispatch (3-layer chain when needed), Mode B detection signals + operating guidelines, and anti-patterns.
163
+
164
+ Re-run the grep to confirm install. Markers must stay verbatim — they're how subsequent `/greprag` runs detect "already installed" and skip this step.
165
+
166
+ ## Step 3c — Permission allowlist (only if `MON_MISSING` from Step 1)
167
+
168
+ Without `Monitor` in the allowlist, every inbox-watcher firing prompts the user to approve. That breaks the reply-listening convention — chip and parent sessions both arm watchers as background tasks, and a permission dialog mid-task drops the agent out of flow.
169
+
170
+ Read `~/.claude/settings.json` and confirm `permissions.allow` contains `"Monitor"`. If not, add it. Recommended baseline for greprag users:
171
+
172
+ ```json
173
+ {
174
+ "permissions": {
175
+ "allow": [
176
+ "Bash(*)",
177
+ "Monitor",
178
+ "Read", "Edit", "Write", "Grep", "Glob",
179
+ "WebFetch", "WebSearch", "Skill", "Agent", "Task"
180
+ ]
181
+ }
182
+ }
183
+ ```
184
+
185
+ `Bash(*)` already covers `greprag inbox`, `greprag send`, `greprag retract`, `greprag watch` etc. — no per-command allow entries needed once Bash is broadly trusted. `Monitor` is the missing piece, because it's its own tool (not Bash) and prompts independently.
186
+
187
+ If the user has a tighter Bash policy (no `Bash(*)`), the per-command minimum for greprag is:
188
+ - `Bash(greprag *)` — covers send, inbox, retract, watch, status, discover
189
+ - `Bash(greprag-hook *)` — covers the hook commands installed in Step 3
190
+ - `Monitor` — inbox watchers
191
+
192
+ Tell the user the change you're proposing before editing settings.json. Don't silently broaden their permission posture.
193
+
194
+ ## Step 3d — Channel plugins (if user has Discord / Telegram / iMessage plugins enabled)
195
+
196
+ Adjacent gotcha worth surfacing during setup. Check whether any channel plugin is enabled in either global or any project `settings.json`:
197
+
198
+ ```bash
199
+ grep -lE '"(discord|telegram|imessage|fakechat)@claude-plugins-official":\s*true' \
200
+ ~/.claude/settings.json \
201
+ $(find . -maxdepth 3 -path '*/.claude/settings.json' 2>/dev/null) 2>/dev/null
202
+ ```
203
+
204
+ If any match: tell the user that channel push delivery requires the `--channels` flag at session launch — being in `settings.json` and `.mcp.json` is not enough. Specifically:
205
+
206
+ - **Setting enables the MCP server to load** → its tools (e.g. `reply`, `fetch_messages`) become available.
207
+ - **`--channels plugin:<name>@<marketplace>` at launch enables push** → inbound `notifications/claude/channel` events surface as `<channel>` blocks in the session context.
208
+
209
+ Without `--channels`, the bot can be DM'd and the bun server receives the event, but Claude Code's harness filters it out. Users observe "typing indicator fires, then bot times out without replying."
210
+
211
+ The flag is hidden from `claude --help` on 2.1.149 (research preview) but accepted on 2.1.80+. **FleetView / Claude Desktop's CCD launcher does not pass `--channels`** — push delivery only works from terminal-launched sessions. Recommend the user launch one terminal-rooted Claude session in the project where the plugin is enabled:
212
+
213
+ ```bash
214
+ cd <project-with-plugin>
215
+ claude --channels plugin:discord@claude-plugins-official
216
+ ```
217
+
218
+ FleetView sessions can still call the plugin's REST tools as a polling workaround, but the realtime path is terminal-only until the launcher catches up.
219
+
220
+ Also recommend: scope the plugin to a single project's `.claude/settings.json`, not global. Discord allows exactly one gateway connection per bot token; if multiple sessions all have the plugin enabled, the bun servers race for the token and Discord drops all but one.
221
+
86
222
  ## Step 4 — Project anchor (only if `project.anchor_found === false`)
87
223
 
88
224
  The current folder has no `.claude/project.json`. Ask the user:
@@ -157,10 +293,17 @@ To send a plain message:
157
293
  greprag send "<markdown body>" --to <address>
158
294
  ```
159
295
 
296
+ `send` prints two lines on success — the delivered-to confirmation **and a retract code**:
297
+ ```
298
+ Sent to alice@greprag.com/abc12345 (a7f3c5e2)
299
+ Retract: greprag retract K9M2X4P7QV
300
+ ```
301
+ The retract code lets the sender pull the message back without layering follow-up "SUPERSEDES" notes on top. See Step 5d.
302
+
160
303
  To send a **rich message** with back-pointers — preferred whenever the message refers to a memory row, a shipped artifact, or specific code lines:
161
304
  ```bash
162
305
  greprag send "Quick heads up — the auth bug I described yesterday repros here." \
163
- --to alice@example.com/paybot \
306
+ --to alice@greprag.com/abc12345 \
164
307
  --memory 04f3e0d4-aa12-44ef-9a01-bb3df2c7e911 \
165
308
  --file src/auth/handler.ts:42 \
166
309
  --file src/middleware/check.ts:10-15 \
@@ -173,8 +316,9 @@ Flags (all repeatable, all optional):
173
316
  - `--artifact <type:id>` — point to a shipped thing. Types: `commit`, `pr`, `deploy`, `release`, `push`, `merge`
174
317
  - `--file <path[:lines]>` — point to a code location. Lines are `42` or `10-15`
175
318
  - `--ref-json '<json>'` — escape hatch for a fully-formed references object (mutually exclusive with the above)
176
- - `--session <id>` — target a specific session under the project. Only the session's `inbox watch --session <id>` sees it; broadcasts (no `--session`) still reach every session-scoped watcher. Equivalent to suffixing the address with `/<id>`.
177
- - `--from-session <id>` — sender's own session UUID. Denormalized onto the message so the recipient learns your session and can address replies back via `--session <your-id>` without re-discovery. Use whenever you expect a reply.
319
+ - `--from-session <id>` — sender's own session UUID. Denormalized onto the message so the recipient learns your session and can address replies back without re-discovery. Use whenever you expect a reply.
320
+
321
+ The target lives in the `--to` address itself (see "Address formats" below). The legacy `--session` and `--project` flags were removed in v0.11 — passing them now errors out with a migration hint.
178
322
 
179
323
  **When to populate references vs. when to leave them off:**
180
324
  - Short chat messages ("pinging you", "deploy is up", "ack") — no references, just body.
@@ -182,20 +326,103 @@ Flags (all repeatable, all optional):
182
326
  - Cross-referencing prior memory — pull memory IDs from a `greprag inbox` listing or from the recap and pass via `--memory`. The recipient agent can fetch the row directly.
183
327
  - Don't hallucinate references. If you can't name a real file path or artifact ID, leave the flag off.
184
328
 
185
- Address formats (all valid):
186
- - `1834729@greprag.com` — canonical numeric handle. Every account has one; opaque, leaks nothing. Get yours from `greprag status --json | jq -r .identity.handle` or `greprag whoami`.
187
- - `1834729@greprag.com/paybot` recipient's paybot project inbox.
188
- - `1834729@greprag.com/paybot/<session-id>` — only the named session sees it (plus broadcasts). Trailing UUID is case-sensitive.
329
+ Address formats (v0.11+):
330
+
331
+ | Form | Use | Behavior |
332
+ |---|---|---|
333
+ | `<handle>@greprag.com` | What you SHARE | Identity-only / receive form. Errors on send — the bare handle has no target. |
334
+ | `<handle>@greprag.com/<session-uuid>` | What you SEND with (normal) | Targets one specific session. UUID or 8-hex short form. Only that session's watcher receives. |
335
+ | `<handle>@greprag.com/<project-name>` | What you SEND with (rare) | Project-wide broadcast — every watcher in that project receives. Reserve for genuine "everyone in this project should know" messages. |
336
+ | `me` / `self` | Shortcut for your own tenant | Receive form only. |
337
+
338
+ Disambiguation rule: a single segment after `/` is a session if it matches `[0-9a-f]{8}` (8-hex short form) or full UUID, otherwise a project name. Project names that look like UUIDs are rejected at registration time so this is always unambiguous.
339
+
340
+ `<handle>` is one of:
341
+ - `1834729@greprag.com` — canonical numeric handle. Opaque, leaks nothing. Get yours from `greprag status --json | jq -r .identity.handle` or `greprag whoami`.
189
342
  - `alice@greprag.com` — opt-in vanity alias (claim with `greprag identity claim alice`).
190
- - `me` / `self` — shortcut for your own tenant inbox (server resolves).
191
343
 
192
344
  **Real emails are NEVER routing addresses.** `users.email` is auth credential only. If you don't know the recipient's numeric handle, ask the user — don't guess from their email. adr: adr/numeric-handles.md
193
345
 
194
- Project-level addressing is the fallback whenever no specific session is in mind. Session-level is for precise routing — chip ↔ parent reply isolation, or any case where multiple sessions on the same project would otherwise share an inbox.
346
+ Session targeting is the default and expected form. Project broadcasts are intentional opt-ins for the rare case where everyone in a project should hear something. adr: adr/address-grammar.md
195
347
 
196
348
  Auto-read semantics: any message returned by `greprag inbox` (without `--all`) is marked read in the same call. Once read, it stops appearing in notifications. TTL deletes read messages after 14 days. Use `keep` to extend before expiry.
197
349
 
198
- ## Step 5c — Health & repair (when memory looks wrong)
350
+ ## Step 5c — Watching the inbox (push delivery)
351
+
352
+ When you've spawned chips that will report back via `greprag send`, or you're waiting on any message that needs to land in real time, run a live SSE watcher instead of polling `greprag inbox` on a heartbeat:
353
+
354
+ ```bash
355
+ greprag inbox watch # tenant-wide stream
356
+ greprag inbox watch --project <name> # only messages addressed to this project
357
+ greprag inbox watch --session <id> # only messages targeting this session (plus broadcasts)
358
+ greprag inbox watch --since <id-or-iso> # resume from a known cursor
359
+ greprag inbox watch --json # emit one JSON object per line (preferred under Monitor)
360
+ ```
361
+
362
+ `--project` and `--session` compose — pass both when a session lives inside a specific project's inbox space. `--session` is the strictest filter: only messages with matching `to_session_id` (or `to_session_id IS NULL` for broadcasts) get through. This is what eliminates cross-session noise when several Claude sessions watch the same project's inbox at once.
363
+
364
+ Each message arrives within ~500ms of the sender's `greprag send` (210ms verified end-to-end). The connection is held open and auto-reconnects with exponential backoff if the server drops; the watcher tracks the last seen message id and uses it as `since=` on reconnect, so nothing is dropped and nothing is duplicated.
365
+
366
+ **Liveness model (post v0.8.5):** the server emits an SSE `: ping` comment every 15s. The client tracks time since the last byte and treats 60s of total silence (4 missed pings) as a dead stream — aborts the fetch, reconnects with the preserved cursor, and the server's per-tenant InboxDO replays any rows that landed in the gap from its tail buffer (or backfills from the DB for older gaps). After replay, the server emits an `event: replay-complete` SSE event with the row count so the watcher logs `replayed N missed row(s), resuming live tail` to stderr. Disconnects and reconnect attempts also log to stderr with the cursor — debugging silent gaps no longer requires inspecting the running process. Pre-`fix`, a silently half-open TCP socket would hang the watcher indefinitely with no log; that failure mode is gone, but watcher delivery is still opportunistic — the `UserPromptSubmit` hook remains the correctness guarantee, surfacing any unread messages at the next user turn.
367
+
368
+ **Two canonical patterns:**
369
+
370
+ ### Parent-side: watch for chip reports BEFORE spawning
371
+
372
+ ```bash
373
+ # Parent arms a Monitor scoped to its own session, then spawns the chip
374
+ # (chip prompt's Block 2 sends with --session <parent-session-id>).
375
+ # Each chip's "done" report becomes one Monitor notification, with no cross-talk
376
+ # from other chips or sessions sharing the parent's project inbox.
377
+ # The while-loop wrapper auto-restarts the SSE process if it dies — a bare
378
+ # `greprag inbox watch` would silently end the Monitor task on any inner crash.
379
+ while true; do greprag inbox watch --session <parent-session-id> --json; echo "[wrapper] watcher exited, restarting in 1s" >&2; sleep 1; done
380
+ ```
381
+
382
+ If the parent has no session identity (rare — older sessions before session-scope shipped), fall back to `--project <parent-project>`. The chip then sends without `--session` and the message reaches every watcher under the project.
383
+
384
+ ### Post-send: listen for replies after `greprag send`
385
+
386
+ Any session that sends a message that could draw a directive in response arms the same watcher on its own inbox in the same turn. Without this, the Stop hook is the only path for the reply to surface — and Stop only fires between user prompts. Mid-task replies are invisible until the next stop boundary.
387
+
388
+ ```bash
389
+ # After: greprag send "..." --to <someone>/<their-project>/<their-session> \
390
+ # --from-session <own-session-id>
391
+ # Arm under Monitor (persistent: true):
392
+ while true; do greprag inbox watch --session <own-session-id> --json; echo "[wrapper] watcher exited, restarting in 1s" >&2; sleep 1; done
393
+ ```
394
+
395
+ The `--from-session` flag on the outgoing message tells the recipient where to address replies; the `--session` filter on the watcher narrows incoming traffic to messages aimed at this exact session (plus general broadcasts). No more sibling-chip cross-talk and no self-echo from tenant-wide sends.
396
+
397
+ This is also the Block 3 pattern for chips — see `~/.claude/docs/agent-coordination.md`. The same rule applies to main sessions, advisor sessions, and any other context that pings someone and expects a response.
398
+
399
+ **Run it under the `Monitor` agent tool, `persistent: true`.** Monitor emits one notification per stdout line — the agent reacts the moment a message lands. **Do NOT use `Bash(run_in_background: true)`** — Bash background notifies only on process completion, and a watcher runs forever, so the agent gets zero events until it manually reads the output file. Confirmed bug, learned the hard way. Stop with `TaskStop` on the Monitor task when the watch is truly no longer needed.
400
+
401
+ The watcher is the right default whenever you'd otherwise loop `greprag inbox` every N seconds — lower latency, cheaper, doesn't burn quota on empty polls.
402
+
403
+ ## Step 5d — Retracting a message you just sent
404
+
405
+ `send` returns a retract code (printed after `Retract:` on the second line of the success output). Use it when you realize a message was wrong-framed and want to pull it back instead of stacking a follow-up "SUPERSEDES" note on top:
406
+
407
+ ```bash
408
+ greprag retract <code>
409
+ ```
410
+
411
+ Behavior is decided by the server based on whether the recipient has already read the message:
412
+
413
+ - **Unread** → the row is hard-deleted. Recipient never sees it. Output: `Retracted (status: deleted — recipient had not read it).`
414
+ - **Read** → message body is replaced with `[RETRACTED BY SENDER at <ts>]`. Recipient still sees the row in `inbox --all`, but the original body is gone. Output: `Marked retracted (status: retracted_after_read — recipient had already read; they'll see the retraction notice in place of the original body).`
415
+ - **Already retracted** → no-op, idempotent. Output: `Already retracted (status: already_retracted — no change).`
416
+ - **Unknown code** → no error, just confirms nothing happened. Output: `Not found (status: not_found — code does not match any message you sent, or the message has already expired).`
417
+
418
+ **When to retract vs. when to send a SUPERSEDES follow-up:**
419
+ - Just sent it, recipient hasn't read yet, and the framing was wrong? → `greprag retract`. Clean inbox state, zero noise.
420
+ - Recipient has already read it? → `greprag retract` still beats a stacked follow-up — they get a placeholder instead of a confusing stale message — and then send a fresh `greprag send "<corrected message>"` with the right framing.
421
+ - Recipient acted on the message already (committed code, made a decision)? → send a follow-up `SUPERSEDES <old-id>: <correction>` so they have full context on what changed and why. Retract still works alongside this to clean the original.
422
+
423
+ Retract codes are sender-scoped — your code cannot retract a message someone else sent. Codes stay valid until the message expires (14 days unread, longer if `keep`'d).
424
+
425
+ ## Step 5e — Health & repair (when memory looks wrong)
199
426
 
200
427
  Triggers: user says "memory looks empty", "I'm missing my history", "fix greprag here", "are there orphans", "consolidate my project IDs"; or `greprag status` reports identity drift; or the session-start recap printed a "[GrepRAG memory: identity drift detected ...]" line.
201
428
 
@@ -218,7 +445,7 @@ Flags:
218
445
 
219
446
  Repair is fully tenant-scoped via the API — `greprag doctor` only ever touches rows under the caller's tenant, and the merge runs in a transaction so a partial failure rolls back cleanly.
220
447
 
221
- ## Step 5d — Corpus (upload + search arbitrary text)
448
+ ## Step 5f — Corpus (upload + search arbitrary text)
222
449
 
223
450
  Episodic memory captures the agent's own work. **Corpus** is the other direction: upload a book, a codebase, a reference doc, a writing-sample library — any text — and search it with lexical grep enriched by write-side vocabulary bridging. Same substrate, same retrieval modes; just a different `kind` on the store.
224
451
 
@@ -0,0 +1,253 @@
1
+ # Agent Coordination
2
+
3
+ How sessions delegate work — chips, agents, and the multi-tier orchestrator pattern. Companion to `/greprag` (inbox transport) and `~/.claude/CLAUDE.md` (the lean reference).
4
+
5
+ ## Two tools, two purposes
6
+
7
+ | Tool | What it spawns | Lands in | Parameters | When to use |
8
+ |---|---|---|---|---|
9
+ | `mcp__ccd_session__spawn_task` | Full Claude Code session ("chip") | Any cwd via `cwd:` param | title, prompt, tldr, cwd | Cross-project work; long-running coordination; user-visible chip UI |
10
+ | `Agent` tool | Subagent instance | Current session's cwd | subagent_type, model, isolation, prompt, run_in_background | One-shot work inside this project; needs specific model/agent type |
11
+
12
+ Picking between them:
13
+
14
+ - **Cross-project? → `spawn_task`** (only it has `cwd`).
15
+ - **In this project, one-shot, specific model? → `Agent`** with `isolation: "worktree"`.
16
+ - **In this project, long campaign? → either** — chip if you want a persistent UI surface; Agent if it's a single delegation.
17
+
18
+ ## Chip convention (every `spawn_task` call)
19
+
20
+ A chip prompt = **Block 0.5 (project facts, optional)** + **Block 1 (worktree-first)** + the actual task + **Block 2 (report back via inbox)** + **Block 3 (stay listening for follow-up)**. Non-negotiable: 1/2/3. Without them the chip pollutes the main checkout (no isolation), the parent has no return channel, or the chip dies after one report and can't be redirected on follow-up. Block 0.5 is recommended but skip when the project has no seeded facts yet.
21
+
22
+ ### Block 0.5 — Project facts (prepend; pull pattern)
23
+
24
+ Before composing the chip prompt, the spawning agent pulls the target project's `chip-startup` facts and inlines them at the top of the prompt:
25
+
26
+ ```bash
27
+ greprag fact query --scope chip-startup --project <chip-project> --limit 10 --format markdown
28
+ ```
29
+
30
+ If the output is non-empty, wrap it in a `**Project Facts (do not re-discover)**` block at the very top of the prompt:
31
+
32
+ ```
33
+ **Project Facts (do not re-discover):**
34
+
35
+ 1. <fact 1 verbatim>
36
+ 2. <fact 2 verbatim>
37
+ ...
38
+
39
+ ---
40
+ ```
41
+
42
+ If the output is empty, skip the block entirely — don't inject placeholder text.
43
+
44
+ **Why this exists.** Chips routinely burn 10–20 startup turns rediscovering project layout (where migrations live, which file owns the CLI dispatch, what the inbox storage shape is). Seeding those answers once and pulling them at spawn makes every future chip skip the search. Contribution side of the protocol — when to seed, scope naming, deliberate review — is in the `/greprag` skill § "Seeding learnings" (`~/.claude/skills/greprag/SKILL.md` or the package copy at `packages/cli/skill/SKILL.md`).
45
+
46
+ ### Block 1 — Worktree-first (prepend to prompt)
47
+
48
+ ```
49
+ **Setup — do this FIRST, before anything else:**
50
+
51
+ ```bash
52
+ cd <chip-cwd>
53
+ git worktree add .claude/worktrees/<slug> -b chip/<slug>
54
+ cd .claude/worktrees/<slug>
55
+ ```
56
+
57
+ All edits, tests, and commits happen in the worktree. The main checkout stays untouched. Pick a slug that matches the chip's title (kebab-case, short — e.g. `discover-cli`, `doctor-merge-fix`).
58
+
59
+ **Your parent's session id is `<parent-session-id>`** — record it; you'll need it in Block 2 to address the report-back so only the parent sees it, not every sibling chip watching the same project inbox.
60
+ ```
61
+
62
+ Fill `<parent-session-id>` from your own (parent) session UUID when composing the spawn_task prompt. If you don't know your session UUID, fall back to project-level addressing throughout Block 2/3 — the chip then sends to `--to <handle>@greprag.com/<parent-project>` (project broadcast, intentional) and the parent watches `--project <parent-project>` (no `--session`). Less precise, still correct — both sides have to be project-scoped for the loop to close.
63
+
64
+ Path convention: `<project>/.claude/worktrees/<slug>/` — same parent directory Claude Code Desktop uses for IDE-checkbox worktrees. One place to look for any active Claude worktree. Branch prefix `chip/` distinguishes agent-spawned from IDE-spawned (`claude/<auto-name>`), so `git branch` output shows provenance at a glance. `/clean-worktrees` skill cleans both.
65
+
66
+ `spawn_task` does NOT auto-create worktrees — only the `Agent` tool does (via `isolation: "worktree"`). Chips run wherever you point them, so the worktree setup must be explicit in the prompt itself.
67
+
68
+ **Chip cleanup discipline (HARD RULE — every chip prompt must enforce this).** Chips **commit and exit**. They do NOT run `git clean -fd`, `git reset --hard`, `git worktree remove` (any target), `git checkout <other-branch>`, raw `rm -rf` of directories, or any destructive shell command outside their own worktree's tracked files. If a chip needs to delete a file it created, use `git rm` and commit the deletion — never raw `rm`. The parent session owns post-merge worktree cleanup; chips never reach for it themselves. This rule exists because parallel worktrees share `.git`, a poorly-scoped cleanup command can wipe another worktree's working tree, and the main checkout has been observed to lose `packages/*/src/` files in this exact pattern. Spawning agents: include "Chip cleanup discipline" verbatim in Block 1 of every chip prompt.
69
+
70
+ **`npm link` discipline.** If a chip needs to smoke-test a CLI build globally, run `npm link` from the main checkout's package dir (`cd <main>/packages/<pkg> && npm link`), NOT from the worktree. Linking from the worktree registers a global symlink that points INTO the worktree; after `git worktree remove` runs in /commit's Phase 4, the symlink dangles and the CLI breaks system-wide until reinstalled. The /commit skill's `guard-npm-links.sh` auto-recovers (re-points at main or unlinks), but the cleanest path is to never create the worktree-pointed symlink in the first place.
71
+
72
+ ### Block 2 — Report back via greprag inbox (append to prompt)
73
+
74
+ ```
75
+ **When done (or stuck), report back via greprag inbox:**
76
+
77
+ ```bash
78
+ greprag send "<status>: <commit hash> on chip/<slug> — <one-line>" \
79
+ --to <your-tenant-handle>@greprag.com/<parent-session-id> \
80
+ --from-session <own-session-id> \
81
+ --artifact commit:<hash> \
82
+ --file <key-file-path>
83
+ ```
84
+
85
+ - `<status>`: `done` | `blocked` | `partial`
86
+ - `<your-tenant-handle>`: parent's `@greprag.com` handle (e.g. `1834729` or a claimed alias like `travis`).
87
+ - `<parent-session-id>`: filled in by the spawning session in Block 1 of this prompt. The full UUID or 8-hex short form both work. This trailing segment IS the target — only the parent's session-scoped watcher receives the message.
88
+ - `<own-session-id>`: this chip's own session UUID. Denormalized onto the message so the parent can address replies back without re-discovering the chip's identity.
89
+ - Body ≤280 chars where possible. If blocked, name the blocker explicitly.
90
+ - Use `--artifact` and `--file` flags to back-reference the actual work (see `/greprag` skill).
91
+
92
+ If `<parent-session-id>` is unknown (parent didn't pass one), send to the parent's project instead: `--to <handle>@greprag.com/<parent-project>` (no session suffix). That's an intentional project broadcast — every watcher in `<parent-project>` receives it, including the parent. Use sparingly; session-targeting is the default. adr: adr/address-grammar.md
93
+
94
+ Send the report BEFORE exiting. The parent agent reads `greprag inbox` on its next turn and picks it up — no polling, no manual chasing.
95
+ ```
96
+
97
+ ### Block 3 — Stay listening for follow-up (append to prompt, runs after Block 2)
98
+
99
+ ```
100
+ **After sending the done report, stay reachable for follow-ups:**
101
+
102
+ Arm a `Monitor` on your own inbox so any directive from main lands as an in-session event. Use the bash-wrapper form — the `while` loop auto-restarts the watcher if the inner SSE process dies (network blip, crash, fork failure). Run this under the **`Monitor`** tool with `persistent: true`:
103
+
104
+ ```bash
105
+ while true; do greprag inbox watch --session <own-session-id> --json; echo "[wrapper] watcher exited, restarting in 1s" >&2; sleep 1; done
106
+ ```
107
+
108
+ - `<own-session-id>` is the chip's own session UUID — same one passed as `--from-session` in Block 2. The filter narrows the stream to messages aimed at this exact session plus broadcasts; sibling chips watching the same project no longer pollute this feed.
109
+ - If you don't have a session id (older sessions), substitute `--project <own-project>` instead of `--session <id>` — wider net but still correct.
110
+ - The chip then idles between events — no token burn, no polling. Each new inbox line = one notification.
111
+ - Restart events go to stderr as `[wrapper] watcher exited…` — visible in the Monitor output file but not as a Monitor notification.
112
+ - When the work is truly done and no follow-up is expected, call `TaskStop` on the Monitor task. Otherwise leave it armed until the session closes.
113
+ - Do NOT drop the `while … done` wrapper. A bare `greprag inbox watch …` will silently end the Monitor task on any inner crash, and any directive sent in the gap is lost until the next user prompt.
114
+ ```
115
+
116
+ **Why not the Stop hook?** The greprag Stop hook ingests inbox messages between user prompts. A Mode B chip running autonomously may never hit a stop boundary; a Mode A chip waiting on a reply mid-task gets the reply only on the next manual interaction. Monitor delivers the reply as an in-session event the moment it lands — no hook lag, no missed directive.
117
+
118
+ ## Reply listening (any session, not just chips)
119
+
120
+ The chip Block 3 pattern generalizes. Any session that sends a message expecting a directive in response should arm a Monitor on its own inbox in the same turn — before the send if you can, so a fast reply doesn't slip past. Use the same bash-wrapper form shown in Block 3 (substitute `--project <own-project>` when no session identity is available), `persistent: true`. Same reasoning: the Stop hook is best-effort for session-end ingestion; Monitor is the only path that catches mid-task replies.
121
+
122
+ **Session scoping is the default in v0.11.** The send-side address grammar — `<handle>@greprag.com/<session-uuid>` — makes the session the only segment, so messages land in exactly one inbox. Project-name addresses (`<handle>@greprag.com/<project>`) are intentional broadcasts, used only when the sender genuinely means "everyone in this project should hear this." A `--session` watcher still passes broadcasts through (by design, so tenant-wide announcements aren't lost), but with session-targeting as the dominant pattern those broadcasts are now rare and recognizable.
123
+
124
+ ## Parent-side: watch for the report
125
+
126
+ If you want the chip's report the instant it lands (not on next turn), start an SSE watcher in the background BEFORE spawning the chip:
127
+
128
+ ```bash
129
+ # preferred — single chip (bash wrapper auto-restarts on inner death)
130
+ while true; do greprag inbox watch --session <parent-session-id> --json; echo "[wrapper] watcher exited, restarting in 1s" >&2; sleep 1; done
131
+
132
+ # fallback / multi-chip campaigns
133
+ while true; do greprag inbox watch --project <parent-project>; echo "[wrapper] watcher exited, restarting in 1s" >&2; sleep 1; done
134
+ ```
135
+
136
+ `--session` is the right default when the chip's Block 2 sends with `--session <parent-session-id>` — exactly one report lands in this watcher per chip. Use `--project` when you've spawned several chips at once and want all their reports on one stream (each chip still tags `--from-session <own-id>`, so the parent reads provenance per message).
137
+
138
+ **Run it under the `Monitor` agent tool.** Monitor emits one notification per stdout line — the parent agent reacts the moment a message lands. **Do NOT use `Bash(run_in_background: true)` for this** — Bash background only notifies on process completion, and a watcher runs forever, so the parent agent gets no events at all until it manually checks the output file. Burned this lesson once already.
139
+
140
+ Sub-1s delivery (verified 210ms in live test), auto-reconnects with cursor-based resume, no polling. Default to this whenever you're waiting on one or more chips. Full pattern: `~/.claude/skills/greprag/SKILL.md` § 5c.
141
+
142
+ ## Parent-project name
143
+
144
+ When spawning, include `<parent-project>` (your current project_name) in the report-back template so the chip knows where to send the report. Get it via `greprag status --json | jq -r '.project.project_name'` or `greprag project-id`.
145
+
146
+ ## Two chip modes
147
+
148
+ Both modes use the same Block 0.5 / 1 / 2 / 3 wrapper — the difference is what the chip does inside.
149
+
150
+ ### Mode A — Ship chip (default)
151
+
152
+ The chip lands in its worktree, does the work, commits checkpoints as progress, reports back via inbox, stays listening for follow-ups. Whether you watch the chip UI mid-flight or it runs end-to-end and inboxes a `done` is a function of how tight the spec is, not a separate mode. A chip that dispatches its own `Agent` sub-tasks mid-work (the "mission commander" pattern) is still Mode A — the Agent dispatch is a behavior the chip's prompt unlocks, not a peer mode.
153
+
154
+ **Use when:** the work is "build X" or "fix Y" or "refactor Z" and the spec is clear enough to ship from. This is the workhorse — reach for it by default.
155
+
156
+ **Operating guidelines:**
157
+
158
+ 1. **All edits, tests, builds, commits happen in the worktree.** Never reach into the parent checkout.
159
+ 2. **Checkpoint commits.** Each logical unit of work gets its own commit (matches the global "checkpoint after every fix/feature" rule). Don't batch a whole feature into one final commit.
160
+ 3. **Verify before reporting done.** Build passes, tests pass, hand-verify the change does what the spec asked. `done` means demonstrably working, not "I wrote code."
161
+ 4. **Never push.** Parent owns the push boundary.
162
+ 5. **No destructive commands.** `git clean`, `git reset --hard`, `git worktree remove`, `git checkout <foreign-branch>`, raw `rm -rf` — all forbidden. Use `git rm` for tracked deletions only.
163
+ 6. **Mid-flight ambiguity → surface it, don't guess.** Either the user types into the chip UI to redirect, OR the chip `greprag send`s a question to main and Monitors its own inbox for the reply.
164
+ 7. **Done-report carries proof.** Pass commit hashes via `--artifact commit:<hash>` and key file paths via `--file <path>`. Not just prose.
165
+
166
+ **Sub-Agent dispatch (still Mode A).** When a discrete sub-task fits a specialized agent (`Explore` for read-only search, `Plan` for design work, `general-purpose` for execution, `code-reviewer` for second opinion), the chip can call `Agent` directly. Pass `model: "haiku" | "sonnet" | "opus"` to scale cost to task. The chip evaluates the Agent's return value and either continues, dispatches another Agent, or inboxes back to main.
167
+
168
+ This gives you a three-layer chain when sub-tasks span model tiers or operator chatter would pollute main's context:
169
+
170
+ ```
171
+ Main session (Opus) ← strategic orchestrator
172
+ ↓ spawn_task(cwd: <target-project>, prompt: "...")
173
+ Mode A chip (Opus) ← tactical commander in target project
174
+ ↓ Agent(subagent_type, model, isolation: "worktree")
175
+ Subagent (any model/type) ← field operator
176
+ ↑ Agent returns to chip
177
+ Chip evaluates, may spawn more Agents, may inbox up
178
+ ↑ greprag send → <your-tenant-email>/<main-project>
179
+ Main session reads inbox, gives next directive via greprag send
180
+ ↓ <your-tenant-email>/<chip-project>
181
+ Chip continues
182
+ ```
183
+
184
+ **What each layer owns:**
185
+
186
+ - **Main** — strategy. Decides what gets delegated. Stays Opus; never burns context on routine sub-tasks.
187
+ - **Chip** — tactical coordination inside a target project. Persists across multiple Agent rounds. Receives directives from main via inbox, dispatches operators, evaluates results, asks for clarification if needed. Picks model per sub-task.
188
+ - **Agent / subagent** — execution. Specific subagent_type and model fit to the task. Returns once when done.
189
+
190
+ **Communication channels:**
191
+
192
+ - Main ↔ chip: greprag inbox (`<handle>@greprag.com/<parent-session-id>` ↔ `<handle>@greprag.com/<chip-session-id>`, falling back to `/<project>` only when a session id is unknown).
193
+ - Chip ↔ subagent: direct return value from the `Agent` tool (no inbox needed — same session).
194
+
195
+ Skip the layering when one Agent call would do — direct dispatch from main is simpler.
196
+
197
+ ### Mode B — Discussion chip
198
+
199
+ The chip lands NOT to ship code, but to be a context-rich conversation partner for design / architecture / debugging questions the orchestrator can't reason about well from grep snippets. The chip reads code as needed, proposes, receives push-back, iterates. Ships nothing without explicit go-ahead — often ships nothing at all and just produces a decision or a scoped follow-up chip prompt.
200
+
201
+ **Detection signals — switch to Mode B when ANY of these fire:**
202
+
203
+ 1. **You catch yourself extrapolating from partial reads.** "Based on these grep hits I think X" — the moment "I think" or "based on snippets" enters your reasoning about architecture, that's the signal. A chip with the repo loaded ground-truths this. Single biggest signal.
204
+ 2. **The user's question is "how should this be shaped?" not "build X."** Design / architecture / "is this the right approach?" / "why is this code like this?" — Mode B. Implementation tasks — Mode A.
205
+ 3. **The user wants to think out loud.** "Bounce something off you" / "thoughts?" / "talk me through this." They want a conversation, not a deliverable.
206
+ 4. **The work will touch multiple subsystems and second-order effects are unknown.** Mode B chip explores the coupling, surfaces what main missed; then either main implements (light coupling) or a follow-up Mode A chip gets a tightened spec (heavy coupling).
207
+
208
+ **Operating guidelines:**
209
+
210
+ - Read code; don't commit.
211
+ - The worktree is scratch space for proposed edits, not a place to ship from.
212
+ - Propose in the chip UI; receive pushback; iterate.
213
+ - Output is a decision: shipped (after explicit go-ahead → transitions into a Mode A finish), parked, or a scoped follow-up Mode A chip prompt.
214
+ - Report-back captures the outcome, not a deliverable.
215
+
216
+ **Chip prompts for Mode B look different from Mode A:**
217
+
218
+ - Frame the open question, not a deliverable.
219
+ - List the sub-questions the user has raised — give the chip the discussion thread, not a spec.
220
+ - Explicitly say "This is a discussion chip, not a task chip. Read code. Propose. Don't ship without go-ahead."
221
+ - Open with a "where do you want to start?" rather than a task list.
222
+
223
+ **Why this beats arguing in main:** orchestrator runs on what it can grep + read in-context. Anything beyond that is plausible-sounding extrapolation. A chip with the repo loaded catches "this coupling exists" / "this billing dependency is non-obvious" / "you missed a callsite" — corrections the orchestrator can't surface itself.
224
+
225
+ ### Picking the slug, model, and subagent_type
226
+
227
+ - **Slug** — kebab-case, short, matches the chip's title. Becomes the worktree branch name (`chip/<slug>`) and the worktree directory (`<project>/.claude/worktrees/<slug>/`).
228
+ - **Model at the chip layer** — defaults to whatever the FleetView/CCD runtime assigns (currently Opus). `spawn_task` has no model param.
229
+ - **Model at the subagent layer** — pass `model: "sonnet"`/`"haiku"`/`"opus"` to the `Agent` tool. Default to the cheapest that fits the task.
230
+ - **subagent_type** — `Explore` for read-only search, `Plan` for design work, `general-purpose` for execution, `code-reviewer` (if installed) for second opinion. Full list in the `Agent` tool description.
231
+
232
+ ### Anti-patterns
233
+
234
+ - **Chip running cleanup commands** — `git clean`, `git reset --hard`, `git worktree remove`, `git checkout` of foreign branches, raw `rm -rf`. Parallel worktrees share `.git`; a chip cleaning "itself" can hit main's working tree. Chips commit and exit; parent owns cleanup.
235
+ - **Chip without Block 1** — pollutes parent checkout. Always include the worktree-setup block.
236
+ - **Chip without Block 2** — parent has no way to know it landed. Always include the report-back block.
237
+ - **Chip without Block 3** — chip dies after one report; parent can't redirect. Always include the reply-listening block.
238
+ - **Sending an expected-reply message without arming Monitor** — Stop hook fires only between user prompts, so a mid-task reply is invisible. Arm `Monitor` on own inbox in the same turn as the `greprag send`.
239
+ - **Spawn_task when Agent would do** — extra session, extra context, slower turnaround. Only reach for spawn_task when you need cross-project or persistence.
240
+ - **Agent when spawn_task would do** — Agent can't change cwd, so cross-project delegation must go through spawn_task.
241
+ - **Polling `greprag inbox` in a loop** — use `greprag inbox watch` under Monitor instead. SSE push, sub-1s latency, free.
242
+
243
+ ## Future blocks (planned, not yet defined)
244
+
245
+ - **Block 0 — Pre-spawn checklist.** Auto-fill parent-project name, generate slug from title, dry-run the worktree path for collisions. Reduces the boilerplate the spawning agent has to compose by hand.
246
+
247
+ **Shipped:** session-scoped routing via the single-segment address grammar `<handle>@greprag.com/<target>` where `<target>` is a session UUID (normal) or a project name (intentional broadcast). v0.11 dropped the legacy `--session`/`--project` send flags and the 3-segment `email/project/session` address — the address itself now carries the target, so missing-target sends error loudly instead of silently broadcasting. adr: adr/address-grammar.md
248
+
249
+ ## See also
250
+
251
+ - `~/.claude/skills/greprag/SKILL.md` — inbox transport, watcher, retract, discover
252
+ - `~/.claude/CLAUDE.md` § Chip Spawning — the lean reference (5 lines) pointing here
253
+ - `~/.claude/CLAUDE.md` § Worktree env — sourcing `.env` from main repo when running in a worktree