greprag 5.13.0 → 5.15.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.
Files changed (41) hide show
  1. package/README.md +7 -6
  2. package/dist/commands/checkpoint-helpers.js +4 -1
  3. package/dist/commands/checkpoint-helpers.js.map +1 -1
  4. package/dist/commands/init.d.ts +2 -0
  5. package/dist/commands/init.js +270 -2
  6. package/dist/commands/init.js.map +1 -1
  7. package/dist/commands/lore.js +7 -5
  8. package/dist/commands/lore.js.map +1 -1
  9. package/dist/commands/memory.d.ts +31 -0
  10. package/dist/commands/memory.js +514 -0
  11. package/dist/commands/memory.js.map +1 -0
  12. package/dist/commands/project.d.ts +16 -0
  13. package/dist/commands/project.js +430 -0
  14. package/dist/commands/project.js.map +1 -0
  15. package/dist/hook.d.ts +1 -1
  16. package/dist/hook.js +9 -10
  17. package/dist/hook.js.map +1 -1
  18. package/dist/index.js +57 -19
  19. package/dist/index.js.map +1 -1
  20. package/dist/project-anchor.d.ts +1 -1
  21. package/dist/project-anchor.js +1 -1
  22. package/dist/session-id.d.ts +30 -25
  23. package/dist/session-id.js +39 -33
  24. package/dist/session-id.js.map +1 -1
  25. package/package.json +2 -1
  26. package/plugin/.claude-plugin/marketplace.json +13 -0
  27. package/plugin/plugins/greprag-inbox/.claude-plugin/plugin.json +7 -0
  28. package/plugin/plugins/greprag-inbox/monitors/monitors.json +8 -0
  29. package/skill/commander/SKILL.md +2 -2
  30. package/skill/content-advisor/SKILL.md +1 -1
  31. package/skill/greprag/SKILL.md +61 -661
  32. package/skill/greprag/docs/corpus.md +98 -0
  33. package/skill/greprag/docs/discord-handoff.md +47 -0
  34. package/skill/greprag/docs/discover.md +28 -0
  35. package/skill/greprag/docs/doctor.md +22 -0
  36. package/skill/greprag/docs/inbox-watch.md +57 -0
  37. package/skill/greprag/docs/inbox.md +100 -0
  38. package/skill/greprag/docs/lore.md +70 -0
  39. package/skill/greprag/docs/memory-advanced.md +23 -0
  40. package/skill/greprag/docs/per-project-flags.md +14 -0
  41. package/skill/greprag/docs/setup.md +208 -0
@@ -1,720 +1,120 @@
1
1
  ---
2
2
  name: greprag
3
3
  description: |
4
- GrepRAG — agentic setup + Odyssey (episodic project memory).
4
+ GrepRAG — agentic setup + memory (episodic project memory, marketed as Odyssey).
5
5
 
6
6
  Single entry point. Runs `greprag status` to learn what's configured,
7
7
  walks the user through any missing setup (email signup, hooks, project
8
- anchor), then surfaces the current project's Odyssey briefing via
9
- `greprag odyssey briefing`.
8
+ anchor), then either searches the project's memory for the operator's
9
+ topic (`greprag memory search "<query>"`) or surfaces the recap
10
+ (`greprag memory recap`) for an open-ended catch-up.
10
11
 
11
12
  Use when: "/greprag", "set up greprag", "greprag status", "configure
12
- memory", "memory briefing", "Odyssey briefing", "catch me up", "what
13
- did we do last week", "what's been happening in this project",
14
- "session context".
13
+ memory", "memory recap", "memory search", "Odyssey briefing", "catch me
14
+ up", "what did we do last week", "what's been happening in this
15
+ project", "find that bug we hit", "search memory for X", "session
16
+ context".
15
17
  metadata:
16
18
  author: travsteward
17
- version: "3.8.0"
19
+ version: "3.9.0"
18
20
  repository: https://github.com/travsteward/greprag
19
21
  license: MIT
20
22
  ---
21
23
 
22
24
  # GrepRAG Advisor
23
25
 
24
- The agent drives all setup and runs the briefing. Single source of truth: `greprag status --json`.
26
+ Single source of truth: `greprag status --json`. Check it → fix any gaps via `docs/setup.md` → search or recap the project's memory.
25
27
 
26
- ### OpenCode vs Claude Code
28
+ OpenCode users: see `docs/setup.md § opencode` for plugin install (`greprag init --opencode`).
27
29
 
28
- - **Claude Code**: hooks in `~/.claude/settings.json` + advisor skill follow steps 1-6 below.
29
- - **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.
30
- - Both share the same anchor (`.claude/project.json` or `.opencode/project.json`) and the same API key.
31
-
32
- ## Step 1 — Get the status
30
+ ## Step 1Status
33
31
 
34
32
  ```bash
35
33
  greprag status --json
36
34
  ```
37
35
 
38
- Parse the JSON. The keys to check, in this order:
39
-
36
+ Parse JSON. Inspect in order:
40
37
  1. `auth.api_key_present`
41
38
  2. `project.anchor_found`
42
39
  3. `project.memory_capture`, `project.session_start_recap`, `project.inbox_notify`
43
40
 
44
- For Claude Code, also check `hooks.session_start_recap`, `hooks.stop_store`, `hooks.post_tool_use_spawn_reminder`. (The legacy `user_prompt_submit_notify` hook was removed in v5.6.1 — live inbox delivery is now the Monitor watcher's job. Don't install it.)
41
+ For Claude Code, also: `hooks.session_start_recap`, `hooks.stop_store`, `hooks.post_tool_use_spawn_reminder`.
45
42
 
46
- Also check the chip-spawn pointer is installed in global CLAUDE.md (Step 3b):
43
+ Chip-spawn convention marker (in `~/.claude/CLAUDE.md`):
47
44
  ```bash
48
- if grep -q "greprag-conventions:start v5" ~/.claude/CLAUDE.md; then echo CONV_V5
49
- elif grep -q "greprag-conventions:start v4" ~/.claude/CLAUDE.md; then echo CONV_V4_NEEDS_UPGRADE
50
- elif grep -q "greprag-conventions:start v3" ~/.claude/CLAUDE.md; then echo CONV_V3_NEEDS_UPGRADE
51
- elif grep -q "greprag-conventions:start v2" ~/.claude/CLAUDE.md; then echo CONV_V2_NEEDS_UPGRADE
52
- elif grep -q "greprag-conventions:start v1" ~/.claude/CLAUDE.md; then echo CONV_V1_NEEDS_UPGRADE
45
+ if grep -q "greprag-conventions:start v5" ~/.claude/CLAUDE.md; then echo CONV_OK
46
+ elif grep -qE "greprag-conventions:start v[1-4]" ~/.claude/CLAUDE.md; then echo CONV_OUTDATED
53
47
  else echo CONV_MISSING; fi
54
48
  test -f ~/.claude/docs/chip-spawn.md && echo DOC_OK || echo DOC_MISSING
55
49
  ```
56
50
 
57
- Also check the permission allowlist (Step 3c):
51
+ Monitor permission:
58
52
  ```bash
59
53
  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')"
60
54
  ```
61
55
 
62
- For each gap, walk the user through the fix. When everything is configured, skip to Step 6 (briefing).
63
-
64
- ## Step 2 — Auth (only if `auth.api_key_present === false`)
65
-
66
- The user has no API key yet. Run the email OTP signup:
67
-
68
- 1. Ask for their email. If `userEmail` is in conversation context (CLAUDE.md, profile), use that and confirm.
69
-
70
- 2. Request the code:
71
- ```bash
72
- curl -sf -X POST "https://api.greprag.com/v1/auth/request-code" \
73
- -H "Content-Type: application/json" \
74
- -d "{\"email\":\"<EMAIL>\"}"
75
- ```
76
-
77
- 3. Read the verification email via the `gmail` skill. Find the most recent message from `noreply@greprag.com` with subject "Your GrepRAG verification code". Extract the 6-digit code. Retry once after 10 seconds if not present.
78
-
79
- 4. Verify and capture the key:
80
- ```bash
81
- curl -sf -X POST "https://api.greprag.com/v1/auth/verify-code" \
82
- -H "Content-Type: application/json" \
83
- -d "{\"email\":\"<EMAIL>\",\"code\":\"<6-DIGIT-CODE>\"}"
84
- ```
85
- Response: `{"ok":true,"apiKey":"grp_live_...","userId":"...","tenantId":"..."}`.
86
-
87
- 5. Write the key into `~/.claude/settings.json` under `env.GREPRAG_API_KEY`. Also set `env.MEMORY_HOOK_ENABLED = "true"`. (Read the file, edit the JSON in-place, write it back.)
88
-
89
- Re-run `greprag status --json` and continue.
90
-
91
- ## Step 3 — Hooks (only if either hook is `false`)
92
-
93
- Edit `~/.claude/settings.json` to add the missing hook(s):
94
-
95
- - **SessionStart recap** (under `hooks.SessionStart`):
96
- ```json
97
- { "matcher": "", "hooks": [{ "type": "command", "command": "greprag-hook recap", "timeout": 3000 }] }
98
- ```
99
- - **Stop store** (under `hooks.Stop`):
100
- ```json
101
- { "matcher": "", "hooks": [{ "type": "command", "command": "greprag-hook store", "timeout": 10000 }] }
102
- ```
103
- - **PreToolUse pre-spawn-check** (under `hooks.PreToolUse`):
104
- ```json
105
- { "matcher": "mcp__ccd_session__spawn_task", "hooks": [{ "type": "command", "command": "greprag-hook pre-spawn-check", "timeout": 3000 }] }
106
- ```
107
- Fires BEFORE every `spawn_task` chip dispatch and validates the call against three machine-checkable rules from `~/.claude/CLAUDE.md § Chip Spawning`: title prefix `Chip: `, Block 1 (`git worktree add` in prompt), Block 2 (`greprag send` in prompt). Returns `permissionDecision: "deny"` with remediation when any rule fails; the agent re-composes the call.
108
-
109
- Append the missing entries to the existing arrays (create the arrays if absent). Don't overwrite existing hooks from other tools.
110
-
111
- **Removing the legacy PostToolUse spawn-reminder hook** (only on upgrade from v0.x → v0.12+): if `~/.claude/settings.json` `hooks.PostToolUse` contains an entry with `matcher: "mcp__ccd_session__spawn_task"` and `command: "greprag-hook spawn-reminder"`, delete that entry. The behavior it carried (arming a Monitor watcher) is now ambient — SessionStart auto-arms the watcher in every greprag-enabled session, so the PostToolUse reminder is vestigial and the underlying subcommand was removed in v0.12.
112
-
113
- ## Step 3b — Convention install (only if marker missing or out-of-date)
114
-
115
- Two pieces install together:
116
-
117
- 1. A single loud pointer line in `~/.claude/CLAUDE.md` — always loaded into every session's context.
118
- 2. The actual chip-spawn protocol at `~/.claude/docs/chip-spawn.md` — read on demand by the agent when about to call `spawn_task`.
119
-
120
- The pointer is short by design: the body costs zero tokens per session that never spawns a chip, the agent reads the doc only when about to act. The PreToolUse `pre-spawn-check` hook enforces title + Block 1/2 at the tool boundary, so an agent that skips the doc still can't ship a bad chip.
121
-
122
- Detect first:
123
- ```bash
124
- if grep -q "greprag-conventions:start v5" ~/.claude/CLAUDE.md; then echo V5
125
- elif grep -q "greprag-conventions:start v4" ~/.claude/CLAUDE.md; then echo V4_UPGRADE
126
- elif grep -q "greprag-conventions:start v3" ~/.claude/CLAUDE.md; then echo V3_UPGRADE
127
- elif grep -q "greprag-conventions:start v2" ~/.claude/CLAUDE.md; then echo V2_UPGRADE
128
- elif grep -q "greprag-conventions:start v1" ~/.claude/CLAUDE.md; then echo V1_UPGRADE
129
- else echo MISSING; fi
130
- test -f ~/.claude/docs/chip-spawn.md && echo DOC_OK || echo DOC_MISSING
131
- ```
132
-
133
- **If `MISSING`**, insert the v5 block into `~/.claude/CLAUDE.md` immediately after the `## Inbox` section (use the Edit tool, marker comments verbatim):
134
-
135
- ```markdown
136
- <!-- greprag-conventions:start v5 -->
137
- **CHIP SPAWN METHOD** → before calling `spawn_task`, read `~/.claude/docs/chip-spawn.md`. Non-negotiable.
138
- <!-- greprag-conventions:end v5 -->
139
- ```
140
-
141
- **If `V4_UPGRADE`**, replace the entire `<!-- greprag-conventions:start v4 -->` … `<!-- greprag-conventions:end v4 -->` block (inclusive of markers) with the v5 single-line pointer above. Tell the user "Upgrading greprag-conventions v4 → v5 (moves the inline body to ~/.claude/docs/chip-spawn.md; CLAUDE.md now carries only a loud pointer read on demand)."
142
-
143
- **If `V3_UPGRADE`, `V2_UPGRADE`, or `V1_UPGRADE`**, same replacement pattern: delete the old block (markers inclusive) and insert the v5 pointer above. Tell the user "Upgrading greprag-conventions v{1|2|3} → v5."
144
-
145
- **Also on any upgrade from v1/v2/v3 → v5**, delete the legacy deep doc if it exists (its content lives at the new `chip-spawn.md` path now):
146
- ```bash
147
- rm -f ~/.claude/docs/agent-coordination.md
148
- ```
149
-
150
- **If `DOC_MISSING`**, the chip-spawn protocol doc must be installed at `~/.claude/docs/chip-spawn.md`. `greprag init` copies it from the npm package on install; if it's missing here, re-run `greprag init` (`init` is idempotent and will re-copy the template). The doc is the body the pointer line references — without it the agent has nothing to read.
151
-
152
- Re-run the grep to confirm install. Markers must stay verbatim — they're how subsequent `/greprag` runs detect "already installed" and skip this step.
153
-
154
- ## Step 3c — Permission allowlist (only if `MON_MISSING` from Step 1)
155
-
156
- 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.
157
-
158
- Read `~/.claude/settings.json` and confirm `permissions.allow` contains `"Monitor"`. If not, add it. Recommended baseline for greprag users:
159
-
160
- ```json
161
- {
162
- "permissions": {
163
- "allow": [
164
- "Bash(*)",
165
- "Monitor",
166
- "Read", "Edit", "Write", "Grep", "Glob",
167
- "WebFetch", "WebSearch", "Skill", "Agent", "Task"
168
- ]
169
- }
170
- }
171
- ```
172
-
173
- `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.
174
-
175
- If the user has a tighter Bash policy (no `Bash(*)`), the per-command minimum for greprag is:
176
- - `Bash(greprag *)` — covers send, inbox, retract, watch, status, discover
177
- - `Bash(greprag-hook *)` — covers the hook commands installed in Step 3
178
- - `Monitor` — inbox watchers
179
-
180
- Tell the user the change you're proposing before editing settings.json. Don't silently broaden their permission posture.
181
-
182
- ## Step 3d — Channel plugins (if user has Discord / Telegram / iMessage plugins enabled)
183
-
184
- Adjacent gotcha worth surfacing during setup. Check whether any channel plugin is enabled in either global or any project `settings.json`:
185
-
186
- ```bash
187
- grep -lE '"(discord|telegram|imessage|fakechat)@claude-plugins-official":\s*true' \
188
- ~/.claude/settings.json \
189
- $(find . -maxdepth 3 -path '*/.claude/settings.json' 2>/dev/null) 2>/dev/null
190
- ```
191
-
192
- 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:
193
-
194
- - **Setting enables the MCP server to load** → its tools (e.g. `reply`, `fetch_messages`) become available.
195
- - **`--channels plugin:<name>@<marketplace>` at launch enables push** → inbound `notifications/claude/channel` events surface as `<channel>` blocks in the session context.
196
-
197
- 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."
198
-
199
- 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:
200
-
201
- ```bash
202
- cd <project-with-plugin>
203
- claude --channels plugin:discord@claude-plugins-official
204
- ```
205
-
206
- 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.
207
-
208
- 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.
209
-
210
- ## Step 4 — Project anchor (only if `project.anchor_found === false`)
211
-
212
- The current folder has no `.claude/project.json`. Ask the user:
213
-
214
- > "GrepRAG isn't set up for this project yet. Set up memory for this folder? (y/n)"
215
-
216
- If yes, ask three preferences:
217
- - "Capture turns into memory here? (y/n)" → `memory_capture`
218
- - "Inject the recap briefing at SessionStart here? (y/n)" → `session_start_recap`
219
- - "How should this project handle inbox notifications? (1) every turn (recommended) / (2) only at session start / (3) off" → `inbox_notify`: `every_turn` | `session_start_only` | `off`
220
-
221
- **Path heuristic**: if `project.cwd` contains `AppData/Roaming/Claude/local-agent-mode-sessions/` or starts with `/tmp/` or `/var/tmp/`, the cwd is an ephemeral session path. Tell the user:
222
-
223
- > "This looks like an ephemeral Claude session directory. Anchor here (won't persist across sessions) or at the stable parent (persists)? (1=here, 2=stable parent)"
224
-
225
- If they pick stable parent, walk up to the nearest stable directory (e.g., `~/AppData/Roaming/Claude/` on Windows, `~` on Unix) and place the anchor there.
226
-
227
- If `project.is_deterministic_fallback === true` AND there's existing memory under that UUID (check via `curl -sf "https://api.greprag.com/v1/memory/by-period?projectId=<project_id>&from=2020-01-01T00:00:00Z&to=$(date -u +%Y-%m-%dT%H:%M:%SZ)&limit=1" -H "Authorization: Bearer ${GREPRAG_API_KEY}"` — if `count > 0`), ask:
228
-
229
- > "Found existing memory under this folder's implicit UUID. Reuse it to keep continuity? (y/n)"
230
-
231
- If yes, use the existing `project_id` in the new anchor file. If no, mint a fresh UUID via `node -e "console.log(crypto.randomUUID())"`.
232
-
233
- Write the file:
234
- ```bash
235
- mkdir -p <cwd>/.claude
236
- cat > <cwd>/.claude/project.json <<EOF
237
- {
238
- "project_id": "<UUID>",
239
- "project_name": "<basename, lowercased>",
240
- "memory_capture": <true|false>,
241
- "session_start_recap": <true|false>,
242
- "inbox_notify": "<every_turn|session_start_only|off>",
243
- "created": "<ISO-NOW>"
244
- }
245
- EOF
246
- ```
247
-
248
- Then register the anchor with the server so inbox addressing (`<email>/<project_name>`) resolves:
249
- ```bash
250
- curl -sf -X POST "https://api.greprag.com/v1/inbox/projects/register" \
251
- -H "Authorization: Bearer ${GREPRAG_API_KEY}" \
252
- -H "Content-Type: application/json" \
253
- -d "{\"project_id\":\"<UUID>\",\"project_name\":\"<basename>\"}"
254
- ```
255
-
256
- If registration returns 409 (project_name conflict with another project under this tenant), ask the user for a unique handle and retry.
257
-
258
- ## Step 5 — Per-project flags (when the user asks to flip them)
259
-
260
- If the user says "turn off recaps here", "stop capturing memory in this folder", or "only notify me of inbox at session start":
261
-
262
- 1. Read `<anchor_path>` from status
263
- 2. Edit the JSON in-place — flip `memory_capture`, `session_start_recap`, or `inbox_notify`
264
- 3. Write it back
265
-
266
- Hooks honor these flags on next fire — no restart needed.
267
-
268
- ## Step 5b — Inbox operations
269
-
270
- When the user asks "check my inbox", "any messages?", or runs `/greprag inbox`:
271
-
272
- ```bash
273
- greprag inbox # list unread (auto-marks read)
274
- greprag inbox --all # full history
275
- greprag inbox keep <id> # extend a read message's TTL
276
- greprag inbox delete <id>
277
- ```
278
-
279
- To send a plain message:
280
- ```bash
281
- greprag send "<markdown body>" --to <address>
282
- ```
283
-
284
- `send` prints two lines on success — the delivered-to confirmation **and a retract code**:
285
- ```
286
- Sent to alice@greprag.com/abc12345 (a7f3c5e2)
287
- Retract: greprag retract K9M2X4P7QV
288
- ```
289
- The retract code lets the sender pull the message back without layering follow-up "SUPERSEDES" notes on top. See Step 5d.
290
-
291
- To send a **rich message** with back-pointers — preferred whenever the message refers to a memory row, a shipped artifact, or specific code lines:
292
- ```bash
293
- greprag send "Quick heads up — the auth bug I described yesterday repros here." \
294
- --to alice@greprag.com/abc12345 \
295
- --memory 04f3e0d4-aa12-44ef-9a01-bb3df2c7e911 \
296
- --file src/auth/handler.ts:42 \
297
- --file src/middleware/check.ts:10-15 \
298
- --artifact commit:7a4d35b \
299
- --artifact pr:#42
300
- ```
301
-
302
- Flags (all repeatable, all optional):
303
- - `--memory <uuid>` — point to a memory row (turn, ship event, episodic summary)
304
- - `--artifact <type:id>` — point to a shipped thing. Types: `commit`, `pr`, `deploy`, `release`, `push`, `merge`
305
- - `--file <path[:lines]>` — point to a code location. Lines are `42` or `10-15`
306
- - `--ref-json '<json>'` — escape hatch for a fully-formed references object (mutually exclusive with the above)
307
- - `--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.
308
-
309
- 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.
310
-
311
- **When to populate references vs. when to leave them off:**
312
- - Short chat messages ("pinging you", "deploy is up", "ack") — no references, just body.
313
- - Bug reports, follow-ups, design decisions — always add the specific code lines (`--file`) and any ship event that's relevant (`--artifact`).
314
- - 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.
315
- - Don't hallucinate references. If you can't name a real file path or artifact ID, leave the flag off.
316
-
317
- Address formats (v0.11+):
318
-
319
- | Form | Use | Behavior |
320
- |---|---|---|
321
- | `<handle>@greprag.com` | What you SHARE | Identity-only / receive form. Errors on send — the bare handle has no target. |
322
- | `<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. |
323
- | `<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. |
324
- | `me` / `self` | Shortcut for your own tenant | Receive form only. |
325
-
326
- 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.
327
-
328
- `<handle>` is one of:
329
- - `1834729@greprag.com` — canonical numeric handle. Opaque, leaks nothing. Get yours from `greprag status --json | jq -r .identity.handle` or `greprag whoami`.
330
- - `alice@greprag.com` — opt-in vanity alias (claim with `greprag identity claim alice`).
331
-
332
- **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
333
-
334
- 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
335
-
336
- 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.
337
-
338
- ## Step 5c — Watching the inbox (push delivery)
339
-
340
- 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:
341
-
342
- ```bash
343
- greprag inbox watch # tenant-wide stream
344
- greprag inbox watch --project <name> # only messages addressed to this project
345
- greprag inbox watch --session <id> # only messages targeting this session (plus broadcasts)
346
- greprag inbox watch --since <id-or-iso> # resume from a known cursor
347
- greprag inbox watch --json # emit one JSON object per line (preferred under Monitor)
348
- ```
349
-
350
- `--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.
351
-
352
- 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.
353
-
354
- **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.
355
-
356
- **Two canonical patterns:**
357
-
358
- ### Parent-side: watch for chip reports BEFORE spawning
359
-
360
- ```bash
361
- # Parent arms a Monitor scoped to its own session, then spawns the chip
362
- # (chip prompt's Block 2 sends with --session <parent-session-id>).
363
- # Each chip's "done" report becomes one Monitor notification, with no cross-talk
364
- # from other chips or sessions sharing the parent's project inbox.
365
- # The while-loop wrapper auto-restarts the SSE process if it dies — a bare
366
- # `greprag inbox watch` would silently end the Monitor task on any inner crash.
367
- while true; do greprag inbox watch --session <parent-session-id> --json; echo "[wrapper] watcher exited, restarting in 1s" >&2; sleep 1; done
368
- ```
369
-
370
- 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
-
372
- ### Post-send: listen for replies after `greprag send`
373
-
374
- 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.
375
-
376
- ```bash
377
- # After: greprag send "..." --to <someone>/<their-project>/<their-session> \
378
- # --from-session <own-session-id>
379
- # Arm under Monitor (persistent: true):
380
- while true; do greprag inbox watch --session <own-session-id> --json; echo "[wrapper] watcher exited, restarting in 1s" >&2; sleep 1; done
381
- ```
382
-
383
- 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.
56
+ ## Step 2 Route gaps to `docs/setup.md`
384
57
 
385
- 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.
386
-
387
- **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.
388
-
389
- 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.
390
-
391
- ## Step 5d — Retracting a message you just sent
392
-
393
- `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:
394
-
395
- ```bash
396
- greprag retract <code>
397
- ```
398
-
399
- Behavior is decided by the server based on whether the recipient has already read the message:
400
-
401
- - **Unread** → the row is hard-deleted. Recipient never sees it. Output: `Retracted (status: deleted — recipient had not read it).`
402
- - **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).`
403
- - **Already retracted** → no-op, idempotent. Output: `Already retracted (status: already_retracted — no change).`
404
- - **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).`
405
-
406
- **When to retract vs. when to send a SUPERSEDES follow-up:**
407
- - Just sent it, recipient hasn't read yet, and the framing was wrong? → `greprag retract`. Clean inbox state, zero noise.
408
- - 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.
409
- - 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.
410
-
411
- 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).
412
-
413
- ## Step 5e — Health & repair (when memory looks wrong)
414
-
415
- 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.
416
-
417
- ```bash
418
- greprag doctor
419
- ```
420
-
421
- What it does:
422
- 1. Reads the current project's identity (project_id + which cascade level resolved it — file / git-derived / global / path-hash)
423
- 2. Computes what the git-derived UUID *would* be (if in a git repo with commits)
424
- 3. Queries the API for sibling project_ids under the same profile name (these are the orphans — usually from old anchor files lost to gitignore or a hash-fallback period before init)
425
- 4. Presents the findings and offers actions:
426
- - **Migrate to git-derived UUID** (recommended when there's drift) — moves current + orphan rows onto the git-derived ID and strips `project_id` from `.claude/project.json` so identity flows from git history going forward
427
- - **Consolidate orphans into current UUID** — keeps the current identity but pulls orphan rows in
428
- - **Dry-run** — runs the recommended action through the API with `dry_run: true` so the user sees exactly what would change before committing
429
-
430
- Flags:
431
- - `--inspect` — diagnose only, no prompts (good for "tell me what's wrong here")
432
- - `--yes` / `-y` — non-interactive; picks the recommended action and runs it
433
-
434
- 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.
435
-
436
- ## Step 5f — Corpus (upload + search arbitrary text)
437
-
438
- Odyssey captures the agent's own work (every turn, hourly/daily/weekly compaction). **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.
439
-
440
- **Design contract (post-v0.8):** GrepRAG does **no LLM work at read time**. The agent (you) formulate the lexical queries. Write-side enrichment makes "insulted" find archaic "wrongeth" passages via tsvector OR. Read-side does pure SQL: combined field-weighted tsvector + ts_rank_cd + websearch_to_tsquery + adjacency-clustered ranking.
441
-
442
- Triggers: "load this book into greprag", "upload the docs", "ingest this PDF" (after they convert it), "search the Marcus Aurelius corpus", "what does the codebase say about X", "find the passage about Y in the book I uploaded".
443
-
444
- ### Upload
445
-
446
- ```bash
447
- greprag corpus upload <file-or-url> [--name "Display Name"] [--kind book]
448
- ```
449
-
450
- - `--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.
451
- - 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.
452
- - `--name` defaults to the filename basename. Prefer an explicit name — the user references the store by name later.
453
- - File or URL must be plain text or markdown. PDFs: ask the user to convert first.
454
- - Cost: one round-trip to ingest + N async Gemini Flash-Lite calls (one per substantive node, drained every 2 min). Read-time cost: $0.
455
-
456
- ### Search — the chain protocol
457
-
458
- Searches are **agent-driven**. You decompose the user's intent into 1–3 lexical queries. There is no server-side intent expansion. The cost of formulation comes from your own token budget (you have the user's context; GrepRAG doesn't).
459
-
460
- #### Query operator syntax (websearch_to_tsquery)
461
-
462
- The query string accepts these operators:
463
-
464
- - `term1 term2` — both required (AND).
465
- - `term1 OR term2` — either suffices.
466
- - `"quoted phrase"` — exact adjacent words.
467
- - `-excluded` — must NOT contain.
468
- - Parenthesize for grouping: `(insulted OR wronged) -metadata`.
469
-
470
- Build queries that bridge the user's modern vocabulary to the corpus register. Stale prompts ("how should I respond when insulted") force every word — useless against archaic text. Decomposed queries ("insulted OR reproach OR contempt") win.
471
-
472
- #### Chain — probe, narrow, expand, cross-reference
473
-
474
- The optimal access pattern for an open-ended user question:
475
-
476
- 1. **Probe** — `greprag corpus search "<store>" "<2-3 broad-vocab query>"` to find the topic region.
477
- 2. **Narrow** — if results scatter, refine with `--section "Chapter VII"` or pass tighter query operators and search again.
478
- 3. **Expand** — for each promising hit, `greprag corpus walk "<store>" <nodeId>` to read the surrounding ±2 nodes.
479
- 4. **Cross-reference** — re-search with a new angle if the first probe missed something the read-back suggests.
480
-
481
- Each call is ~50–150ms. Two to four calls is normal; don't fear chaining.
482
-
483
- #### Single-store search
484
-
485
- ```bash
486
- greprag corpus search "<store name or UUID>" "<lexical query>" [--limit 5] [--section "Book VII"] [--shape dialogue]
487
- ```
488
-
489
- Each result carries: `nodeId` (stable 8-char anchor), `position`, `headingPath`, `score`, `content`.
490
-
491
- #### Multistore search (cross-corpus questions)
492
-
493
- ```bash
494
- curl -sf -X POST "$GREPRAG_API_URL/v1/search" \
495
- -H "Authorization: Bearer $GREPRAG_API_KEY" \
496
- -H "Content-Type: application/json" \
497
- -d '{
498
- "queries": ["insulted OR reproach", "wronged OR injustice"],
499
- "storeIds": ["..."],
500
- "limit": 8,
501
- "adjacencyWindow": 3,
502
- "adjacencyAlpha": 0.3,
503
- "filters": {"section": "Book VII"}
504
- }'
505
- ```
506
-
507
- Omit `storeIds` to search every store under the calling tenant. RRF fuses across (store × query) pairs; adjacency boosts surface semantic clusters (a node whose neighbors are also hits ranks higher).
508
-
509
- ### Walk
510
-
511
- ```bash
512
- greprag corpus walk "<store>" <nodeId> [--before 2 --after 2]
513
- ```
514
-
515
- Surrounding-context fetch. ~50ms, no LLM.
516
-
517
- ### List / delete / status
518
-
519
- ```bash
520
- greprag corpus list [--kind book]
521
- greprag corpus status "<store>" # write-side enrichment progress
522
- greprag corpus delete "<store>" --yes
523
- ```
524
-
525
- ### When to reach for corpus vs. Odyssey
526
-
527
- | Want to … | Use |
58
+ | Gap | Section |
528
59
  |---|---|
529
- | Pull yesterday's daily summary, last week's weekly | `greprag odyssey briefing` (Step 6 flow) |
530
- | Ask "what shipped on this branch last week?" | `greprag odyssey ships --last 50` or `odyssey daily --last 7` |
531
- | Backfill a missed compaction window | `greprag odyssey compact <hour\|day\|week>` |
532
- | Load a book the user paste-bombed into the chat | `corpus upload` then `corpus search` |
533
- | Search a codebase the user wants the agent to learn | `corpus upload --kind codebase` |
534
- | Cross-corpus question across multiple uploads | `POST /v1/search` with omitted `storeIds` |
535
-
536
- Odyssey is the agent's own past. Corpus is everything else.
60
+ | `auth.api_key_present === false` | `docs/setup.md § auth` |
61
+ | Any hook is false | `docs/setup.md § hooks` |
62
+ | Convention marker missing/outdated, or `DOC_MISSING` | `docs/setup.md § conventions` |
63
+ | `MON_MISSING` | `docs/setup.md § permissions` |
64
+ | `project.anchor_found === false` | `docs/setup.md § anchor` |
65
+ | Channel plugin enabled but no `--channels` flag | `docs/setup.md § channels` |
537
66
 
538
- ## Step 5g Commander (Discord DM bridge talk to the user from their phone)
67
+ Re-run `greprag status --json` after each fix. When clean, proceed to Step 3.
539
68
 
540
- For the full operator-facing flow see `/commander` (skill at `~/.claude/skills/commander/SKILL.md`). This section is the orchestrator-side summary so a greprag session can drive the same surface without loading the commander skill explicitly.
69
+ Per-project flag flips (turn off recaps here, etc.): `docs/per-project-flags.md`.
541
70
 
542
- When the user wants to step away from the desk and continue the conversation on their phone, route the thread through the greprag Discord bot. There are two surfaces one-time pairing (identity) and per-session handoff (active routing). Plus an emergency-router fallback: if the user DMs the bot with no handoff active, the bot auto-links to the most-recently-attached session watcher under their tenant. Tag `references.discord.emergency_route` on the inbox row flags the auto-link; reply with self-identification on first response.
71
+ ## Step 3Memory access (when configured)
543
72
 
544
- ### Pairing (one-time per tenant)
545
-
546
- `greprag discord pair` generates a 6-char code. The user DMs `@greprag` on Discord with `/pair <code>`. After that, the user's snowflake is bound to their greprag tenant. DMs from that snowflake land as inbox messages on `default_project_id` (the project they paired from).
547
-
548
- You don't run this — it's a one-time setup the user does themselves. Detect "I'm paired" via `greprag discord me`: returns `paired: true` and the pairing's project_name.
549
-
550
- ### Handoff (per-session routing pin)
551
-
552
- The pattern the user almost always means by "let's continue on Discord":
553
-
554
- ```bash
555
- greprag discord handoff --ttl 60 --json
556
- ```
557
-
558
- Run it under `Monitor` (persistent: true). The command pins DMs from the user's snowflake to (this project, this session) for 60 min, fires a confirmation DM to the user's phone, then **blocks** streaming the session's inbox to stdout as JSON. Each line that prints is one Discord DM landing — Monitor delivers them as notifications right back into your turn. The pin slides forward 30+ min on every inbound, so an active thread stays anchored.
559
-
560
- Replies go out via:
561
-
562
- ```bash
563
- greprag send --to discord:<snowflake> "your message body"
564
- ```
565
-
566
- The CLI handles UTF-8, Discord's 2000-char limit, optional `--ref-json '{"discord":{"reply_to_message_id":"..."}}'` for threading. **Do not use curl for this** — bash on Windows mangles em-dashes / curly quotes / emoji into Win-1252 bytes that render as `?` on Discord. Node fetch (which the CLI uses) is UTF-8 native.
567
-
568
- For long agent turns where the auto-typing's 10-second window expires, call `greprag discord typing` between work steps to refresh the indicator. Silent on success.
569
-
570
- `greprag discord unhandoff` releases the pin early (DMs revert to default project). Pin also expires naturally via the TTL.
571
-
572
- ### Canonical handoff flow
573
-
574
- User says "let's keep going on Discord" / "DM me" / "I'm stepping out":
575
-
576
- 1. Confirm pairing with `greprag discord me`. If unpaired, tell the user to run `greprag discord pair` and DM `/pair <code>` first.
577
- 2. Resolve current session_id (`CLAUDE_SESSION_ID` env, or the 8-hex from SessionStart context).
578
- 3. Arm: `Monitor` with command `greprag discord handoff --session <8-hex> --project <name> --ttl 60 --json`, persistent.
579
- 4. Tell the user the pin is live; the bot already DMed them. Each reply from Discord will fire as a Monitor notification.
580
- 5. On each notification, parse the JSON body (`body` field = user's message text). Draft your reply. Send via `greprag send --to discord:<snowflake> "..."`. The snowflake is in `references.discord.snowflake`.
581
-
582
- ## Step 6 — Briefing (when everything is configured)
583
-
584
- The Odyssey briefing is the SessionStart-shaped recap — the most recent weekly summary plus the last seven daily summaries. Use the CLI verb:
73
+ Two access patterns pick by intent.
585
74
 
75
+ **A. Search by topic** — when the operator references a past problem, bug, decision, or topic. Reach for this first.
586
76
  ```bash
