greprag 0.10.0 → 5.0.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.
@@ -0,0 +1,125 @@
1
+ # Setup — First-Run Gateway
2
+
3
+ The advisor's first invocation enters bootstrap. Setup runs once, written to a config file, then subsequent invocations skip directly to the standard protocol.
4
+
5
+ ## Portfolio root resolution
6
+
7
+ Resolution order:
8
+
9
+ 1. Env var `CONTENT_ADVISOR_ROOT`
10
+ 2. Config file `~/.claude/content-advisor.json` with `{ "portfolio_root": "/abs/path" }`
11
+ 3. Marker file scan up the cwd tree — looks for `docs/ventures.md` and `docs/strategy/focus.md`
12
+ 4. Fallback default: `C:/orchestrator`
13
+ 5. None applicable → ask user, save to config
14
+
15
+ The advisor never operates against an unresolved portfolio root.
16
+
17
+ ## Setup flow
18
+
19
+ ```
20
+ /content-advisor (no config detected)
21
+
22
+ [Step 1] Locate portfolio root
23
+ → default C:/orchestrator; confirm or override
24
+ → save to ~/.claude/content-advisor.json
25
+
26
+ [Step 2] Check GrepRAG
27
+ → command -v greprag → exits 0?
28
+ → test -n "$GREPRAG_API_KEY"? (source ~/.env if missing)
29
+ → greprag discover --json → returns ≥1 project?
30
+ → any failure → walk user through /greprag setup
31
+
32
+ [Step 3] Verify writer skills present
33
+ → ~/.claude/skills/x-writer/SKILL.md exists?
34
+ → ~/.claude/skills/blog-writer/SKILL.md exists?
35
+ → ~/.claude/skills/newsletter-writer/SKILL.md exists?
36
+ → any missing → "Run /skill-publish from C:/openwriter to install the writer masters."
37
+
38
+ [Step 4] Read WRITER-CONVENTION.md
39
+ → C:/openwriter/skills/WRITER-CONVENTION.md (source of truth for handoff brief shape)
40
+ → if absent, advisor still works but warns the contract is unverified
41
+
42
+ [Step 4.5] Per-venture ICP (Ideal Customer Profile) derivation
43
+ → For each venture in `project_to_venture`:
44
+ a) Search for an existing avatar / audience doc:
45
+ - OpenWriter workspaces with titles like "Audience", "Audience & Reader Journey", "Avatar", "ICP"
46
+ - The venture's marketing-site repo for `content/audience.md` or similar
47
+ - If found → store pointer in config under `icp_per_venture[venture]` as
48
+ `"openwriter:<docId>"` or `"file:<absolute-path>"`
49
+ b) If no doc exists, conduct a short interview (5-7 questions max):
50
+ - Who is the buyer? (one sentence)
51
+ - What's their current state? (the pain that brings them in)
52
+ - What do they pick up your content hoping for?
53
+ - What's the recognition shock they want? (their life mirrored back)
54
+ - What do they walk away with that's actionable this week?
55
+ - What's the failure mode of content that doesn't land?
56
+ - Optional: who do they trust today that you're competing with?
57
+ c) Write the interview output to `docs/icp/<venture>.md` in the portfolio
58
+ root and store the pointer in config.
59
+ → Per-venture ICP is the demand-side spec the advisor reads at rank time
60
+ (see Rule 5 in `decision-rules.md`).
61
+
62
+ [Step 5] Verify portfolio docs
63
+ → docs/ventures.md, docs/strategy/focus.md present?
64
+ → each missing → "Run /business-advisor to scaffold portfolio docs."
65
+
66
+ [Step 6] Project ↔ venture mapping
67
+ → greprag discover --json lists project names
68
+ → match each to a venture umbrella (often 1:1; some ventures span multiple repos)
69
+ → save to ~/.claude/content-advisor.json under `project_to_venture`
70
+
71
+ [Step 7] Optional: per-venture cadence overrides
72
+ → defaults in docs/decision-rules.md (X daily, newsletter weekly, blog 2×/mo)
73
+ → user can override per venture in config under `cadence_overrides`
74
+
75
+ [Step 8] Lock in
76
+ → run one full pass, present opportunity list as the first output
77
+ → confirm config persisted
78
+ ```
79
+
80
+ ## Config file format
81
+
82
+ `~/.claude/content-advisor.json`:
83
+
84
+ ```json
85
+ {
86
+ "portfolio_root": "C:/orchestrator",
87
+ "greprag_api_url": "https://api.greprag.com",
88
+ "project_to_venture": {
89
+ "openwriter": "openwriter",
90
+ "openwriter-site": "openwriter",
91
+ "openwriter-publish": "openwriter",
92
+ "paybot": "paybot",
93
+ "paybot-portal": "paybot",
94
+ "tournamentmale": "tournament-male",
95
+ "tm-book": "tournament-male",
96
+ "orchestrator": "personal"
97
+ },
98
+ "cadence_overrides": {
99
+ "openwriter": { "blog": "weekly" }
100
+ },
101
+ "icp_per_venture": {
102
+ "your-venture-here": "openwriter:doc_abc123",
103
+ "another-venture": "file:C:/path/to/portfolio/docs/icp/another-venture.md"
104
+ },
105
+ "channels_per_venture": {
106
+ "tournament-male": ["x", "newsletter", "blog"],
107
+ "paybot": ["x", "blog"],
108
+ "openwriter": ["x", "blog"],
109
+ "personal": ["x", "newsletter"]
110
+ }
111
+ }
112
+ ```
113
+
114
+ `channels_per_venture` is the gate that prevents the advisor from proposing a blog post for a venture that has no blog. Default behavior when a venture is missing from this map: assume all three channels eligible.
115
+
116
+ ## Re-running setup
117
+
118
+ Delete `~/.claude/content-advisor.json` and re-invoke. Or invoke with "redo setup step N" to re-enter one sub-flow.
119
+
120
+ ## Failure modes
121
+
122
+ - **GrepRAG unreachable** → advisor cannot run. Setup blocks. Source-farmer rule needs ship-events; nothing else compensates.
123
+ - **Writer skills missing** → advisor still produces the list but flags handoff commands as unverified.
124
+ - **Portfolio docs missing** → tier prioritization disabled (all opportunities treated equal). Surface a warning.
125
+ - **No projects in greprag discover** → no source material. Advisor exits with "no episodic memory yet — write code, ship something, then check back."
@@ -0,0 +1,89 @@
1
+ # Writing Activity
2
+
3
+ The "what have we already written" stream. Pairs with episodic memory to drive the anti-duplication and cadence-floor rules.
4
+
5
+ ## What we want to know per channel per venture
6
+
7
+ | Channel | The question | Source |
8
+ |---|---|---|
9
+ | X | When was the last post? What topics in last 7d? | x-strategy cache, or fxtwitter recent timeline |
10
+ | Blog | When was the last post? What topics in last 30d? | git log on the venture's marketing-site repo + frontmatter scan |
11
+ | Newsletter | When was the last issue sent? What was its through-line? | `mcp__openwriter__list_newsletter_issues` |
12
+ | OpenWriter drafts | What's in flight right now (un-shipped drafts touched in last 14d)? | `mcp__openwriter__list_documents` filtered by recency |
13
+
14
+ ## Per-source procedure
15
+
16
+ ### OpenWriter drafts (in-flight)
17
+
18
+ ```
19
+ list_workspaces → for each workspace:
20
+ list_documents → filter where updatedAt > now-14d AND not in trash
21
+ → for each doc: extract { id, title, workspace_name, updatedAt, tags }
22
+ → infer channel from workspace name conventions (blog/newsletter/x/scratch)
23
+ OR from tags if present
24
+ → infer venture from workspace name OR explicit metadata
25
+ ```
26
+
27
+ These are CRUCIAL — an in-flight draft on topic X means "don't propose another piece on X." Surface them as "in progress" markers, not opportunities.
28
+
29
+ ### Newsletter sends
30
+
31
+ ```
32
+ list_newsletter_issues → sort desc by sentAt → take top 4
33
+ → for each: { id, subject, sentAt, doc_id }
34
+ → most recent sentAt → "newsletter last sent N days ago"
35
+ → if N > cadence floor (default 7d): cadence-floor opportunity for newsletter
36
+ ```
37
+
38
+ ### Blog history
39
+
40
+ For each venture with a marketing-site repo (path resolved via `project_to_venture` config + scanning `ventures.md` for repo paths):
41
+
42
+ ```
43
+ git -C <repo> log --since="30 days ago" --name-only --pretty=format:'%h|%ci|%s'
44
+ → filter file changes to blog content paths (src/content/blog/**, content/posts/**, etc.)
45
+ → group commits by post file → { post_file, first_commit_date, latest_commit_date }
46
+ → most recent → "blog last shipped N days ago"
47
+ ```
48
+
49
+ The blog-content path convention varies per site; try common patterns:
50
+ - `src/content/blog/**` (Astro)
51
+ - `content/posts/**` (Hugo)
52
+ - `_posts/**` (Jekyll)
53
+ - `app/blog/**/page.mdx` (Next.js)
54
+
55
+ If no match, fall back to scanning frontmatter (`---\npubDate:`) in any `.md`/`.mdx` file modified in window.
56
+
57
+ ### X activity
58
+
59
+ Three options, in preference order:
60
+
61
+ 1. **`/x-strategy` cache** — if present at a known path, parse the latest cached export.
62
+ 2. **`mcp__x__*` tools** — if the X MCP is connected, query recent tweets for @Meta_Trav.
63
+ 3. **fxtwitter timeline** — public, free; parse the user's recent posts.
64
+
65
+ What we want: list of `{ posted_at, text, type: thread|single|article|comic, topic_inferred }`. Topic inference is best-effort — a 30-word excerpt is enough to dedupe against memory rows.
66
+
67
+ ## Output of this stream
68
+
69
+ A per-venture-per-channel activity map:
70
+
71
+ ```json
72
+ {
73
+ "tournament-male": {
74
+ "x": { "last_at": "2026-05-24T...", "topics_7d": ["six-week challenge", "kettlebell program"] },
75
+ "newsletter": { "last_at": "2026-05-19T...", "subject": "Week of May 19" },
76
+ "blog": { "last_at": "2026-04-30T...", "recent_topics": ["bible study cohort"] }
77
+ },
78
+ "paybot": {
79
+ "x": { "last_at": "2026-05-23T...", "topics_7d": ["upgrade flow ship"] },
80
+ "blog": { "last_at": "2026-05-10T...", "recent_topics": ["new pricing"] }
81
+ }
82
+ }
83
+ ```
84
+
85
+ Plus a separate "in-flight drafts" list across all ventures (the OpenWriter list_documents output, filtered by recency).
86
+
87
+ ## Failure tolerance
88
+
89
+ Any one of these sources can be down without breaking the advisor — they're enrichment. The minimum viable run is: greprag memory + ventures.md + focus.md. Everything else just sharpens ranking.
@@ -133,9 +133,15 @@ Delegating work — `spawn_task` chip vs `Agent` tool, two chip modes, the workt
133
133
 
