@getmarrow/mcp 3.9.71 → 3.9.73

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.71
107
+ ## What's New in v3.9.73
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.
110
+
111
+ ## Previous: v3.9.72
112
+
113
+ v3.9.72 requires SDK `3.7.61` so MCP installations cannot resolve to an SDK that recursively intercepts its own Marrow control-plane traffic. The MCP tool contract is unchanged; this release aligns the tested package chain.
114
+
115
+ ## Previous: v3.9.71
108
116
 
109
117
  v3.9.71 makes the advertised Grok control loop true:
110
118
 
@@ -113,7 +121,7 @@ v3.9.71 makes the advertised Grok control loop true:
113
121
  - Grok native hooks are installed under `~/.grok/hooks/marrow.json` and hook parsers accept Grok camelCase envelopes;
114
122
  - idle spool nudge drains up to 40 current-namespace events so the queue does not sit as a nag;
115
123
  - if `risk_gate.enforced` is false, the gate is advisory — do not describe it as a live block;
116
- - `marrow_commit.decision_id` may come from `marrow_think`, `marrow_auto`, or `marrow_agent_runtime.runtime_authorization.id`.
124
+ - `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.
117
125
 
118
126
  ## Previous: v3.9.69
119
127
 
@@ -334,12 +342,14 @@ With installed native hooks, protected tool calls follow this automatically. For
334
342
 
335
343
  1. Call `marrow_agent_runtime` or `marrow_decision_brief`.
336
344
  2. Stop when the returned decision is `block` or `review_required`; otherwise follow its prior lesson and proof contract.
337
- 3. Call `marrow_think` or `marrow_auto` to record intent and obtain the `decision_id` that will be closed. `marrow_agent_runtime.runtime_authorization.id` is also accepted.
345
+ 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.
338
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.
339
347
  5. Call `marrow_commit` with that `decision_id`, the outcome, gate receipt, and required proof.
340
348
 
341
349
  `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.
342
350
 
351
+ `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`.
352
+
343
353
  Example pre-action request:
344
354
 
