@getmarrow/install 0.1.25 → 0.1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,104 +1,66 @@
1
1
  # @getmarrow/install
2
2
 
3
- Universal installer for Marrow passive agent setup.
3
+ Universal installer for Marrow agent governance, proof, and passive control setup.
4
4
 
5
- Use it when you want Marrow to detect the local agent/runtime environment and wire the safest passive integration automatically.
5
+ Use it when you want Marrow to detect the local agent/runtime environment and wire the safest passive governance integration automatically.
6
6
 
7
7
  ```bash
8
8
  npx @getmarrow/install --dry-run
9
9
  npx @getmarrow/install --yes
10
10
  npx @getmarrow/install --repair
11
11
  npx @getmarrow/install doctor
12
+ npx @getmarrow/install govern
12
13
  npx @getmarrow/install fleet
13
14
  npx @getmarrow/install integrations
14
15
  npx @getmarrow/install hermes
15
16
  npx @getmarrow/install openclaw
16
17
  ```
17
18
 
18
- ## What's New in v0.1.25
19
-
20
- v0.1.25 adds first-class harness add-on paths for Hermes Agent and OpenClaw.
21
-
22
- - `npx @getmarrow/install integrations` lists Marrow-supported harness add-ons.
23
- - `npx @getmarrow/install hermes` shows the Hermes attachment path and, when `MARROW_API_KEY` is present, verifies the backend integration contract.
24
- - `npx @getmarrow/install openclaw` shows the OpenClaw attachment path and verifies the backend integration contract.
25
- - `npx @getmarrow/install govern` now detects Hermes config files alongside Codex, Claude Code, Cursor, OpenCode, OpenClaw, CI scripts, and custom commands.
26
- - Hermes `/goal`, verification evidence, `/learn`, `/journey`, and background subagents map into Marrow runtime gates, proof packs, fleet lessons, governance timeline, and outcome closure.
27
- - OpenClaw sessions, handoff/result files, watchdog checkpoints, silent exits, and release supervisor results map into Marrow workflow sessions, proof packs, stale-outcome detection, and reusable handoff lessons.
28
-
29
- This is the intended positioning: keep the harness your team already uses, and add Marrow as the governance, proof, and fleet-intelligence layer around it.
30
-
31
- Examples:
32
-
33
- ```bash
34
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install hermes
35
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install openclaw
36
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install integrations --json
37
- ```
38
-
39
- ## What's New in v0.1.20
19
+ ## What's New in v0.1.26
40
20
 
41
- v0.1.20 adds the Fleet Operator TUI for teams running multiple agents under one Marrow account.
21
+ v0.1.26 expands Marrow's supported harness registry so teams can attach governance to the agent tools, IDE agents, model CLIs, MCP clients, CI runners, and custom harnesses they already use.
42
22
 
43
- - `npx @getmarrow/install fleet` opens a terminal operator view when run in a real TTY.
44
- - CI/headless agents can use `npx @getmarrow/install fleet --no-interactive` for a stable text snapshot or `--json` for machine-readable status.
45
- - The view shows live agents, active workflows, risky actions waiting for proof, failed/stale outcomes, backpressure/capacity status, recent decisions, degraded hooks, and deploy/publish/merge gate posture.
46
- - Operators can press Enter to inspect an agent and print the exact fix command when hooks, outcome closure, or status coverage is degraded.
47
- - The command reads existing Marrow account endpoints and degrades gracefully when a route is unavailable, so it is safe to use during incidents.
23
+ - `npx @getmarrow/install integrations` lists supported surfaces, support level, install command, capture path, and detection signals.
24
+ - `GET /v1/agent/data-quality` lets agents verify attribution coverage after install, including agent ID, source metadata, harness/client, workflow type, outcome closure, and exact repair guidance.
25
+ - `GET /v1/agent/integrations/{client}` gives supported harnesses a per-client setup guide with install command, capture points, source metadata, runtime/commit/batch mapping, and exact next action.
26
+ - `npx @getmarrow/install govern` detects Codex, Claude Code, Cursor, Cursor Composer, Windsurf, Cline, OpenCode, Hermes, OpenClaw, Gemini, Grok, DeepSeek, Qwen, Kimi, MiniMax, GLM, MCP clients, CI scripts, and custom commands.
27
+ - Hermes Agent and OpenClaw remain first-class add-ons.
28
+ - Codex, Claude Code, Cursor, Cursor Composer, Windsurf, Cline, OpenCode, Gemini, Grok, DeepSeek, Qwen, Kimi, MiniMax, GLM, MCP clients, CI scripts, and custom shell/API harnesses can use MCP/SDK hooks, the governed runner, or `POST /v1/agent/integrations/events`.
29
+ - Custom harness events should include `harness`, `event_type`, `agent_id`, and `action`, so Marrow can return the right runtime, commit, or batch-ingest next step without storing unsupported or under-attributed raw payloads.
48
30
 
49
- Example:
31
+ The positioning is simple: keep the harness your team already uses, and add Marrow as the governance, proof, and fleet-intelligence layer around it.
50
32
 
51
- ```bash
52
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install fleet
53
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install fleet --no-interactive
54
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install fleet --json
55
- ```
33
+ ## What's New in v0.1.24
56
34
 
57
- ## What's New in v0.1.14
35
+ v0.1.24 aligns the installer docs with Marrow's control-plane direction.
58
36
 
59
- v0.1.14 adds adaptive governance mode recommendations without silent auto-switching.
37
+ - Marrow is positioned as an agent governance, proof, and intelligence layer, not a single-agent memory app.
38
+ - The recommended setup path remains passive by default: install once, then let agents call runtime gates, completion contracts, and outcome closure as they work.
39
+ - Hermes Agent is a supported client label and integration target; Marrow maps Hermes goals, verification evidence, learning, journey, and subagent outcomes into fleet governance proof.
40
+ - New backend surfaces include governance control-plane proof, completion-contract evaluation, fleet governance timeline, and buyer-grade value proof.
60
41
 
61
- - `npx @getmarrow/install govern` now detects project signals such as `package.json`, deploy/publish scripts, `wrangler` config, GitHub workflows, migrations, Cursor/Codex/Claude files, and MCP config.
62
- - When `MARROW_API_KEY` is present, the TUI asks Marrow for a recommended mode: `passive`, `pilot`, or `enforce`.
63
- - The TUI shows the exact reasons, confidence, and selected command before the user applies anything.
64
- - User choice is explicit. Marrow logs whether the recommendation was accepted or overridden, but it does not silently switch modes.
65
- - Policy profiles are supported by the backend/SDK/MCP so businesses can define rules like local=passive, staging=pilot, production deploys=enforce.
42
+ ## What's New in v0.1.23
66
43
 
67
- Example recommendation:
68
-
69
- ```text
70
- Recommended mode: pilot
71
- Reason:
72
- - Node project detected
73
- - Cloudflare Worker detected
74
- - GitHub workflow detected
75
- - No owner approval policy configured yet
76
- ```
44
+ v0.1.23 improves attribution quality so Marrow can produce cleaner per-agent, per-harness, and per-workflow value reports.
77
45
 
