@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 +406 -0
- package/dist/cli.cjs +5164 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +15 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.js +5156 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +5203 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +902 -0
- package/dist/index.d.ts +902 -0
- package/dist/index.js +5166 -0
- package/dist/index.js.map +1 -0
- package/package.json +70 -0
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.
|