345
355
  ```json
package/dist/cli.js CHANGED
@@ -25,7 +25,6 @@ const hook_contract_2 = require("./hook-contract");
25
25
  const ping_state_1 = require("./ping-state");
26
26
  const control_path_state_1 = require("./control-path-state");
27
27
  const redact_1 = require("./redact");
28
- const runtime_contract_1 = require("./runtime-contract");
29
28
  const status_cache_1 = require("./status-cache");
30
29
  const habit_loop_copy_1 = require("./habit-loop-copy");
31
30
  const host_capability_1 = require("./host-capability");
@@ -848,13 +847,13 @@ if (process.argv[2] !== 'keys') {
848
847
  {
849
848
  name: 'marrow_commit',
850
849
  description: 'Close a recorded action with success/failure, a specific outcome, and required proof. ' +
851
- 'decision_id may come from marrow_think, marrow_auto, or marrow_agent_runtime.runtime_authorization.id. ' +
850
+ 'decision_id comes from marrow_think, marrow_auto, or an arbitration runtime that actually created a decision. ' +
852
851
  'Use the gate receipt from marrow_agent_runtime for consequential work. ' +
853
852
  'Outcome closure is required for accountable fleet learning.',
854
853
  inputSchema: {
855
854
  type: 'object',
856
855
  properties: {
857
- decision_id: { type: 'string', description: 'decision_id from marrow_think, marrow_auto, or marrow_agent_runtime.runtime_authorization.id' },
856
+ decision_id: { type: 'string', description: 'decision_id from marrow_think, marrow_auto, or an arbitration runtime that created a decision' },
858
857
  success: { type: 'boolean', description: 'Did the action succeed?' },
859
858
  outcome: { type: 'string', description: 'What happened — be specific, this trains the hive' },
860
859
  caused_by: { type: 'string', description: 'Optional: what caused this action' },
@@ -937,6 +936,10 @@ if (process.argv[2] !== 'keys') {
937
936
  },
938
937
  proof: { type: 'object', description: 'Measured completion evidence for gated work.' },
939
938
  gate_receipt_id: { type: 'string', description: 'Fresh receipt returned by marrow_agent_runtime.' },
939
+ operation_id: {
940
+ type: 'string',
941
+ 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.',
942
+ },
940
943
  },
941
944
  required: ['action'],
942
945
  },
@@ -2010,35 +2013,20 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2010
2013
  const suppliedProof = args.proof && typeof args.proof === 'object' && !Array.isArray(args.proof)
2011
2014
  ? (0, redact_1.redactSensitiveValue)(args.proof)
2012
2015
  : undefined;
2013
- let runtimeGate = null;
2014
- if (highRisk) {
2015
- runtimeGate = await withControlDeadline((signal) => (0, index_1.marrowAgentRuntime)(API_KEY, BASE_URL, {
2016
- action: (0, redact_1.redactSensitiveText)(action),
2017
- type,
2018
- agent_id: FLEET_AGENT_ID,
2019
- session_id: SESSION_ID,
2020
- proof: suppliedProof,
2021
- context: { source: 'mcp_auto_risk_upgrade' },
2022
- }, SESSION_ID, FLEET_AGENT_ID, signal), { highRisk: true, toolName: 'marrow_auto.runtime' });
2023
- storeRuntimeGuidance(runtimeGate);
2024
- }
2025
- const canonicalRuntimeReceiptId = (0, runtime_contract_1.runtimeAuthorizationReceiptId)(runtimeGate);
2026
2016
  const suppliedRuntimeReceiptId = typeof args.gate_receipt_id === 'string'
2027
2017
  ? args.gate_receipt_id
2028
- : canonicalRuntimeReceiptId;
2029
- const proofCanClose = !highRisk
2030
- || (0, runtime_contract_1.highRiskRuntimeCanClose)(runtimeGate, suppliedProof, suppliedRuntimeReceiptId);
2031
- const acceptedSuccess = proofCanClose ? outcomeSuccess : undefined;
2018
+ : undefined;
2032
2019
  const delivery = () => (0, index_1.marrowAuto)(API_KEY, BASE_URL, {
2033
2020
  action,
2034
2021
  outcome,
2035
- success: acceptedSuccess,
2022
+ success: outcomeSuccess,
2036
2023
  type,
2037
2024
  proof: suppliedProof,
2038
2025
  gate_receipt_id: suppliedRuntimeReceiptId || undefined,
2039
2026
  // Low-risk one-shot capture does not need a policy gate. Consequential
2040
- // work already obtained and validated canonical runtime authorization.
2027
+ // work obtains exactly one canonical runtime authorization inside auto.
2041
2028
  auto_gate: highRisk,
2029
+ operation_id: typeof args.operation_id === 'string' ? args.operation_id : undefined,
2042
2030
  }, SESSION_ID, FLEET_AGENT_ID, 8_000);
2043
2031
  let delivered = null;
2044
2032
  let deliveryFailure = null;
@@ -2048,6 +2036,9 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2048
2036
  catch (err) {
2049
2037
  deliveryFailure = (0, request_reliability_1.structuredRequestFailure)(err);
2050
2038
  }
2039
+ const runtimeGate = delivered?.runtime_gate || null;
2040
+ if (runtimeGate)
2041
+ storeRuntimeGuidance(runtimeGate);
2051
2042
  const receipt = await (0, lifecycle_spool_1.recordLifecycleEvent)({
2052
2043
  apiKey: API_KEY,
2053
2044
  baseUrl: BASE_URL,
@@ -2055,18 +2046,18 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2055
2046
  event: {
2056
2047
  event_type: delivered?.committed
2057
2048
  ? 'outcome_committed'
2058
- : !highRisk && acceptedSuccess === false
2049
+ : !highRisk && outcomeSuccess === false
2059
2050
  ? 'tool_failed'
2060
- : !highRisk && acceptedSuccess === true
2051
+ : !highRisk && outcomeSuccess === true
2061
2052
  ? 'tool_completed'
2062
2053
  : 'goal_started',
2063
2054
  harness: process.env.MARROW_CLIENT || process.env.MARROW_HARNESS || 'mcp',
2064
2055
  agent_id: FLEET_AGENT_ID,
2065
2056
  session_id: SESSION_ID,
2066
- decision_id: delivered?.decision_id,
2057
+ decision_id: delivered?.decision_id || undefined,
2067
2058
  action,
2068
2059
  outcome_state: delivered?.committed ? 'closed' : 'pending',
2069
- success: delivered?.committed ? acceptedSuccess : highRisk ? undefined : acceptedSuccess,
2060
+ success: delivered?.committed ? outcomeSuccess : highRisk ? undefined : outcomeSuccess,
2070
2061
  adapter_version: hook_contract_2.MCP_ADAPTER_VERSION,
2071
2062
  capability_level: 'mcp',
2072
2063
  },
@@ -2077,20 +2068,34 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2077
2068
  warnings: cachedOrientWarnings.map(formatWarningActionably),
2078
2069
  logging: delivered?.committed
2079
2070
  ? 'governed_commit_confirmed'
2080
- : delivered
2081
- ? 'intent_confirmed'
2082
- : 'durably_queued',
2071
+ : delivered?.resumable
2072
+ ? 'resume_required'
2073
+ : delivered
2074
+ ? 'intent_confirmed'
2075
+ : 'durably_queued',
2083
2076
  receipt,
2084
2077
  completion_state: delivered?.committed
2085
2078
  ? 'closed_with_proof'
2086
- : !proofCanClose
2079
+ : delivered?.phase === 'proof_required'
2087
2080
  ? 'pending_required_proof'
2088
- : outcomeSuccess === undefined
2081
+ : delivered?.phase === 'decision_created' || outcomeSuccess === undefined
2089
2082
  ? 'pending_evidence'
2090
2083
  : 'delivery_pending',
2091
2084
  decision_id: delivered?.decision_id || null,
2085
+ operation_id: delivered?.operation_id || (typeof args.operation_id === 'string' ? args.operation_id : null),
2086
+ phase: delivered?.phase || null,
2087
+ resumable: delivered?.resumable || false,
2088
+ retry_after_ms: delivered?.retry_after_ms ?? null,
2089
+ phase_timings_ms: delivered?.phase_timings_ms || null,
2090
+ exact_next_action: delivered?.committed
2091
+ ? 'The governed outcome is closed. Reuse this decision_id only for read-only trace inspection.'
2092
+ : delivered?.phase === 'proof_required'
2093
+ ? 'Attach the required measured proof and retry marrow_auto with this same operation_id and unchanged action, context, and surfaces.'
2094
+ : delivered?.resumable
2095
+ ? 'Retry marrow_auto with this same operation_id. Do not start a new auto operation.'
2096
+ : 'Close this decision after the real outcome is known.',
2092
2097
  live_delivery: {
2093
- accepted: Boolean(delivered),
2098
+ accepted: Boolean(delivered?.decision_id),
2094
2099
  committed: Boolean(delivered?.committed),
2095
2100
  ...(deliveryFailure ? { failure: deliveryFailure } : {}),
2096
2101
  },