78
- ## What's New in v0.1.13
46
+ - Installer self-tests and governed runner calls attach `source_meta.channel`, `source_meta.client`, and inferred workflow intent by default.
47
+ - Generated passive runtime keeps using SDK defaults for `agent_id`, harness/client, source channel, and user intent attribution.
48
+ - Set `MARROW_CLIENT`, `MARROW_HARNESS`, or `MARROW_AGENT_CLIENT` to labels such as `codex`, `claude-code`, `cursor`, `gemini`, `qwen`, `opencode`, `hermes`, `openclaw`, or `custom`.
49
+ - Invalid or unknown client labels fall back to `custom` instead of breaking onboarding.
50
+ - Marrow still does not store prompts, completions, tool stdout/stderr, plaintext API keys, or raw model output for this feature.
79
51
 
80
- v0.1.13 turns `npx @getmarrow/install govern` into an interactive terminal setup flow when run in a real TTY.
52
+ Business value: dashboards and reports can show which agents, harnesses, and workflow types are improving instead of grouping too much work into "unknown."
81
53
 
82
- - Select Codex, Claude Code, Cursor, OpenCode, OpenClaw, CI scripts, or a custom command with arrow keys.
83
- - Choose passive setup, governed pilot mode, or governed enforce mode.
84
- - Run passive setup + self-test from the TUI after explicit confirmation.
85
- - Check Marrow status and test the before-action gate from the same screen.
86
- - Print the exact command for the selected harness/mode so users know what to run next.
87
- - Exit cleanly with `q`, `Esc`, or `Ctrl+C`.
88
- - CI/non-TTY usage remains stable with `npx @getmarrow/install govern --no-interactive`.
54
+ ## Governed Runner
89
55
 
90
- This keeps Marrow passive-first: install once, verify Marrow is active, then let agents use the runtime/gate path automatically for risky work.
91
-
92
- ## What's New in v0.1.12
93
-
94
- v0.1.12 adds the Marrow governed runner for businesses that want agent governance without replacing their existing harness.
56
+ The Marrow governed runner is for businesses that want agent governance without replacing their existing harness.
95
57
 
96
58
  - `npx @getmarrow/install govern` prints a setup panel for detected harnesses and recommended protected commands.
97
59
  - `npx @getmarrow/install run --agent <agent-id> -- <command>` wraps existing agent, deploy, merge, publish, migration, and verification commands with Marrow's pre-action runtime gate.
98
60
  - Risky actions can fail closed by default when Marrow requires owner approval, blocks an action, or requires missing proof.
99
61
  - Successful and failed commands automatically close outcomes through `/v1/agent/commit` with a redacted proof pack.
100
62
  - The runner sends action and command metadata only; it does not upload command stdout, stderr, full environment values, or plaintext API keys.
101
- - This gives teams a thin governance path for Codex, Claude Code, OpenClaw, OpenCode, Cursor, CI scripts, and custom shell-based agents.
63
+ - This gives teams a thin governance path for Codex, Claude Code, Cursor, Cursor Composer, Windsurf, Cline, OpenClaw, Hermes, OpenCode, Gemini, Grok, DeepSeek, Qwen, Kimi, MiniMax, GLM, MCP clients, CI scripts, and custom shell-based agents.
102
64
 
103
65
  Business value: Marrow can sit in front of the commands that matter most, tell the agent what prior lesson or proof is required before action, and produce an audit-ready outcome trail after the command finishes.
104
66
 
@@ -110,28 +72,22 @@ Preview the detected harnesses and protected command examples:
110
72
  npx @getmarrow/install govern
111
73
  ```
112
74
 
113
- In a real terminal, this opens the interactive setup flow. In CI or scripts, use:
114
-
115
- ```bash
116
- npx @getmarrow/install govern --no-interactive
117
- ```
118
-
119
75
  Run a harmless command through Marrow:
120
76
 
121
77
  ```bash
122
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install run --agent codex-prod --profile production -- node -e "process.exit(0)"
78
+ MARROW_API_KEY=<your_marrow_key> npx @getmarrow/install run --agent codex-prod --profile production -- node -e "process.exit(0)"
123
79
  ```
124
80
 
125
81
  Gate a production action before the agent executes it:
126
82
 
127
83
  ```bash
128
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install gate "deploy production worker after tests pass"
84
+ MARROW_API_KEY=<your_marrow_key> npx @getmarrow/install gate "deploy production worker after tests pass"
129
85
  ```
130
86
 
131
87
  Wrap a real deploy, publish, merge, or migration command only after the agent has the required proof:
132
88
 
133
89
  ```bash
134
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install run \
90
+ MARROW_API_KEY=<your_marrow_key> npx @getmarrow/install run \
135
91
  --agent deploy-agent \
136
92
  --type deploy \
137
93
  --profile production \
@@ -141,15 +97,6 @@ MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install run \
141
97
 
142
98
  Use `--policy warn` for pilot mode and `--fail-open` only for non-production local workflows where Marrow should never block execution.
143
99
 
144
- ## What's New in v0.1.10
145
-
146
- - First-run output now explains the value in agent/user language: your agent is no longer starting from zero.
147
- - Self-test prints first proof: setup decision captured, outcome closed, runtime gate active, and risky work now gets a pre-action brief.
148
- - Fresh accounts get a guided prompt to try immediately: "I am about to deploy to production. What should I check first?"
149
- - Existing accounts/fleets show stronger proof when available: avoided mistakes, reused winning decisions, prevented risky actions, and token/time savings.
150
- - Generated SDK passive runtime now fails soft if `@getmarrow/sdk` is missing and the installer prints the exact dependency fix.
151
- - Docs now make the universal installer the default path; SDK and MCP are advanced/manual integration paths.
152
-
153
100
  ## Which Install Path Should I Use?
154
101
 
155
102
  Start here unless you already know you need a lower-level integration:
@@ -167,12 +114,20 @@ Use the lower-level packages only when you need direct control:
167
114
 
168
115
  The three packages are not three competing onboarding paths. `@getmarrow/install` is the front door; SDK and MCP are the implementation paths underneath it.
169
116
 
117
+ For cleaner attribution, set an agent id and optional client label before install:
118
+
119
+ ```bash
120
+ export MARROW_FLEET_AGENT_ID=codex-deploy-agent
121
+ export MARROW_CLIENT=codex
122
+ npx @getmarrow/install --yes
123
+ ```
124
+
170
125
  ## Agent Value Proof Quickstart
171
126
 
172
127
  One command should prove Marrow is active and useful:
173
128
 
174
129
  ```bash
175
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install --yes
130
+ MARROW_API_KEY=<your_marrow_key> npx @getmarrow/install --yes
176
131
  ```
177
132
 
178
133
  Expected result:
@@ -180,9 +135,12 @@ Expected result:
180
135
  - Marrow writes the safest detected MCP/SDK/agent config.
181
136
  - A harmless setup decision is created and its outcome is committed.
182
137
  - `/v1/agent/status` confirms capture health and missing hooks.
138
+ - `/v1/agent/data-quality` confirms whether attribution is clean enough for per-agent, per-harness, and per-workflow value proof.
183
139
  - `/v1/agent/runtime` verifies the one-call runtime gate and returns the before-action intervention contract.
184
140
  - `/v1/agent/first-value` returns the five-minute proof payload used by installer, SDK, and MCP clients.
141
+ - `/v1/agent/value/proof` returns token value proof from passive model-usage capture.
185
142
  - The installer prints: "Your agent is no longer starting from zero."
