@getmarrow/mcp 3.9.74 → 3.9.76

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
@@ -104,7 +104,15 @@ 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.74
107
+ ## What's New in v3.9.76
108
+
109
+ v3.9.76 fixes owner-approved `marrow_auto` closeout by binding an arbitrated operation to the exact server-created arbitration decision, rejecting decision mismatches before commit, and returning an honest terminal action for non-arbitrated `review_required` gates. Chat and proof text cannot substitute for a dashboard-issued approval receipt, and only a backend `committed: true` response closes the operation.
110
+
111
+ ## Previous: v3.9.75
112
+
113
+ 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.
114
+
115
+ ## Previous: v3.9.74
108
116
 
109
117
  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
118
 
@@ -119,7 +127,7 @@ v3.9.71 makes the advertised Grok control loop true:
119
127
  - default tools include `marrow_think` so the official loop can create a `decision_id` without `MARROW_TOOL_PROFILE=full`;
120
128
  - process identity prefers `MARROW_KEY_<ROLE>` when it matches `MARROW_AGENT_ID`, so a leaked fleet env cannot 403 every status call;
121
129
  - Grok native hooks are installed under `~/.grok/hooks/marrow.json` and hook parsers accept Grok camelCase envelopes;
122
- - Grok hooks are advisory telemetry/context only. Consequential execution requires `npx @getmarrow/install run --agent <agent-id> -- -- <command>`;
130
+ - 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;
123
131
  - idle spool nudge drains up to 40 current-namespace events so the queue does not sit as a nag;
124
132
  - if `risk_gate.enforced` is false, the gate is advisory — do not describe it as a live block;
125
133
  - `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.
@@ -189,7 +197,7 @@ v3.9.62 integrates four model-neutral reliability and capability contracts:
189
197
  - `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;
190
198
  - 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.
191
199
 
192
- 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 advisory and client-self-reported; the governed wrapper is the consequential-action boundary.
200
+ 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.
193
201
 
194
202
  ## Previous: v3.9.61
195
203
 
@@ -212,7 +220,7 @@ v3.9.60 restores the complete control-and-proof loop for ordinary MCP clients:
212
220
  - a plan-gated handoff is reported as unavailable for the current plan, not as an API or authentication outage;
213
221
  - the release canary runs with the customer's default client deadlines instead of silently overriding them.
214
222
 
215
- 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, Gemini, and similar CLI harnesses must use `npx @getmarrow/install run --agent <agent-id> -- -- <command>` for consequential commands.
223
+ 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.
216
224
 
217
225
  ## Previous: v3.9.59
218
226
 
@@ -344,12 +352,12 @@ Configured hooks can provide cooperative telemetry and context, but they are not
344
352
  1. Call `marrow_agent_runtime` or `marrow_decision_brief`.
345
353
  2. Stop when the returned decision is `block` or `review_required`; otherwise follow its prior lesson and proof contract.
346
354
  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.
347
- 4. Perform the action only when its gate allows it. For Codex, Grok, Gemini, and similar CLI harnesses, use the governed wrapper: `npx @getmarrow/install run --agent <agent-id> -- -- <command>`.
355
+ 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>`.
348
356
  5. Call `marrow_commit` with that `decision_id`, the outcome, gate receipt, and required proof.
349
357
 
350
358
  `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.
351
359
 
352
- `marrow_auto` returns an `operation_id`, phase, and resumable state. If a client deadline is reached before closure, retry with the same `operation_id`; Marrow reuses the same tenant-scoped runtime authorization, think decision, and commit idempotency keys instead of opening another decision. When the phase is `proof_required`, add the requested proof and retry with that same operation ID and unchanged action/context/surfaces. Proof is validated and bound at commit; changing the tenant or action scope is rejected. A closed response reports `phase: "closed"`, `committed: true`, and `resumable: false`.
360
+ `marrow_auto` returns an `operation_id`, phase, and resumable state. If a client deadline is reached before closure, retry with the same `operation_id`; Marrow reuses the same tenant-scoped runtime authorization, decision, and commit idempotency keys instead of opening another decision. When the phase is `proof_required`, add the requested proof and retry with that same operation ID and unchanged action/context/surfaces. An arbitrated runtime binds the operation directly to the arbitration response's server-created `decision_id`; `marrow_auto` does not open a separate decision. When an arbitrated result returns `owner_approval_required`, do not retry proof: approve that exact arbitration decision in an authenticated Marrow dashboard, then call `marrow_auto` once with the same operation ID, `arbitration_receipt_id`, and server-issued `owner_approval_receipt_id`. A non-arbitrated `review_required` result is terminal for that operation because the backend cannot issue a compatible dashboard receipt; start a new supported `marrow_arbitrate` review instead. Chat or proof text is never an approval receipt. Proof and receipts are validated and bound at commit; changing the tenant or action scope is rejected. A closed response reports `phase: "closed"`, `committed: true`, and `resumable: false`.
353
361
 
