@getmarrow/mcp 3.9.73 → 3.9.75

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 (46) hide show
  1. package/README.md +28 -19
  2. package/dist/cli.js +31 -27
  3. package/dist/cli.js.map +1 -1
  4. package/dist/control-state.d.ts +25 -0
  5. package/dist/control-state.d.ts.map +1 -0
  6. package/dist/control-state.js +112 -0
  7. package/dist/control-state.js.map +1 -0
  8. package/dist/hook-context.d.ts +1 -1
  9. package/dist/hook-context.d.ts.map +1 -1
  10. package/dist/hook-context.js +18 -9
  11. package/dist/hook-context.js.map +1 -1
  12. package/dist/hook-contract.d.ts +43 -15
  13. package/dist/hook-contract.d.ts.map +1 -1
  14. package/dist/hook-contract.js +358 -44
  15. package/dist/hook-contract.js.map +1 -1
  16. package/dist/hook-pre-action.d.ts +19 -1
  17. package/dist/hook-pre-action.d.ts.map +1 -1
  18. package/dist/hook-pre-action.js +208 -30
  19. package/dist/hook-pre-action.js.map +1 -1
  20. package/dist/hook-session.d.ts +1 -1
  21. package/dist/hook-session.d.ts.map +1 -1
  22. package/dist/hook-session.js +86 -41
  23. package/dist/hook-session.js.map +1 -1
  24. package/dist/hook-tool-policy.d.ts +2 -0
  25. package/dist/hook-tool-policy.d.ts.map +1 -1
  26. package/dist/hook-tool-policy.js +23 -2
  27. package/dist/hook-tool-policy.js.map +1 -1
  28. package/dist/hook.d.ts +14 -2
  29. package/dist/hook.d.ts.map +1 -1
  30. package/dist/hook.js +51 -29
  31. package/dist/hook.js.map +1 -1
  32. package/dist/host-capability.d.ts +23 -16
  33. package/dist/host-capability.d.ts.map +1 -1
  34. package/dist/host-capability.js +41 -61
  35. package/dist/host-capability.js.map +1 -1
  36. package/dist/index.d.ts +6 -2
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +167 -120
  39. package/dist/index.js.map +1 -1
  40. package/dist/lifecycle-spool.d.ts +1 -5
  41. package/dist/lifecycle-spool.d.ts.map +1 -1
  42. package/dist/lifecycle-spool.js +11 -28
  43. package/dist/lifecycle-spool.js.map +1 -1
  44. package/package.json +1 -1
  45. package/scripts/control-path-canary.cjs +28 -2
  46. package/server.json +2 -2
package/README.md CHANGED
@@ -66,7 +66,7 @@ Set the key through trusted secret storage:
66
66
  export MARROW_API_KEY=mrw_live_...
