Skip to content

Wire web-app agent pairing to the real claim → register → scope flow #214

@hanwencheng

Description

@hanwencheng

Context

The parent-control web app's pairing screen (apps/parent-control/app/_components/pairing.tsx) is a UI mockup, not wired to the real flow. A master can pair a real agent (e.g. the §10.2 Hermes-sandbox agent) only via the CLI harness (harness/phase1-wire-demo.sh Phase P); the web app cannot. This is the deferred "connect the agent — web-app side" follow-up from #207.

Goal: a master pairs a real agent from the parent-control web app — claim its one-time pairing code, register its device on-chain, grant its initial scope (Touch ID) — mirroring phase1-wire-demo.sh --real --webauthn, but driven from the web UI.

Current state

Works today (reusable):

  • CLI pairing — the genuine §10.2 flow (phase1-wire-demo.sh Phase P: depairP.0 agent shows a code → P.1 master claims → P.2 registerAgentDeviceP.3 setScopeWithWebauthn).
  • Agent sideagentkeys-daemon --request-pairing generates a K10 device key in the sandbox + displays the one-time pairing code.
  • Broker/v1/agent/pairing/claim (the CLI already hits it).
  • Daemon — WebAuthn / Touch ID (K11 enroll) + /v1/actors/:id/scope/grant (for existing actors).

Mock / missing:

  • pairing.tsx + App.tsx acceptPairing / refreshPairing operate on local React state (pairingRequests = useState([])); "accept · Touch ID" opens a ceremony modal with nothing real behind it.
  • The daemon ui-bridge has no /v1/agent/pairing/* routes — no claim, no poll-for-codes, no register-a-new-agent-device. Its routes cover email auth, K11 enroll, onboarding, existing-actor scope/revoke, memory/config/classify/credentials.
  • The client seam (apps/parent-control/lib/client/{types,daemon,empty}.ts) has no pairing methods.

Scope (the build)

  • Daemon ui-bridge routes for the master-side web pairing, mirroring CLI Phase P:
    • poll / accept a pairing code → broker /v1/agent/pairing/claim (P.1)
    • list awaiting-approval / retrieve pending (P.1c)
    • registerAgentDevice on-chain for the fresh device key (P.2)
    • initial scope grant via the existing WebAuthn path (P.3) — reuse setScopeWithWebauthn / the /v1/actors/:id/scope/grant machinery
  • Client methods (types.ts + daemon.ts + empty.ts stubs): listPairingRequests, acceptPairing / claimPairing.
  • Wire App.tsx: refreshPairing → real poll; acceptPairing → real claim → register → scope ceremony (replace the local-state mock).
  • Docs: split docs/operator-runbook-wire.md into Part 1 (CLI, existing) + Part 2 (web-app), and write the web-app pairing runbook.

Acceptance

  • From the parent-control web app, a master claims a real Hermes-sandbox agent's pairing code, registerAgentDevice lands on-chain, and the agent's memory:<ns> scope is granted via one Touch ID — with no CLI.
  • The agent then reads its permitted memory — the same guarantee phase1-wire-demo.sh --real --webauthn proves, but web-driven.
  • The pairing UI's requests come from a real daemon poll, not demo data; decline + the device list reflect real state.
  • A web-app pairing runbook exists; operator-runbook-wire.md is split CLI vs web.

Effort

~L (full-stack: daemon pairing routes + on-chain register glue + frontend client + wiring + runbook). The agent side, the broker claim endpoint, and WebAuthn already exist — so the bulk is the master-side web glue + on-chain register.

References


Flow clarifications (2026-06)

From the end-to-end onboarding flow review — these refine #214's scope (the master side):

  • Authorization happens at pairing. When the master claims the agent's code and grants scope (P.3), it authorizes the agent's cred:<service> + memory:<ns> scopes — including the LLM key the master previously vaulted (cred:openrouter, catalog category ai-services) and the memory namespaces the agent may read (e.g. kids / family). These are scope grants, not "config" access — DataClass::Config is master-only; the agent holds no config cap.
  • Master designates a DEFAULT LLM key at authorization. The no-UI AI-toy case has no developer selection UI on the device, so the master-set default is what the agent uses out of the box. (A developer CLI can override — --select 1, default = first.)
  • Pairing display = runtime QR. When the device has a screen, the daemon shows the pairing_code as a QR (arch.md §10.2 "DISPLAY pairing_code (QR / screen text)"). No-screen devices → send the code to a companion appdeferred (most cases covered; not a static manufacture-time package QR, so no pre-provisioning work).

Split with #216 (agent side): #214 covers the master side — claim → register → grant scope → designate the default LLM key. The agent side — pairing → cred-fetch the authorized vaulted LLM key → wire hermes plants it into Hermes + integrates the authorized memory (replacing the operator-env shortcut) — is tracked in #216 (blocked by #214). Together they are the full end-to-end "the agent uses the key + memory the master authorized."

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/brokerBroker server, cap-token issuance, OIDC issuancearea/daemonagentkeys-daemon (sidecar) workarea/identityHDKD actor tree, K-key inventory, identity ceremonyarea/uiParent-control UI, vendor onboarding portal, audit dashboardenhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions