@getmarrow/mcp 3.9.81 → 3.9.83

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
@@ -87,6 +87,14 @@ For most new installations, start with the universal installer instead:
87
87
  npx @getmarrow/install activate
88
88
  ```
89
89
 
90
+ After setup writes MCP configuration or hooks, restart the agent host and review/enable its hook trust. Then verify the reloaded environment:
91
+
92
+ ```bash
93
+ npx -y @getmarrow/install@latest doctor --self-test
94
+ ```
95
+
96
+ Successful setup alone does not mean this process reloaded or that hooks are active. Keep savings at zero until observed usage supplies evidence.
97
+
90
98
  ## Tool Profiles
91
99
 
92
100
  Ordinary setup does not require `MARROW_TOOL_PROFILE`. When the variable is unset, Marrow uses the `primary` profile and exposes exactly the 17 tools in [Primary MCP Tools](#primary-mcp-tools).
@@ -116,7 +124,23 @@ npx -y --package=@getmarrow/mcp@latest marrow-mcp ping
116
124
 
117
125
  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.
118
126
 
119
- ## What's New in v3.9.81
127
+ ## What's New in v3.9.83
128
+
129
+ v3.9.83 confirms pending automatic writes by replaying the same authenticated operation and request, with one retry owner and a four-second attempt ceiling inside the unchanged eight-second total budget. Numeric and date-based server retry delays are preserved. Conflicting receipts never confirm closure, and unavailable or unverified results remain pending.
130
+
131
+ Post-action commit lookup now preserves the original general/empty-surface defaults and optional explicit target. It remains observation-only. Receipt expiry uses an explicit normal runtime request for the original scope, followed by a separate verified commit; it does not extend the old receipt or grant retrospective permission. Transient lifecycle delivery retries preserve the queued event and its stable identity across restart within bounded scheduling and attempt limits. Queued, server-accepted, and committed remain separate facts.
132
+
133
+ Before upgrading, finish existing pending auto operations with their current verified client. Older auto requests omitted supplied surfaces from think; correcting nonempty surfaces can therefore expose an idempotency conflict for that old operation. Do not reinterpret the conflict, open a replacement operation, use a silent legacy fallback, or automatically downgrade. Omitted/empty surface operations preserve their original canonical scope. This is a scope-correctness change, not a promise that every pending old-client operation can resume across an upgrade.
134
+
135
+ Default primary guidance uses runtime followed by commit and exposes exactly 17 tools. Auto remains available in explicitly selected core/full profiles. SDK `3.7.62` and installer `0.1.56` are unchanged; install MCP `3.9.83`, reload the host, review hook trust, and verify before claiming the updated client is active.
136
+
137
+ ### Previous release: v3.9.82
138
+
139
+ v3.9.82 batches client reliability fixes for `marrow_auto`. Continuations honor the server's finite retry delay within the existing eight-second core budget; when the delay cannot fit, the same operation remains pending with retry guidance. Gated auto reuses the server-created decision after checking its canonical scope, and ordinary owner approval can resume that decision when the backend explicitly declares the supported proof contract. The installed bytes of v3.9.81 cannot provide these client changes; update MCP for this behavior. SDK and installer versions are unchanged.
140
+
141
+ Auto now durably queues its lifecycle receipt before responding and starts the existing bounded background delivery afterward. A queued receipt is not server acceptance, while `live_delivery.committed` separately reports confirmed governed closure. New numeric response timings distinguish core work, durable enqueue, and response construction. The canary preserves these measurements and distinguishes pending completion, owner approval, and missing proof from malformed responses or transport failures; an uncommitted canary still fails. These changes do not promise fixed latency or eliminate outages.
142
+
143
+ ### Previous release: v3.9.81
120
144
 
121
145
  v3.9.81 adds bounded structured failure evidence to the authenticated eleven-tool control-path canary. Failed runs identify the observed stage, tool, error class, timing, and completed checks without retaining credentials, customer payloads, or arbitrary error text. Protocol and write failures observed after the final response or during shutdown now fail closed; the canary's own bounded cleanup remains compatible with a successful run. The eleven live-tool requirements, client deadlines, package identity checks, and retry limits are unchanged.
122
146
 
@@ -162,7 +186,7 @@ v3.9.71 makes the advertised Grok control loop true:
162
186
  - 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;
163
187
  - idle spool nudge drains up to 40 current-namespace events so the queue does not sit as a nag;
164
188
  - if `risk_gate.enforced` is false, the gate is advisory — do not describe it as a live block;
165
- - `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
+ - `marrow_commit.decision_id` comes from `marrow_think`, `marrow_auto`, or an arbitration runtime that actually created a decision. A normal runtime may create or reuse a decision: follow runtime.decision_id and completion_contract. Keep runtime.runtime_authorization.id separate as gate_receipt_id.
166
190
 