67
67
  ```
68
68
 
69
- For native pre-action enforcement, Marrow accepts the process environment or an owner-controlled `~/.marrow/env` file with owner-only permissions. Repository-local `.env` files are intentionally ignored for enforcement identity so project content cannot replace the account, agent, or API endpoint used to authorize a protected action.
69
+ For Claude Code's cooperative pre-action hook, Marrow accepts the process environment or an owner-controlled `~/.marrow/env` file with owner-only permissions. Repository-local `.env` files are intentionally ignored so project content cannot replace the account, agent, or API endpoint used for guidance. The public hook callback is still a client self-report, not certified host provenance or an external enforcement boundary.
70
70
 
71
71
  Then configure the MCP server:
72
72
 
@@ -104,9 +104,13 @@ npx -y --package=@getmarrow/mcp@latest marrow-mcp ping
104
104
 
105
105
  Detection and notification are automatic. After explicit installer activation, the local controller may restore only Marrow-managed hooks/configuration. Package upgrades, owner policy, credentials, and unrelated configuration remain explicit and subject to the operator's normal change policy.
106
106
 
107
- ## What's New in v3.9.73
107
+ ## What's New in v3.9.75
108
108
 
109
- v3.9.73 keeps one automatic operation bound to its original runtime authorization and decision across timeout and proof-required retries, then closes that exact decision once verified proof is supplied.
109
+ v3.9.75 adds explicit Codex, Cursor/Composer, Cline, Windsurf, and Gemini CLI native hook entrypoints. Gemini BeforeTool returns strict fixed allow/deny JSON, AfterTool returns neutral JSON after compact outcome capture, and AfterAgent closes one turn without reading prompt/response content or requesting a retry. Project hook trust and enablement remain user-controlled, and configuration stays client-self-reported rather than certified coverage.
110
+
111
+ ## Previous: v3.9.74
112
+
113
+ v3.9.74 keeps one automatic operation bound to its original runtime authorization and decision across timeout and proof-required retries, then closes that exact decision once verified proof is supplied. One outer `marrow_auto` invocation normally completes think and commit in-band within its bounded eight-second client budget. The release canary allows that complete client budget plus bounded response overhead rather than cutting the operation off at five seconds.
110
114
 
111
115
  ## Previous: v3.9.72
112
116
 
@@ -119,6 +123,7 @@ v3.9.71 makes the advertised Grok control loop true:
119
123
  - default tools include `marrow_think` so the official loop can create a `decision_id` without `MARROW_TOOL_PROFILE=full`;
120
124
  - process identity prefers `MARROW_KEY_<ROLE>` when it matches `MARROW_AGENT_ID`, so a leaked fleet env cannot 403 every status call;
121
125
  - Grok native hooks are installed under `~/.grok/hooks/marrow.json` and hook parsers accept Grok camelCase envelopes;
126
+ - Grok native PreToolUse, PostToolUse/PostToolUseFailure, and nonblocking Stop hooks provide bounded client-reported gating, result evidence, and one turn closeout. The governed wrapper remains an explicit bounded fallback;
122
127
  - idle spool nudge drains up to 40 current-namespace events so the queue does not sit as a nag;
123
128
  - if `risk_gate.enforced` is false, the gate is advisory — do not describe it as a live block;
124
129
  - `marrow_commit.decision_id` comes from `marrow_think`, `marrow_auto`, or an arbitration runtime that actually created a decision. A normal runtime authorization is a gate receipt, not a decision.
@@ -186,9 +191,9 @@ v3.9.62 integrates four model-neutral reliability and capability contracts:
186
191
  - standalone `marrow_status` uses the bounded compact API contract and can return a fresh, owner-only last-known status projection without treating it as a live gate or authorization;
187
192
  - ordinary runtime responses expose typed `runtime_authorization` backed by the authoritative gate receipt and omit `decision_id` unless the server actually created a decision;
188
193
  - `spool-status` and `drain-spool` report the active credential namespace separately from isolated legacy debt, and a clear active namespace exits successfully without replaying, merging, editing, or deleting old-key files;
189
- - initialize, prompt, setup, and tool responses qualify coverage by `host_capability`: MCP tools are on demand, while native hooks, an owned SDK process, a governed runner, or a custom event adapter cover only the scope proved by observed Marrow receipts.
194
+ - initialize, prompt, setup, and tool responses qualify coverage by `host_capability`: MCP tools are on demand, while client-self-reported hook activity remains visible but never certifies coverage or control.
190
195
 
191
- The default surface is seven tools (runtime, think, commit, ask, status, auto, handoff status) and the prompt remains named `marrow-always-on`. Host and model labels are display-only and never change auth, tenant, plan, policy, proof, schema, or API behavior. Grok always-on coverage is native hooks plus MCP; it is verified only from observed receipts.
196
+ The default surface is seven tools (runtime, think, commit, ask, status, auto, handoff status) and the prompt remains named `marrow-always-on`. Host and model labels are display-only and never change auth, tenant, plan, policy, proof, schema, or API behavior. Grok hook activity is client-self-reported and does not certify observed coverage; the governed wrapper remains an explicit bounded fallback.
192
197
 
193
198
  ## Previous: v3.9.61
194
199
 
@@ -204,14 +209,14 @@ v3.9.61 keeps an authoritative proof-pack rejection distinct from a control-path
204
209
  v3.9.60 restores the complete control-and-proof loop for ordinary MCP clients:
205
210
 
206
211
  - cached guidance no longer cuts live status, ask, runtime, or handoff reads down to an impossible 500 ms deadline;
207
- - `marrow_auto` waits for the bounded think-and-commit path and reports the live decision and proof result in-band;
212
+ - `marrow_auto` normally waits for the bounded think-and-commit path and reports the live decision and proof result in-band; if the client deadline is reached, the returned operation ID continues that same decision;
208
213
  - `marrow_commit` now shares the same abort and deadline contract as the other control calls;
209
214
  - transient retries use a one-second delay so a slow edge path is not immediately hit again;
210
215
  - spool status surfaces backlogs under older credential namespaces without replaying them across an unverified tenant boundary;
211
216
  - a plan-gated handoff is reported as unavailable for the current plan, not as an API or authentication outage;
212
217
  - the release canary runs with the customer's default client deadlines instead of silently overriding them.
213
218
 
214
- MCP-only hosts receive the same model-neutral control instructions and six-tool default surface, but MCP transport alone is on demand. A host or model label never changes that coverage contract. Marrow reports passive coverage only from observed lifecycle receipts, not from configuration detection.
219
+ The current package gives MCP-only hosts the same model-neutral control instructions and seven-tool default surface, but MCP transport alone remains on demand. A host or model label never changes that coverage contract. Public lifecycle callbacks and hook activity are client-self-reported and cannot verify or certify passive coverage; independent authority is required. Codex, Grok, and Gemini can use configured native hooks after restart and host hook review; the governed wrapper remains an explicit bounded fallback.
215
220
 
216
221
  ## Previous: v3.9.59
217
222
 
@@ -290,7 +295,7 @@ It preserves the signed action-permit and update controls introduced in v3.9.52.
290
295
 
291
296
  ## Previous: v3.9.52
292
297
 
293
- v3.9.52 combines operator-controlled client update notices with signed, action-bound permit verification in native hooks. Official MCP requests identify the installed package version, and passive context renders a request-specific server advisory with exact update and verification commands:
298
+ v3.9.52 combines operator-controlled client update notices with signed, action-bound permit verification in the cooperative Claude Code hook path. That permit flow does not authenticate hook provenance or certify always-on coverage. Official MCP requests identify the installed package version, and passive context renders a request-specific server advisory with exact update and verification commands:
294
299
 
295
300
  - update availability or unrecognized version metadata appears during normal authenticated runtime/status activity;
296
301
  - messaging clearly states that hosted Marrow services are already current and that no local change was applied;
@@ -298,7 +303,7 @@ v3.9.52 combines operator-controlled client update notices with signed, action-b
298
303
  - unknown versions do not imply a vulnerability, while server-designated security requirements remain distinct;
299
304
  - existing MCP tools and older server responses remain compatible when no advisory is returned.
300
305
 
301
- The native `PreToolUse` hook verifies the permit before protected work can execute. It obtains the runtime gate, records the exact governed decision, requests a permit bound to that gate, decision, target, and canonical action surfaces, and consumes it immediately before returning control to the harness:
306
+ The Claude Code `PreToolUse` hook cooperatively verifies the permit before returning control to that harness. It obtains the runtime gate, records the exact governed decision, requests a permit bound to that gate, decision, target, and canonical action surfaces, and consumes it before returning. The callback itself remains client-self-reported and is not a certified external choke point:
302
307
 
303
308
  - protected deploy, publish, merge, migration, credential, and production actions fail closed on timeout or permit failure;
304
309
  - the permit is bound to the authenticated account, key, agent, session, action, target, canonical action surfaces, decision, and runtime gate;
@@ -307,13 +312,13 @@ The native `PreToolUse` hook verifies the permit before protected work can execu
307
312
  - the bounded hook timeout prevents a control-plane wait from hanging the agent indefinitely;
308
313
  - low-risk work retains passive/advisory behavior unless account policy requires stronger enforcement.
309
314
 
310
- It preserves the verifiable native-hook coverage introduced in v3.9.50:
315
+ It preserves native-hook activity diagnostics introduced in v3.9.50, with the current trust boundary applied:
311
316
 
312
- - agents and owners can distinguish “MCP configured” from “pre-action, result, and session hooks actually observed”;
317
+ - agents and owners can distinguish “MCP configured” from client-reported pre-action, result, and session activity without treating either as certification;
313
318
  - `PreToolUse` requests the Marrow runtime gate before matched actions and maps `block` to deny and `review_required` to operator review;
314
319
  - matching `PreToolUse` and result hooks share Claude Code's tool-use correlation while the session shares one workflow identity;
315
- - generic integration events cannot claim native-hook coverage unless the native adapter supplies that evidence;
316
- - retries preserve correlation and capability evidence in the owner-only durable spool;
320
+ - generic integration events and public hook entrypoints cannot claim certified native-hook coverage;
321
+ - retries preserve correlation and explicitly `client_self_reported` activity in the owner-only durable spool;
317
322
  - configuration drift can be diagnosed without sending configuration contents;
318
323
  - missing outcome closure remains visible rather than treating tool or session exit as business success;
319
324
  - existing MCP tools and lifecycle inputs remain compatible.
@@ -334,16 +339,16 @@ It preserves `marrow_arbitrate` from v3.9.49, the session-orientation hardening
334
339
 
335
340
  Existing MCP tools and stable context API names remain compatible. Authentication, policy, proof, and validation failures are surfaced rather than retried as network failures.
336
341
 
337
- Coverage percentages are produced only when Marrow has exact observed receipts. An installed config without observed hooks is shown as warming up or degraded, with `npx @getmarrow/install --repair` as the bounded repair path.
342
+ Client hook activity alone never produces certified coverage percentages. An installed config or API-key-authenticated callback is shown as client-self-reported activity; certification requires an independent authority not supplied by the public MCP hook entrypoints.
338
343
 
339
344
  ## Governed Action Flow
340
345
 
341
- With installed native hooks, protected tool calls follow this automatically. For explicit/custom MCP flows before deploys, merges, publishes, migrations, credential changes, financial operations, or customer-impacting work:
346
+ Configured hooks can provide cooperative telemetry and context, but they are not a certified execution boundary. Before deploys, merges, publishes, migrations, credential changes, financial operations, or customer-impacting work:
342
347
 
343
348
  1. Call `marrow_agent_runtime` or `marrow_decision_brief`.
344
349
  2. Stop when the returned decision is `block` or `review_required`; otherwise follow its prior lesson and proof contract.
345
350
  3. Call `marrow_think` or `marrow_auto` to record intent and obtain the `decision_id` that will be closed. Keep `marrow_agent_runtime.runtime_authorization.id` separate as the gate receipt for consequential work.
346
- 4. Perform the action only when its gate allows it. For a hard external choke point, run the command through `npx @getmarrow/install run`; it verifies the signed action permit immediately before execution.
351
+ 4. Perform the action only when its gate allows it. Codex, Grok, and Gemini use configured native hooks only after restart and host hook review. The governed wrapper remains an explicit bounded fallback: `npx @getmarrow/install run --agent <agent-id> -- -- <command>`.
347
352
  5. Call `marrow_commit` with that `decision_id`, the outcome, gate receipt, and required proof.
348
353
 
349
354
  `marrow_agent_runtime` returns `runtime_authorization` with the authoritative gate receipt. Ordinary runtime checks do not create a decision, so they omit `decision_id`; call `marrow_think` (or use `marrow_auto`) when a decision must be created and closed. An arbitration runtime that actually creates a decision returns that server-created `decision_id`. This contract is identical across MCP-compatible hosts and SDK-owned runtimes.
@@ -444,22 +449,26 @@ it does not run models, retain prompts, or infer a winner from labels.
444
449
 
445
450
  ## Passive Use
446
451
 
447
- `npx -y --package=@getmarrow/mcp@latest marrow-mcp setup` configures supported prompt, pre-action, tool-result, and session-stop hooks. Configuration is not proof that the host invoked them. Marrow reports native passive coverage only after it observes the required prompt, pre-action, action-result, and session-end receipts.
452
+ `npx -y --package=@getmarrow/mcp@latest marrow-mcp setup` configures supported prompt, pre-action, tool-result, and session-stop hooks. Configuration, public hook argv, and API-key-authenticated callbacks are client self-reports. They preserve raw lifecycle activity but do not prove that the host invoked a hook or certify passive control.
448
453
 
449
454
  ### Capability and coverage contract
450
455
 
451
456
  | Integration mode | Coverage Marrow can claim |
452
457
  | --- | --- |
453
458
  | MCP tools-only | On demand; covers only explicit MCP tool calls |
454
- | Verified native hooks | Passive only for the lifecycle stages backed by observed hook receipts |
459
+ | Configured native hooks | Cooperative telemetry/context only; activity is client-self-reported and coverage remains unverified |
455
460
  | `createPassiveRuntime().install()` | Only the owned Node process, and only while that runtime is installed and running |
456
461
  | Governed runner | Only the command launched through the wrapper |
457
462
  | Custom host | Requires a bounded event adapter; covers only the lifecycle events whose receipts Marrow observes |
458
463
 
459
- This contract is model-neutral. A model name, host header, config file, installed hook entry, or successful MCP handshake does not certify passive coverage. Only observed Marrow receipts do. An unknown MCP host therefore gets the generic `mcp-client` identity and the same on-demand tools, schemas, and API semantics as a named host.
464
+ This contract is model-neutral. A model name, host header, API key, public hook entrypoint, config file, installed hook entry, successful MCP handshake, or client-self-reported lifecycle callback does not certify passive coverage or enforcement. An unknown MCP host therefore gets the generic `mcp-client` identity and the same on-demand tools, schemas, and API semantics as a named host.
460
465
 
461
466
  When invoked by a supported host, the configured hooks send compact classifications and lifecycle receipts. They do not need raw prompts, completions, command output, tool output, or credentials. A completed tool or session does not automatically become a successful business outcome; explicit success/failure closure is required.
462
467
 
468
+ Setup installs distinct Claude Code and Grok hook entrypoints. The public entrypoint supplies only a client-reported display label; it is not host provenance. Hook event JSON cannot select the lifecycle harness or agent. Agent identity comes only from owner configuration when present, otherwise the request omits it so the authenticated service can derive the credential-bound identity. Every hook lifecycle event is marked `source: client_self_reported` and omits `capability_level: native_hooks`, adapter certification, configuration fingerprints, expected hooks, and observed-hook certification fields. Legacy, unknown, and custom entrypoints stay generic.
469
+
470
+ Claude Code hooks may cooperatively request guidance and apply the harness permission response, but that does not certify always-on control. Codex native hooks map both block and review-required gates to the supported synchronous deny response. Cursor and Composer use the same Cursor-native pre-action, result, failure, and stop adapters. Cline uses native pre-action and post-tool adapters plus TaskCancel closeout; its documented TaskComplete hook remains coming soon and is not claimed as observed coverage. Windsurf uses native pre-action, success-result, and response-closeout adapters and requires Restricted Mode to be off. Gemini CLI uses native BeforeTool, AfterTool, and AfterAgent adapters; AfterAgent is the deterministic per-turn closeout and no SessionEnd delivery is claimed. Grok uses global native PreToolUse, PostToolUse/PostToolUseFailure, and one nonblocking Stop closeout; Marrow's generated Grok file contains no duplicate SessionEnd closeout. These native paths keep MCP on demand and require restart plus host hook review. Cursor, Cline, Windsurf, Gemini, and Grok deny protected review-required or unavailable-control work when their native contracts cannot make a generic ask enforceable. All activity remains client-self-reported rather than verified host telemetry, and the governed wrapper remains an explicit bounded fallback. Unknown and custom hosts remain on demand unless they provide a bounded event adapter, whose activity is still not certification without an independent authority.
471
+
463
472
  Transient lifecycle receipts use a bounded owner-only spool and are retried with stable event IDs. Operators can inspect and drain it without exposing event content:
464
473
 
465
474
  ```bash