143
+ - The installer prints: "Token value proof" with capture status, observed model calls, token totals, estimated savings, confidence, and exact next action.
186
144
  - Fresh accounts get a first useful action to try immediately.
187
145
  - Accounts with history get proof such as avoided mistakes, reused winning decisions, prevented risky actions, or estimated time/token savings.
188
146
 
@@ -196,39 +154,6 @@ I am about to deploy to production. What should I check first?
196
154
 
197
155
  Marrow should answer with `proceed`, `warn`, `block`, or `owner_approval_required`, plus required proof and matching fleet lessons/playbooks before the agent acts. This is the first product moment: not just "hooks installed", but "the agent is being warned before risky work."
198
156
 
199
- ## Fleet Scale Startup Guidance
200
-
201
- For business fleets, agents can read `GET /v1/agent/scale/capacity-contract` after install or during startup. The capacity contract tells the agent whether the account is under backpressure, when low-risk runtime guidance can be reused, when high-risk actions must still call Marrow, and how to batch low-risk telemetry through `/v1/agent/ingest/batch`.
202
-
203
- This keeps Marrow passive without making it chatty. The current contract models the common `50 businesses x 50 agents = 2,500 agents` rollout shape and gives agents an exact next action: cache low-risk runtime guidance briefly, batch command/tool telemetry, and preserve proof-gated checks for deploys, publishes, merges, migrations, secrets, billing, and destructive work.
204
-
205
- ## Fleet Operator TUI
206
-
207
- Use the operator TUI when a human owner or orchestrator agent needs to understand fleet health before acting:
208
-
209
- ```bash
210
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install fleet
211
- ```
212
-
213
- It shows:
214
-
215
- - live agents and selected agent inspection
216
- - active workflows
217
- - risky actions waiting for proof
218
- - failed or stale outcomes
219
- - backpressure and capacity guidance
220
- - recent decisions
221
- - degraded hooks
222
- - deploy, publish, and merge gate status
223
- - exact fix commands for common degraded states
224
-
225
- For automated reports or headless agents:
226
-
227
- ```bash
228
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install fleet --no-interactive
229
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install fleet --json
230
- ```
231
-
232
157
  ## What It Detects
233
158
 
234
159
  - OpenClaw-style workspaces
@@ -236,6 +161,8 @@ MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install fleet --json
236
161
  - Codex/agent instruction files such as `AGENTS.md`
237
162
  - Claude Code settings and hooks
238
163
  - Cursor project folders
164
+ - Cursor Composer, Windsurf, Cline, and OpenCode project markers
165
+ - Gemini, Grok, DeepSeek, Qwen, Kimi, MiniMax, and GLM command/profile markers
239
166
  - MCP config files
240
167
  - Node projects
241
168
  - Python projects
@@ -262,10 +189,10 @@ npx @getmarrow/install --md --dry-run
262
189
 
263
190
  ## Self-Test
264
191
 
265
- When `MARROW_API_KEY` is present, the installer creates a harmless test decision, commits the outcome, reads `/v1/agent/status`, calls the one-call runtime, and prints the first useful Marrow signal.
192
+ When `MARROW_API_KEY` is present, the installer creates a harmless test decision, commits the outcome, reads `/v1/agent/status`, calls the one-call runtime, reads `/v1/agent/value/proof`, and prints the first useful Marrow signal plus token value proof.
266
193
 
267
194
  ```bash
268
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install --yes
195
+ MARROW_API_KEY=<your_marrow_key> npx @getmarrow/install --yes
269
196
  ```
270
197
 
271
198
  Skip self-test:
@@ -277,13 +204,13 @@ npx @getmarrow/install --yes --no-self-test
277
204
  Doctor check:
278
205
 
279
206
  ```bash
280
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install doctor
207
+ MARROW_API_KEY=<your_marrow_key> npx @getmarrow/install doctor
281
208
  ```
282
209
 
283
210
  Repair missing hooks/config:
284
211
 
285
212
  ```bash
286
- MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install --repair
213
+ MARROW_API_KEY=<your_marrow_key> npx @getmarrow/install --repair
287
214
  ```
288
215
 
289
216
  ## SDK Dependency
@@ -296,10 +223,40 @@ npm install @getmarrow/sdk
296
223
 
297
224
  The generated runtime now fails soft with an explicit warning if the SDK package is missing, so onboarding does not crash a user process.
298
225
 
226
+ ## Passive Token Value Proof
227
+
228
+ Token value proof is default-on when the installer writes `.marrow/passive-runtime.mjs`.
229
+
230
+ In supported Node/TypeScript agents, the SDK passive runtime wraps outbound model-provider `fetch` responses and captures compact `usage` blocks when providers return them. MCP and harness integrations can also attach `model_usage` to `marrow_commit` or call `marrow_model_usage` when the harness exposes usage metadata.
231
+
232
+ Captured fields are intentionally narrow:
233
+
234
+ - provider and model
235
+ - input, output, cached, and total token counts
236
+ - optional cost and latency estimates
237
+ - agent, workflow, session, and decision linkage
238
+ - Marrow intervention type, such as `runtime_gate`, `proof_pack`, or `before_you_act`
239
+
240
+ Marrow does not capture prompt text, completion text, raw tool output, command output, full environment values, or plaintext secrets for token value proof.
241
+
242
+ Disable capture only when a project requires it:
243
+
244
+ ```bash
245
+ MARROW_PASSIVE_TOKEN_USAGE=false
246
+ ```
247
+
248
+ Day-one behavior:
249
+
250
+ - Fresh install: `Token usage capture is ready; no model calls have been reported yet.`
251
+ - After observed usage: Marrow reports model calls, total tokens, estimated tokens saved, confidence, trend, and next action.
252
+ - After workflows complete: agents should show the returned `token_value_signal` or value proof in owner updates so users see savings without opening a dashboard.
253
+
299
254
 
300
255
  ## Trust and Data Boundaries
301
256
 
302
- Marrow is tenant-aware by design. Private account, fleet, memory, workflow, and proof-pack data stays scoped to the authenticated account and authorized agent-bound keys. Shared/hive learning uses visibility-controlled, sanitized aggregate signals; it is not raw cross-customer decision sharing.
257
+ Marrow is tenant-aware by design. Private account, fleet, workflow, proof-pack, and agent data stays scoped to the authenticated account and authorized agent-bound keys.
258
+
259
+ Enterprise tenants receive a strong private governance baseline from day one: risk gates, proof requirements, workflow templates, private/account learning, and exact next actions. Teams that enable sanitized aggregate contribution unlock richer k-anonymous collective workflow guidance. Contribution never means raw prompts, decisions, proof packs, code, secrets, account identifiers, agent identifiers, or customer identities.
303
260
 
304
261
  For business pilots, review the live trust notes before production rollout: https://getmarrow.ai/docs#trust-boundaries
305
262
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@getmarrow/install",
3
- "version": "0.1.25",
4
- "description": "Universal installer for Marrow passive agent setup.",
3
+ "version": "0.1.27",
4
+ "description": "Universal installer for Marrow agent governance, proof, and passive control setup.",
5
5
  "bin": {
6
6
  "marrow-install": "bin/marrow-install.js"
7
7
  },
@@ -15,9 +15,10 @@
15
15
  "marrow",
16
16
  "mcp",
17
17
  "installer",
18
+ "passive-runtime",
18
19
  "governance",
19
- "runner",
20
- "passive-runtime"
20
+ "proof-packs",
21
+ "agent-control-plane"
21
22
  ],
