Skip to content

feat(desktop): detect durable agents managed by self-hosted harnesses - #4146

Draft
dspury wants to merge 6 commits into
block:mainfrom
Lunar-Park:pr/durable-harness-roster
Draft

feat(desktop): detect durable agents managed by self-hosted harnesses#4146
dspury wants to merge 6 commits into
block:mainfrom
Lunar-Park:pr/durable-harness-roster

Conversation

@dspury

@dspury dspury commented Aug 1, 2026

Copy link
Copy Markdown

Summary

  • add read-only durable agent roster discovery for supported self-hosted harnesses
  • expose harness-neutral candidate and result types through the Tauri and desktop API boundary
  • distinguish unsupported harnesses from host or parsing failures so callers can fall back to manual identity entry
  • bound local and SSH roster probes with output markers, non-interactive execution, and a timeout

Why

Host discovery can identify which harnesses are installed, but connecting a self-hosted agent also needs to identify the specific durable agent inside that harness. A harness may manage multiple named agents, so treating the whole harness as one agent loses the routing identity the user intends to connect.

Validation

  • cargo test --manifest-path desktop/src-tauri/Cargo.toml remote_probe::roster --lib (26 passed)
  • cargo fmt --manifest-path desktop/src-tauri/Cargo.toml --check
  • just desktop-tauri-clippy
  • cd desktop && pnpm typecheck
  • cd desktop && pnpm check

Stack

Stacked on #4144. The incremental change for this PR is commit 33a5142e4.

dspury added 6 commits July 31, 2026 14:17
Signed-off-by: dspury <demitriusspury@gmail.com>
Buzz has only ever had one answer to "where does this agent's key live" —
Buzz minted it and it is in this machine's keyring — so nothing in the code
asked. A self-hosted agent breaks that: a real agent with a real pubkey whose
secret was minted on, and never leaves, a machine the user owns. Every
lifecycle affordance Buzz offers (start, stop, deploy, tombstone, profile
republish) is predicated on holding that key.

`ConnectedAgentRecord` in `connected-agents.json`, beside `managed-agents.json`
and read by nothing else. The type carries a pubkey, a Buzz-local name, an
`~/.ssh/config` host, and an observed harness label — no key, no command, no
timeout, no auto-start flag, no pid.

Never-spawned is structural. It is not that the lifecycle paths skip these
records; it is that they cannot receive one. `load_managed_agents` — the reader
behind spawn, deploy, auto-start restore, owner-signed kind:30177 reconcile,
profile republish, and delete-with-tombstone — returns `ManagedAgentRecord`,
and a connected agent is a different type in a different file. There is no
filter to maintain and no field for a future reader to misinterpret.

An earlier cut of this got there differently: `KeyCustody { Local, Remote }` on
`ManagedAgentRecord`, plus a custody filter inside `load_managed_agents`. It
worked and it was tested, but it had three costs. It made "Buzz must not act on
this agent" a value every reader had to interpret correctly rather than a shape
they could not misuse. It required `save_managed_agents` to re-read the
connected third, because otherwise each of the dozens of existing
`load → mutate → save` sites would silently erase every connected agent — a
sharp edge that needed its own regression test. And it obliged all ~20
`ManagedAgentRecord { .. }` literals in the tree to name a custody field they
have no opinion on, which put eight already-oversized upstream files over the
desktop size ratchet.

Separating the type retires all three. `storage.rs`, `storage_tests.rs`,
`types.rs`, and `reconcile.rs` are byte-identical to upstream; the churn in the
other 23 files is gone; the erase-on-unrelated-save failure mode does not exist,
because the two stores share no payload to drop a half of. Nothing splits an
upstream file and nothing touches the ratchet.

What a type cannot state on its own is covered by cross-store tests: a
connected row does not satisfy `ManagedAgentRecord` and an owned row does not
satisfy `ConnectedAgentRecord` (which is why `host` is a plain `String` — as an
`Option` an owned row read from the wrong file would deserialize into a
connected agent that can never be probed); a connected save leaves
`managed-agents.json` byte-identical; the connected store holds nothing
key-shaped, which is what makes the ordinary non-`0o600` write correct.

Uniqueness is the one property that does not partition, so `connect` checks
both stores: one identity with a row in each would be two answers to "who is
this pubkey", and a duplicate name is ambiguous at every mention site. It also
covers the key-less definition half, whose names are just as mentionable.

Two publish paths stay cut. Connecting emits no kind:30177 — that event is the
owner asserting "I manage this agent" and is what `delete_managed_agent`
tombstones, so publishing it would let Buzz claim, and later revoke, the
directory entry for an agent it cannot restart. A self-hosted agent's directory
presence is its own replaceable kind:10100. And `disconnect_remote_agent` is
not `delete_managed_agent`: it drops Buzz's local pointer with no process stop,
no keyring delete, and no tombstone or NIP-IA archive, because those would
remove a working agent from every member picker on the relay.

Desktop surface: a Connected Agents section listing host, harness, and
reachability, with a connect dialog driven by the parsed ssh config. It renders
no start/stop control — `ConnectedAgentSummary` has no `status`, `pid`, or
`needsRestart` to render one from, which is a property of the type rather than a
rule someone has to remember.

1910 backend tests and 3782 desktop JS tests pass; fmt, clippy, tsc, biome, and
all three `pnpm check` guards are clean against base `upstream/main`.

Signed-off-by: dspury <demitriusspury@gmail.com>
(cherry picked from commit 0987111)
Signed-off-by: dspury <demitriusspury@gmail.com>
(cherry picked from commit 4a20284)
(cherry picked from commit f43c379)
Signed-off-by: dspury <demitriusspury@gmail.com>
Signed-off-by: dspury <demitriusspury@gmail.com>
Signed-off-by: dspury <demitriusspury@gmail.com>
(cherry picked from commit aa4d335)
(cherry picked from commit a3cfcad)
Signed-off-by: dspury <demitriusspury@gmail.com>
Signed-off-by: dspury <demitriusspury@gmail.com>
Signed-off-by: dspury <demitriusspury@gmail.com>
@dspury
dspury marked this pull request as ready for review August 1, 2026 17:44
@dspury
dspury requested a review from a team as a code owner August 1, 2026 17:44
@dspury
dspury marked this pull request as draft August 1, 2026 17:49
@dspury dspury changed the title Detect durable agents managed by self-hosted harnesses feat(desktop): detect durable agents managed by self-hosted harnesses Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant