greprag 5.3.0 → 5.5.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,131 @@
1
+ ---
2
+ name: discord
3
+ description: |
4
+ Discord DM bridge for greprag. Pair your Discord account once, then DM the
5
+ bot to talk to the agent in any open Claude session. Handoff temporarily
6
+ pins your DMs to one specific session — say "let's continue on Discord"
7
+ before stepping away from the desk and your phone keeps the same thread
8
+ alive.
9
+
10
+ Use when: "/discord", "discord", "pair my discord", "step away", "let's
11
+ continue on discord", "let's continue on phone", "DM me", "handoff to
12
+ discord", "discord handoff", "discord status", "am I paired", "what's my
13
+ discord state", "I'm going for a walk", "I'll be afk".
14
+ metadata:
15
+ author: travsteward
16
+ version: "1.0.0"
17
+ repository: https://github.com/travsteward/greprag
18
+ license: MIT
19
+ ---
20
+
21
+ # Discord DM bridge
22
+
23
+ The agent runs `greprag discord me` to learn the current state, then branches into pair / handoff / status. Everything else is one shell command per branch.
24
+
25
+ ## Step 1 — Get the state
26
+
27
+ ```bash
28
+ greprag discord me
29
+ ```
30
+
31
+ Parse the JSON. Three states:
32
+
33
+ - `paired: false` → user has never paired this tenant. Run **pair flow**.
34
+ - `paired: true` and `handoff === null` → paired, no active pin. If the user asked to step away (any trigger phrase), run **handoff flow**. Otherwise just print **status**.
35
+ - `paired: true` and `handoff !== null` → active pin live. Print **status with handoff details**.
36
+
37
+ ## Step 2 — Pair flow (only if not paired)
38
+
39
+ ```bash
40
+ greprag discord pair
41
+ ```
42
+
43
+ Prints the 6-char code. Tell the user verbatim:
44
+
45
+ > DM `@greprag` on Discord: `/pair <CODE>` (expires in 15 min).
46
+
47
+ When they confirm the bot replied with "Paired," re-run `greprag discord me` to verify, then continue. If the user wanted a handoff (their original request mentioned stepping away), proceed to Step 3 once paired.
48
+
49
+ ## Step 3 — Handoff flow (the killer feature)
50
+
51
+ Trigger: user said anything implying "I'm leaving the desk and want this thread to follow me to Discord" — *step away*, *continue on phone*, *handoff*, *DM me*, *afk*, *I'll be walking*.
52
+
53
+ Resolve the session id from the SessionStart hook's `additionalContext` (8-hex form). Resolve the project name from the current anchor (`greprag project-id`'s sibling lookup, or the explicit `--project` flag).
54
+
55
+ Arm the watcher under **Monitor with `persistent: true`**, wrapped in the `while true` restart loop so a process death (npm install mid-session, network blip, supervisor bug) auto-recovers:
56
+
57
+ ```bash
58
+ greprag discord handoff --session <8-hex> --project <name> --ttl 60 --no-watch && \
59
+ while true; do
60
+ greprag inbox watch --project <name> --session <8-hex> --json --no-supervise
61
+ echo "[wrapper] watcher exited, restarting in 1s" >&2
62
+ sleep 1
63
+ done
64
+ ```
65
+
66
+ Two halves on purpose:
67
+ 1. `discord handoff --no-watch` writes the pin server-side (`active_project_id`, `active_session_id`, `active_expires_at`) and fires the confirmation DM to the user's phone. Returns immediately.
68
+ 2. The `while true` loop tails the session inbox via SSE. Each line printed = one Discord DM landing as a Monitor notification.
69
+
70
+ **Never use the bare `greprag discord handoff` form without `--no-watch` for production handoff.** It self-streams, but a process death (e.g. `npm i -g greprag@latest` from another shell wipes the install dir) takes the watcher down with no restart. The wrapped two-step is the resilient form.
71
+
72
+ Tell the user: "Handoff pinned for 60 min. Reply on Discord — your messages route to this session. Bot already DMed you a confirmation."
73
+
74
+ ## Step 4 — Replying to inbound DMs
75
+
76
+ Each Monitor notification carries the full event payload: `body` is the user's message text, `references.discord.snowflake` is their Discord ID.
77
+
78
+ Send your reply via the CLI:
79
+
80
+ ```bash
81
+ greprag send --to discord:<snowflake> "your reply text"
82
+ ```
83
+
84
+ The CLI uses Node fetch (UTF-8 native) — em-dashes, curly quotes, emoji all render correctly. **Do NOT use curl from bash on Windows** for Discord sends — the local code page (Win-1252) mangles non-ASCII bytes into `?` on the user's phone.
85
+
86
+ For long agent turns where you're drafting >10s, refresh the typing indicator between work steps:
87
+
88
+ ```bash
89
+ greprag discord typing
90
+ ```
91
+
92
+ Silent on success. Tells Discord to show "GrepRAG is typing…" for another 10s.
93
+
94
+ If the reply exceeds 2000 chars (Discord's hard limit), split on paragraph boundaries and send multiple messages with continuation markers.
95
+
96
+ ## Step 5 — Status (when paired with no handoff intent, or to inspect)
97
+
98
+ Print verbatim:
99
+
100
+ ```
101
+ Discord pairing:
102
+ Tenant: travis (or whatever me.snowflake points to)
103
+ Default route: <me.project_name> (project_id <me.project_id>)
104
+ Snowflake: <me.snowflake>
105
+ Paired at: <me.paired_at>
106
+ Last DM in: <me.last_seen_inbound_at or "(never)">
107
+ ```
108
+
109
+ If `handoff !== null`:
110
+
111
+ ```
112
+ Active handoff pin:
113
+ Project: <me.handoff.project_name>
114
+ Session: <me.handoff.session_id>
115
+ Expires: <me.handoff.expires_at> (sliding — each inbound DM extends by ≥30 min)
116
+ ```
117
+
118
+ Offer: *"Run `greprag discord unhandoff` to clear the pin and revert DMs to default routing."*
119
+
120
+ ## Hard rules
121
+
122
+ - **Don't auto-handoff without user intent.** If the user just asked "am I paired?", show status — don't arm a Monitor.
123
+ - **Always use the wrapped form** in production. The bare `discord handoff` is for testing only.
124
+ - **Send replies via the CLI**, not curl. UTF-8 correctness, parser correctness, and the success-print all break in subtle ways otherwise.
125
+ - **Never `npm i -g greprag@latest`** from a session with a running handoff watcher — it kills the watcher mid-stream. Either land the upgrade before arming, or stop the Monitor first.
126
+ - **Pin scope is one snowflake → one session at a time.** A new handoff in another session supersedes the prior one silently.
127
+
128
+ ## Related skills
129
+
130
+ - `/greprag` — broader greprag setup (memory, inbox, corpus). Step 5g there carries the same handoff guidance for sessions invoked through greprag-as-orchestrator.
131
+ - The `discord-notify` skill (separate, global) sends one-off Discord webhook pings for attention. Not related to this skill — that's a webhook, this is a paired DM bridge.
@@ -139,9 +139,9 @@ Delegating work — `spawn_task` chip vs `Agent` tool, two chip modes, the workt
139
139
  while true; do greprag inbox watch --session <own-session-id> --json; echo "[wrapper] watcher exited, restarting in 1s" >&2; sleep 1; done
140
140
  ```
141
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.
142
+ Run under `Monitor` with `persistent: true`. Get `<own-session-id>` from this session's SessionStart hook system-reminder ("Your greprag session id: `<8-hex>`") — every session gets one. The `--project <own-project>` form is a legacy backstop for sessions where SessionStart never fired and should fire essentially never; using it as a default broadcasts traffic to every sibling session in the project (observed cross-talk in production). The Stop hook only fires between user prompts; without Monitor, mid-task replies are invisible until the next stop boundary.
143
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.
144
+ For real-time chip reports, the parent arms the same wrapped watcher with `--session <parent-session-id>` (always available from the orchestrator's own SessionStart hook — substitute it before the chip prompt leaves your turn). The `--project <parent-project>` variant is for genuine multi-chip-campaign cases where you've fanned out N chips in parallel and want all reports on one stream; do not reach for it because you "forgot" your session id. Each stdout line = one notification. Do NOT use `Bash(run_in_background)` — it only fires on process completion, not per line; a watcher never exits, so the parent gets zero events. Do NOT use the bare `greprag inbox watch` without the `while true` wrapper — if the inner watcher dies you go silently deaf with no restart.
145
145
  <!-- greprag-conventions:end v3 -->
146
146
  ```
147
147
 
@@ -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 <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.
62
+ Fill `<parent-session-id>` with the orchestrator's own session UUID before sending the prompt. The SessionStart hook prints it as the first system-reminder of every session ("Your greprag session id: `<8-hex>`") both the full UUID and the 8-hex short form are accepted by the address grammar. Never leave the placeholder unfilled, and never substitute the literal string `<parent-session-id>` into the chip prompt. The project-level fallback (`--to <handle>@greprag.com/<parent-project>`) is a legacy backstop for sessions that predate the SessionStart hook (vanishingly rare in current sessions); cross-project broadcasts pollute every sibling chip's inbox and force the parent to demux noise. Treat that as a bug, not a default. If you genuinely cannot find your session id in the SessionStart reminder, error out rather than broadcasting at the project level. adr: `C:/greprag/adr/address-grammar.md`
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
 
@@ -105,8 +105,8 @@ Arm a `Monitor` on your own inbox so any directive from main lands as an in-sess
105
105
  while true; do greprag inbox watch --session <own-session-id> --json; echo "[wrapper] watcher exited, restarting in 1s" >&2; sleep 1; done
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.
109
- - If you don't have a session id (older sessions), substitute `--project <own-project>` instead of `--session <id>` wider net but still correct.
108
+ - `<own-session-id>` is the chip's own session UUID — find it in this session's SessionStart hook system-reminder ("Your greprag session id: `<8-hex>`"). Use the same value you passed as `--from-session` in Block 2. The session filter narrows the stream to messages aimed at this exact session plus broadcasts; sibling chips watching the same project no longer pollute this feed.
109
+ - The `--project <own-project>` substitution exists only as a legacy backstop for sessions that predate the SessionStart hook. In current sessions the hook always fires; if the reminder isn't present, error out rather than broadcasting at the project level — project-scope makes every sibling watcher see your traffic and has been observed to cause silent cross-talk in production.
110
110
  - The chip then idles between events — no token burn, no polling. Each new inbox line = one notification.
111
111
  - Restart events go to stderr as `[wrapper] watcher exited…` — visible in the Monitor output file but not as a Monitor notification.
112
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.
@@ -126,14 +126,14 @@ The chip Block 3 pattern generalizes. Any session that sends a message expecting
126
126
  If you want the chip's report the instant it lands (not on next turn), start an SSE watcher in the background BEFORE spawning the chip:
127
127
 
128
128
  ```bash
129
- # preferred — single chip (bash wrapper auto-restarts on inner death)
129
+ # default — single chip, session-scoped (bash wrapper auto-restarts on inner death)
130
130
  while true; do greprag inbox watch --session <parent-session-id> --json; echo "[wrapper] watcher exited, restarting in 1s" >&2; sleep 1; done
131
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
132
+ # only for genuine multi-chip campaigns (N chips fanned out in parallel, want one merged stream)
133
+ while true; do greprag inbox watch --project <parent-project> --json; echo "[wrapper] watcher exited, restarting in 1s" >&2; sleep 1; done
134
134
  ```
135
135
 
136
- `--session` is the right default when the chip's Block 2 sends with `--session <parent-session-id>` exactly one report lands in this watcher per chip. Use `--project` when you've spawned several chips at once and want all their reports on one stream (each chip still tags `--from-session <own-id>`, so the parent reads provenance per message).
136
+ `--session` is the default. Substitute `<parent-session-id>` from the orchestrator's own SessionStart system-reminder. The `--project` form is ONLY for the case where the parent is genuinely orchestrating multiple chips in parallel and wants every chip's reports on one merged stream (each chip still tags `--from-session <own-id>` for provenance). Do not reach for `--project` because you don't have your session id handy — the SessionStart hook puts it in your context at the top of every session.
137
137
 
138
138
  **Run it under the `Monitor` agent tool.** Monitor emits one notification per stdout line — the parent agent reacts the moment a message lands. **Do NOT use `Bash(run_in_background: true)` for this** — Bash background only notifies on process completion, and a watcher runs forever, so the parent agent gets no events at all until it manually checks the output file. Burned this lesson once already.
139
139