22
23
  "repository": {
23
24
  "type": "git",
@@ -45,6 +45,7 @@ Options:
45
45
  --fail-closed If Marrow is unreachable, block the command
46
46
  --owner-approved <ref> Owner approval reference for review-required gates
47
47
  --proof-file <path> JSON proof to include on outcome commit
48
+ --client <label> Harness/client label. Defaults to MARROW_CLIENT, MARROW_HARNESS, or MARROW_AGENT_CLIENT
48
49
  --base-url <url> Marrow API base URL
49
50
  --key <key> Marrow API key. Prefer MARROW_API_KEY
50
51
  --json Print machine-readable result after completion
@@ -77,6 +78,40 @@ function redactedCommand(command) {
77
78
  return command.map((part) => shellQuote(redact(part))).join(' ');
78
79
  }
79
80
 
81
+ function normalizeClientLabel(value) {
82
+ const raw = String(value || '').trim().toLowerCase();
83
+ if (!raw) return '';
84
+ const normalized = raw
85
+ .replace(/[^a-z0-9._-]+/g, '-')
86
+ .replace(/^-+|-+$/g, '')
87
+ .slice(0, 64);
88
+ const aliases = {
89
+ claude: 'claude-code',
90
+ claude_code: 'claude-code',
91
+ 'cursor-composer': 'composer',
92
+ 'openai-codex': 'codex',
93
+ openai: 'codex',
94
+ 'gemini-cli': 'gemini',
95
+ 'grok-cli': 'grok',
96
+ 'deepseek-cli': 'deepseek',
97
+ 'qwen-cli': 'qwen',
98
+ 'kimi-cli': 'kimi',
99
+ 'minimax-cli': 'minimax',
100
+ 'glm-cli': 'glm',
101
+ };
102
+ return aliases[normalized] || normalized || 'custom';
103
+ }
104
+
105
+ function sourceClient(value) {
106
+ return normalizeClientLabel(
107
+ value
108
+ || process.env.MARROW_CLIENT
109
+ || process.env.MARROW_HARNESS
110
+ || process.env.MARROW_AGENT_CLIENT
111
+ || '@getmarrow/install',
112
+ );
113
+ }
114
+
80
115
  function displayText(value, maxLength = 120) {
81
116
  const text = redact(String(value || ''))
82
117
  .replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g, '')
@@ -160,13 +195,23 @@ function detectProjectSignals(cwd = process.cwd()) {
160
195
  addFile('AGENTS.md', 'agent_instructions');
161
196
  addFile('CLAUDE.md', 'agent_instructions');
162
197
  addFile('.mcp.json', 'mcp_config');
198
+ addFile('mcp.json', 'mcp_config');
163
199
  addFile('.cursor', 'cursor_project');
200
+ addFile('.windsurf', 'windsurf_project');
201
+ addFile('.cline', 'cline_project');
164
202
  addFile('hermes.json', 'hermes_config');
165
203
  addFile('hermes.yaml', 'hermes_config');
166
204
  addFile('hermes.yml', 'hermes_config');
167
205
  addFile('.hermes', 'hermes_config');
168
206
  addFile('openclaw.json', 'openclaw_config');
169
207
  addFile('.openclaw', 'openclaw_config');
208
+ addFile('.gemini', 'gemini_profile');
209
+ addFile('.grok', 'grok_profile');
210
+ addFile('.deepseek', 'deepseek_profile');
211
+ addFile('.qwen', 'qwen_profile');
212
+ addFile('.kimi', 'kimi_profile');
213
+ addFile('.minimax', 'minimax_profile');
214
+ addFile('.glm', 'glm_profile');
170
215
 
171
216
  for (const script of packageScripts) {
172
217
  if (/\b(deploy|publish|release|migrate|migration|smoke|check|test)\b/i.test(script)) {
@@ -204,6 +249,7 @@ function parseBaseOptions(argv, startIndex = 0) {
204
249
  proofFile: '',
205
250
  type: '',
206
251
  action: '',
252
+ client: sourceClient(),
207
253
  interactive: null,
208
254
  };
209
255
  let i = startIndex;
@@ -224,6 +270,7 @@ function parseBaseOptions(argv, startIndex = 0) {
224
270
  options.failOpen = false;
225
271
  } else if (arg === '--owner-approved') options.ownerApproval = argv[++i] || options.ownerApproval;
226
272
  else if (arg === '--proof-file') options.proofFile = argv[++i] || options.proofFile;
273
+ else if (arg === '--client' || arg === '--harness') options.client = sourceClient(argv[++i] || options.client);
227
274
  else if (arg === '--base-url') options.baseUrl = argv[++i] || options.baseUrl;
228
275
  else if (arg === '--key') {
229
276
  options.apiKey = argv[++i] || options.apiKey;
@@ -295,11 +342,28 @@ function headers(options) {
295
342
  'Content-Type': 'application/json',
296
343
  'X-Marrow-Agent-Id': options.agentId,
297
344
  'X-Marrow-Session-Id': options.sessionId,
345
+ 'X-Marrow-Client': sourceClient(options.client),
298
346
  'User-Agent': '@getmarrow/install governed-runner',
299
347
  };
300
348
  return h;
301
349
  }
302
350
 
351
+ function sourceMeta(options, channel, extra = {}) {
352
+ const client = sourceClient(options.client);
353
+ return {
354
+ channel,
355
+ client,
356
+ harness: client,
357
+ runner: '@getmarrow/install',
358
+ agent_id: options.agentId,
359
+ session_id: options.sessionId,
360
+ profile: options.profile,
361
+ governed: true,
362
+ ...(extra.action ? { user_intent: displayText(extra.action, 160) } : {}),
363
+ ...extra,
364
+ };
365
+ }
366
+
303
367
  function dataOf(json) {
304
368
  return json && typeof json === 'object' && json.data && typeof json.data === 'object' ? json.data : json;
305
369
  }
@@ -340,22 +404,26 @@ function defaultProof(input) {
340
404
  exit_code: input.exitCode,
341
405
  runner: '@getmarrow/install run',
342
406
  profile: input.options.profile,
407
+ source_meta: sourceMeta(input.options, 'proof', { action: input.action }),
343
408
  ...(input.options.ownerApproval ? { owner_approval: { approved_by: 'owner', reference: input.options.ownerApproval } } : {}),
344
409
  ...proof,
345
410
  };
346
411
  }
347
412
 
348
413
  async function preflightRuntime(options, action, type, commandText) {
414
+ const meta = sourceMeta(options, 'runtime', { action, command: commandText, action_type: type });
349
415
  return requestJson(options, 'POST', '/v1/agent/runtime', {
350
416
  action,
351
417
  type,
352
418
  surfaces: inferSurfaces(commandText || action),
419
+ source_meta: meta,
353
420
  context: {
354
421
  runner: '@getmarrow/install run',
355
422
  profile: options.profile,
356
423
  command: commandText,
357
424
  policy: options.policy,
358
425
  governed: true,
426
+ source_meta: meta,
359
427
  },
360
428
  });
361
429
  }
@@ -383,6 +451,7 @@ async function recommendGovernanceMode(options, project = detectProjectSignals()
383
451
  id: options.agentId,
384
452
  role: 'setup',
385
453
  },
454
+ source_meta: sourceMeta(options, 'mode_recommend', { action }),
386
455
  });
387
456
  }