167
191
  ## Previous: v3.9.69
168
192
 
@@ -379,19 +403,29 @@ Client hook activity alone never produces certified coverage percentages. An ins
379
403
 
380
404
  ## Governed Action Flow
381
405
 
406
+ With `MARROW_TOOL_PROFILE` unset, the default primary profile uses `marrow_agent_runtime` followed by `marrow_commit`. It exposes 17 tools; `marrow_auto` is available only after an explicit `core` or `full` selection and MCP restart. Primary status and lessons use `marrow_agent_status` and `marrow_fleet_lessons`.
407
+
382
408
  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:
383
409
 
384
410
  1. Call `marrow_agent_runtime` or `marrow_decision_brief`.
385
411
  2. Stop when the returned decision is `block` or `review_required`; otherwise follow its prior lesson and proof contract.
386
- 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.
412
+ 3. Reuse a server-created runtime `decision_id` when the completion contract identifies it. Call `marrow_think` when decision creation is still required; explicitly selected core/full profiles can also use `marrow_auto`. Keep `marrow_agent_runtime.runtime_authorization.id` separate as the gate receipt for consequential work.
387
413
  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>`.
388
414
  5. Call `marrow_commit` with that `decision_id`, the outcome, gate receipt, and required proof.
389
415
 
390
- `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.
416
+ `marrow_agent_runtime` returns `runtime_authorization` with the authoritative gate receipt. An ordinary or arbitrated runtime that creates a decision also returns its server-created `decision_id`; follow `completion_contract.decision_creation_required` and preserve the returned scope. When decision creation is required, call `marrow_think`; core/full can also use `marrow_auto`. Auto requests the existing expanded runtime response to check receipt identity, decision, action, agent, session, and expiry before reusing that decision; it does not obtain a second authorization fetch.
391
417
 
392
418
  A `review_required`, `block`, or `outcome_observation_only` result never permits the action. If the action already occurred and its real result must be preserved, `marrow_commit` can ask runtime to bind observation delivery to the existing decision, action, session, and agent. The exact backend `outcome_observation_only` correlation is non-durable and non-authorizing, so MCP never sends it as a gate, arbitration, or owner-approval receipt. An accepted observation reports `committed: false`, `outcome_state: "observed_unverified"`, `authorization_granted: false`, and `trusted_learning_applied: false`, plus the backend's `exact_next_action`. This is durable delivery, so do not retry or spool the same observation. To promote it into trusted learning, obtain the named authorization and proof, then make an explicit new commit attempt using the exact observed payload. Never synthesize a decision, receipt, approval, or authorization.
393
419
 
394
- `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`.
420
+ `marrow_auto` returns an `operation_id`, phase, and resumable state. For a resumable pending phase, respect `retry_after_ms` and use the same operation ID, tenant, agent, session, action, type, surfaces, outcome, proof and receipt payload; auto never shortens the requested finite delay to fit its core budget. When the phase is `proof_required`, supply the requested measured evidence before retrying that operation. Stable phase idempotency keys preserve the original decision and outcome across retries; the backend remains authoritative for acceptance and conflicts. A four-second automatic write attempt ceiling leaves replay time inside the existing eight-second total budget. Long server delays remain pending without waiting beyond that budget. Malformed or unbounded Retry-After headers stop automatic continuation. Only committed:true confirms closure; pending is not evidence that a server write failed.
421
+
422
+ If a receipt expires while the same decision remains open, explicitly request normal runtime again with the original action, type, surfaces, agent and session. A fresh request key is required: replaying the old runtime key replays its old receipt. Verify the returned `runtime.decision_id` still matches the original, keep the new `runtime.runtime_authorization.id` as `gate_receipt_id`, and satisfy the current proof and approval contract. For a scope with an explicit target, use the `marrowAgentRuntime` library or `POST /v1/agent/runtime` preserving that target; the public MCP runtime schema does not expose target. Do not renew through post-action `auto_gate`: it only obtains observation truth. A fresh receipt never retrospectively authorizes an action taken without permission, and a changed scope is a different decision. Expired or used receipts may return an accepted `observed_unverified` result with `committed:false`; that is not closure.
423
+
424
+ For an ordinary gate, continue only when the server declares `completion_contract.owner_approval.mode: "ordinary_non_arbitrated"`. Auto waits in `owner_approval_required` until the caller actually obtains explicit owner approval for the exact work and supplies `proof.owner_approval = { approved_by: "owner", reference: "approved-release-bundle" }` together with required measured proof. Then call auto once with the same operation ID and original decision/receipt scope. The object records actual approval; it is not permission to infer approval from action text, a model response, or `human_directed`. Unknown ordinary completion contracts remain stopped without automatically starting arbitration. The backend checks receipt ownership, scope, expiry, and proof before confirming closure.
425
+
426
+ For arbitration, the ordinary proof marker is not accepted. Approve the exact arbitration decision in the authenticated Marrow dashboard, then call auto with the same operation ID, `arbitration_receipt_id`, and server-issued `owner_approval_receipt_id`. Proof or chat text cannot substitute for this dashboard receipt. A CLI closed response reports `phase: "closed"`, `live_delivery.committed: true`, and `resumable: false`; the library result uses `committed: true`. Neither an ordinary marker nor an outcome record changes a stopped action into an allowed action.
427
+
428
+ The CLI's lifecycle `receipt.queued: true` means its stable event is stored locally for later bounded delivery; `receipt.accepted: false` must not be read as server acceptance. Transient failures preserve the queued event and retry schedule for later bounded delivery, including after restart. Server retry guidance is respected. Authentication and terminal delivery errors remain failed with explicit repair guidance. Process exit can interrupt the background nudge, leaving the event for a later run. `phase_timings_ms.total` measures core auto phases. `response_timings_ms` contains numeric `core`, `durable_enqueue`, and `full_response`; the last ends at response construction and excludes subsequent stdout drain and host processing. Canary `latency_ms` independently measures the MCP round trip, while `attempts` and `retry_wait_ms` describe measured outer tool retries, not internal database or network calls.
395
429
 
396
430
  Example pre-action request:
397
431
 
package/dist/cli.js CHANGED
@@ -165,17 +165,21 @@ Use Marrow according to the capability evidence returned by the MCP server:
165
165
 
166
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.
167
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.
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
+ 3. **After meaningful work:** Record the real success or failure with \`marrow_commit\`; \`marrow_auto\` is available only in explicitly selected core/full profiles. A tool exit or session end is not proof that the business outcome succeeded.
169
169
  4. **Unfinished work:** Leave pending outcomes visible. Do not invent success to clear a closure item.
170
170
  5. **To explain an intervention:** Use \`marrow_decision_trace\`, then relay its \`intervention_receipt\` in one factual sentence when Marrow blocked, warned, or required review. Stay quiet for routine low-risk work.
171
- 6. **To query authorized history:** Call \`marrow_ask("plain english question")\` — ask what failed, what worked, and what policy should apply.
171
+ 6. **To query authorized history:** Use \`marrow_fleet_lessons\` in the default primary profile; core/full provide \`marrow_ask\` for authorized history.
172
172
  7. **When an update is reported:** Tell the operator and use the returned exact update and verification commands only when local change policy permits. Never silently change packages or configuration.
173
173
 
174
174
  Do not skip the gate or outcome. Marrow's value comes from controlling the action before execution and preserving evidence afterward.
175
175
 
176
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.
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
+ With MARROW_TOOL_PROFILE unset, use the 17-tool primary runtime → commit flow. Reuse runtime.decision_id when its completion_contract identifies a created decision; keep runtime.runtime_authorization.id separate as gate_receipt_id. Use marrow_think only when decision creation is required. Explicit core/full profiles also expose marrow_auto: continue a pending response only after retry_after_ms with the same operation_id and unchanged scope, outcome, proof, and receipts. Only committed:true confirms closure; queued lifecycle delivery is separate.
179
+
180
+ For an expired receipt on a still-open decision, explicitly request normal runtime with the original scope and a fresh request key, verify the returned decision_id, and follow the current proof/approval contract. Post-action auto_gate is observation-only and cannot renew permission. Fresh receipts never retrospectively authorize earlier work.
181
+
182
+ After authorized setup via \`npx -y --package=@getmarrow/mcp@latest marrow-mcp setup\`, reload the host, review/enable hook trust, then run \`npx -y @getmarrow/install@latest doctor --self-test\`. Configuration alone does not prove runtime coverage; empty savings remain zero until observed usage exists.
179
183
  ${MARROW_BLOCK_END}`;