587
- greprag odyssey briefing
77
+ greprag memory search "<query>"
588
78
  ```
79
+ Query syntax is `websearch_to_tsquery`: AND is default, `OR` explicit, `"phrases"` quoted, `-negation` drops terms. Prints ranked hits (top 5) with node IDs, shape tag, score, content. Flags: `--shape daily`, `--limit 10`, `--format json`.
589
80
 
590
- That prints the markdown briefing directly. The agent surfaces it verbatim. To target another project under the same tenant: `--project <name>`. To pull raw JSON for downstream tooling: `--format json`.
591
-
592
- Per-shape access (use these when the briefing isn't what's wanted):
593
-
81
+ **B. Recap by time** an open-ended "catch me up". Most recent weekly + last seven daily summaries.
594
82
  ```bash
595
- greprag odyssey daily --last 7 # newest 7 daily summaries
596
- greprag odyssey weekly --last 2 # newest 2 weekly summaries
597
- greprag odyssey hourly --last 24 # newest 24 hourly summaries (within last 7 days)
598
- greprag odyssey turns --last 20 # raw per-turn envelopes (21-day TTL)
599
- greprag odyssey ships --last 50 # ship-event rows (commits/PRs/deploys/releases)
600
- greprag odyssey compact <hour|day|week> # manual compaction trigger (backfill / admin)
83
+ greprag memory recap
601
84
  ```
85
+ Emit the markdown verbatim — the compactor already shaped it. Do not rewrite or summarize. Other projects: `--project <name>`. Raw JSON: `--format json`.
602
86
 
603
- All accept `--project <name>`, `--from ISO --to ISO`, and `--format markdown|json`. See `greprag odyssey help` for the full list.
604
-
605
- If the briefing prints `No episodic rows yet for <project> — compaction runs hourly. Check back after the first active session.`, that's the canonical empty-state message.
606
-
607
- Otherwise present what the CLI emitted verbatim. Do not rewrite or summarize — the compactor already shaped it.
608
-
609
- **Naming note.** The valid `--type` values for the underlying HTTP endpoint `/v1/memory/by-period` are `turn`, `hourly`, `daily`, `weekly`, `ship-event`. Earlier versions of this doc referenced `episodic-daily` / `episodic-weekly` — those values silently return zero rows because no node ever had that shape. The `greprag odyssey` CLI uses the correct values; prefer the CLI over raw curl.
610
-
611
- If the agent absolutely needs raw curl (advanced / scripted use):
87
+ Empty-state output (canonical, do not paraphrase):
88
+ > No episodic rows yet for <project> — compaction runs hourly. Check back after the first active session.
612
89
 
90
+ Per-shape pulls (when neither search nor recap fits):
613
91
  ```bash
