Skip to content

feat(mobile): full hosted-agent management through owner-key routes - #201

Merged
RossHartmann merged 5 commits into
mainfrom
feat/mobile-hosted-agent-management
Oct 17, 2026
Merged

RossHartmann merged 5 commits into
mainfrom
feat/mobile-hosted-agent-management

Conversation

@RossHartmann

Copy link
Copy Markdown

Why

#198 shipped hosted-agent create and delete on the phone. Listing, live state, start/stop and edit were blocked because the server exposed them only behind Kiingo bearer-token routes. Kiingo/kiingo 4adc7ab472e2 adds owner-key routes for these. This PR makes the phone use them, so Ross can fully manage all of his hosted agents from Buzz mobile, including the ones he created on desktop.

What

Client (shared/hosted_agents/). All calls are POSTs under BUZZ_HOSTED_AGENTS_URL. Each one carries a kind-27236 proof with content buzz-provider-owner-v1.

  • /owner/agents/list. The proof has five tags in this order: action=list, provider, request, community, expires. The response must answer this exact request. Each agent's state is parsed into a snapshot: provider agent id, public key, name, provider config, instructions, profile revision, desired and observed state, last ready time and error code.
  • /owner/agents/update and /owner/agents/control (status, pause, resume, reconcile). The proof has seven tags: action, provider, request, agent=<provider_agent_id>, community, payload, expires. payload is the SHA-256 of the canonical body without the proof. It is computed with the same canonical JSON (canonical_json.dart) that matches stableBuzzHostedJSON.
  • Fresh proofs, fixed request id. The API burns each write proof after one use. Every attempt signs a new proof, while the request id stays fixed for the whole operation. A lost answer, or a replayed or expired proof, is therefore retried once, and the retry is idempotent on the API.
  • Revision conflicts (buzz_hosted_profile_revision_conflict) refresh the list. A lifecycle action then retries once against the newest revision, because pausing or resuming doesn't depend on the profile. An edit is not retried. The form adopts the new revision and asks the owner to review the change and save again.

Agents page:

  • It lists every hosted agent with its live state (Running, Starting, Updating, Paused, Needs attention, ...) plus its harness and model, using the catalog's names. Pull to refresh.
  • Tapping an agent opens its status, harness, model, last ready time and last error. The actions are Edit, Pause or Resume, Check status, Reconcile and Delete.
  • Edit reuses the create form, starting from the agent's current values. It uses the same schema rules and preflight gate, and the button reads Save.
  • Delete uses the existing confirmed delete, which is now possible for any agent because the list returns its provider_agent_id. Afterwards the phone sends what the desktop's own delete sends for every managed agent: the owner's kind:30177 tombstone and a NIP-IA 9035 retired request. The tombstone also makes desktops drop their local record. The agent's kind:0 profile is left alone, as on desktop.
  • After an edit, the kind:30177 record is republished only for agents whose record the phone itself published. Desktop-created records can carry a definition link that the phone must not overwrite.
  • The owner's non-hosted kind:30177 agents remain listed read-only.

Known limitation (server side)

A rename changes the server-side name but not the agent's kind:0 profile, so Buzz keeps showing the old name. The hosted supervisor never sets BUZZ_ACP_PROFILE_DISPLAY_NAME. buzz-acp's profile_publication.rs already republishes kind:0 when that variable is set. Passing the endpoint's display name from the supervisor would fix it.

Footprint

Validation

  • dart format --set-exit-if-changed, flutter analyze, the fork-boundary guard and the file-size check (base origin/main) all pass.
  • New test sources are in mobile/test/shared/hosted_agents/hosted_agent_management_test.dart. They cover snapshot parsing, the list proof's tags, the write proof's binding to the canonical body, re-signing a replayed proof with the same request id, and surfacing a revision conflict without retrying it. Per policy, none ran on the Mac.
  • The new routes were not called against production.

🤖 Generated with Claude Code

RossHartmann and others added 5 commits October 16, 2026 14:32
The Agents page now lists every hosted agent the owner has, desktop-created
ones included, with live state from POST /owner/agents/list. Each agent can
be paused or resumed, have its status checked, be reconciled, be edited
(name, instructions, harness and model through the same schema form and
preflight as create), and be deleted through confirmed delete, followed by
the desktop's kind:30177 tombstone and NIP-IA archive.

Writes go to /owner/agents/update and /owner/agents/control with a
buzz-provider-owner-v1 proof that binds the agent and the SHA-256 of the
canonical body. Every attempt signs a fresh single-use proof. A fixed
request id makes a retry after a lost answer, or a replayed or expired
proof, idempotent. A revision conflict refreshes the list. Lifecycle
actions then retry once on the newest revision; an edit asks the owner to
review and save again. Test sources are included; none ran locally.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Ross Hartmann <[email protected]>
@RossHartmann
RossHartmann merged commit 828439a into main Oct 17, 2026
RossHartmann pushed a commit that referenced this pull request Oct 17, 2026
…am-60de1db0

Conflict resolutions:
- iOS Xcode 27 picks (#199) and the block#7745 backport (#208) are upstream
  commits already in the 97e1f6a snapshot: take the sync side for every
  #199 path and drop both drop/upstream-present deltas.
- deny.toml: keep upstream's ignores and main's RUSTSEC-2026-0367/0368/0369;
  the sync tree pulls zip 8.6.0 via mesh-llm v0.76.2, re-audited: plugin
  manager and autoupdate still never call extract() and write plain files.
- Message Details (#205): desktop composes the host ref with the right-click
  root ref; mobile adds Details to upstream's grouped action sheet (the
  popover was removed upstream in block#8280) with a Tabler info-circle icon;
  retired-notice filtering passes agentPubkeys at upstream's new
  formatTimeline call sites.
- Hosted agents (#201): Lucide icons -> BuzzIcons (lucide removed upstream).
- Inventory: sync inventory plus main's new deltas (remote signer, guest
  alert Review, Message Details) and the merged hosted-agents delta paths.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
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