@haven_ai/connect 0.0.0-dev.202609031523.fd49e1a

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 ADDED
@@ -0,0 +1,406 @@
1
+ # @haven_ai/connect
2
+
3
+ Connect Agent 2 local connector.
4
+
5
+ This command runs in the user's agent environment. It generates the agent
6
+ signing key and API key locally, stores them locally, and sends Haven only the
7
+ public signing address, proof signature, and API-key hash. Haven never receives
8
+ the private key or plaintext API key.
9
+
10
+ ```sh
11
+ npx -y @haven_ai/connect@alpha --setup hv_setup_... --api https://api.haven.example --ack-local-tools --runtime claude-code
12
+ ```
13
+
14
+ `@alpha` is the **production** channel, and the Haven dashboard hands you the
15
+ exact command to run — copy that rather than this one, which uses placeholder
16
+ values. Since #2422 the package in it is per-deployment: the backend's setup
17
+ response names it in `connector_package`, and a non-production deployment can be
18
+ configured to hand out a different channel such as `@haven_ai/connect@dev`.
19
+ Read `connector_package` rather than assuming any particular backend's channel. Pinning `@alpha` by hand against such a backend
20
+ installs a signer that skews against it — the signer refuses to sign an
21
+ `x402_expected_context_version` it does not know.
22
+
23
+ The connector writes owner-only credential files outside the project by default:
24
+
25
+ - `~/.haven/agents/<agent-id>/identity.json` contains the Haven API key.
26
+ - `~/.haven/agents/<agent-id>/signer.json` contains the local signer key.
27
+
28
+ The API key identifies the agent. It cannot spend by itself. Payments still need
29
+ the locally held signer key and the user-approved on-chain Haven wallet rules.
30
+
31
+ Use `--credentials-dir <path>` to choose a different local credential directory.
32
+ Do not point it at a project repository, shared folder, or cloud-synced folder.
33
+
34
+ Use `--ack-local-tools` with Haven-generated setup prompts. It prepares the
35
+ local Haven tools acknowledgement during setup so Codex and Claude Code can load
36
+ Haven after a normal restart.
37
+
38
+ ## Supported runtimes
39
+
40
+ The default setup writes the hosted Haven MCP (using the agent API key for
41
+ identity) plus a separate local signer. The API key identifies the agent; the
42
+ locally held signer key and the user's approved Haven wallet rules remain the
43
+ spending authority.
44
+
45
+ | Runtime | Configuration written by setup | Activate the new entry |
46
+ | --- | --- | --- |
47
+ | Claude Code | User MCP registry | Start a new Claude Code session. |
48
+ | Codex CLI | `~/.codex/config.toml` | Start a fresh session, for example `codex resume --last`. |
49
+ | Codex Desktop | `~/.codex/config.toml` | Quit and reopen the app. |
50
+ | Cursor | Cursor MCP configuration | Wait for hot reload; no app restart is required. |
51
+ | VS Code / VS Code Insiders | VS Code MCP configuration | Wait for hot reload; no app restart is required. |
52
+ | Claude Desktop | Claude Desktop MCP configuration | Quit and reopen the app. |
53
+ | Hermes Agent | `$HERMES_HOME/config.yaml` + `.env`, or `~/.hermes/config.yaml` + `.env` | Start a new session; gateway users run `/restart`. |
54
+
55
+ ## After setup
56
+
57
+ 1. Return to Haven and approve the budget. Approval — not restarting —
58
+ unlocks the Haven tools.
59
+ 2. Activate the runtime using the table above.
60
+ 3. In the activated runtime, run the read-only `haven_get_agent` and
61
+ `haven_get_allowances` tools to confirm the Haven wallet and live budget.
62
+ Do not sign, fund, or create a payment to verify setup.
63
+
64
+ ### `--doctor` reports every agent, not just one (#1697)
65
+
66
+ With several agents wired into one runtime (`--name`), the doctor enumerates
67
+ every credential directory on the machine and classifies each one:
68
+
69
+ | Classification | Meaning |
70
+ | --- | --- |
71
+ | `wired` | Its MCP pair is present in this runtime's config. Fully checked. |
72
+ | `superseded` | It holds credentials, but no config entry points at it. Reported, never silently skipped — its API key may still spend. |
73
+ | `retired` | Tombstoned (see below); key material removed. |
74
+ | `orphaned` | No usable identity and no tombstone. |
75
+
76
+ The exit code is non-zero if **any** wired agent fails **any** check — not
77
+ only the one the report's main section describes. In `--json`, the same
78
+ information is on `agents[]`, each entry carrying `slug`, `agentId`,
79
+ `directory`, `classification` and its own `checks[]`; the flat `checks` array
80
+ is retained and still describes one agent, so a single-agent install reads as
81
+ it always did.
82
+
83
+ One check is worth calling out: **`identity_match`** compares the agent the
84
+ stored API key actually authenticates as against the `delegate_address` in
85
+ that directory's `signer.json`. A mismatch means the runtime would quote as
86
+ one agent and sign as another, and it fails hard. This is the half of that
87
+ hazard a local tool can know — the doctor still cannot see inside an
88
+ already-running host, which is why the restart guidance below matters.
89
+
90
+ ## Retiring an old agent directory
91
+
92
+ Re-running setup creates a NEW agent and retires nothing. Long-lived MCP hosts
93
+ (gateways, TUI workers, editors, desktop apps) load their MCP wiring once, at
94
+ process start — a host started before your latest setup keeps spawning the OLD
95
+ agent's signer path forever, and when that directory is later removed the spawn
96
+ failure surfaces only as a masked "Connection closed" retried every few
97
+ minutes. Two rules follow:
98
+
99
+ 1. **Restart EVERY long-lived host after a setup or retirement, not just one.**
100
+ Each process holds the snapshot from its own start time, so after a chain of
101
+ re-setups each host can be parked on a *different* old agent.
102
+ 2. **Tombstone a directory before (or instead of) deleting it:**
103
+
104
+ ```
105
+ npx @haven_ai/connect@alpha --tombstone ~/.haven/agents/<directory> --reason "superseded" --json
106
+ ```
107
+
108
+ This replaces the directory's signer wrapper with a diagnostic that logs the
109
+ retirement (agent id, date, reason, restart guidance) to the host's MCP
110
+ stderr log on every probe, and records it in `TOMBSTONE.json` for
111
+ `--doctor`. It touches no key material and revokes nothing — revoke the
112
+ agent on the Haven agent page yourself. Delete the tombstone only once every
113
+ long-lived host has been restarted.
114
+
115
+ **Pass a real DIRECTORY, not an agent id.** A named agent lives at its wiring
116
+ slug, which never equals its agent id — so `~/.haven/agents/<agent-id>` does
117
+ not exist for one, and the command refuses with
118
+ `tombstone_directory_not_found` having retired nothing. List `~/.haven/agents`
119
+ or read the `directory` values out of `--doctor --json`.
120
+
121
+ Under `--json`, success is `{"tombstoned": true, …}` on stdout with exit 0,
122
+ and a refusal is `{"tombstoned": false, "error": {"code", "next_action"}}`
123
+ with exit 1 — so check the result rather than assuming silence means success
124
+ (#2175). The `message` field is present only for connector-authored refusals;
125
+ an unexpected filesystem error keeps its raw text on stderr alone.
126
+
127
+ ### Unwiring an agent (`--unwire`, #2169)
128
+
129
+ Connect has always been able to *write* a pair into a runtime config and never
130
+ able to *erase* one — so a "reset" left the old `mcp_servers` pair and (on
131
+ Hermes) the `MCP_HAVEN_API_KEY` dotenv line behind, and the runtime quoted as
132
+ one agent while signing as another. `--unwire` is the erase half:
133
+
134
+ ```
135
+ npx @haven_ai/connect@alpha --unwire ~/.haven/agents/<directory> [--reason "..."]
136
+ npx @haven_ai/connect@alpha --unwire --name research [--reason "..."]
137
+ ```
138
+
139
+ It tombstone-first (so a stale long-lived host still hears `HAVEN-TOMBSTONE`,
140
+ never a masked `ENOENT`), then removes THAT agent's hosted + signer pair from
141
+ every runtime config it appears in (Hermes YAML, Codex TOML, the Cursor / VS
142
+ Code / Insiders / Claude Desktop JSON configs), plus the Hermes dotenv API-key
143
+ line — bare `MCP_HAVEN_API_KEY` or named `MCP_HAVEN_<SLUG>_API_KEY`. Finally it
144
+ tears down the target directory's local key material (signer key, any abandoned
145
+ re-key, the stored API key) so `--doctor` reports `retired`, not the
146
+ still-spend-capable `superseded`; the #2155 tombstone mirror keeps the record.
147
+
148
+ An **unnamed** pair (`haven` / `haven-signer`) is shared by every unnamed agent
149
+ and is only removed when this directory's wrapper is the one the config
150
+ launches (or its key is the one the Hermes env holds) — otherwise `--unwire`
151
+ **refuses** rather than unwire a different, working agent. Nothing is ever
152
+ revoked on the backend; `connect reports, the user decides` (#1688) survives,
153
+ and revocation stays an owner action on the Haven agent page. Restart every
154
+ long-lived host afterwards, as with any retirement.
155
+
156
+ ### Structured output for automation
157
+
158
+ Pass `--json` when a launcher needs a machine-readable completion record. Connect
159
+ writes progress and human recovery notes to stderr and exactly one JSON object
160
+ to stdout, with `schema_version: 1` and `outcome` set to `complete`,
161
+ `action_required`, or `failed`. Structured runs skip the interactive
162
+ budget-approval wait so the record is emitted promptly; approve in the Haven
163
+ dashboard whenever ready and verify later with the read-only `haven_get_agent`
164
+ tool. The object includes runtime/topology status,
165
+ probe result, activation and next-action guidance, approval state/expiry (null
166
+ when the backend does not provide an approval expiry), the two
167
+ read-only verification tools, `hosted_mcp_url`, and `superseded_agent_ids`. It
168
+ contains no API key, private key, credential
169
+ contents, full credential paths, or full delegate address. The same redacted
170
+ object is available to library callers as `runConnect(...).outcome`; the older
171
+ fields remain for additive compatibility.
172
+
173
+ `hosted_mcp_url` is the hosted MCP endpoint this run wired up — **not** the
174
+ backend URL you passed as `--api`. The hosted MCP server is a separate
175
+ deployment, so the two differing is intended topology, not an environment
176
+ mismatch. It is non-secret: the same string goes into your own MCP config file,
177
+ and the API key travels beside it in a header.
178
+
179
+ `superseded_agent_ids` lists the other agent directories on this machine. A
180
+ re-run mints a NEW agent and retires nothing, so those older agents still hold
181
+ live API and signing keys — revoke them on the Haven agent page if you meant to
182
+ replace them. Empty on a clean first run; an empty list is not a guarantee,
183
+ since a scan that cannot read the credential root also yields one rather than
184
+ failing a completed setup.
185
+
186
+ For a recoverable install, configuration, probe, consent, or manual-runtime
187
+ condition, inspect `error.code` and `error.next_action`, then follow the safe
188
+ next action. A failed setup emits `outcome: "failed"` with a stable error code;
189
+ it never presents credential material as a recovery diagnostic.
190
+
191
+ ### Recovering the record after a lost stream
192
+
193
+ Connect also writes its terminal outcome to `last-connect-outcome.json` in the
194
+ agent's credential directory (`~/.haven/agents/<slug-or-agent-id>/`) — the same
195
+ object, pretty-printed, for every terminal state. **If your harness stopped
196
+ watching before the connector finished, read that file rather than guessing
197
+ from your runtime's MCP listing.** A first run downloads and installs the
198
+ signer, which can take several minutes on a cold cache; a command harness that
199
+ gives up during it sees the install heartbeat as the last line and never the
200
+ verdict. The setup usually finished.
201
+
202
+ A refusal that happens before any credentials are written (an undetermined
203
+ runtime, an expired setup challenge, an unsupported Node) writes no file,
204
+ because nothing was created that could need recovering. The write is
205
+ best-effort and never changes the verdict: a setup that completed stays
206
+ completed even if the record could not be written.
207
+
208
+ If the setup challenge expires, return to Haven to start a fresh connection and
209
+ rerun Connect. If a runtime write, installation, or probe fails, follow the
210
+ structured `error.next_action` (or its human equivalent). The `other` runtime
211
+ is the manual exception: finish the secret-free file-reference setup it prints,
212
+ then start a fresh runtime session. Do not manually edit managed runtime
213
+ configuration or paste credentials into prompts, logs, or configuration files.
214
+
215
+ Connect abbreviates the public delegate address in normal output. Operators who
216
+ need its full public identifier can inspect the owner-only, non-secret
217
+ `agent.json` orientation file that Connect reports; do not inspect or share
218
+ `identity.json` or `signer.json` for diagnostics because they contain secrets.
219
+
220
+ For Hermes, Connect stores the hosted-MCP API key in the matching owner-only
221
+ `.env` file and keeps only `Bearer ${MCP_HAVEN_API_KEY}` in `config.yaml`.
222
+ Hermes requires its Python MCP SDK support to be installed. If Haven tools do
223
+ not appear after restart, run `pip install mcp` in the Hermes environment, then
224
+ restart Hermes and check `hermes mcp list`.
225
+
226
+ ## Why there is no pre-registration confirmation prompt
227
+
228
+ Connect mints a signing key and registers the agent as soon as it runs, without
229
+ an extra "about to create agent X, proceed?" gate. That is deliberate: the
230
+ consent already happened when the user minted the one-time setup prompt in the
231
+ Haven dashboard, which enumerates exactly what the command may do. The setup
232
+ stays cancellable from the dashboard throughout, and the registered agent
233
+ starts `pending_approval` with zero spending authority — no budgeted spend can
234
+ move until the user approves the budget in Haven. The exact sweep-recovery
235
+ routes remain available only to recover a stranded delegate balance and do not
236
+ grant spending authority. A CLI-side confirmation would add friction without
237
+ adding a security boundary. (The local-signer tool-exposure
238
+ acknowledgement is a separate, machine-checkable consent about what the local
239
+ MCP tools expose, not a registration gate.)
240
+
241
+ ## Running setup again
242
+
243
+ Each setup prompt is one-time and each successful run creates a **new** agent
244
+ with its own freshly minted key pair. Re-running Connect on an
245
+ already-configured machine behaves as follows (characterized in
246
+ `storage.test.ts`, `config-writers.test.ts`, `runtime.test.ts`, and
247
+ `runtime-install.test.ts`, #1544/#1569):
248
+
249
+ - **Re-running an already-consumed setup command** fails cleanly before any
250
+ credential file or runtime configuration is touched — Haven refuses the
251
+ consumed setup when Connect resolves it (or, in a rare concurrent-run race,
252
+ at registration). The key pair minted for the attempt exists only in memory
253
+ and is discarded. Start a fresh connection from the Haven dashboard instead.
254
+ - **Running a fresh setup on a configured machine** writes the new agent's
255
+ credentials into its own directory under `~/.haven/agents/<agent-id>/`,
256
+ alongside the previous agent's directory, which stays byte-identical.
257
+ Nothing is rotated, revoked, or deleted locally.
258
+ - **Runtime MCP entries are replaced, not duplicated**: Connect owns the
259
+ `haven` and `haven-signer` entries (and the managed Codex/Hermes
260
+ equivalents) and re-points them at the newest agent's credentials.
261
+ Unrelated MCP servers and configuration are preserved. Without `--name`, one
262
+ runtime is therefore wired to one Haven agent — the newest one. With
263
+ `--name`, each agent owns its own suffixed pair and they coexist; see
264
+ [Running several agents in one runtime](#running-several-agents-in-one-runtime).
265
+ - **The previous agent is not revoked by a re-run.** Its credentials remain on
266
+ disk and its authority remains whatever its on-chain rules say. Revoke
267
+ agents you no longer use from the Haven dashboard, then delete their
268
+ credential directories.
269
+ - **A re-run never overwrites an existing credential file.** A write that would
270
+ collide with an existing `identity.json`/`signer.json`/`agent.json` is
271
+ refused outright (and a partially failed write rolls itself back), so a
272
+ re-run cannot corrupt stored key material. **`--rekey` is the one exception,
273
+ and it is a different operation** — it deliberately replaces a credential set
274
+ in place, at an unchanged path, and is the supported way to replace a key
275
+ rather than accumulate agents. See
276
+ [Replacing an agent's signing key](#replacing-an-agents-signing-key-rekey).
277
+
278
+ ## Running several agents in one runtime
279
+
280
+ `--name <slug>` gives an agent its own MCP server pair and its own credential
281
+ directory, so several agents coexist in one runtime instead of replacing each
282
+ other:
283
+
284
+ ```sh
285
+ npx -y @haven_ai/connect@alpha --setup hv_setup_... --api https://api.haven.example \
286
+ --name research --runtime claude-code
287
+ ```
288
+
289
+ As above, `@alpha` here is the production channel and the placeholders are
290
+ illustrative: take the package from the setup response's `connector_package`
291
+ and add `--name` to the command the dashboard gave you.
292
+
293
+ | | Without `--name` | With `--name research` |
294
+ |---|---|---|
295
+ | MCP entries | `haven`, `haven-signer` | `haven-research`, `haven-signer-research` |
296
+ | Credentials | `~/.haven/agents/<agent-id>/` | `~/.haven/agents/research/` |
297
+
298
+ A writer only ever touches the pair it owns, so adding a named agent cannot
299
+ disturb the bare pair or another named one. Omitting `--name` is byte-identical
300
+ to how the connector behaved before named pairs existed, so nothing already
301
+ wired needs changing.
302
+
303
+ The slug is **1–32 lowercase letters, digits and single hyphens**, validated
304
+ before anything is written, and **immutable once wired** — it is the server name
305
+ and tool prefix every host depends on. `haven`, `signer` and `signer-*` are
306
+ refused, because their derived names would collide with another pair's.
307
+
308
+ > A current connector reports the resolved server name (`haven`, or
309
+ > `haven-<slug>`) to Haven at registration, and the dashboard shows it on each
310
+ > agent, so you can match an agent to its config entry without leaving the
311
+ > browser ([#1878](https://github.com/d-hinders/Haven-AI/issues/1878)). It is a
312
+ > label, not authority — nothing keys off it.
313
+ >
314
+ > Agents connected before that shipped read **"MCP name not recorded"**: Haven
315
+ > genuinely does not know, and guessing would name the wrong pair for anyone who
316
+ > used `--name`. They keep working exactly as they are; `--doctor` on the machine
317
+ > still maps them, and reconnecting records the name.
318
+
319
+ ## Replacing an agent's signing key (`--rekey`)
320
+
321
+ If an agent's signing key is lost or exposed, replace it: same agent, same name,
322
+ same history, new key. This does **not** create a new agent, and it is not the
323
+ same as running setup again.
324
+
325
+ Re-key is authorised by the **account owner in the dashboard** — the connector
326
+ never calls Haven's re-key endpoints, which refuse an agent credential by
327
+ design. So it runs in two phases with the dashboard between them:
328
+
329
+ ```sh
330
+ # 1. On this machine: generate the new key, print its public address.
331
+ npx -y @haven_ai/connect@alpha --rekey [--name research]
332
+
333
+ # 2. In the dashboard: agent → Replace signing key → paste that address.
334
+ # Sign the steps. It shows a new API key ONCE.
335
+
336
+ # 3. Back here: write the new credentials and rewire this agent's MCP pair.
337
+ npx -y @haven_ai/connect@alpha --rekey-finish --api-key sk_agent_... \
338
+ --runtime claude-code [--name research]
339
+ ```
340
+
341
+ **Phase one prints the exact phase-two command — prefer it over the line above.**
342
+ Since [#2423](https://github.com/d-hinders/Haven-AI/issues/2423) the connector
343
+ builds that command from the npm dist-tag **it** was published under, so a build
344
+ installed from a non-production channel tells you to finish with that same
345
+ channel rather than sending you to production mid-re-key. `@alpha` here is the
346
+ production channel and is right for a production install; it is not right for
347
+ every install, which is why the tool computes it and this page cannot.
348
+
349
+ Between the two phases nothing has changed: the agent keeps working on its old
350
+ key until you finish. Phase one refuses up front what the backend would refuse
351
+ anyway — a legacy-rail account, a revoked agent — so you find out before signing
352
+ anything. Phase two refuses to write unless the pasted key authenticates,
353
+ belongs to **this** agent, and Haven's recorded signing address matches the one
354
+ this machine generated.
355
+
356
+ **Pass `--runtime` on the finish step.** Your API key lives inside the MCP config
357
+ as well as in the credential files, so without it the credentials are correct and
358
+ every wired host still presents the retired key and fails with 401.
359
+
360
+ **Then restart every long-lived host** — not just the one in front of you. Each
361
+ long-running process loaded its wiring at startup and is still holding the old
362
+ key. The connector prints the exact restart command for your runtime; the sweep
363
+ across the rest is yours.
364
+
365
+ > **If the key is lost, check for a balance on it first.** An agent's delegate
366
+ > address can hold a small amount from x402 settlement, and sweeping it needs a
367
+ > signature from that key. After a re-key it is unrecoverable — by you and by
368
+ > Haven. Haven's preflight reads the balance and refuses until you say what
369
+ > happened to it. Full detail:
370
+ > [Replacing an agent's signing key](../../docs/product/agent-key-rotation.md).
371
+
372
+ ## Diagnosing a stuck setup: `--doctor` / `--repair` (#1589)
373
+
374
+ ```bash
375
+ npx @haven_ai/connect@alpha --doctor --runtime codex-desktop
376
+ npx @haven_ai/connect@alpha --doctor --repair --runtime codex-desktop
377
+ ```
378
+
379
+ `--doctor` is read-only and needs NO setup token: it checks the runtime config,
380
+ the agent credential files, the pinned signer runtime install, the hosted MCP
381
+ (authorized `tools/list`), and starts the local signer for a real stdio
382
+ handshake — reporting its advertised compat versions. Every failing check
383
+ prints one concrete repair action; the exit code is non-zero on any failure.
384
+ Add `--json` for a machine-readable report. No secret material is ever
385
+ printed.
386
+
387
+ `--doctor` also probes every OTHER agent credential directory it did not
388
+ select (#1688). A re-run of setup mints a NEW agent and retires nothing, so
389
+ a directory from a previous setup can hold an API key that still
390
+ authenticates — meaning any host that started before the re-run keeps
391
+ spending as the agent you believe you replaced. A superseded directory
392
+ whose key is still live is a FAILING check naming the agent id, with the
393
+ repair spelled out: revoke it on the Haven agent page, then remove the
394
+ directory. An already-revoked one reports as informational; an unreachable
395
+ probe is a note, never a verdict. Connect never revokes or deletes
396
+ credentials itself — it reports, you decide. The setup completion output
397
+ names superseded agents the moment they are created, for the same reason.
398
+ One honest limit: "newest" is decided by file mtime, so a restored backup or
399
+ a sync tool that rewrites timestamps can make doctor examine the wrong
400
+ directory as current — before revoking anything, confirm the agent id
401
+ against the Haven agent page, which is the authority on which agent is
402
+ which.
403
+
404
+ `--repair` re-runs what setup already owns — reinstall the pinned signer
405
+ runtime, rewrite the wrapper + sidecar, and re-write the runtime config from
406
+ the STORED credentials. It never touches keys and never needs a new token.