614
- PROJECT_ID=$(greprag project-id)
615
- TO=$(node -e "console.log(new Date().toISOString())")
616
- FROM=$(node -e "const d=new Date(); d.setDate(d.getDate()-7); console.log(d.toISOString())")
617
- curl -sf "https://api.greprag.com/v1/memory/by-period?projectId=${PROJECT_ID}&from=${FROM}&to=${TO}&type=daily&limit=7" \
618
- -H "Authorization: Bearer ${GREPRAG_API_KEY}"
92
+ greprag memory daily --last 7
93
+ greprag memory weekly --last 2
94
+ greprag memory hourly --last 24
95
+ greprag memory turns --last 20
96
+ greprag memory ships --last 50
97
+ greprag memory compact <hour|day|week>
619
98
  ```
99
+ All accept `--project <name>`, `--from ISO --to ISO`, `--format markdown|json`. See `greprag memory help`.
620
100
 
621
- The route name stays `/v1/memory/by-period` Odyssey is the user-facing brand, the HTTP surface kept its internal name for compatibility.
622
-
623
- ## Step 6b — Seeding lore (LEARNINGS substrate)
624
-
625
- Lore = what was learned. Project-specific emergent knowledge — gotchas, discovered constraints, drift-prone observations. Distinct from static project knowledge (which belongs in CLAUDE.md / docs / code structure). Whenever you waste tokens *discovering* something a future agent shouldn't have to re-discover, seed it as project lore. Discovery is fine the first time — the failure mode is repeating it every time a chip spawns or a new session opens.
626
-
627
- ### When to seed
628
-
629
- Three signatures of discovery waste — if you see one in your own trace, seed the result so the next agent skips the search:
101
+ Aliases (silent back-compat): `greprag memory briefing` `recap` (renamed v5.16.0); `greprag odyssey ...` still works for v5.8.0-era scripts. Raw curl + `--type` value catalog: `docs/memory-advanced.md`.
630
102
 
631
- - **Search cascade.** ≥3 `Glob` / `Grep` calls to find a path that should be obvious (where do migrations live? where's the inbox table? which file owns the CLI dispatch?). Seed the answer with `scope: chip-startup`.
632
- - **Schema archaeology.** ≥3 file `Read`s to reconstruct the shape of a data type, a JSONB column, or an API request body. Seed the shape (1–3 lines) with `scope: <subsystem>-touch`.
633
- - **Trial-and-error env probing.** Multiple `Bash` attempts at the same env operation (different SSL flags, different connection strings, repeated "is this var set?" checks). Seed the working invocation with `scope: env`.
103
+ ## Proactive-fire rules
634
104
 
635
- ### How to seed
105
+ **ABOUT TO BACKGROUND A `greprag inbox watch`? USE THE `Monitor` AGENT TOOL, NOT `Bash(run_in_background: true)`.** Bash background notifies only on process completion; watchers run forever, so the agent gets zero events until it manually reads the output file. Wrap with `while true; do greprag inbox watch ...; done` so the loop survives inner crashes. Full pattern: `docs/inbox-watch.md`.
636
106
 
637
- ```bash
638
- greprag lore add "<one-sentence learning, optionally with a file path>" --scope <scope> [--project <name>]
639
- ```
640
-
641
- Examples:
642
- ```bash
643
- greprag lore add "Migrations live at repo root: migrations/<NNN>_<name>.sql. Apply with node scripts/apply-migration.cjs migrations/<file>.sql." --scope chip-startup
644
-
645
- greprag lore add "Inbox storage uses JSONB metadata on nodes (store kind='inbox'). No inbox_messages table — dropped in migration 035. See packages/core/src/inbox.ts." --scope inbox-touch
646
-
647
- greprag lore add "Build everything from repo root: npm run build (Turborepo). Forced rebuild: npm run build -- --force." --scope general
648
- ```
649
-
650
- **Scope naming.** Free-form strings — there is no enum. Check what's already in use before inventing a new label:
651
-
652
- ```bash
653
- greprag lore scopes [--project <name>]
654
- ```
655
-
656
- Conventional scopes:
657
- - `chip-startup` — what a freshly-spawned chip needs in its first 5 turns. Layout, build commands, test runners, key file paths.
658
- - `general` — applies to almost any session in this project.
659
- - `<subsystem>-touch` — lore that matters only when editing a specific subsystem (`inbox-touch`, `episodic-touch`, `enrichment-touch`).
660
- - `env` — environment / credentials / DB connection gotchas.
661
-
662
- Pick the narrowest scope that still applies. A lore entry about migration paths is `chip-startup` (every chip needs it); one about how the hourly compactor's prompt versioning works is `episodic-touch` (only relevant if you're editing that subsystem).
663
-
664
- ### Reading lore back (pull pattern)
665
-
666
- ```bash
667
- greprag lore query --scope chip-startup --limit 10 --format markdown # for inlining into a chip prompt
668
- greprag lore query --scope inbox-touch --query "session routing" # lexical-rank within a scope
669
- greprag lore query --query "how do migrations apply" --limit 5 # cross-scope, lexical-rank only
670
- greprag lore list # human-review every entry, grouped by scope
671
- greprag lore delete <nodeId> # prune stale entry (nodeId printed in list)
672
- ```
673
-
674
- `--format markdown` returns a numbered list with no decoration — drop it straight into a `**Project Lore**` block when spawning a chip.
675
-
676
- ### Deliberate review (via /lore-advisor)
677
-
678
- Lore decays as code moves — paths change, conventions die, "learned that X" stops being true. Run `/lore-advisor` periodically (especially after a refactor or rename) to audit drift, mine episodic memory for newly-emerged learnings, and promote project-agnostic entries to global rules.
679
-
680
- ### Chip-spawn pull pattern
681
-
682
- When you compose a `spawn_task` chip prompt, pull `chip-startup` lore into the prompt before dispatching. Full convention lives in `~/.claude/docs/chip-spawn.md`; the one-liner is: `greprag lore query --scope chip-startup --project <project> --limit 10 --format markdown`, then wrap the output in a `**Project Lore**` block at the top of the prompt. Skip the block when the output is empty.
683
-
684
- ## Step 7 — Cross-project discovery (for advisor agents)
685
-
686
- When the user is in a cross-project advisor context ("content-advisor",
687
- "business-advisor") and you need to know which projects this tenant has
688
- memory in, call `discover` — one request returns every project plus
689
- per-shape row counts and activity ranges. No need to know directory paths
690
- upfront, no need to page through `/v1/memory/by-period` and risk one
691
- high-activity project crowding out structured rows from quieter ones.
692
-
693
- ```bash
694
- greprag discover --json
695
- ```
696
-
697
- Response shape:
698
- ```json
699
- {
700
- "tenant": { "id": "...", "userEmail": "..." },
701
- "projects": [
702
- { "id": "<uuid>", "name": "openwriter", "anchor": "registered",
703
- "row_counts": { "turn": 197, "hourly": 8, "daily": 1, "weekly": 0, "ship-event": 12 },
704
- "first_activity": "2026-05-12T08:00:00Z",
705
- "last_activity": "2026-05-25T11:42:00Z" }
706
- ],
707
- "crystallization_types": ["turn","hourly","daily","weekly","ship-event"],
708
- "totals": { "rows": 1234, "projects": 7 }
709
- }
710
- ```
107
+ **ABOUT TO SEND TO A `@gmail.com` / `@anthropic.com` / REAL EMAIL ADDRESS? STOP — `users.email` IS NEVER A ROUTING ADDRESS.** Use the numeric handle (`1834729@greprag.com`) or claimed vanity alias (`travis@greprag.com`). If you don't know the recipient's handle, ASK — don't guess from their email. adr: adr/numeric-handles.md. Full grammar: `docs/inbox.md § address`.
711
108
 
712
- `anchor: "registered"` means the project was registered via
713
- `/v1/inbox/projects/register` (has a row in the `projects` table — inbox
714
- addressing as `<email>/<project_name>` works). `anchor: "fallback"` means
715
- the project is only known via memory-store metadata — still has memory,
716
- but no registry entry, so its name may be the path-derived basename and
717
- inbox-by-name resolution will not find it.
109
+ ## Reference index
718
110
 
719
- From there, pick a `projectId` from the list and fetch its briefing via
720
- the Step 6 queries.
111
+ - `docs/setup.md` auth · hooks · conventions · permissions · channels · anchor · opencode · bulk-register
112
+ - `docs/per-project-flags.md` flip `memory_capture` / `session_start_recap` / `inbox_notify`
113
+ - `docs/inbox.md` — `greprag send`, `greprag inbox`, address grammar, retract
114
+ - `docs/inbox-watch.md` — SSE watcher patterns, liveness model, parent-side / post-send patterns
115
+ - `docs/doctor.md` — `greprag doctor` (identity drift, orphan consolidation)
116
+ - `docs/corpus.md` — upload + search arbitrary text (books, codebases, voice samples)
117
+ - `docs/discord-handoff.md` — Commander DM bridge (`greprag discord pair/handoff`)
118
+ - `docs/memory-advanced.md` — raw curl, `/v1/memory/by-period` `--type` values, naming note
119
+ - `docs/lore.md` — seed + query project-specific learnings
120
+ - `docs/discover.md` — cross-project advisor lookup (`greprag discover`)