greprag 5.78.1 → 5.78.6

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.
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # GrepRAG
2
2
 
3
- Agent memory as a service. Episodic project memory for Claude Code, Codex, and OpenCode — captures supported agent turns, compacts into hourly/daily/weekly summaries, and exposes two access patterns: lexical search by topic (`greprag memory search "<query>"`) or a session recap (`greprag memory recap`). The memory product line is marketed as **Odyssey**. Also handles cross-project async messaging via inbox.
3
+ Private agent memory service for existing GrepRAG tenants. New accounts are
4
+ closed; the npm client remains available so current users can install updates.
4
5
 
5
6
  ## Quick Start
6
7
 
@@ -8,7 +9,8 @@ Agent memory as a service. Episodic project memory for Claude Code, Codex, and O
8
9
  npm i -g greprag
9
10
  ```
10
11
 
11
- Then either run `/greprag` inside a supported agent, or run `greprag init` in a terminal. Bare `greprag init` detects Claude Code, Codex, and OpenCode; if more than one is present in a non-interactive shell, it prints the explicit command to use.
12
+ An existing API key is required. Then either run `/greprag` inside a supported
13
+ agent, or run `greprag init --api-key <existing-key>` in a terminal.
12
14
 
13
15
  ### Claude Code
14
16
 
@@ -23,13 +25,9 @@ greprag init --claude
23
25
  Run `/greprag` in Codex after install, or:
24
26
 
25
27
  ```bash
26
- greprag init --codex --tenant-id <your-handle>
28
+ greprag init --codex --api-key <existing-key>
27
29
  ```
28
30
 
29
- Example: `greprag init --codex --tenant-id tanya`.
30
- The handle becomes your public GrepRAG address, such as
31
- `tanya@greprag.com`.
32
-
33
31
  Codex requires one extra trust step: after init/update, open Codex Desktop
34
32
  Settings -> Settings -> Hooks, trust the 6 GrepRAG hooks, then start a fresh
35
33
  session.
@@ -67,7 +65,7 @@ greprag status --all-platforms
67
65
  | `greprag status --all-platforms` | Check auth, hooks/plugins, skills, and project anchor |
68
66
  | `greprag init` | Detect/ask which agent to configure |
69
67
  | `greprag init --claude` | Configure Claude Code hooks + skill |
70
- | `greprag init --codex --tenant-id <handle>` | Configure Codex hooks + skill |
68
+ | `greprag init --codex --api-key <key>` | Configure Codex hooks + skill |
71
69
  | `greprag codex doctor` | Diagnose Codex hooks, session id, and trust path |
72
70
  | `greprag init --opencode` | Configure OpenCode plugin |
73
71
  | `greprag init --global` | Global anchor for ephemeral sessions |
@@ -84,7 +82,7 @@ greprag status --all-platforms
84
82
 
85
83
  - Node.js 18+
86
84
  - Claude Code, Codex, or OpenCode
87
- - A GrepRAG handle or API key. `--tenant-id <handle>` provisions the key.
85
+ - An API key for an existing GrepRAG tenant.
88
86
 
89
87
  ## How it works
90
88
 
@@ -65,8 +65,8 @@ function context(input) {
65
65
  `Branch: ${chip.worktree.branch}`,
66
66
  `Parent session: ${chip.parent.sessionId || 'not recorded'}`,
67
67
  `Finish by committing the durable result, then send the parent the commit artifact, checks, caveats, Cleanup line, and Archive: yes|no in the actual native task message. After delivery, Archive: yes means archive this child task yourself. The optional host command is ${cli} codex chip report ${chip.id}.`,
68
- // adr: adr/codex-landing-doctrine.md — one delivery owner, including FIX missions.
69
- 'Landing: the parent is the delivery owner for merge, post-merge branch/manifest bookkeeping, and any profile-declared push/deploy/release; the child owns routine archival of its own task after the terminal message is delivered. Do not edit the parent checkout or independently cross delivery boundaries. A mission whose first line begins `FIX:` (emitted by `greprag fix spawn`) is writable in its isolated checkout/worktree and hands its verified commit/result to that owner without a human approval gate. If no live parent exists and the chip carries the full-goal mission, it becomes delivery owner. `greprag fix spawn` only prints the mission; visible Codex task dispatch creates the isolated checkout/worktree.',
68
+ // adr: adr/codex-landing-doctrine.md — parent mission owner, including FIX missions.
69
+ 'Landing: the parent mission owner integrates the result, handles post-merge branch/manifest bookkeeping, and follows any profile-declared push/deploy/release; the child owns routine archival of its own task after the terminal message is delivered. Do not edit the parent checkout or independently cross delivery boundaries. A mission whose first line begins `FIX:` (emitted by `greprag fix spawn`) is writable in its isolated checkout/worktree and hands its verified commit/result to that parent without a human approval gate. If no live parent exists and the chip carries the full-goal mission, it follows the repo profile as mission owner. `greprag fix spawn` only prints the mission; visible Codex task dispatch creates the isolated checkout/worktree.',
70
70
  ];
71
71
  if ((0, model_1.chipMissionKind)(chip) === 'fix') {
72
72
  lines.push('Harness: Codex. Mission: visible native FIX chip with ordinary writable authority, not a same-session helper.', 'Scope: repair GrepRAG-owned harness surfaces in this checkout: load entries, skill templates, docs, hook context, CLI messages, and tests. Codex owns native task creation, worktrees, permissions, Git, and task lifecycle.', 'Own diagnosis, implementation, tests, commit, and parent report. Inspect Codex behavior only far enough to correct GrepRAG guidance or report a precise external blocker.', 'FIX peer handoff: if a peer offers to coordinate, integrate, rework, or take over a harness repair, hand off branch/commit, dirty files, checks, blockers, and caveats. Do not defend patch ownership; peers may take ownership within their assigned GrepRAG harness scope.', 'Visible delegation route: load `codex-chip-spawn` and create the child with `codex_app__create_thread` using the current project worktree target; load `chip-leader` for multi-chip seams. Same-session helper tools never satisfy a visible-chip requirement.');
@@ -40,5 +40,5 @@ Report when done:
40
40
  ${reportInstruction}
41
41
  - Include a \`Cleanup:\` line naming the task, worktree, and branch actions. When done use \`Cleanup: child archives own task; Codex may prune managed worktree; parent may delete branch after merge\`; when anything must remain open use \`Cleanup: keep task/worktree/branch because ...\`.
42
42
  - Put the archive decision in the actual message sent to the LEAD: \`Archive: yes\` or \`Archive: no — <reason>\`. After that message is delivered, \`Archive: yes\` means call \`set_thread_archived\` for your own task; \`Archive: no\` means leave it open. Never make the parent perform routine child-task archival.
43
- - Landing: do not independently merge, push, deploy, or manually delete the worktree — the parent is the delivery owner and integrates the result, follows the repo profile, and deletes the branch after merge. If this task begins \`FIX:\` (a fix-spawn mission), hand the verified commit/result to that owner without a human approval gate. If no live parent exists and this task carries the full-goal mission, become delivery owner. \`greprag fix spawn\` only prints the mission; visible Codex task dispatch creates the isolated checkout/worktree.`;
43
+ - Landing: do not independently merge, push, deploy, or manually delete the worktree — the parent mission owner integrates the result, follows the repo profile, and deletes the branch after merge. If this task begins \`FIX:\` (a fix-spawn mission), hand the verified commit/result to that parent without a human approval gate. If no live parent exists and this task carries the full-goal mission, follow the repo profile as mission owner. \`greprag fix spawn\` only prints the mission; visible Codex task dispatch creates the isolated checkout/worktree.`;
44
44
  }
