@haven_ai/connect 0.1.28-alpha.0 → 0.1.30-alpha.0

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
@@ -52,6 +52,57 @@ spending authority.
52
52
  `haven_get_allowances` tools to confirm the Haven wallet and live budget.
53
53
  Do not sign, fund, or create a payment to verify setup.
54
54
 
55
+ ### `--doctor` reports every agent, not just one (#1697)
56
+
57
+ With several agents wired into one runtime (`--name`), the doctor enumerates
58
+ every credential directory on the machine and classifies each one:
59
+
60
+ | Classification | Meaning |
61
+ | --- | --- |
62
+ | `wired` | Its MCP pair is present in this runtime's config. Fully checked. |
63
+ | `superseded` | It holds credentials, but no config entry points at it. Reported, never silently skipped — its API key may still spend. |
64
+ | `retired` | Tombstoned (see below); key material removed. |
65
+ | `orphaned` | No usable identity and no tombstone. |
66
+
67
+ The exit code is non-zero if **any** wired agent fails **any** check — not
68
+ only the one the report's main section describes. In `--json`, the same
69
+ information is on `agents[]`, each entry carrying `slug`, `agentId`,
70
+ `directory`, `classification` and its own `checks[]`; the flat `checks` array
71
+ is retained and still describes one agent, so a single-agent install reads as
72
+ it always did.
73
+
74
+ One check is worth calling out: **`identity_match`** compares the agent the
75
+ stored API key actually authenticates as against the `delegate_address` in
76
+ that directory's `signer.json`. A mismatch means the runtime would quote as
77
+ one agent and sign as another, and it fails hard. This is the half of that
78
+ hazard a local tool can know — the doctor still cannot see inside an
79
+ already-running host, which is why the restart guidance below matters.
80
+
81
+ ## Retiring an old agent directory
82
+
83
+ Re-running setup creates a NEW agent and retires nothing. Long-lived MCP hosts
84
+ (gateways, TUI workers, editors, desktop apps) load their MCP wiring once, at
85
+ process start — a host started before your latest setup keeps spawning the OLD
86
+ agent's signer path forever, and when that directory is later removed the spawn
87
+ failure surfaces only as a masked "Connection closed" retried every few
88
+ minutes. Two rules follow:
89
+
90
+ 1. **Restart EVERY long-lived host after a setup or retirement, not just one.**
91
+ Each process holds the snapshot from its own start time, so after a chain of
92
+ re-setups each host can be parked on a *different* old agent.
93
+ 2. **Tombstone a directory before (or instead of) deleting it:**
94
+
95
+ ```
96
+ npx @haven_ai/connect@alpha --tombstone ~/.haven/agents/<id> --reason "superseded"
97
+ ```
98
+
99
+ This replaces the directory's signer wrapper with a diagnostic that logs the
100
+ retirement (agent id, date, reason, restart guidance) to the host's MCP
101
+ stderr log on every probe, and records it in `TOMBSTONE.json` for
102
+ `--doctor`. It touches no key material and revokes nothing — revoke the
103
+ agent on the Haven agent page yourself. Delete the tombstone only once every
104
+ long-lived host has been restarted.
105
+
55
106
  ### Structured output for automation
56
107
 
57
108
  Pass `--json` when a launcher needs a machine-readable completion record. Connect