180
184
  let dir = process.cwd();
181
185
  let claudeMdPath = null;
@@ -850,14 +854,14 @@ if (process.argv[2] !== 'keys') {
850
854
  {
851
855
  name: 'marrow_commit',
852
856
  description: 'Close a recorded action with success/failure, a specific outcome, and required proof. ' +
853
- 'decision_id comes from marrow_think, marrow_auto, or an arbitration runtime that actually created a decision. ' +
857
+ 'decision_id comes from marrow_think, marrow_auto, or a runtime that actually created a decision. ' +
854
858
  'Use the gate receipt from marrow_agent_runtime for consequential work. ' +
855
859
  'The exact non-authorizing outcome_observation_only runtime correlation may submit an observed_unverified result, but is never sent as receipt evidence and never authorizes action or trusted learning. ' +
856
860
  'Only committed:true closes trusted outcome learning.',
857
861
  inputSchema: {
858
862
  type: 'object',
859
863
  properties: {
860
- decision_id: { type: 'string', description: 'decision_id from marrow_think, marrow_auto, or an arbitration runtime that created a decision' },
864
+ decision_id: { type: 'string', description: 'decision_id from marrow_think, marrow_auto, or a runtime that created a decision' },
861
865
  success: { type: 'boolean', description: 'Did the action succeed?' },
862
866
  outcome: { type: 'string', description: 'What happened — be specific, this trains the hive' },
863
867
  caused_by: { type: 'string', description: 'Optional: what caused this action' },
@@ -868,9 +872,10 @@ if (process.argv[2] !== 'keys') {
868
872
  gate_receipt_id: { type: 'string', description: 'Canonical receipt id from marrow_agent_runtime.runtime_authorization.id for risky work.' },
869
873
  arbitration_receipt_id: { type: 'string', description: 'Required for arbitrated work: use marrow_arbitrate.arbitration.receipt_id from the same runtime response.' },
870
874
  owner_approval_receipt_id: { type: 'string', description: 'Single-use owner approval receipt issued by authenticated dashboard review for review_required arbitration.' },
871
- action: { type: 'string', description: 'Optional original action. If provided and gate_receipt_id is omitted, MCP can fetch a matching runtime gate receipt before commit.' },
872
- type: { type: 'string', description: 'Optional original action type for auto gate lookup, e.g. deploy, publish, merge, handoff, implementation.' },
873
- surfaces: { type: 'array', items: { type: 'string' }, description: 'Optional surfaces for auto gate receipt, e.g. github, cloudflare, npm, production.' },
875
+ action: { type: 'string', description: 'Optional exact original action for post-action observation lookup. This lookup cannot renew execution authority.' },
876
+ target: { type: 'string', description: 'Exact original target, if supplied when the decision was created.' },
877
+ type: { type: 'string', description: 'Exact original action type for observation lookup; defaults to general.' },
878
+ surfaces: { type: 'array', items: { type: 'string' }, description: 'Exact original surfaces for observation lookup; omitted and empty both mean no surfaces.' },
874
879
  auto_gate: { type: 'boolean', description: 'If true/default and action is provided, fetch runtime truth bound to this existing decision. Authorizing receipts preserve normal closure; exact outcome_observation_only correlation can submit only an observed_unverified result and is omitted from receipt evidence.' },
875
880
  model_usage: { type: 'object', description: 'Optional compact token/cost/latency counts. Do not include raw prompts or completions.' },
876
881
  },
@@ -926,7 +931,7 @@ if (process.argv[2] !== 'keys') {
926
931
  },
927
932
  {
928
933
  name: 'marrow_auto',
929
- 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.',
934
+ description: 'Durably capture activity with bounded core completion. Respect retry_after_ms and reuse operation_id for pending continuation. Server-declared ordinary approval requires actual owner approval supplied in proof; arbitration requires its dashboard receipt. Lifecycle receipt queued is separate from server acceptance. Risky completion requires a fresh gate and measured proof.',
930
935
  inputSchema: {
931
936
  type: 'object',
932
937
  properties: {
@@ -1285,7 +1290,7 @@ if (process.argv[2] !== 'keys') {
1285
1290
  description: 'One-call agent-native Marrow loop. Returns passive status, decision brief, risk gate, relevant lessons, ' +
1286
1291
  'template suggestion, required proof pack, before-you-act instruction, and exact next action. ' +
1287
1292
  'Its runtime_authorization is the authoritative gate receipt; it returns decision_id only when runtime actually creates a decision. ' +
1288
- 'Use marrow_auto or marrow_think to create the decision_id required for outcome closure. ' +
1293
+ 'Reuse its server-created decision_id for outcome closure; use marrow_auto or marrow_think only when the completion contract requires decision creation. ' +
1289
1294
  'Use this before meaningful work when you want Marrow to guide the whole action in one call.',
1290
1295
  inputSchema: {
1291
1296
  type: 'object',
@@ -1920,6 +1925,7 @@ if (process.argv[2] !== 'keys') {
1920
1925
  // Request handler
1921
1926
  async function handleRequest(req) {
1922
1927
  const { id, method, params } = req;
1928
+ const responseStartedAt = performance.now();
1923
1929
  // [FIX #15] Enforce initialize-first per MCP spec
1924
1930
  if (!initialized && method !== 'initialize') {
1925
1931
  error(id, -32002, 'Server not initialized. Send initialize first.');
@@ -1934,7 +1940,7 @@ if (process.argv[2] !== 'keys') {
1934
1940
  capabilities: { tools: {}, prompts: {} },
1935
1941
  serverInfo: { name: 'marrow', version: hook_contract_2.MCP_ADAPTER_VERSION },
1936
1942
  ...(AUTO_ENROLL ? {
1937
- instructions: `Call marrow_think before meaningful work to create the decision_id. Use marrow_agent_runtime before consequential actions and obey fresh allow/warn/review_required/block only when risk_gate.enforced is true; if enforced is false the gate is advisory, not a live block. Use marrow_ask for relevant prior lessons, and close outcomes with marrow_commit using that decision_id. Infrastructure failures are not policy denials; continue only low-risk reversible work from the returned outage-safe brief, and require a fresh gate for high-risk work. ${(0, host_capability_1.hostCapabilityInstructions)(hostCapability)}`,
1943
+ instructions: `Use marrow_agent_runtime before consequential actions and follow its gate, proof and approval contract. Reuse runtime.decision_id when completion_contract identifies a created decision; keep runtime.runtime_authorization.id separate as gate_receipt_id. Call marrow_think only when decision creation is required. Close outcomes with marrow_commit; only committed:true confirms closure. ${activeToolProfile() === 'primary' ? 'The default primary profile exposes 17 tools. Use marrow_agent_status for status and marrow_fleet_lessons for prior lessons.' : 'This explicitly selected core/full profile also provides marrow_auto, marrow_status and marrow_ask. Resume pending auto only after retry_after_ms with the same operation_id and unchanged scope, outcome, proof and receipts.'} An advisory risk_gate.enforced:false is not live enforcement; review_required or block still does not grant permission. Infrastructure failures are not policy denials; continue only low-risk reversible work from returned outage-safe guidance and require a fresh gate for high-risk work. ${(0, host_capability_1.hostCapabilityInstructions)(hostCapability)}`,
1938
1944
  } : {}),
1939
1945
  _meta: { host_capability: hostCapability },
1940
1946
  });
@@ -2008,7 +2014,7 @@ When runtime/status returns a client_update notice, tell the operator and use it
2008
2014
 
2009
2015
  ## Outcome closure
2010
2016
 
2011
- A successful command or tool exit is not proof that the business outcome succeeded. After meaningful work, close the real outcome with marrow_commit or marrow_auto and include success or failure plus the required evidence. If the result is unknown, leave it pending. Never invent success to clear a closure item.
2017
+ A successful command or tool exit is not proof that the business outcome succeeded. After meaningful work, use the default primary runtime → marrow_commit flow and include success or failure plus required evidence. Reuse runtime.decision_id and keep runtime.runtime_authorization.id separate as gate_receipt_id. Explicit core/full profiles also expose marrow_auto; resume pending only after retry_after_ms with the same operation_id and unchanged scope/body. Only committed:true confirms closure. If the result is unknown, leave it pending. Never invent success to clear a closure item.
2012
2018
 
2013
2019
  Use marrow_decision_trace when you need to explain why Marrow changed an action. Its intervention_receipt packages the relevant gate, required workflow, permit follow-through, proof, and recorded outcome without raw context, proof values, or another tenant's data. After a meaningful intervention, relay one factual receipt summary to the operator. Stay quiet for routine low-risk work.
2014
2020
 
@@ -2124,6 +2130,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2124
2130
  arbitration_receipt_id: args.arbitration_receipt_id,
2125
2131
  owner_approval_receipt_id: args.owner_approval_receipt_id,
2126
2132
  action: args.action,
2133
+ target: args.target,
2127
2134
  type: args.type,
2128
2135
  surfaces: args.surfaces,
2129
2136
  auto_gate: args.auto_gate,
@@ -2234,19 +2241,22 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2234
2241
  }, SESSION_ID, FLEET_AGENT_ID, 8_000);
2235
2242
  let delivered = null;
2236
2243
  let deliveryFailure = null;
2244
+ const coreStartedAt = performance.now();
2237
2245
  try {
2238
2246
  delivered = await delivery();
2239
2247
  }
2240
2248
  catch (err) {
2241
2249
  deliveryFailure = (0, request_reliability_1.structuredRequestFailure)(err);
2242
2250
  }
2251
+ const coreDurationMs = Math.floor(performance.now() - coreStartedAt);
2243
2252
  const runtimeGate = delivered?.runtime_gate || null;
2244
2253
  if (runtimeGate)
2245
2254
  storeRuntimeGuidance(runtimeGate);
2255
+ const enqueueStartedAt = performance.now();
2246
2256
  const receipt = await (0, lifecycle_spool_1.recordLifecycleEvent)({
2247
2257
  apiKey: API_KEY,
2248
2258
  baseUrl: BASE_URL,
2249
- deferDelivery: false,
2259
+ deferDelivery: true,
2250
2260
  event: {
2251
2261
  ...(delivered?.operation_id ? {
2252
2262
  event_id: `auto_${delivered.committed ? 'closed' : 'pending'}_${delivered.operation_id}`,
@@ -2268,6 +2278,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2268
2278
  source: 'client_self_reported',
2269
2279
  },
2270
2280
  });
2281
+ const enqueueDurationMs = Math.floor(performance.now() - enqueueStartedAt);
2271
2282
  const response = {
2272
2283
  action,
2273
2284
  outcome: outcome || 'pending',
@@ -2317,9 +2328,19 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
2317
2328
  client_update: (0, request_reliability_1.localClientUpdate)(),
2318
2329
  ...(runtimeGate ? { runtime_gate: runtimeGate } : {}),
2319
2330
  };
2331
+ // Measure through response construction; stdout/host consumption occurs
2332
+ // after this snapshot and is not represented as server phase latency.
2333
+ response.response_timings_ms = {
2334
+ core: coreDurationMs,
2335
+ durable_enqueue: enqueueDurationMs,
2336
+ full_response: Math.floor(performance.now() - responseStartedAt),
2337
+ };
2320
2338
  success(id, {
2321
2339
  content: [{ type: 'text', text: JSON.stringify(response, null, 2) }],
2322
2340
  });
2341
+ // The existing bounded owner handles rejection and preserves queued
2342
+ // receipts across exit/restart. Network work never holds this response.
2343
+ void (0, lifecycle_spool_1.nudgeLifecycleSpool)({ apiKey: API_KEY, baseUrl: BASE_URL, agentId: FLEET_AGENT_ID });
2323
2344
  return;
2324
2345
  }
2325
2346
  if (toolName === 'marrow_ask') {