@@ -96,7 +96,7 @@ async function doctorCodex(args, deps) {
96
96
  const hooks = readCodexHooks();
97
97
  const startup = (0, codex_startup_1.codexStartupInfo)();
98
98
  console.log('Codex doctor\n');
99
- console.log(` API key: ${cfg.apiKey ? 'configured' : 'missing (run greprag init --codex --tenant-id <handle>)'}`);
99
+ console.log(` API key: ${cfg.apiKey ? 'configured' : 'missing (existing tenants: run greprag init --codex --api-key <key>)'}`);
100
100
  console.log(` Current thread: ${codexSession ? `${codexSession}${session8 ? ` (${session8})` : ''}` : 'not found (run Codex once or pass --session)'}`);
101
101
  console.log(` Hooks file: ${fs.existsSync(hooksPath) ? hooksPath : 'missing'}`);
102
102
  console.log(' Hook trust: Codex Desktop Settings -> Settings -> Hooks, then trust the GrepRAG hooks');
@@ -86,7 +86,7 @@ function codexStartupInfo() {
86
86
  }
87
87
  function installCodexStartup() {
88
88
  console.error('Codex startup watcher install is retired.');
89
- console.error('Run `greprag init --codex --tenant-id <handle>` and trust the Codex hooks.');
89
+ console.error('Run `greprag init --codex --api-key <existing-key>` and trust the Codex hooks.');
90
90
  console.error('Inbox rows surface through SessionStart drain and UserPromptSubmit codex-notify.');
91
91
  process.exit(1);
92
92
  }
@@ -467,7 +467,7 @@ remove only cleans up stale login files.`;
467
467
  function printCodexWatcherRetired() {
468
468
  console.error('Codex live watcher is retired.');
469
469
  console.error('Codex inbox rows surface through SessionStart drain and UserPromptSubmit codex-notify.');
470
- console.error('Run `greprag init --codex --tenant-id <handle>` and trust the Codex hooks.');
470
+ console.error('Run `greprag init --codex --api-key <existing-key>` and trust the Codex hooks.');
471
471
  }
472
472
  async function runCodex(args) {
473
473
  const sub = args[0];
@@ -125,10 +125,10 @@ function buildCollisionDirective(peers, myShort, alias) {
125
125
  + `Coordinate BEFORE touching shared files: (1) message each peer now with a contextual heads-up — `
126
126
  + `Codex peers: use \`codex_app.list_threads\` to find the task and its repo/workspace, then \`codex_app.send_message_to_thread\` to send the heads-up; `
127
127
  + `GrepRAG watcher/cross-harness peers: \`greprag send "…what you're about to touch…" --to ${handle}@greprag.com/<their-8hex> --from-session ${myShort}\` `
128
- + `(YOU compose and send it — this is a notice, not an auto-send; watcher rows are not the Codex peer source of truth); `
128
+ + `(YOU compose and send it — this is a notice, not an auto-send; recipients reply only for a concrete conflict, silence is approval, and you never poll or wait; watcher rows are not the Codex peer source of truth); `
129
129
  + `(2) do your code work in a worktree on its own branch (\`git worktree add .claude/worktrees/<slug> -b <branch>\`); `
130
- + `(3) at completion resolve \`.greprag/delivery.json\`, include every ready peer commit/result, and let one delivery owner `
131
- + `integrate and finish the declared push/deploy/release path. Never edit the shared default checkout concurrently.`);
130
+ + `(3) at completion resolve \`.greprag/delivery.json\`, send one fire-and-forget delivery notice, then continue immediately without polling, waiting, status reads, or follow-ups; `
131
+ + `sweep every ready same-repo commit, ignore all uncommitted and untracked work, resolve conflicts directly, and finish the declared push/deploy/release path. Never edit the shared default checkout concurrently.`);
132
132
  }