134
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
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 `greprag inbox watch --session <own-session-id> --json` with `persistent: true` (or `--project <own-project>` as a project-wide fallback 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.
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
137
 
138
- For real-time chip reports, the parent runs `greprag inbox watch --session <parent-session-id>` (preferred) or `--project <parent-project>` 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.
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.
139
145
  <!-- greprag-conventions:end v3 -->
140
146
  ```
141
147
 
@@ -289,7 +295,7 @@ greprag send "<markdown body>" --to <address>
289
295
 
290
296
  `send` prints two lines on success — the delivered-to confirmation **and a retract code**:
291
297
  ```
292
- Sent to alice@example.com/paybot (a7f3c5e2)
298
+ Sent to alice@greprag.com/abc12345 (a7f3c5e2)
293
299
  Retract: greprag retract K9M2X4P7QV
294
300
  ```
295
301
  The retract code lets the sender pull the message back without layering follow-up "SUPERSEDES" notes on top. See Step 5d.
@@ -297,7 +303,7 @@ The retract code lets the sender pull the message back without layering follow-u
297
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:
298
304
  ```bash
299
305
  greprag send "Quick heads up — the auth bug I described yesterday repros here." \
300
- --to alice@example.com/paybot \
306
+ --to alice@greprag.com/abc12345 \
301
307
  --memory 04f3e0d4-aa12-44ef-9a01-bb3df2c7e911 \
302
308
  --file src/auth/handler.ts:42 \
303
309
  --file src/middleware/check.ts:10-15 \
@@ -310,8 +316,9 @@ Flags (all repeatable, all optional):
310
316
  - `--artifact <type:id>` — point to a shipped thing. Types: `commit`, `pr`, `deploy`, `release`, `push`, `merge`
311
317
  - `--file <path[:lines]>` — point to a code location. Lines are `42` or `10-15`
312
318
  - `--ref-json '<json>'` — escape hatch for a fully-formed references object (mutually exclusive with the above)
313
- - `--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>`.
314
- - `--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.
315
322
 
316
323
  **When to populate references vs. when to leave them off:**
317
324
  - Short chat messages ("pinging you", "deploy is up", "ack") — no references, just body.
@@ -319,16 +326,24 @@ Flags (all repeatable, all optional):
319
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.
320
327
  - Don't hallucinate references. If you can't name a real file path or artifact ID, leave the flag off.
321
328
 
322
- Address formats (all valid):
323
- - `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`.
324
- - `1834729@greprag.com/paybot` recipient's paybot project inbox.
325
- - `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`.
326
342
  - `alice@greprag.com` — opt-in vanity alias (claim with `greprag identity claim alice`).
327
- - `me` / `self` — shortcut for your own tenant inbox (server resolves).
328
343
 
329
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
330
345
 
331
- 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
332
347
 
333
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.
334
349
 
@@ -359,7 +374,9 @@ Each message arrives within ~500ms of the sender's `greprag send` (210ms verifie
359
374
  # (chip prompt's Block 2 sends with --session <parent-session-id>).
360
375
  # Each chip's "done" report becomes one Monitor notification, with no cross-talk
361
376
  # from other chips or sessions sharing the parent's project inbox.
362
- greprag inbox watch --session <parent-session-id> --json
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
363
380
  ```
364
381
 
365
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.
@@ -371,7 +388,8 @@ Any session that sends a message that could draw a directive in response arms th
371
388
  ```bash
372
389
  # After: greprag send "..." --to <someone>/<their-project>/<their-session> \
373
390
  # --from-session <own-session-id>
374
- # Arm: greprag inbox watch --session <own-session-id> --json (Monitor, persistent: true)
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
375
393
  ```
376
394
 
377
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.
@@ -438,11 +456,11 @@ Triggers: "load this book into greprag", "upload the docs", "ingest this PDF" (a
438
456
  ### Upload
439
457
 
440
458
  ```bash
441
- greprag corpus upload <file-or-url> [--name "Display Name"] [--kind book] [--enrichment-style book]
459
+ greprag corpus upload <file-or-url> [--name "Display Name"] [--kind book]
442
460
  ```
443
461
 
444
- - `--kind` defaults to `book`. Valid: `book`, `codebase`, `voice`, `generic`.
445
- - `--enrichment-style` picks the write-side prompt template. Valid: `book` (narrative/philosophy, default), `codebase` (source code), `transcript` (dialogue/interview), `reference` (technical docs), `generic` (mixed/unknown). If omitted, auto-derived from `--kind`. Pass it explicitly when the content shape differs from the default — e.g. a transcript uploaded as `--kind generic --enrichment-style transcript`.
462
+ - `--kind` is organizational metadata. Valid: `book`, `codebase`, `voice`, `generic`. Defaults to `book`. Lets you filter `greprag corpus list --kind codebase` later; doesn't change the enrichment prompt.
463
+ - Enrichment is GR5 phrase-aware, applied uniformly to all corpus kinds the single Narrow C prompt extracts single-word synonyms (graph expansion) and multi-word phrase variants (concept-level bridging). No per-kind prompt forking.
446
464
  - `--name` defaults to the filename basename. Prefer an explicit name — the user references the store by name later.
447
465
  - File or URL must be plain text or markdown. PDFs: ask the user to convert first.
448
466
  - Cost: one round-trip to ingest + N async Gemini Flash-Lite calls (one per substantive node, drained every 2 min). Read-time cost: $0.
@@ -523,7 +541,7 @@ greprag corpus delete "<store>" --yes
523
541
  | Pull yesterday's daily summary, last week's weekly | `/v1/memory/by-period` (Step 6 briefing flow) |
524
542
  | Ask "what did I work on with the auth migration?" | `/v1/memory/by-period` filtered by keywords |
525
543
  | Load a book the user paste-bombed into the chat | `corpus upload` then `corpus search` |
526
- | Search a codebase the user wants the agent to learn | `corpus upload --kind codebase --enrichment-style codebase` |
544
+ | Search a codebase the user wants the agent to learn | `corpus upload --kind codebase` |
527
545
  | Cross-corpus question across multiple uploads | `POST /v1/search` with omitted `storeIds` |
528
546
 
529
547
  Episodic memory is the agent's own past. Corpus is everything else.
@@ -59,7 +59,7 @@ All edits, tests, and commits happen in the worktree. The main checkout stays un
59
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
60
  ```
61
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 <email>/<parent-project>` (no session suffix) and the parent watches `--project <parent-project>` (no `--session`). Less precise, still correct.
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
63
 
64
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
65
 
@@ -67,6 +67,8 @@ Path convention: `<project>/.claude/worktrees/<slug>/` — same parent directory
67
67
 
68
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
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
+
70
72
  ### Block 2 — Report back via greprag inbox (append to prompt)
71
73
 
72
74
  ```
@@ -74,21 +76,20 @@ Path convention: `<project>/.claude/worktrees/<slug>/` — same parent directory
74
76
 
75
77
  ```bash
76
78
  greprag send "<status>: <commit hash> on chip/<slug> — <one-line>" \
77
- --to <your-tenant-email>/<parent-project> \
78
- --session <parent-session-id> \
79
+ --to <your-tenant-handle>@greprag.com/<parent-session-id> \
79
80
  --from-session <own-session-id> \
80
81
  --artifact commit:<hash> \
81
82
  --file <key-file-path>
82
83
  ```
83
84
 
84
85
  - `<status>`: `done` | `blocked` | `partial`
85
- - `<parent-project>`: the project_name of the session that spawned you (it's in this prompt's metadata if unknown)
86
- - `<parent-session-id>`: filled in by the spawning session in Block 1 of this prompt.
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.
87
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.
88
89
  - Body ≤280 chars where possible. If blocked, name the blocker explicitly.
89
90
  - Use `--artifact` and `--file` flags to back-reference the actual work (see `/greprag` skill).
90
91
 
91
- If `<parent-session-id>` is unknown (parent didn't pass one), drop both `--session` and `--from-session` the message falls back to project-wide delivery and reaches every watcher under `<parent-project>`, including the parent.
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
92
93
 
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.
94
95
  ```
@@ -98,33 +99,38 @@ Send the report BEFORE exiting. The parent agent reads `greprag inbox` on its ne
98
99
  ```
99
100
  **After sending the done report, stay reachable for follow-ups:**
100
101
 
101
- Arm a `Monitor` on your own inbox so any directive from main lands as an in-session event. Run this under the **`Monitor`** tool with `persistent: true`:
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`:
102
103
 
103
104
  ```bash
104
- greprag inbox watch --session <own-session-id> --json
105
+ while true; do greprag inbox watch --session <own-session-id> --json; echo "[wrapper] watcher exited, restarting in 1s" >&2; sleep 1; done
105
106
  ```
106
107
 
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.
108
- - If you don't have a session id (older sessions), fall back to `--project <own-project> --json` — wider net but still correct.
109
+ - If you don't have a session id (older sessions), substitute `--project <own-project>` instead of `--session <id>` — wider net but still correct.
109
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.
110
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.
111
114
  ```
112
115
 
113
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.
114
117
 
115
118
  ## Reply listening (any session, not just chips)
116
119
 
117
- 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 `greprag inbox watch --session <own-session-id> --json`, `persistent: true` (or `--project <own-project>` when no session identity is available). Same reasoning: the Stop hook is best-effort for session-end ingestion; Monitor is the only path that catches mid-task replies.
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.
118
121
 
119
- **Session scoping replaces the old self-echo workaround.** A `--session` watcher filters incoming traffic to messages whose `to_session_id` matches this session OR is null (broadcasts). A `greprag send --to <own-tenant-email>` (no project, no session) still echoes back as a broadcast and reaches every watcher — but the noise of sibling chips and unrelated project mail is gone. Old guidance: "expect echoes, ignore silently." New guidance: pass `--session <own-session-id>` on the watcher and the only echoes left are genuine broadcasts you actually want to see. To avoid even those, use `--to <email>/<project>/<their-session>` with `--from-session <own-session-id>` and the message lands in exactly one inbox.
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.
120
123
 
121
124
  ## Parent-side: watch for the report
122
125
 
123
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:
124
127
 
125
128
  ```bash
126
- greprag inbox watch --session <parent-session-id> --json # preferred single chip
127
- greprag inbox watch --project <parent-project> # fallback / multi-chip campaigns
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
128
134
  ```
129
135
 
130
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).
@@ -183,7 +189,7 @@ Chip continues
183
189
 
184
190
  **Communication channels:**
185
191
 
186
- - Main ↔ chip: greprag inbox (`<email>/<parent-project>` ↔ `<email>/<chip-project>`).
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).
187
193
  - Chip ↔ subagent: direct return value from the `Agent` tool (no inbox needed — same session).
188
194
 
189
195
  Skip the layering when one Agent call would do — direct dispatch from main is simpler.
@@ -216,9 +222,10 @@ The chip lands NOT to ship code, but to be a context-rich conversation partner f
216
222
 
217
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.
218
224
 
219
- ### Picking the slug, model, and subagent_type
225
+ ### Picking the title, slug, model, and subagent_type
220
226
 
221
- - **Slug** — kebab-case, short, matches the chip's title. Becomes the worktree branch name (`chip/<slug>`) and the worktree directory (`<project>/.claude/worktrees/<slug>/`).
227
+ - **Title** — ALWAYS prefix with `Chip: ` then the imperative action phrase. Format: `Chip: <verb-phrase>` (e.g. `Chip: Fix stale README badge`, `Chip: Wire Narrow C into core`, `Chip: GR5 collapse style prompts`). The `Chip: ` prefix is non-negotiable — it makes chip-spawned sessions instantly recognizable in the FleetView UI vs. IDE-checkbox-spawned `claude/` sessions and human-driven sessions. The verb phrase MUST NOT itself repeat "chip" — the prefix already marks it as one. Imperative verb phrase under ~50 chars after the prefix.
228
+ - **Slug** — kebab-case, short, matches the post-prefix portion of the title. Becomes the worktree branch name (`chip/<slug>`) and the worktree directory (`<project>/.claude/worktrees/<slug>/`).
222
229
  - **Model at the chip layer** — defaults to whatever the FleetView/CCD runtime assigns (currently Opus). `spawn_task` has no model param.
223
230
  - **Model at the subagent layer** — pass `model: "sonnet"`/`"haiku"`/`"opus"` to the `Agent` tool. Default to the cheapest that fits the task.
224
231
  - **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.
@@ -238,7 +245,7 @@ The chip lands NOT to ship code, but to be a context-rich conversation partner f
238
245
 
239
246
  - **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.
240
247
 
241
- **Shipped:** session-scoped routing (`--session` / `--from-session` on `greprag send`, `--session` on `greprag inbox watch`, 3-segment `<email>/<project>/<session-id>` address grammar) the cleaner-routing solution previously planned as "ephemeral chip-inbox addresses." Lives directly on the canonical session UUID instead of synthesizing a chip-id, so no new address types or registry rows.
248
+ **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
242
249
 
243
250
  ## See also
244
251