@@ -124,16 +175,104 @@ already-configured machine behaves as follows (characterized in
124
175
  - **Runtime MCP entries are replaced, not duplicated**: Connect owns the
125
176
  `haven` and `haven-signer` entries (and the managed Codex/Hermes
126
177
  equivalents) and re-points them at the newest agent's credentials.
127
- Unrelated MCP servers and configuration are preserved. One runtime is
128
- therefore wired to one Haven agent — the newest one.
178
+ Unrelated MCP servers and configuration are preserved. Without `--name`, one
179
+ runtime is therefore wired to one Haven agent — the newest one. With
180
+ `--name`, each agent owns its own suffixed pair and they coexist; see
181
+ [Running several agents in one runtime](#running-several-agents-in-one-runtime).
129
182
  - **The previous agent is not revoked by a re-run.** Its credentials remain on
130
183
  disk and its authority remains whatever its on-chain rules say. Revoke
131
184
  agents you no longer use from the Haven dashboard, then delete their
132
185
  credential directories.
133
- - **Connect never overwrites an existing credential file.** A write that would
186
+ - **A re-run never overwrites an existing credential file.** A write that would
134
187
  collide with an existing `identity.json`/`signer.json`/`agent.json` is
135
188
  refused outright (and a partially failed write rolls itself back), so a
136
- re-run cannot corrupt stored key material.
189
+ re-run cannot corrupt stored key material. **`--rekey` is the one exception,
190
+ and it is a different operation** — it deliberately replaces a credential set
191
+ in place, at an unchanged path, and is the supported way to replace a key
192
+ rather than accumulate agents. See
193
+ [Replacing an agent's signing key](#replacing-an-agents-signing-key-rekey).
194
+
195
+ ## Running several agents in one runtime
196
+
197
+ `--name <slug>` gives an agent its own MCP server pair and its own credential
198
+ directory, so several agents coexist in one runtime instead of replacing each
199
+ other:
200
+
201
+ ```sh
202
+ npx -y @haven_ai/connect@alpha --setup hv_setup_... --api https://api.haven.example \
203
+ --name research --runtime claude-code
204
+ ```
205
+
206
+ | | Without `--name` | With `--name research` |
207
+ |---|---|---|
208
+ | MCP entries | `haven`, `haven-signer` | `haven-research`, `haven-signer-research` |
209
+ | Credentials | `~/.haven/agents/<agent-id>/` | `~/.haven/agents/research/` |
210
+
211
+ A writer only ever touches the pair it owns, so adding a named agent cannot
212
+ disturb the bare pair or another named one. Omitting `--name` is byte-identical
213
+ to how the connector behaved before named pairs existed, so nothing already
214
+ wired needs changing.
215
+
216
+ The slug is **1–32 lowercase letters, digits and single hyphens**, validated
217
+ before anything is written, and **immutable once wired** — it is the server name
218
+ and tool prefix every host depends on. `haven`, `signer` and `signer-*` are
219
+ refused, because their derived names would collide with another pair's.
220
+
221
+ > A current connector reports the resolved server name (`haven`, or
222
+ > `haven-<slug>`) to Haven at registration, and the dashboard shows it on each
223
+ > agent, so you can match an agent to its config entry without leaving the
224
+ > browser ([#1878](https://github.com/d-hinders/Haven-AI/issues/1878)). It is a
225
+ > label, not authority — nothing keys off it.
226
+ >
227
+ > Agents connected before that shipped read **"MCP name not recorded"**: Haven
228
+ > genuinely does not know, and guessing would name the wrong pair for anyone who
229
+ > used `--name`. They keep working exactly as they are; `--doctor` on the machine
230
+ > still maps them, and reconnecting records the name.
231
+
232
+ ## Replacing an agent's signing key (`--rekey`)
233
+
234
+ If an agent's signing key is lost or exposed, replace it: same agent, same name,
235
+ same history, new key. This does **not** create a new agent, and it is not the
236
+ same as running setup again.
237
+
238
+ Re-key is authorised by the **account owner in the dashboard** — the connector
239
+ never calls Haven's re-key endpoints, which refuse an agent credential by
240
+ design. So it runs in two phases with the dashboard between them:
241
+
242
+ ```sh
243
+ # 1. On this machine: generate the new key, print its public address.
244
+ npx -y @haven_ai/connect@alpha --rekey [--name research]
245
+
246
+ # 2. In the dashboard: agent → Replace signing key → paste that address.
247
+ # Sign the steps. It shows a new API key ONCE.
248
+
249
+ # 3. Back here: write the new credentials and rewire this agent's MCP pair.
250
+ npx -y @haven_ai/connect@alpha --rekey-finish --api-key sk_agent_... \
251
+ --runtime claude-code [--name research]
252
+ ```
253
+
254
+ Between the two phases nothing has changed: the agent keeps working on its old
255
+ key until you finish. Phase one refuses up front what the backend would refuse
256
+ anyway — a legacy-rail account, a revoked agent — so you find out before signing
257
+ anything. Phase two refuses to write unless the pasted key authenticates,
258
+ belongs to **this** agent, and Haven's recorded signing address matches the one
259
+ this machine generated.
260
+
261
+ **Pass `--runtime` on the finish step.** Your API key lives inside the MCP config
262
+ as well as in the credential files, so without it the credentials are correct and
263
+ every wired host still presents the retired key and fails with 401.
264
+
265
+ **Then restart every long-lived host** — not just the one in front of you. Each
266
+ long-running process loaded its wiring at startup and is still holding the old
267
+ key. The connector prints the exact restart command for your runtime; the sweep
268
+ across the rest is yours.
269
+
270
+ > **If the key is lost, check for a balance on it first.** An agent's delegate
271
+ > address can hold a small amount from x402 settlement, and sweeping it needs a
272
+ > signature from that key. After a re-key it is unrecoverable — by you and by
273
+ > Haven. Haven's preflight reads the balance and refuses until you say what
274
+ > happened to it. Full detail:
275
+ > [Replacing an agent's signing key](../../docs/product/agent-key-rotation.md).
137
276
 
138
277
  ## Diagnosing a stuck setup: `--doctor` / `--repair` (#1589)
139
278
 
@@ -150,6 +289,23 @@ prints one concrete repair action; the exit code is non-zero on any failure.
150
289
  Add `--json` for a machine-readable report. No secret material is ever
151
290
  printed.
152
291
 
292
+ `--doctor` also probes every OTHER agent credential directory it did not
293
+ select (#1688). A re-run of setup mints a NEW agent and retires nothing, so
294
+ a directory from a previous setup can hold an API key that still
295
+ authenticates — meaning any host that started before the re-run keeps
296
+ spending as the agent you believe you replaced. A superseded directory
297
+ whose key is still live is a FAILING check naming the agent id, with the
298
+ repair spelled out: revoke it on the Haven agent page, then remove the
299
+ directory. An already-revoked one reports as informational; an unreachable
300
+ probe is a note, never a verdict. Connect never revokes or deletes
301
+ credentials itself — it reports, you decide. The setup completion output
302
+ names superseded agents the moment they are created, for the same reason.
303
+ One honest limit: "newest" is decided by file mtime, so a restored backup or
304
+ a sync tool that rewrites timestamps can make doctor examine the wrong
305
+ directory as current — before revoking anything, confirm the agent id
306
+ against the Haven agent page, which is the authority on which agent is
307
+ which.
308
+
153
309
  `--repair` re-runs what setup already owns — reinstall the pinned signer
154
310
  runtime, rewrite the wrapper + sidecar, and re-write the runtime config from
155
311
  the STORED credentials. It never touches keys and never needs a new token.