133
133
  /** Reduce the watcher list to OTHER live sessions that are NOT in my repo
134
134
  * (cross-repo). Excludes self, same-repo collisions (those get the LOUD
@@ -12,15 +12,15 @@ exports.buildDeliveryAnnounce = buildDeliveryAnnounce;
12
12
  // adr: adr/delivery-announce-pilot.md
13
13
  function coordinationLine(platform) {
14
14
  if (platform === 'codex') {
15
- return 'Codex: at the merge/deploy gate, call codex_app.list_threads unfiltered, filter to peers in the same repo, and inspect their current summaries/status. Use codex_app.send_message_to_thread only for visible evidence of an unlanded ready commit, overlapping integration, or a concrete blocker. Peers with nothing actionable stay silent; do not solicit or send negative acknowledgements or routine completion follow-ups. Delivery owner: rename this task `DEPLOY: <existing title>` for operator visibility only; transfer the prefix on handoff; remove it before reporting delivery complete or abandoned.';
15
+ return 'Codex: send one fire-and-forget delivery notice to same-repo peers with codex_app.send_message_to_thread, then continue immediately. Recipients reply only for a concrete conflict; silence is approval. Never poll, call wait_threads, re-read peers, ask for status, or send delivery follow-ups.';
16
16
  }
17
17
  if (platform === 'claude-code') {
18
- return 'Claude Code: at the merge/deploy gate, inspect peers in the same repo and send one concise delivery notice only for visible evidence of an unlanded ready commit, overlapping integration, or a concrete blocker. Peers with nothing actionable stay silent; do not solicit or send negative acknowledgements or routine completion follow-ups.';
18
+ return 'Claude Code: send one fire-and-forget delivery notice to same-repo peers, then continue immediately. Recipients reply only for a concrete conflict; silence is approval. Never poll, wait, ask for status, or send delivery follow-ups.';
19
19
  }
20
20
  if (platform === 'opencode') {
21
- return 'OpenCode: at the merge/deploy gate, use the GrepRAG project/session registry and send one concise notice only for visible evidence of an unlanded ready commit, overlapping integration, or a concrete blocker. Peers with nothing actionable stay silent; do not solicit or send negative acknowledgements or routine completion follow-ups.';
21
+ return 'OpenCode: send one fire-and-forget delivery notice to same-repo peers through the GrepRAG registry, then continue immediately. Recipients reply only for a concrete conflict; silence is approval. Never poll, wait, ask for status, or send delivery follow-ups.';
22
22
  }
23
- return 'At the merge/deploy gate, inspect peers in the same repo and send one concise notice only for visible evidence of an unlanded ready commit, overlapping integration, or a concrete blocker. Peers with nothing actionable stay silent; do not solicit or send negative acknowledgements or routine completion follow-ups.';
23
+ return 'Send one fire-and-forget delivery notice to same-repo peers, then continue immediately. Recipients reply only for a concrete conflict; silence is approval. Never poll, wait, ask for status, or send delivery follow-ups.';
24
24
  }
25
25
  function buildDeliveryAnnounce(env) {
26
26
  if (!env.deliveryRepo)
@@ -29,8 +29,9 @@ function buildDeliveryAnnounce(env) {
29
29
  return [
30
30
  `[DELIVERY — ${project}]`,
31
31
  'Commit useful, passing work.',
32
+ 'Only committed Git state participates in delivery. Ignore all uncommitted and untracked work in every checkout.',
32
33
  coordinationLine(env.platform),
33
- 'Include visible ready peer commits and clear known blockers, then merge to the default branch and deploy immediately. Silence means nothing actionable and does not block delivery.',
34
+ 'Sweep every ready same-repo commit into the integration train, resolve conflicts directly, merge to the default branch, and deploy immediately.',
34
35
  'Use this repo\'s delivery profile and verify production.',
35
36
  ].join('\n');
36
37
  }
@@ -623,7 +623,7 @@ async function runFix(args) {
623
623
  // THE friction reflex (grepragOS, 2026-07-12): one unit of friction ⇒
624
624
  // one fix-chip mission now. The mission detects Git capability and tells
625
625
  // native dispatch to use a worktree or serialized project-local mode;
626
- // the chip fixes, verifies, commits useful work, then hands to the delivery owner. Replaces queue-first
626
+ // the chip fixes, verifies, commits useful work, then hands to the mission owner. Replaces queue-first
627
627
  // `fix log` as doctrine.
628
628
  return (0, mechanic_spawn_1.fixSpawn)(rest);
629
629
  }
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  /** greprag init — configure agent clients for GrepRAG memory.
3
3
  *
4
- * 1. Obtain API key (provided or provisioned)
4
+ * 1. Obtain an existing API key (provided or already cached)
5
5
  * 2. Validate key against health endpoint
6
6
  * 3. Update the target platform's native hooks/plugin/config */