388
457
 
@@ -402,6 +471,7 @@ async function recordGovernanceModeSelection(options, state) {
402
471
  },
403
472
  selected_mode: selected,
404
473
  selection_source: selected === state.recommendation.recommended_mode ? 'accepted' : 'overridden',
474
+ source_meta: sourceMeta(options, 'mode_selection', { action: 'selected Marrow governance mode for this project' }),
405
475
  });
406
476
  }
407
477
 
@@ -453,13 +523,16 @@ function runChild(command, env = process.env) {
453
523
  }
454
524
 
455
525
  async function createDecision(options, action, type) {
526
+ const meta = sourceMeta(options, 'think', { action, action_type: type });
456
527
  return requestJson(options, 'POST', '/v1/agent/think', {
457
528
  action,
458
529
  type,
530
+ source_meta: meta,
459
531
  context: {
460
532
  runner: '@getmarrow/install run',
461
533
  profile: options.profile,
462
534
  governed: true,
535
+ source_meta: meta,
463
536
  },
464
537
  });
465
538
  }
@@ -470,6 +543,7 @@ async function commitOutcome(options, decisionId, success, outcome, proof, gateR
470
543
  success,
471
544
  outcome,
472
545
  proof,
546
+ source_meta: sourceMeta(options, 'commit', { action: outcome }),
473
547
  };
474
548
  if (gateReceiptId) body.gate_receipt_id = gateReceiptId;
475
549
  return requestJson(options, 'POST', '/v1/agent/commit', body);
@@ -851,14 +925,51 @@ function fleetPanel(snapshot) {
851
925
  ].filter(Boolean).join('\n');
852
926
  }
853
927
 