package/dist/cli.js CHANGED
@@ -11,6 +11,7 @@
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  const index_1 = require("./index");
14
+ const control_state_1 = require("./control-state");
14
15
  const hook_1 = require("./hook");
15
16
  const hook_contract_1 = require("./hook-contract");
16
17
  const hook_context_1 = require("./hook-context");
@@ -40,16 +41,16 @@ function parseArgs() {
40
41
  if (args[i] === 'setup' || args[i] === '--setup') {
41
42
  result.setup = true;
42
43
  }
43
- if (args[i] === 'hook' || args[i] === '--hook') {
44
+ if (['hook', '--hook', 'claude-hook', 'cline-hook', 'codex-hook', 'cursor-hook', 'gemini-hook', 'grok-hook', 'windsurf-hook'].includes(args[i])) {
44
45
  result.hook = true;
45
46
  }
46
- if (args[i] === 'context-hook' || args[i] === '--context-hook') {
47
+ if (['context-hook', '--context-hook', 'claude-context-hook', 'codex-context-hook', 'grok-context-hook'].includes(args[i])) {
47
48
  result.contextHook = true;
48
49
  }
49
- if (args[i] === 'pre-action-hook' || args[i] === '--pre-action-hook') {
50
+ if (['pre-action-hook', '--pre-action-hook', 'claude-pre-action-hook', 'cline-pre-action-hook', 'codex-pre-action-hook', 'cursor-pre-action-hook', 'gemini-pre-action-hook', 'grok-pre-action-hook', 'windsurf-pre-action-hook'].includes(args[i])) {
50
51
  result.preActionHook = true;
51
52
  }
52
- if (args[i] === 'session-hook' || args[i] === '--session-hook') {
53
+ if (['session-hook', '--session-hook', 'claude-session-hook', 'cline-session-hook', 'codex-session-hook', 'cursor-session-hook', 'gemini-session-hook', 'grok-session-hook', 'windsurf-session-hook'].includes(args[i])) {
53
54
  result.sessionHook = true;
54
55
  }
55
56
  if (args[i] === 'spool-status' || args[i] === '--spool-status') {
@@ -162,7 +163,7 @@ function runSetup() {
162
163
 
163
164
  Use Marrow according to the capability evidence returned by the MCP server:
164
165
 
165
- 1. **MCP baseline is on demand:** MCP transport exposes tools; it does not provide passive hooks. Call Marrow tools explicitly unless observed receipts verify another capability mode.
166
+ 1. **MCP baseline is on demand:** MCP transport exposes tools; it does not provide passive hooks. Public hook callbacks and local configuration are client-self-reported activity, not certified coverage.
166
167
  2. **Before risky actions:** Respect the returned \`allow\`, \`warn\`, \`review_required\`, or \`block\` decision and its proof contract. Call \`marrow_agent_runtime\` explicitly when verified passive coverage cannot cover the action.
167
168
  3. **After meaningful work:** Record the real success or failure with \`marrow_commit\` or \`marrow_auto\`. A tool exit or session end is not proof that the business outcome succeeded.
168
169
  4. **Unfinished work:** Leave pending outcomes visible. Do not invent success to clear a closure item.
@@ -172,9 +173,9 @@ Use Marrow according to the capability evidence returned by the MCP server:
172
173
 
173
174
  Do not skip the gate or outcome. Marrow's value comes from controlling the action before execution and preserving evidence afterward.
174
175
 
175
- Capability boundaries: verified native hooks cover only their observed lifecycle; \`createPassiveRuntime().install()\` covers only its owned Node process while installed; a governed runner covers only its wrapped command; and a custom host needs a bounded event adapter. A model name, host label, or installed configuration is not proof of coverage. Only observed Marrow receipts certify it.
176
+ Capability boundaries: configured native hooks provide cooperative client-reported control and lifecycle evidence only; \`createPassiveRuntime().install()\` covers only its owned Node process while installed; a governed wrapper covers only its wrapped command; and a custom host needs a bounded event adapter. A model name, host label, API key, public hook entrypoint, installed configuration, or client-self-reported callback is not proof of coverage or enforcement. Codex, Grok, and Gemini use configured native hooks only after restart and the host's hook review; the governed wrapper remains an explicit bounded fallback.
176
177
 
177
- For one-shot logging: \`marrow_auto({ action: "did X", outcome: "result Y", success: true })\` — one call, done.
178
+ For bounded outcome capture: \`marrow_auto({ action: "did X", outcome: "result Y", success: true })\`. One outer invocation normally completes think and commit in-band within its bounded client budget. If the host or network deadline is reached, retry with the returned \`operation_id\`; Marrow continues the same operation and never opens a second decision.
178
179
  ${MARROW_BLOCK_END}`;
179
180
  let dir = process.cwd();
180
181
  let claudeMdPath = null;
@@ -217,44 +218,44 @@ ${MARROW_BLOCK_END}`;
217
218
  }
218
219
  const hookInstall = (0, hook_1.installPostToolUseHook)(process.cwd());
219
220
  if (hookInstall.installed) {
220
- process.stdout.write('Configured PostToolUse hook. Coverage remains unverified until Marrow observes action-result receipts.\n');
221
+ process.stdout.write('Configured PostToolUse hook. Activity is client-self-reported and does not certify action-result coverage.\n');
221
222
  }
222
223
  else {
223
- process.stdout.write('PostToolUse hook configuration is present. Coverage remains unverified until Marrow observes action-result receipts.\n');
224
+ process.stdout.write('PostToolUse hook configuration is present. Activity is client-self-reported and does not certify action-result coverage.\n');
224
225
  }
225
226
  const contextHookInstall = (0, hook_context_1.installUserPromptSubmitHook)(process.cwd());
226
227
  if (contextHookInstall.installed) {
227
- process.stdout.write('Configured UserPromptSubmit hook. Passive prompt coverage remains unverified until Marrow observes prompt receipts.\n');
228
+ process.stdout.write('Configured UserPromptSubmit hook. Activity is client-self-reported and does not certify passive prompt coverage.\n');
228
229
  }
229
230
  else {
230
- process.stdout.write('UserPromptSubmit hook configuration is present. Passive prompt coverage remains unverified until Marrow observes prompt receipts.\n');
231
+ process.stdout.write('UserPromptSubmit hook configuration is present. Activity is client-self-reported and does not certify passive prompt coverage.\n');
231
232
  }
232
233
  const preActionHookInstall = (0, hook_pre_action_1.installPreActionHook)(process.cwd());
233
234
  if (preActionHookInstall.installed) {
234
- process.stdout.write('Configured PreToolUse hook. Pre-action coverage remains unverified until Marrow observes pre-action receipts.\n');
235
+ process.stdout.write('Configured PreToolUse hook. Activity is client-self-reported and does not certify pre-action control.\n');
235
236
  }
236
237
  else {
237
- process.stdout.write('PreToolUse hook configuration is present. Pre-action coverage remains unverified until Marrow observes pre-action receipts.\n');
238
+ process.stdout.write('PreToolUse hook configuration is present. Activity is client-self-reported and does not certify pre-action control.\n');
238
239
  }
239
240
  const sessionHookInstall = (0, hook_session_1.installSessionEndHook)(process.cwd());
240
241
  if (sessionHookInstall.installed) {
241
- process.stdout.write('Configured Stop hook. Session-end coverage remains unverified until Marrow observes session-end receipts.\n');
242
+ process.stdout.write('Configured Stop hook. Activity is client-self-reported and does not certify session-end coverage.\n');
242
243
  }
243
244
  else {
244
- process.stdout.write('Stop hook configuration is present. Session-end coverage remains unverified until Marrow observes session-end receipts.\n');
245
+ process.stdout.write('Stop hook configuration is present. Activity is client-self-reported and does not certify session-end coverage.\n');
245
246
  }
246
247
  const grokHookInstall = (0, hook_contract_1.installGrokNativeHooks)();
247
248
  if (grokHookInstall.installed) {
248
- process.stdout.write(`Configured Grok native hooks at ${grokHookInstall.settingsPath}. Coverage remains unverified until Marrow observes Grok lifecycle receipts.\n`);
249
+ process.stdout.write(`Configured Grok native pre-action, result, and nonblocking turn-closeout hooks at ${grokHookInstall.settingsPath}. Restart Grok and inspect /hooks before relying on them. Activity remains client-self-reported and does not certify observed coverage.\n`);
249
250
  }
250
251
  else {
251
- process.stdout.write(`Grok native hook configuration is present at ${grokHookInstall.settingsPath}. Coverage remains unverified until Marrow observes Grok lifecycle receipts.\n`);
252
+ process.stdout.write(`Grok native hook configuration is present at ${grokHookInstall.settingsPath}. Restart Grok and inspect /hooks before relying on it. Activity remains client-self-reported and does not certify observed coverage.\n`);
252
253
  }
253
254
  process.stdout.write(`Hook settings: ${hookInstall.settingsPath}\n`);
254
255
  process.stdout.write('Set MARROW_AUTO_HOOK=false to disable passive hooks.\n');
255
256
  process.stdout.write('Set MARROW_PASSIVE_BRIEF=false to disable automatic decision briefs, or MARROW_PASSIVE_BRIEF=always to brief every prompt.\n');
256
257
  process.stdout.write('Set MARROW_HOOK_DEBUG=true for write-side hook diagnostics, or MARROW_CONTEXT_HOOK_DEBUG=true for prompt-context diagnostics.\n');
257
- process.stdout.write('Setup completed. MCP tools remain on demand; passive coverage is reported only after Marrow observes the required hook receipts.\n');
258
+ process.stdout.write('Setup completed. MCP tools remain on demand; configured hook activity is client-self-reported and does not certify passive coverage or enforcement.\n');
258
259
  process.exit(0);
259
260
  }
260
261
  const cliArgs = parseArgs();
@@ -534,6 +535,7 @@ if (process.argv[2] !== 'keys') {
534
535
  : null)
535
536
  || (0, request_reliability_1.localClientUpdate)(),
536
537
  control_path: (0, control_path_state_1.controlPathStats)(toolName),
538
+ local_control: (0, control_state_1.localControlEvidence)(Boolean(API_KEY)),
537
539
  lifecycle_spool: {
538
540
  state: spool.failed > 0 || spool.pending > 0 ? spool.state : 'clear',
539
541
  pending: spool.pending,
@@ -902,7 +904,7 @@ if (process.argv[2] !== 'keys') {
902
904
  },
903
905
  {
904
906
  name: 'marrow_run',
905
- description: 'One-call governed outcome capture. Records intent, obtains a gate for risky work, and closes only with an explicit measured result.',
907
+ description: 'Governed outcome capture. Records intent, obtains a gate for risky work, and closes only with an explicit measured result.',
906
908
  inputSchema: {
907
909
  type: 'object',
908
910
  properties: {
@@ -922,7 +924,7 @@ if (process.argv[2] !== 'keys') {
922
924
  },
923
925
  {
924
926
  name: 'marrow_auto',
925
- description: 'Durably capture low-risk activity without blocking. Outcomes remain pending unless success is explicit; risky completion still requires a fresh gate and measured proof.',
927
+ description: 'Durably capture low-risk activity. One outer invocation normally completes in-band within the bounded client budget; a deadline continuation reuses the same operation_id and never opens a second decision. Outcomes remain pending unless success is explicit; risky completion still requires a fresh gate and measured proof.',
926
928
  inputSchema: {
927
929
  type: 'object',
928
930
  properties: {
@@ -1771,7 +1773,7 @@ if (process.argv[2] !== 'keys') {
1771
1773
  prompts: [
1772
1774
  {
1773
1775
  name: 'marrow-always-on',
1774
- description: 'Marrow control and proof contract, qualified by verified host capability and observed lifecycle receipts.',
1776
+ description: 'Marrow control and proof contract. MCP tools are on demand; host activity is client-self-reported and coverage remains unverified without independent authority.',
1775
1777
  arguments: [],
1776
1778
  _meta: { host_capability: mcpHostCapability() },
1777
1779
  },
@@ -1791,7 +1793,7 @@ if (process.argv[2] !== 'keys') {
1791
1793
  }
1792
1794
  const hostCapability = mcpHostCapability();
1793
1795
  success(id, {
1794
- description: 'Marrow control and proof contract — coverage is capability-qualified and receipt-verified',
1796
+ description: 'Marrow control and proof contract — MCP tools are on demand, host activity is client-self-reported, and coverage is unverified without independent authority',
1795
1797
  _meta: { host_capability: hostCapability },
1796
1798
  messages: [
1797
1799
  {
@@ -1804,12 +1806,12 @@ if (process.argv[2] !== 'keys') {
1804
1806
 
1805
1807
  ${(0, host_capability_1.hostCapabilityInstructions)(hostCapability)}
1806
1808
 
1807
- When verified by observed receipts, native hooks can cover these bounded lifecycle stages:
1809
+ Configured native hooks can cooperatively report or inject context for these bounded lifecycle stages, but their callbacks are client-self-reported activity and do not certify control:
1808
1810
  - UserPromptSubmit can request relevant policy, warnings, lessons, and a decision brief before risky work.
1809
1811
  - PostToolUse can record compact tool success or failure receipts.
1810
1812
  - Stop can keep unfinished outcomes visible instead of silently treating session exit as success.
1811
1813
 
1812
- Hooks never make a blocked action safe. Before a consequential action, respect the returned allow, warn, review_required, or block decision and its required proof. Call marrow_agent_runtime explicitly when verified passive coverage cannot cover the action.
1814
+ Hooks never make a blocked action safe and are not an external execution choke point. Before a consequential action, respect the returned allow, warn, review_required, or block decision and its required proof. Codex, Grok, and Gemini use configured native hooks only after restart and host hook review; the governed wrapper remains an explicit bounded fallback.
1813
1815
 
1814
1816
  When runtime/status returns a client_update notice, tell the operator and use its exact update and verification commands only when local change policy permits. Never silently change packages or configuration.
1815
1817
 
@@ -2044,6 +2046,9 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2044
2046
  baseUrl: BASE_URL,
2045
2047
  deferDelivery: false,
2046
2048
  event: {
2049
+ ...(delivered?.operation_id ? {
2050
+ event_id: `auto_${delivered.committed ? 'closed' : 'pending'}_${delivered.operation_id}`,
2051
+ } : {}),
2047
2052
  event_type: delivered?.committed
2048
2053
  ? 'outcome_committed'
2049
2054
  : !highRisk && outcomeSuccess === false
@@ -2058,8 +2063,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2058
2063
  action,
2059
2064
  outcome_state: delivered?.committed ? 'closed' : 'pending',
2060
2065
  success: delivered?.committed ? outcomeSuccess : highRisk ? undefined : outcomeSuccess,
2061
- adapter_version: hook_contract_2.MCP_ADAPTER_VERSION,
2062
- capability_level: 'mcp',
2066
+ source: 'client_self_reported',
2063
2067
  },
2064
2068
  });
2065
2069
  const response = {
@@ -2283,7 +2287,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2283
2287
  }
2284
2288
  if (toolName === 'marrow_agent_status') {
2285
2289
  const result = await (0, index_1.marrowAgentStatus)(API_KEY, BASE_URL, args.period || '7d', args.agentId || FLEET_AGENT_ID, SESSION_ID, FLEET_AGENT_ID);
2286
- success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
2290
+ success(id, { content: [{ type: 'text', text: JSON.stringify({ ...result, local_control: (0, control_state_1.localControlEvidence)(Boolean(API_KEY)) }, null, 2) }] });
2287
2291
  return;
2288
2292
  }
2289
2293
  if (toolName === 'marrow_runtime_status') {