7
7
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
@@ -162,42 +162,24 @@ function describeTarget(target) {
162
162
  function explicitInitHint() {
163
163
  return [
164
164
  'Run one of:',
165
- ' greprag init --codex --tenant-id <your-handle>',
166
- ' greprag init --claude --tenant-id <your-handle>',
167
- ' greprag init --opencode --tenant-id <your-handle>',
168
- ' greprag init --grok --tenant-id <your-handle>',
165
+ ' greprag init --codex --api-key <existing-key>',
166
+ ' greprag init --claude --api-key <existing-key>',
167
+ ' greprag init --opencode --api-key <existing-key>',
168
+ ' greprag init --grok --api-key <existing-key>',
169
169
  ].join('\n');
170
170
  }
171
- function normalizeHandle(raw) {
172
- return raw.trim().toLowerCase().replace(/@greprag\.com$/i, '');
173
- }
174
- function validateHandle(handle) {
175
- return /^[a-z0-9-]{3,32}$/.test(handle);
176
- }
177
- async function promptForHandle() {
178
- const handle = normalizeHandle(await prompt(' Choose your public GrepRAG handle, e.g. tanya -> tanya@greprag.com: '));
179
- if (!validateHandle(handle)) {
180
- console.error(' Error: public handle must be 3-32 chars: lowercase letters, numbers, and hyphens.');
181
- process.exit(1);
182
- }
183
- const answer = (await prompt(` This will create/use public handle ${handle}@greprag.com. Continue? (Y/n): `)).trim().toLowerCase();
184
- if (answer && answer !== 'y' && answer !== 'yes') {
185
- console.error(' Setup cancelled before provisioning a public handle.');
186
- process.exit(1);
187
- }
188
- return handle;
189
- }
190
- async function resolveProvisionHandle(opts) {
171
+ // Existing tenants keep working; init no longer creates public accounts.
172
+ // adr: adr/private-service.md
173
+ function failMissingApiKey(opts) {
191
174
  if (opts.tenantId) {
192
- const handle = normalizeHandle(opts.tenantId);
193
- if (!validateHandle(handle)) {
194
- console.error(' Error: --tenant-id must be 3-32 chars: lowercase letters, numbers, and hyphens.');
195
- process.exit(1);
196
- }
197
- console.log(` Public handle: ${handle}@greprag.com`);
198
- return handle;
175
+ console.error(' Error: --tenant-id no longer provisions a GrepRAG account.');
176
+ }
177
+ else {
178
+ console.error(' Error: no existing GrepRAG API key was found.');
199
179
  }
200
- return promptForHandle();
180
+ console.error(' GrepRAG is a private service and is not accepting new accounts.');
181
+ console.error(' Existing users can pass --api-key <existing-key>.');
182
+ process.exit(1);
201
183
  }
202
184
  async function chooseInitTarget() {
203
185
  const detections = detectAgentTargets();
@@ -250,8 +232,7 @@ async function runInit(opts) {
250
232
  // global anchor, skill, chip-spawn doc, CLAUDE.md patch), THEN bulk-register
251
233
  // every other git repo. Pure superset of `greprag init`.
252
234
  //
253
- // Reuse the existing GREPRAG_API_KEY from settings if one is already there,
254
- // so re-runs don't churn the tenant's key via the provision path.
235
+ // Reuse the existing GREPRAG_API_KEY from settings if one is already there.
255
236
  if (opts.all) {
256
237
  let apiKey = opts.apiKey || readSharedApiKey();
257
238
  await runInit({ ...opts, all: false, apiKey });
@@ -290,15 +271,7 @@ async function runInit(opts) {
290
271
  // Step 1: Get API key
291
272
  let apiKey = opts.apiKey || readSharedApiKey();
292
273
  if (!apiKey) {
293
- const tenantId = await resolveProvisionHandle(opts);
294
- console.log(` Provisioning API key for public handle ${tenantId}@greprag.com...`);
295
- const result = await provision(tenantId);
296
- if (!result.ok) {
297
- console.error(` Error: ${result.error}`);
298
- process.exit(1);
299
- }
300
- apiKey = result.apiKey;
301
- console.log(` API key created: ${apiKey.slice(0, 17)}...`);
274
+ failMissingApiKey(opts);
302
275
  }
303
276
  // Step 2: Validate key
304
277
  console.log(' Validating API key...');
@@ -415,18 +388,10 @@ async function runInit(opts) {
415
388
  * repo gets the same project_id from both inits (idempotent). */
416
389
  async function runOpenCodeInit(opts) {
417
390
  console.log('\n greprag init — Setting up agent memory for OpenCode\n');
418
- // Step 1: Get API key (same provision path as Claude Code init)
391
+ // Step 1: Get an existing API key.
419
392
  let apiKey = opts.apiKey || readSharedApiKey();
420
393
  if (!apiKey) {
421
- const tenantId = await resolveProvisionHandle(opts);
422
- console.log(` Provisioning API key for public handle ${tenantId}@greprag.com...`);
423
- const result = await provision(tenantId);
424
- if (!result.ok) {
425
- console.error(` Error: ${result.error}`);
426
- process.exit(1);
427
- }
428
- apiKey = result.apiKey;
429
- console.log(` API key created: ${apiKey.slice(0, 17)}...`);
394
+ failMissingApiKey(opts);
430
395
  }
431
396
  // Step 2: Validate key
432
397
  console.log(' Validating API key...');
@@ -581,21 +546,13 @@ async function runOpenCodeInit(opts) {
581
546
  async function runCodexInit(opts) {
582
547
  console.log('\n greprag init — Setting up agent memory for Codex\n');
583
548
  if (opts.installWatcher) {
584
- console.error(' Error: Codex startup watcher install is retired. Run: greprag init --codex --tenant-id <handle>');
549
+ console.error(' Error: Codex startup watcher install is retired. Run: greprag init --codex --api-key <existing-key>');
585
550
  console.error(' Codex inbox rows surface through SessionStart drain and UserPromptSubmit codex-notify.');
586
551
  process.exit(1);
587
552
  }
588
553
  let apiKey = opts.apiKey || readSharedApiKey();
589
554
  if (!apiKey) {
590
- const tenantId = await resolveProvisionHandle(opts);
591
- console.log(` Provisioning API key for public handle ${tenantId}@greprag.com...`);
592
- const result = await provision(tenantId);
593
- if (!result.ok) {
594
- console.error(` Error: ${result.error}`);
595
- process.exit(1);
596
- }
597
- apiKey = result.apiKey;
598
- console.log(` API key created: ${apiKey.slice(0, 17)}...`);
555
+ failMissingApiKey(opts);
599
556
  }
600
557
  console.log(' Validating API key...');
601
558
  const valid = await validateKey(apiKey);
@@ -739,15 +696,7 @@ async function runGrokInit(opts) {
739
696
  console.log('\n greprag init — Setting up agent memory for Grok Build\n');
740
697
  let apiKey = opts.apiKey || readSharedApiKey();
741
698
  if (!apiKey) {
742
- const tenantId = await resolveProvisionHandle(opts);
743
- console.log(` Provisioning API key for public handle ${tenantId}@greprag.com...`);
744
- const result = await provision(tenantId);
745
- if (!result.ok) {
746
- console.error(` Error: ${result.error}`);
747
- process.exit(1);
748
- }
749
- apiKey = result.apiKey;
750
- console.log(` API key created: ${apiKey.slice(0, 17)}...`);
699
+ failMissingApiKey(opts);
751
700
  }
752
701
  console.log(' Validating API key...');
753
702
  const valid = await validateKey(apiKey);
@@ -1027,19 +976,6 @@ function writeProjectPath(projectName, repoPath) {
1027
976
  fs.mkdirSync(dir, { recursive: true });
1028
977
  fs.writeFileSync(file, JSON.stringify(registry, null, 2) + '\n');
1029
978
  }
1030
- // -- Provisioning -----------------------------------------------------------
1031
- async function provision(tenantId) {
1032
- const res = await fetch(`${API_URL}/v1/keys/provision`, {
1033
- method: 'POST',
1034
- headers: { 'Content-Type': 'application/json' },
1035
- body: JSON.stringify({ tenantId }),
1036
- });
1037
- const body = await res.json();
1038
- if (!res.ok) {
1039
- return { ok: false, error: body.error || `HTTP ${res.status}` };
1040
- }
1041
- return { ok: true, apiKey: body.apiKey };
1042
- }
1043
979
  // -- Validation -------------------------------------------------------------
1044
980
  async function validateKey(apiKey) {
1045
981
  try {
@@ -1774,26 +1710,12 @@ function applySettings(settings, apiKey) {
1774
1710
  else {
1775
1711
  changes.push('PreToolUse crush-wrap hook already configured (skipped)');
1776
1712
  }
1777
- // Coordinate-GATE cross-session coordination reflex (TIER 2). PreToolUse
1778
- // matcher `Bash`: on a risky shared-state action (git merge/push/deploy) the
1779
- // hook does a FRESH inbox-watchers read and, if another live session is working
1780
- // in THIS repo, injects coordination context before the irreversible action.
1781
- // Non-risky Bash calls classify locally and cost no
1782
- // network. Pairs with the SessionStart collision-check (TIER 1 roster).
1783
- // docs/collision-schematic.md
1784
- const coordinateGateHook = {
1785
- matcher: 'Bash',
1786
- hooks: [{ type: 'command', command: 'greprag-hook coordinate-gate', timeout: 5000 }],
1787
- };
1788
- if (!hasGrepragHookWithMatcher(settings.hooks.PreToolUse, 'coordinate-gate', 'Bash')) {
1789
- if (!settings.hooks.PreToolUse)
1790
- settings.hooks.PreToolUse = [];
1791
- settings.hooks.PreToolUse.push(coordinateGateHook);
1792
- changes.push('Added PreToolUse hook (coordinate-gate, matcher=Bash)');
1793
- }
1794
- else {
1795
- changes.push('PreToolUse coordinate-gate hook already configured (skipped)');
1796
- }
1713
+ // Delivery coordination is fire-and-forget. Remove the retired PreToolUse
1714
+ // polling gate from existing Claude installs; the old subcommand is also a
1715
+ // no-op so updated binaries stop polling before the next init.
1716
+ const removedCoordinateGate = removeGrepragHook(settings.hooks, 'PreToolUse', 'coordinate-gate');
1717
+ if (removedCoordinateGate)
1718
+ changes.push('Removed retired PreToolUse coordinate-gate hook');
1797
1719
  // Governed compact (Chip D) — two local-only hooks, no API calls.
1798
1720
  // PreCompact: render the transcript main chain to pixel-font PNG pages
1799
1721
  // (lossless archive, CCR-indexed) BEFORE compaction summarizes it away.
@@ -1964,7 +1886,7 @@ const GREPRAG_CLI_BODY = `## greprag CLI (cross-project memory + async messaging
1964
1886
  - \`email send --to <real-addr> --from <handle>@greprag.com --subject "s" (--body "t" | --body-file <f|->)\` — sends a **REAL outbound SMTP email** from your greprag address to any recipient (\`--attach\`/\`--cc\`/\`--bcc\`/\`--html-file\` available). \`email pending\` · \`email pull\` = drain inbound. **Use this — not \`send\` — when the user says "email X".** The \`send\`-vs-\`email send\` collision is the trap: only \`email send\` is actual email.
1965
1887
  - \`memory search "q"\` · \`memory recap\` (alias \`briefing\`) — search a topic/bug · session catch-up digest; narrative-pyramid tiers \`turns\`·\`hourly\`·\`daily\`·\`weekly\`·\`ships\` (commits/PRs/deploys), each \`--last N\` · \`--from/--to ISO\` · \`--project\`
1966
1888
  - \`corpus upload <file|url> --raw|--enriched [--index]\` · \`corpus search "q" --all\` — ingest + search arbitrary text (books, codebases, refs); \`--raw\` lexical, \`--enriched\` adds LLM vocab bridge; \`--index\` = a multi-doc "index, no bundle" source (llms.txt/sitemap) → one library store, members refreshed cheap-signal-only (ETag→lastmod→content-length, no full-read floor)
1967
- - \`fix spawn "<one unit of friction>"\` · \`fix search|repair\` — THE friction reflex: one visible fix-chip mission per unit; it detects Git before dispatch (worktree for Git, serialized project-local for non-Git/no-commit); the chip fixes, verifies, commits useful work, and hands it to the mission delivery owner (\`fix log\` = audit notes only) · search/repair the fix queue
1889
+ - \`fix spawn "<one unit of friction>"\` · \`fix search|repair\` — THE friction reflex: one visible fix-chip mission per unit; it detects Git before dispatch (worktree for Git, serialized project-local for non-Git/no-commit); the chip fixes, verifies, commits useful work, and hands it to the mission owner (\`fix log\` = audit notes only) · search/repair the fix queue
1968
1890
  - \`status\` · \`doctor\` — install/auth/hooks state · repair orphan project_id + identity drift
1969
1891
  Hard rule: AI never auto-acts on a brief — summarize + confirm.`;
1970
1892
  /** The previous SHIPPED default (v5.39.x and earlier, pre-markers, unmarked).
@@ -1977,7 +1899,7 @@ const GREPRAG_CLI_BODY_V1 = `## greprag CLI (cross-project memory + async messag
1977
1899
  - \`send "md" --to <handle>@greprag.com[/<8hex>]\` — message a session (\`/<8hex>\`) or cold-open a front desk (bare handle); Discord DM: \`--to discord:<snowflake>\`
1978
1900
  - \`memory search "q"\` · \`memory recap\` (alias \`briefing\`) — search a topic/bug · session catch-up digest; narrative-pyramid tiers \`turns\`·\`hourly\`·\`daily\`·\`ships\` (commits/PRs/deploys), each \`--last N\` · \`--from/--to ISO\` · \`--project\`
1979
1901
  - \`corpus upload <file|url> --raw|--enriched\` · \`corpus search "q" --all\` — ingest + search arbitrary text (books, codebases, refs); \`--raw\` lexical, \`--enriched\` adds LLM vocab bridge
1980
- - \`fix spawn "<unit>"\`|\`fix search\` — emit one visible fix-chip mission per friction unit; native dispatch creates the isolated checkout/worktree; the chip fixes, verifies, commits useful work, and hands it to the mission delivery owner
1902
+ - \`fix spawn "<unit>"\`|\`fix search\` — emit one visible fix-chip mission per friction unit; native dispatch creates the isolated checkout/worktree; the chip fixes, verifies, commits useful work, and hands it to the mission owner
1981
1903
  - \`status\` · \`doctor\` — install/auth/hooks state · repair orphan project_id + identity drift
1982
1904
  Hard rule: AI never auto-acts on a brief — summarize + confirm.`;
1983
1905
  /** The managed-section registry for ~/.claude/CLAUDE.md. Add a spec here to put
@@ -19,8 +19,8 @@ exports.mechanicSpawn = mechanicSpawn;
19
19
  *
20
20
  * The chip's contract is simple: identify the exact friction, make the
21
21
  * smallest durable root-cause fix, explain the friction and fix in human
22
- * terms, then hand its commit/result to the mission's delivery owner. A full-goal
23
- * chip with no live parent becomes that owner and follows the repo profile.
22
+ * terms, then hand its commit/result to the mission owner. A full-goal
23
+ * chip with no live parent follows the repo profile as mission owner.
24
24
  *
25
25
  * This command does NOT create the child task or its workspace. The caller
26
26
  * owns dispatch through a visible native chip/task mechanism. Git projects
@@ -116,7 +116,7 @@ function buildFixMission(friction, scope, parentSession, type = inferFixType(fri
116
116
  '3. Confirm you are not in the caller/parent checkout. If you are, STOP and report `CHIP DISPATCH BLOCKED: workspaceMode=worktree was not honored`.',
117
117
  ],
118
118
  work: 'Work as an ordinary unrestricted read/write session in the dispatch-provided isolated worktree.',
119
- completion: 'Use focused tests or checks that prove the fix and commit useful work. If a live parent owns delivery, report the commit and checks so it can integrate and clean up. If no live parent exists and this is the full-goal mission, resolve `.greprag/delivery.json` and become the delivery owner. Gate only effects outside ordinary repo delivery.',
119
+ completion: 'Use focused tests or checks that prove the fix and commit useful work. If a live parent owns the mission, report the commit and checks so it can integrate and clean up. If no live parent exists and this is the full-goal mission, resolve `.greprag/delivery.json` and follow the repo profile as mission owner. Gate only effects outside ordinary repo delivery.',
120
120
  }
121
121
  : {
122
122
  selected: 'Workspace mode: local -> no usable Git HEAD detected; native dispatch targets the current project directory directly.',
@@ -125,14 +125,14 @@ function buildFixMission(friction, scope, parentSession, type = inferFixType(fri
125
125
  '3. Confirm the caller yielded file writes while this FIX chip runs. If concurrent writes are still possible, STOP and report `CHIP DISPATCH BLOCKED: workspaceMode=local requires serialized writes`.',
126
126
  ],
127
127
  work: 'Work as an ordinary unrestricted read/write session in the dispatch-provided local project directory; the caller must not write there concurrently.',
128
- completion: 'Use focused tests or checks that prove the fix and report the exact files and checks to the live parent/delivery owner. With no Git boundary there is nothing to merge or push; preserve recovery material until the owner confirms the handoff.',
128
+ completion: 'Use focused tests or checks that prove the fix and report the exact files and checks to the live parent/mission owner. With no Git boundary there is nothing to merge or push; preserve recovery material until the owner confirms the handoff.',
129
129
  };
130
130
  return [
131
131
  `FIX: [${type}] ${summary}`,
132
132
  '',
133
133
  '**Basic instruction**',
134
134
  'You are a visible FIX chip for exactly one friction unit. Do not absorb adjacent friction; name it in your report so the caller can spawn it separately.',
135
- 'Route by durable repair surface, not symptom. Identify the exact friction, fix it, explain the friction in human terms, explain what you changed and why it solves the friction, then hand the verified result to the mission delivery owner without creating a second approval gate.',
135
+ 'Route by durable repair surface, not symptom. Identify the exact friction, fix it, explain the friction in human terms, explain what you changed and why it solves the friction, then hand the verified result to the mission owner without creating a second approval gate.',
136
136
  '',
137
137
  '**Type router**',
138
138
  `Selected type: ${type} -> ${FIX_TYPE_ROUTES[type]}.`,
@@ -164,7 +164,7 @@ function buildFixMission(friction, scope, parentSession, type = inferFixType(fri
164
164
  '- Fix made: <files/behavior changed>',
165
165
  '- Why it works: <why this prevents the class of friction>',
166
166
  '- Checks: <commands run and result>',
167
- '- Delivery owner: <live parent task, or self when this is the full-goal mission>',
167
+ '- Mission owner: <live parent task, or self when this is the full-goal mission>',
168
168
  '- Next boundary: <integrate/cleanup/profile delivery, or none for local mode>',
169
169
  '',
170
170
  `Harness scope: ${scope}.`,
@@ -202,7 +202,7 @@ async function fixSpawn(args, opts = {}) {
202
202
  parentSession: parentSession || null,
203
203
  mission,
204
204
  dispatch: workspaceMode === 'worktree'
205
- ? 'Create a visible native chip/task using the harness worktree path, then send this mission as its first turn. The chip fixes, verifies, commits, and hands the result to the mission delivery owner.'
205
+ ? 'Create a visible native chip/task using the harness worktree path, then send this mission as its first turn. The chip fixes, verifies, commits, and hands the result to the mission owner.'
206
206
  : 'No usable Git HEAD was detected. Create a visible native chip/task using the harness project-local path; do not attempt a worktree or initialize Git. Yield caller file writes until the chip reports back. The chip fixes, verifies, and hands the result to the mission owner.',
207
207
  };
208
208
  console.log(JSON.stringify(handoff, null, 2));
@@ -546,7 +546,7 @@ USAGE
546
546
  greprag mechanic spawn "<friction>" DEPRECATED alias of "greprag fix spawn" (the
547
547
  friction reflex — one visible fix-chip mission
548
548
  per unit; native dispatch creates the isolated
549
- checkout/worktree; chip hands off to the delivery owner).
549
+ checkout/worktree; chip hands off to the mission owner).
550
550
  [--parent-session <native-id>] Caller creates the native child task.
551
551
  greprag mechanic off [--note "<t>"] PANIC SWITCH — suspend ALL repairs. Local file
552
552
  (~/.greprag/state/mechanic-off.json), no
@@ -69,7 +69,7 @@ function buildMission(input) {
69
69
  '**Repair contract**',
70
70
  'Work as an ordinary unrestricted read/write session in the isolated checkout.',
71
71
  'Find and repair the reusable root mechanism; own discovery, repair, tests, verification, and commit.',
72
- 'Finish it through the Delivery System: confer with live peers first (`greprag inbox watchers`), resolve `.greprag/delivery.json`, include every ready peer commit/result, and let one delivery owner integrate, verify, push, deploy, or release exactly as the profile declares. If a live parent already owns delivery, report your commit and checks for integration; if no parent is available and this is the full-goal mission, become the delivery owner. Gate only effects outside ordinary repo delivery.',
72
+ 'Finish it through the Delivery System: resolve `.greprag/delivery.json`, send one fire-and-forget notice, then continue immediately without polling, waiting, status reads, or follow-ups. Sweep every ready same-repo commit, ignore all uncommitted and untracked work, resolve conflicts directly, and integrate, verify, push, deploy, or release exactly as the profile declares. Recipients reply only for a concrete conflict; silence is approval. Gate only effects outside ordinary repo delivery.',
73
73
  'Report DONE or BLOCKED natively to the parent task; do not use a mandatory GrepRAG completion ceremony.',
74
74
  '',
75
75
  '**Friction / mission**',
@@ -27,7 +27,7 @@ function buildOsPrimer(env) {
27
27
  '• Doctrine vs state: methods ship in the CLI (`greprag load`); live state lives in the repo. A skill that depends on repo state carries a "STATE — read these first" block naming exact paths.',
28
28
  '• Discoverability: every durable artifact must be findable next session — docs auto-register, skills auto-mirror, decisions get a dated ADR/decision-log entry, everything else gets its path named in the owning skill/doc. If nothing points at it, you didn\'t finish.',
29
29
  '• Pull before derive: `greprag memory search` / `corpus search` / `load` BEFORE asking the operator or re-deriving what the project already knows. Friction or an env/toolchain/worktree/secret bootstrap roadblock → search Memory for the exact error/friction + repo/tool before inventing a workaround. Clear overcome → apply it and continue. Named person/org/project/repo/customer/handle or unexplained proper noun → search Memory before guessing, unless fully defined in-turn.',
30
- `• Unresolved friction ⇒ fix: only when Memory has no answer, the remembered overcome fails, or the same friction repeats. Then type by durable repair surface (\`harness|doctrine|injection|env|code\`) ⇒ \`greprag fix spawn --type <type> "<unit>"\`. It PRINTS a fix-chip mission — YOU then create the visible child task with that mission as its first message (how: \`greprag load ${spawnEntry}\`, or your harness's native task tool). Repo write = isolated worktree; data-only row/diagnosis = no repo write. One unresolved unit per chip; the chip fixes, verifies, commits useful work, and hands it to the mission delivery owner.`,
30
+ `• Unresolved friction ⇒ fix: only when Memory has no answer, the remembered overcome fails, or the same friction repeats. Then type by durable repair surface (\`harness|doctrine|injection|env|code\`) ⇒ \`greprag fix spawn --type <type> "<unit>"\`. It PRINTS a fix-chip mission — YOU then create the visible child task with that mission as its first message (how: \`greprag load ${spawnEntry}\`, or your harness's native task tool). Repo write = isolated worktree; data-only row/diagnosis = no repo write. One unresolved unit per chip; the chip fixes, verifies, commits useful work, and hands it to the mission owner.`,
31
31
  '• Teach the system, not the chat: explained twice by the operator ⇒ it belongs in a skill / load entry / STATE block / ADR, not the conversation.',
32
32
  ].join('\n');
33
33
  }
@@ -20,7 +20,6 @@ const assistant_reminder_1 = require("./assistant-reminder");
20
20
  const memory_reflex_1 = require("./memory-reflex");
21
21
  const arm_reminder_1 = require("./arm-reminder");
22
22
  const friction_reminder_1 = require("./friction-reminder");
23
- const collision_reminder_1 = require("./collision-reminder");
24
23
  const version_reminder_1 = require("./version-reminder");
25
24
  const enrichment_health_reminder_1 = require("./enrichment-health-reminder");
26
25
  const skill_gain_reminder_1 = require("./skill-gain-reminder");
@@ -56,7 +55,6 @@ exports.REGISTRY = [
56
55
  memory_reflex_1.memoryPrimerModule,
57
56
  arm_reminder_1.watcherArmModule,
58
57
  friction_reminder_1.mechanicFrictionModule,
59
- collision_reminder_1.collisionMatchModule, // source: 'command' — evaluated at PreToolUse, not UserPromptSubmit
60
58
  ];
61
59
  /** Derive a harness's registry by EXCLUSION, never by include-list. A module with no
62
60
  * `harnesses` declaration ships to every harness; a declared list scopes it. This is
@@ -91,8 +91,8 @@ function parseProfile(root, raw) {
91
91
  errors.push('git.defaultBranch is invalid');
92
92
  if (!remote || !/^[A-Za-z0-9._-]+$/.test(remote))
93
93
  errors.push('git.remote is invalid');
94
- if (strategy !== 'merge' && strategy !== 'rebase' && strategy !== 'ff-only') {
95
- errors.push('git.integrationStrategy must be merge, rebase, or ff-only');
94
+ if (strategy !== 'merge' && strategy !== 'rebase' && strategy !== 'ff-only' && strategy !== 'pr') {
95
+ errors.push('git.integrationStrategy must be merge, rebase, ff-only, or pr');
96
96
  }
97
97
  if (typeof pushDeploys !== 'boolean')
98
98
  errors.push('git.pushDeploys must be boolean');
package/dist/hook.js CHANGED
@@ -112,10 +112,6 @@ const archive_1 = require("./commands/archive");
112
112
  // repo (cloud watcher registry) and inject a coordinate-now directive. All real
113
113
  // logic lives in ./commands/collision-check. docs/schematic-triggers.md
114
114
  const collision_check_1 = require("./commands/collision-check");
115
- // Coordinate-GATE (PreToolUse) — on risky shared-state actions, Claude/OpenCode
116
- // consult the watcher registry and inject advisory context. Codex no longer
117
- // uses this gate.
118
- const coordinate_gate_1 = require("./commands/coordinate-gate");
119
115
  // (The asyncRewake idle-wake poll was REVERTED 2026-06-23 — falsified: a detached
120
116
  // process's exit-2 has no harness event to attach to in true deep idle, so it never
121
117
  // woke an idle session. Only a live Monitor task delivers to idle. adr: adr/monitor-
@@ -2165,68 +2161,6 @@ function stateUpdate(input) {
2165
2161
  }
2166
2162
  catch { /* state update is best-effort — never block the turn */ }
2167
2163
  }
2168
- /** PreToolUse coordinate-GATE. On a risky shared-state action (git merge / push /
2169
- * deploy), Claude/OpenCode do a FRESH inbox-watchers read and inject the roster;
2170
- * Codex denies until committed, artifact-bound native task conferral evidence
2171
- * exists. The network read fires ONLY for non-Codex risky commands — a non-risky
2172
- * Bash call is classified locally and exits silent. NO dedup for non-Codex: a
2173
- * fresh read every fire (a stale roster at merge is the exact failure it
2174
- * prevents). Reads only the watcher registry (no inbox content) — no eavesdrop
2175
- * surface. Watcher misses fail quiet. docs/collision-schematic.md */
2176
- async function coordinateGate(input) {
2177
- const cwd = input.cwd || process.cwd();
2178
- const cfg = (0, hook_runtime_1.getHookConfig)(cwd);
2179
- if (!cfg.enabled || !cfg.apiKey)
2180
- return; // unconfigured → silent
2181
- const short = (0, session_id_1.truncateSessionId)(input.session_id);
2182
- if (!short)
2183
- return; // no session id → silent
2184
- // Local + cheap: classify BEFORE any network so non-risky calls cost nothing.
2185
- const toolInput = (input.tool_input || {});
2186
- const trigger = (0, coordinate_gate_1.triggerFromPreToolUse)(input.tool_name || '', toolInput);
2187
- if (!trigger)
2188
- return; // not a risky action → silent
2189
- let anchor;
2190
- try {
2191
- anchor = (0, project_anchor_1.readAnchor)(cwd);
2192
- }
2193
- catch {
2194
- return;
2195
- }
2196
- if (!anchor.projectId)
2197
- return; // unanchored → nothing to match
2198
- // I/O stays in the hook: fresh peer read off the hot path → env.collisionPeers.
2199
- const peers = await (0, coordinate_gate_1.resolveCollisionPeers)({
2200
- short,
2201
- projectId: anchor.projectId,
2202
- projectName: anchor.projectName,
2203
- apiUrl: cfg.apiUrl,
2204
- apiKey: cfg.apiKey,
2205
- alias: (0, session_id_1.readIdentityAlias)(),
2206
- });
2207
- if (peers.length === 0)
2208
- return; // no live peer in this repo → proceed
2209
- // Route through the registry: build the command-read env, run the command-source
2210
- // modules (the collision Match). The standalone gate is now a registry citizen.
2211
- const env = {
2212
- short, turnCount: 0, stress: 0, armed: false, sessionUnread: 0,
2213
- alias: (0, session_id_1.readIdentityAlias)(),
2214
- toolCommand: typeof toolInput.command === 'string' ? toolInput.command : '',
2215
- collisionPeers: peers,
2216
- };
2217
- const fired = (0, reminder_registry_1.collectReminders)(env, (0, app_settings_1.filterEnabledInterrupts)((0, reminder_registry_1.commandModules)()));
2218
- if (!fired.length)
2219
- return;
2220
- // Effect: inject as additionalContext — advisory heads-up, NO permission pause.
2221
- // `ask` was too intrusive (prompted on every git op while peers were live); inject
2222
- // keeps the agent aware without a manual-allow.
2223
- process.stdout.write(JSON.stringify({
2224
- hookSpecificOutput: {
2225
- hookEventName: input.hook_event_name || 'PreToolUse',
2226
- additionalContext: fired.map(f => f.line).join('\n\n'),
2227
- },
2228
- }) + '\n');
2229
- }
2230
2164
  /** Detached background child: refetch the matchset + rewrite the cache. */
2231
2165
  async function guardRefresh(input) {
2232
2166
  const cwd = input.cwd || process.cwd();
@@ -2386,10 +2320,9 @@ async function main() {
2386
2320
  await drain(input);
2387
2321
  }
2388
2322
  else if (subcommand === 'coordinate-gate') {
2389
- // Claude/OpenCode PreToolUse[Bash] fresh watcher read + context injection
2390
- // when a risky shared-state action has a live same-repo peer.
2391
- // docs/collision-schematic.md
2392
- await coordinateGate(input);
2323
+ // Retired delivery polling gate. Kept as a no-op so old installed hook
2324
+ // configs stop polling immediately and remain compatible until init cleanup.
2325
+ return;
2393
2326
  }
2394
2327
  else if (subcommand === 'codex-coordinate-gate') {
2395
2328
  // Retired Codex PreToolUse coordination gate. Kept as a no-op so older