928
+ const GENERIC_GOVERNED_COMMAND = 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install run --agent <agent-id> --profile production --policy warn -- <harness-command>';
929
+
930
+ function localSupportedHarnesses() {
931
+ return [
932
+ { display_name: 'OpenAI Codex', client_label: 'codex', category: 'agent_harness', support_level: 'governed_runner', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install run --agent codex-prod -- codex' },
933
+ { display_name: 'Claude Code', client_label: 'claude-code', category: 'agent_harness', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/mcp setup' },
934
+ { display_name: 'Cursor', client_label: 'cursor', category: 'ide_agent', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/mcp setup' },
935
+ { display_name: 'Cursor Composer', client_label: 'composer', category: 'ide_agent', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/mcp setup' },
936
+ { display_name: 'Windsurf', client_label: 'windsurf', category: 'ide_agent', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/mcp setup' },
937
+ { display_name: 'Cline', client_label: 'cline', category: 'ide_agent', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/mcp setup' },
938
+ { display_name: 'OpenCode', client_label: 'opencode', category: 'agent_harness', support_level: 'governed_runner', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install run --agent opencode-prod -- opencode' },
939
+ { display_name: 'Hermes Agent', client_label: 'hermes', category: 'agent_harness', support_level: 'first_class_addon', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install hermes' },
940
+ { display_name: 'OpenClaw', client_label: 'openclaw', category: 'agent_harness', support_level: 'first_class_addon', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install openclaw' },
941
+ { display_name: 'Gemini CLI', client_label: 'gemini', category: 'model_cli', support_level: 'governed_runner', install_command: GENERIC_GOVERNED_COMMAND },
942
+ { display_name: 'Grok CLI', client_label: 'grok', category: 'model_cli', support_level: 'governed_runner', install_command: GENERIC_GOVERNED_COMMAND },
943
+ { display_name: 'DeepSeek', client_label: 'deepseek', category: 'model_cli', support_level: 'governed_runner', install_command: GENERIC_GOVERNED_COMMAND },
944
+ { display_name: 'Qwen', client_label: 'qwen', category: 'model_cli', support_level: 'governed_runner', install_command: GENERIC_GOVERNED_COMMAND },
945
+ { display_name: 'Kimi', client_label: 'kimi', category: 'model_cli', support_level: 'governed_runner', install_command: GENERIC_GOVERNED_COMMAND },
946
+ { display_name: 'MiniMax', client_label: 'minimax', category: 'model_cli', support_level: 'governed_runner', install_command: GENERIC_GOVERNED_COMMAND },
947
+ { display_name: 'GLM', client_label: 'glm', category: 'model_cli', support_level: 'governed_runner', install_command: GENERIC_GOVERNED_COMMAND },
948
+ { display_name: 'MCP-compatible clients', client_label: 'mcp', category: 'mcp_client', support_level: 'native_mcp_or_sdk', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/mcp setup' },
949
+ { display_name: 'CI scripts and deploy runners', client_label: 'ci', category: 'ci_runner', support_level: 'governed_runner', install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install run --agent ci-release --profile production --policy enforce -- <ci-or-deploy-command>' },
950
+ { display_name: 'Custom shell/API harness', client_label: 'custom', category: 'custom_runner', support_level: 'event_contract', install_command: 'POST /v1/agent/integrations/events with harness, event_type, agent_id, and action' },
951
+ ];
952
+ }
953
+
854
954
  function detectHarnesses(cwd = process.cwd()) {
855
955
  const candidates = [
856
956
  { name: 'Codex', command: 'codex', detected: fs.existsSync(path.join(cwd, 'AGENTS.md')) || fs.existsSync(path.join(os.homedir(), '.codex')) },
857
957
  { name: 'Claude Code', command: 'claude -p', detected: fs.existsSync(path.join(cwd, 'CLAUDE.md')) || fs.existsSync(path.join(os.homedir(), '.claude.json')) },
858
958
  { name: 'Cursor', command: 'cursor', detected: fs.existsSync(path.join(cwd, '.cursor')) || fs.existsSync(path.join(os.homedir(), '.cursor')) },
959
+ { name: 'Cursor Composer', command: 'cursor composer', detected: fs.existsSync(path.join(cwd, '.cursor')) || fs.existsSync(path.join(os.homedir(), '.cursor')) },
960
+ { name: 'Windsurf', command: 'windsurf', detected: fs.existsSync(path.join(cwd, '.windsurf')) || fs.existsSync(path.join(os.homedir(), '.windsurf')) },
961
+ { name: 'Cline', command: 'cline', detected: fs.existsSync(path.join(cwd, '.cline')) || fs.existsSync(path.join(cwd, '.vscode')) },
859
962
  { name: 'OpenCode', command: 'opencode', detected: fs.existsSync(path.join(cwd, 'opencode.json')) || fs.existsSync(path.join(os.homedir(), '.opencode')) },
860
963
  { name: 'Hermes Agent', command: 'hermes', detected: fs.existsSync(path.join(cwd, 'hermes.json')) || fs.existsSync(path.join(cwd, '.hermes')) || fs.existsSync(path.join(os.homedir(), '.hermes')) || fs.existsSync(path.join(os.homedir(), '.hermes-agent')) },
861
964
  { name: 'OpenClaw', command: 'openclaw agent', detected: fs.existsSync(path.join(os.homedir(), '.openclaw')) },
965
+ { name: 'Gemini CLI', command: 'gemini', detected: fs.existsSync(path.join(cwd, '.gemini')) || fs.existsSync(path.join(os.homedir(), '.gemini')) },
966
+ { name: 'Grok CLI', command: 'grok', detected: fs.existsSync(path.join(cwd, '.grok')) || fs.existsSync(path.join(os.homedir(), '.grok')) },
967
+ { name: 'DeepSeek', command: 'deepseek', detected: fs.existsSync(path.join(cwd, '.deepseek')) || fs.existsSync(path.join(os.homedir(), '.deepseek')) },
968
+ { name: 'Qwen', command: 'qwen', detected: fs.existsSync(path.join(cwd, '.qwen')) || fs.existsSync(path.join(os.homedir(), '.qwen')) },
969
+ { name: 'Kimi', command: 'kimi', detected: fs.existsSync(path.join(cwd, '.kimi')) || fs.existsSync(path.join(os.homedir(), '.kimi')) },
970
+ { name: 'MiniMax', command: 'minimax', detected: fs.existsSync(path.join(cwd, '.minimax')) || fs.existsSync(path.join(os.homedir(), '.minimax')) },
971
+ { name: 'GLM', command: 'glm', detected: fs.existsSync(path.join(cwd, '.glm')) || fs.existsSync(path.join(os.homedir(), '.glm')) },
972
+ { name: 'MCP-compatible client', command: 'mcp client', detected: fs.existsSync(path.join(cwd, '.mcp.json')) || fs.existsSync(path.join(cwd, 'mcp.json')) },
862
973
  { name: 'CI script', command: 'npm test', detected: fs.existsSync(path.join(cwd, 'package.json')) },
863
974
  { name: 'Custom command', command: '<your-agent-command>', detected: true },
864
975
  ];
@@ -970,9 +1081,10 @@ async function integrationOnly(parsed, name) {
970
1081
 
971
1082
  async function integrationsOnly(parsed) {
972
1083
  const local = {
973
- integration_registry_version: 'local.harness-addons-v1',
974
- supported_harnesses: ['hermes', 'openclaw'].map((name) => localIntegrationManifest(name)),
975
- exact_next_action: 'Run npx @getmarrow/install hermes or npx @getmarrow/install openclaw for a harness-specific setup path.',
1084
+ integration_registry_version: 'local.broad-harness-support-v2',
1085
+ first_class_addons: ['hermes', 'openclaw'].map((name) => localIntegrationManifest(name)),
1086
+ supported_harnesses: localSupportedHarnesses(),
1087
+ exact_next_action: 'Pick the harness your team already uses. Use the install_command shown here, or send compact events to /v1/agent/integrations/events.',
976
1088
  };
977
1089
  let registry = local;
978
1090
  let source = 'local';
@@ -990,9 +1102,10 @@ async function integrationsOnly(parsed) {
990
1102
  'Marrow Harness Integrations',
991
1103
  '',
992
1104
  `Source: ${source}`,
993
- 'Supported add-ons:',
994
- ...harnesses.map((harness) => ` - ${displayText(harness.client_label || harness.integration || harness.title, 40)} ${displayText(harness.install_command || harness.install_commands?.[0] || '', 120)}`),
1105
+ 'Supported harnesses and model CLIs:',
1106
+ ...harnesses.map((harness) => ` - ${displayText(harness.display_name || harness.client_label || harness.integration || harness.title, 40)} [${displayText(harness.support_level || 'supported', 24)}] ${displayText(harness.install_command || harness.install_commands?.[0] || '', 120)}`),
995
1107
  '',
1108
+ 'First-class add-on guides: hermes, openclaw',
996
1109
  `Next: ${displayText(registry.exact_next_action, 140)}`,
997
1110
  registry.api_warning ? `API warning: ${displayText(registry.api_warning, 120)}` : '',
998
1111
  ].filter(Boolean).join('\n') + '\n');
@@ -1622,6 +1735,10 @@ module.exports = {
1622
1735
  parseArgs,
1623
1736
  redact,
1624
1737
  redactedCommand,
1738
+ normalizeClientLabel,
1739
+ sourceClient,
1740
+ sourceMeta,
1741
+ headers,
1625
1742
  inferType,
1626
1743
  inferSurfaces,
1627
1744
  commandForSelection,
@@ -1648,6 +1765,7 @@ module.exports = {
1648
1765
  buildFleetState,
1649
1766
  renderFleetTui,
1650
1767
  runFleetInteractive,
1768
+ localSupportedHarnesses,
1651
1769
  localIntegrationManifest,
1652
1770
  renderIntegrationPanel,
1653
1771
  integrationOnly,
package/src/installer.js CHANGED
@@ -6,6 +6,35 @@ const crypto = require('node:crypto');
6
6
  const DEFAULT_BASE_URL = 'https://api.getmarrow.ai';
7
7
  const MARROW_BLOCK_START = '<!-- marrow:passive-start -->';
8
8
  const MARROW_BLOCK_END = '<!-- marrow:passive-end -->';
9
+ const SOURCE_CLIENTS = new Set(['claude-code', 'cursor', 'windsurf', 'openclaw', 'codex', 'gemini', 'grok', 'deepseek', 'qwen', 'kimi', 'minimax', 'cline', 'opencode', 'hermes', 'glm', 'custom', 'unknown']);
10
+
11
+ function sourceClient() {
12
+ const raw = String(process.env.MARROW_CLIENT || process.env.MARROW_HARNESS || process.env.MARROW_AGENT_CLIENT || '').trim().toLowerCase().replace(/\s+/g, '-').replace(/^@/, '');
13
+ const aliases = {
14
+ claude: 'claude-code',
15
+ claude_code: 'claude-code',
16
+ 'claude-code': 'claude-code',
17
+ cursor: 'cursor',
18
+ windsurf: 'windsurf',
19
+ openclaw: 'openclaw',
20
+ codex: 'codex',
21
+ 'openai-codex': 'codex',
22
+ gemini: 'gemini',
23
+ google: 'gemini',
24
+ grok: 'grok',
25
+ deepseek: 'deepseek',
26
+ qwen: 'qwen',
27
+ kimi: 'kimi',
28
+ minimax: 'minimax',
29
+ cline: 'cline',
30
+ opencode: 'opencode',
31
+ 'open-code': 'opencode',
32
+ hermes: 'hermes',
33
+ 'hermes-agent': 'hermes',
34
+ glm: 'glm',
35
+ };
36
+ return aliases[raw] || (SOURCE_CLIENTS.has(raw) ? raw : 'custom');
37
+ }
9
38
 
10
39
  function parseArgs(argv) {
11
40
  const options = {
@@ -105,12 +134,6 @@ function findUp(startDir, names, maxDepth = 8) {
105
134
  }
106
135
 
107
136
  function projectRoot(startDir) {
108
- const resolved = path.resolve(startDir);
109
- if (path.basename(resolved) === '.marrow') return path.dirname(resolved);
110
- if (path.basename(resolved) === 'env' && path.basename(path.dirname(resolved)) === '.marrow') {
111
- return path.dirname(path.dirname(resolved));
112
- }
113
- if (exists(path.join(resolved, '.marrow'))) return resolved;
114
137
  const marker = findUp(startDir, ['package.json', 'pyproject.toml', 'requirements.txt', '.git', 'AGENTS.md', 'CLAUDE.md']);
115
138
  return marker ? path.dirname(marker) : path.resolve(startDir);
116
139
  }
@@ -289,14 +312,16 @@ Marrow should run passively after install:
289
312
 
290
313
  - Use MCP hooks when available: \`npx -y @getmarrow/mcp setup\`.
291
314
  - Use SDK passive runtime in owned Node processes: \`createPassiveRuntime().install()\`.
292
- - Before risky work, use Marrow's before-action intervention from \`GET /v1/agent/status\` or \`POST /v1/agent/runtime\`.
315
+ - Keep passive token/model usage proof enabled so Marrow can show token, cost, latency, and workflow savings after real work completes.
316
+ - Before risky work, use Marrow's decision brief or passive prompt hook.
293
317
  - After meaningful work, record the outcome so future agents learn from it.
294
318
  - Check health with \`marrow_agent_status\` or \`GET /v1/agent/status\`.
295
319
 
296
320
  Required environment:
297
321
 
298
322
  - \`MARROW_API_KEY\`
299
- - Optional: \`MARROW_BASE_URL\`, \`MARROW_FLEET_AGENT_ID\`
323
+ - Optional: \`MARROW_BASE_URL\`, \`MARROW_FLEET_AGENT_ID\`, \`MARROW_CLIENT\`
324
+ - Optional: \`MARROW_PASSIVE_TOKEN_USAGE=false\` disables compact provider usage capture when needed.
300
325
  ${MARROW_BLOCK_END}`;
301
326
  }
302
327
 
@@ -318,6 +343,7 @@ if (apiKey && !globalThis.__MARROW_PASSIVE_RUNTIME__) {
318
343
  useAgentRuntime: process.env.MARROW_AGENT_RUNTIME !== 'false',
319
344
  useWorkflowGate: process.env.MARROW_WORKFLOW_GATE !== 'false',
320
345
  requireOutcomeClosure: process.env.MARROW_REQUIRE_OUTCOME_CLOSURE !== 'false',
346
+ captureModelUsage: process.env.MARROW_PASSIVE_TOKEN_USAGE !== 'false',
321
347
  });
322
348
 
323
349
  runtime.install();
@@ -333,12 +359,14 @@ function envExample() {
333
359
  return `MARROW_API_KEY=mrw_live_replace_me
334
360
  MARROW_BASE_URL=${DEFAULT_BASE_URL}
335
361
  MARROW_FLEET_AGENT_ID=agent-or-fleet-id
362
+ MARROW_CLIENT=codex
336
363
  MARROW_ENFORCEMENT_MODE=auto
337
364
  MARROW_PASSIVE_BRIEF=auto
338
365
  MARROW_PASSIVE_VALUE_REPORT=true
339
366
  MARROW_AGENT_RUNTIME=true
340
367
  MARROW_WORKFLOW_GATE=true
341
368
  MARROW_REQUIRE_OUTCOME_CLOSURE=true
369
+ MARROW_PASSIVE_TOKEN_USAGE=true
342
370
  `;
343
371
  }
344
372
 
@@ -567,6 +595,7 @@ async function runSelfTest(options) {
567
595
  authorization: `Bearer ${options.apiKey}`,
568
596
  'content-type': 'application/json',
569
597
  'x-marrow-session-id': `install-${Date.now()}`,
598
+ 'x-marrow-client': sourceClient(),
570
599
  };
571
600
  if (options.agentId) headers['x-marrow-agent-id'] = options.agentId;
572
601
 
@@ -577,6 +606,11 @@ async function runSelfTest(options) {
577
606
  body: JSON.stringify({
578
607
  type: 'process',
579
608
  action: 'Marrow passive install self-test: verify SDK/MCP hooks can record a harmless setup event',
609
+ source_meta: {
610
+ channel: 'cli',
611
+ client: sourceClient(),
612
+ user_intent: 'operate',
613
+ },
580
614
  }),
581
615
  });
582
616
 
@@ -633,8 +667,14 @@ async function runSelfTest(options) {
633
667
  ok: false,
634
668
  error: error instanceof Error ? error.message : String(error),
635
669
  }));
636
- const firstValueSignal = buildFirstValueSignal(status, runtime, performance, firstValue);
637
- const installValueMoment = buildInstallValueMoment(firstValueSignal, status, runtime, performance, firstValue);
670
+ const valueProof = await requestJson(`${baseUrl}/v1/agent/value/proof?period_days=30`, { headers })
671
+ .catch((error) => ({
672
+ ok: false,
673
+ error: error instanceof Error ? error.message : String(error),
674
+ }));
675
+ const tokenValueProof = buildTokenValueProof(valueProof);
676
+ const firstValueSignal = buildFirstValueSignal(status, runtime, performance, firstValue, tokenValueProof);
677
+ const installValueMoment = buildInstallValueMoment(firstValueSignal, status, runtime, performance, firstValue, tokenValueProof);
638
678
  return {
639
679
  skipped: false,
640
680
  decision_id: decisionId,
@@ -646,11 +686,11 @@ async function runSelfTest(options) {
646
686
  auto_outcome_closure: status.auto_outcome_closure || null,
647
687
  runtime_active: Boolean(runtime && runtime.ok !== false),
648
688
  runtime_exact_next_action: runtime.exact_next_action || null,
649
- runtime_before_you_act: runtime.intervention?.agent_copy || runtime.intervention?.before_action || runtime.before_you_act || null,
650
- runtime_intervention: runtime.intervention || null,
689
+ runtime_before_you_act: runtime.before_you_act || null,
651
690
  first_value: firstValue && firstValue.ok !== false ? firstValue : null,
652
691
  first_value_signal: firstValueSignal,
653
692
  install_value_moment: installValueMoment,
693
+ token_value_proof: tokenValueProof,
654
694
  performance_proof: performance && performance.ok !== false ? {
655
695
  avoided_mistakes: performance.avoided_mistakes ?? performance.avoided_repeated_mistakes ?? 0,
656
696
  reused_winning_decisions: performance.reused_winning_decisions ?? 0,
@@ -662,11 +702,30 @@ async function runSelfTest(options) {
662
702
  };
663
703
  }
664
704
 
665
- function buildInstallValueMoment(firstValueSignal = {}, status = {}, runtime = {}, performance = {}, firstValue = {}) {
705
+ function buildTokenValueProof(valueProof = {}) {
706
+ const modelUsage = valueProof && valueProof.ok !== false
707
+ ? valueProof.model_usage || valueProof.token_value_signal || valueProof
708
+ : null;
709
+ if (!modelUsage || typeof modelUsage !== 'object') {
710
+ return {
711
+ enabled: true,
712
+ capture_default: 'on_when_sdk_mcp_or_installer_hooks_available',
713
+ observed: { model_calls: 0, tokens: { total: 0 } },
714
+ savings: { estimated_tokens_saved: 0, estimated_minutes_saved: 0, confidence: 'none', method: 'warming_up' },
715
+ proof_line: 'Token usage capture is ready; no model calls have been reported yet.',
716
+ exact_next_action: 'Keep passive token capture enabled so Marrow can attach usage proof after real model calls complete.',
717
+ };
718
+ }
719
+ return modelUsage;
720
+ }
721
+
722
+ function buildInstallValueMoment(firstValueSignal = {}, status = {}, runtime = {}, performance = {}, firstValue = {}, tokenValueProof = null) {
666
723
  if (firstValue && firstValue.ok !== false && firstValue.first_value) {
724
+ const proof = Array.isArray(firstValue.first_value.proof) ? [...firstValue.first_value.proof] : [];
725
+ if (tokenValueProof?.proof_line && !proof.includes(tokenValueProof.proof_line)) proof.push(tokenValueProof.proof_line);
667
726
  return {
668
727
  headline: firstValue.headline || firstValue.first_value.headline || 'Your agent is no longer starting from zero.',
669
- proof: Array.isArray(firstValue.first_value.proof) ? firstValue.first_value.proof : [],
728
+ proof,
670
729
  fleet_signal: firstValue.history_signal?.summary || 'Fresh account: Marrow will build fleet memory from this first captured outcome.',
671
730
  try_this_now: firstValue.first_value.try_this_now || 'Ask your agent: "I am about to deploy to production. What should I check first?"',
672
731
  expected_response: firstValue.first_value.expected_response || 'Marrow should answer with a risk gate, required proof, and any matching fleet lessons before the agent acts.',
@@ -676,9 +735,7 @@ function buildInstallValueMoment(firstValueSignal = {}, status = {}, runtime = {
676
735
 
677
736
  const proof = firstValueSignal.value_proof || [];
678
737
  const hasFleetSignal = proof.length > 0;
679
- const runtimeLesson = runtime.intervention?.agent_copy
680
- || runtime.intervention?.before_action
681
- || runtime.before_you_act
738
+ const runtimeLesson = runtime.before_you_act
682
739
  || runtime.before_you_act_injection?.message
683
740
  || runtime.exact_next_action
684
741
  || firstValueSignal.first_lesson;
@@ -689,18 +746,19 @@ function buildInstallValueMoment(firstValueSignal = {}, status = {}, runtime = {
689
746
  'Captured this setup decision',
690
747
  'Closed the outcome successfully',
691
748
  'Runtime gate is ' + (firstValueSignal.active ? 'active' : 'installed'),
692
- runtime.intervention?.must_use_before_action ? 'Before-action intervention is active for risky work' : runtimeLesson ? 'Future risky work now gets a pre-action brief' : 'Future risky work now gets checked before action',
749
+ runtimeLesson ? 'Future risky work now gets a pre-action brief' : 'Future risky work now gets checked before action',
750
+ tokenValueProof?.proof_line || 'Token usage proof is active and warming up after the first model call',
693
751
  ],
694
752
  fleet_signal: hasFleetSignal
695
753
  ? 'Marrow already found signal: ' + proof.join('; ') + '.'
696
754
  : 'Fresh account: Marrow will start building fleet memory from this first captured outcome.',
697
755
  try_this_now: 'Ask your agent: "I am about to deploy to production. What should I check first?"',
698
- expected_response: 'Marrow should answer with proceed/warn/block, required proof, and any matching prior lesson/playbook before the agent acts.',
699
- first_lesson: runtimeLesson || 'Marrow will stop agents before risky or repeated work and surface the prior lesson/playbook.',
756
+ expected_response: 'Marrow should answer with a risk gate, required proof, and any matching fleet lessons before the agent acts.',
757
+ first_lesson: runtimeLesson || 'Marrow will surface prior lessons before risky or repeated work.',
700
758
  };
701
759
  }
702
760
 
703
- function buildFirstValueSignal(status, runtime, performance, firstValue = {}) {
761
+ function buildFirstValueSignal(status, runtime, performance, firstValue = {}, tokenValueProof = null) {
704
762
  if (firstValue && firstValue.ok !== false && firstValue.first_value) {
705
763
  const capture = firstValue.capture || {};
706
764
  const proof = firstValue.value_proof || {};
@@ -709,11 +767,13 @@ function buildFirstValueSignal(status, runtime, performance, firstValue = {}) {
709
767
  if (Number(proof.reused_winning_decisions || 0) > 0) proofBits.push(`${proof.reused_winning_decisions} reused winning decision(s)`);
710
768
  if (Number(proof.prevented_bad_actions || 0) > 0) proofBits.push(`${proof.prevented_bad_actions} prevented risky action(s)`);
711
769
  if (Number(proof.estimated_tokens_saved || 0) > 0) proofBits.push(`~${proof.estimated_tokens_saved} tokens saved`);
770
+ if (Number(tokenValueProof?.savings?.estimated_tokens_saved || 0) > 0) proofBits.push(`~${tokenValueProof.savings.estimated_tokens_saved} measured model tokens saved`);
771
+ else if (tokenValueProof?.proof_line) proofBits.push(tokenValueProof.proof_line);
712
772
  return {
713
773
  active: Boolean(firstValue.active),
714
774
  headline: `Marrow active: ${(capture.surfaces || ['decisions']).join(', ')} captured.`,
715
775
  captured: capture.surfaces || ['decisions'],
716
- first_lesson: firstValue.first_value.first_lesson || runtime?.intervention?.agent_copy,
776
+ first_lesson: firstValue.first_value.first_lesson,
717
777
  value_proof: proofBits,
718
778
  next_action: firstValue.next_action?.reason || 'Keep working; Marrow will capture outcomes and reuse lessons automatically.',
719
779
  };
@@ -736,6 +796,8 @@ function buildFirstValueSignal(status, runtime, performance, firstValue = {}) {
736
796
  if (Number(proof.prevented_bad_actions || 0) > 0) proofBits.push(`${proof.prevented_bad_actions} prevented risky action(s)`);
737
797
  const tokens = proof.token_time_saved_estimate?.estimated_tokens_saved || 0;
738
798
  if (tokens > 0) proofBits.push(`~${tokens} tokens saved`);
799
+ if (Number(tokenValueProof?.savings?.estimated_tokens_saved || 0) > 0) proofBits.push(`~${tokenValueProof.savings.estimated_tokens_saved} measured model tokens saved`);
800
+ else if (tokenValueProof?.proof_line) proofBits.push(tokenValueProof.proof_line);
739
801
 
740
802
  const firstLesson = runtime.before_you_act
741
803
  || runtime.before_you_act_injection?.message
@@ -799,6 +861,20 @@ function printReport(report) {
799
861
  process.stdout.write(`- Next: ${report.selfTest.first_value_signal.next_action}\n`);
800
862
  }
801
863
  }
864
+ if (report.selfTest.token_value_proof) {
865
+ const proof = report.selfTest.token_value_proof;
866
+ const observed = proof.observed || {};
867
+ const savings = proof.savings || {};
868
+ const tokens = observed.tokens || {};
869
+ process.stdout.write('\nToken value proof:\n');
870
+ process.stdout.write(`- passive capture: ${proof.enabled ? 'on' : 'unknown'}\n`);
871
+ process.stdout.write(`- model calls observed: ${observed.model_calls || 0}\n`);
872
+ process.stdout.write(`- tokens observed: ${tokens.total || 0}\n`);
873
+ process.stdout.write(`- estimated tokens saved: ${savings.estimated_tokens_saved || 0}\n`);
874
+ if (savings.confidence) process.stdout.write(`- confidence: ${savings.confidence}\n`);
875
+ if (proof.proof_line) process.stdout.write(`- proof: ${proof.proof_line}\n`);
876
+ if (proof.exact_next_action) process.stdout.write(`- next: ${proof.exact_next_action}\n`);
877
+ }
802
878
  }
803
879
 
804
880
  if (report.remediation) {
@@ -949,4 +1025,5 @@ module.exports = {
949
1025
  inspectNpmTokenConfig,
950
1026
  inspectSdkDependency,
951
1027
  buildInstallValueMoment,
1028
+ buildTokenValueProof,
952
1029
  };