354
362
  Example pre-action request:
355
363
 
@@ -463,7 +471,7 @@ When invoked by a supported host, the configured hooks send compact classificati
463
471
 
464
472
  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.
465
473
 
466
- Claude Code hooks may cooperatively request guidance and apply the harness permission response, but that does not certify always-on control. Grok hooks are advisory telemetry/context only: `grok-pre-action-hook` never issues, verifies, or consumes an action permit and never claims enforcement. Codex, Grok, Gemini, and similar CLI harnesses must run consequential commands through `npx @getmarrow/install run --agent <agent-id> -- -- <command>`. Unknown and custom hosts remain on demand unless they provide a bounded event adapter, whose activity is still not certification without an independent authority.
474
+ 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.
467
475
 
468
476
  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:
469
477
 
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 (['hook', '--hook', 'claude-hook', 'grok-hook'].includes(args[i])) {
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 (['context-hook', '--context-hook', 'claude-context-hook', 'grok-context-hook'].includes(args[i])) {
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 (['pre-action-hook', '--pre-action-hook', 'claude-pre-action-hook', 'grok-pre-action-hook'].includes(args[i])) {
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 (['session-hook', '--session-hook', 'claude-session-hook', 'grok-session-hook'].includes(args[i])) {
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') {
@@ -172,7 +173,7 @@ 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: configured native hooks provide cooperative telemetry or context 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. For Codex, Grok, Gemini, and similar CLI harnesses, run consequential commands through \`npx @getmarrow/install run --agent <agent-id> -- -- <command>\`.
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
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}`;
@@ -245,10 +246,10 @@ ${MARROW_BLOCK_END}`;
245
246
  }
246
247
  const grokHookInstall = (0, hook_contract_1.installGrokNativeHooks)();
247
248
  if (grokHookInstall.installed) {
248
- process.stdout.write(`Configured Grok advisory hooks at ${grokHookInstall.settingsPath}. Their activity is client-self-reported and never certifies coverage or enforcement; consequential commands require npx @getmarrow/install run --agent <agent-id> -- -- <command>.\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 advisory hook configuration is present at ${grokHookInstall.settingsPath}. Its activity is client-self-reported and never certifies coverage or enforcement; consequential commands require npx @getmarrow/install run --agent <agent-id> -- -- <command>.\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');
@@ -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,
@@ -936,6 +938,8 @@ if (process.argv[2] !== 'keys') {
936
938
  },
937
939
  proof: { type: 'object', description: 'Measured completion evidence for gated work.' },
938
940
  gate_receipt_id: { type: 'string', description: 'Fresh receipt returned by marrow_agent_runtime.' },
941
+ arbitration_receipt_id: { type: 'string', description: 'For arbitrated work, the arbitration receipt returned by the same server-side review flow.' },
942
+ owner_approval_receipt_id: { type: 'string', description: 'Short-lived, single-use receipt issued by authenticated dashboard owner approval. Chat text is not an approval receipt.' },
939
943
  operation_id: {
940
944
  type: 'string',
941
945
  description: 'Opaque 8-80 character resume token. Reuse it only with the original tenant, action, context, and surfaces; proof may be added after proof_required.',
@@ -1809,7 +1813,7 @@ Configured native hooks can cooperatively report or inject context for these bou
1809
1813
  - PostToolUse can record compact tool success or failure receipts.
1810
1814
  - Stop can keep unfinished outcomes visible instead of silently treating session exit as success.
1811
1815
 
1812
- 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. For Codex, Grok, Gemini, and similar CLI harnesses, use npx @getmarrow/install run --agent <agent-id> -- -- <command>.
1816
+ 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
1817
 
1814
1818
  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
1819
 
@@ -2016,6 +2020,12 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2016
2020
  const suppliedRuntimeReceiptId = typeof args.gate_receipt_id === 'string'
2017
2021
  ? args.gate_receipt_id
2018
2022
  : undefined;
2023
+ const suppliedArbitrationReceiptId = typeof args.arbitration_receipt_id === 'string'
2024
+ ? args.arbitration_receipt_id
2025
+ : undefined;
2026
+ const suppliedOwnerApprovalReceiptId = typeof args.owner_approval_receipt_id === 'string'
2027
+ ? args.owner_approval_receipt_id
2028
+ : undefined;
2019
2029
  const delivery = () => (0, index_1.marrowAuto)(API_KEY, BASE_URL, {
2020
2030
  action,
2021
2031
  outcome,
@@ -2023,6 +2033,8 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2023
2033
  type,
2024
2034
  proof: suppliedProof,
2025
2035
  gate_receipt_id: suppliedRuntimeReceiptId || undefined,
2036
+ arbitration_receipt_id: suppliedArbitrationReceiptId,
2037
+ owner_approval_receipt_id: suppliedOwnerApprovalReceiptId,
2026
2038
  // Low-risk one-shot capture does not need a policy gate. Consequential
2027
2039
  // work obtains exactly one canonical runtime authorization inside auto.
2028
2040
  auto_gate: highRisk,
@@ -2078,11 +2090,15 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2078
2090
  receipt,
2079
2091
  completion_state: delivered?.committed
2080
2092
  ? 'closed_with_proof'
2081
- : delivered?.phase === 'proof_required'
2082
- ? 'pending_required_proof'
2083
- : delivered?.phase === 'decision_created' || outcomeSuccess === undefined
2084
- ? 'pending_evidence'
2085
- : 'delivery_pending',
2093
+ : delivered?.phase === 'review_required'
2094
+ ? 'review_required_terminal'
2095
+ : delivered?.phase === 'owner_approval_required'
2096
+ ? 'pending_owner_approval'
2097
+ : delivered?.phase === 'proof_required'
2098
+ ? 'pending_required_proof'
2099
+ : delivered?.phase === 'decision_created' || outcomeSuccess === undefined
2100
+ ? 'pending_evidence'
2101
+ : 'delivery_pending',
2086
2102
  decision_id: delivered?.decision_id || null,
2087
2103
  operation_id: delivered?.operation_id || (typeof args.operation_id === 'string' ? args.operation_id : null),
2088
2104
  phase: delivered?.phase || null,
@@ -2091,11 +2107,15 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2091
2107
  phase_timings_ms: delivered?.phase_timings_ms || null,
2092
2108
  exact_next_action: delivered?.committed
2093
2109
  ? 'The governed outcome is closed. Reuse this decision_id only for read-only trace inspection.'
2094
- : delivered?.phase === 'proof_required'
2095
- ? 'Attach the required measured proof and retry marrow_auto with this same operation_id and unchanged action, context, and surfaces.'
2096
- : delivered?.resumable
2097
- ? 'Retry marrow_auto with this same operation_id. Do not start a new auto operation.'
2098
- : 'Close this decision after the real outcome is known.',
2110
+ : delivered?.exact_next_action
2111
+ ? delivered.exact_next_action
2112
+ : delivered?.phase === 'owner_approval_required'
2113
+ ? 'Approve this exact arbitration decision in the authenticated Marrow dashboard, then call marrow_auto once with this same operation_id, arbitration_receipt_id, and the server-issued owner_approval_receipt_id. Do not retry proof or use chat approval text.'
2114
+ : delivered?.phase === 'proof_required'
2115
+ ? 'Attach the required measured proof and retry marrow_auto with this same operation_id and unchanged action, context, and surfaces.'
2116
+ : delivered?.resumable
2117
+ ? 'Retry marrow_auto with this same operation_id. Do not start a new auto operation.'
2118
+ : 'Close this decision after the real outcome is known.',
2099
2119
  live_delivery: {
2100
2120
  accepted: Boolean(delivered?.decision_id),
2101
2121
  committed: Boolean(delivered?.committed),
@@ -2285,7 +2305,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2285
2305
  }
2286
2306
  if (toolName === 'marrow_agent_status') {
2287
2307
  const result = await (0, index_1.marrowAgentStatus)(API_KEY, BASE_URL, args.period || '7d', args.agentId || FLEET_AGENT_ID, SESSION_ID, FLEET_AGENT_ID);
2288
- success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
2308
+ success(id, { content: [{ type: 'text', text: JSON.stringify({ ...result, local_control: (0, control_state_1.localControlEvidence)(Boolean(API_KEY)) }, null, 2) }] });
2289
2309
  return;
2290
2310
  }
2291
2311
  if (toolName === 'marrow_runtime_status') {