Context
Today agentkeys wire plants the agent's LLM key from the operator's OPENROUTER_API_KEY env var (harness/phase1-wire-demo.sh:1072 writes it into ~/.hermes/.env + hermes config set model.*). That's a demo shortcut, not the design. The real guarantee is: the agent uses the key the master authorized it to fetch from the master's vault — never an ambient operator env var. This issue builds that path.
It's the agent-side complement to #214 (the master-side web pairing): #214 pairs + authorizes; this issue makes the agent actually fetch + use what it was authorized. Deferred from #207. Aligns with arch.md §10.2 + docs/plan/web-flow/onboarding-classifier-distribution.md §1.1 (cred:<service> authorizes "fetch/use the credential").
The agent-side sequence (this issue)
pairing (→ #214: master claims code, registers device, grants cred:<service> + memory:<ns> scopes)
→ cred-fetch (agent fetches its AUTHORIZED LLM key from the master's vault via its cred:<service> cap — NO operator env)
→ wire hermes (plant the fetched key into Hermes' model config + integrate the authorized memory/configs + enable Hermes + openviking)
→ the surprise (the agent works, using the key + memory the master authorized — for the AI-toy case the toy backend is also a sandbox)
Scope
- Cred-fetch in the wire path — the agent fetches its authorized LLM key (
cred:<service> scope → cap-mint → STS → cred worker → S3), via the shared agentkeys-backend-client path. No new broker/worker code (the cred-fetch cap + worker exist).
- Replace the env-key write —
wire plants the vault-fetched key into Hermes (~/.hermes/.env + hermes config set model.*), instead of reading the operator's OPENROUTER_API_KEY. The operator env becomes a dev-only fallback, clearly labelled.
- Default-key selection (step 6).
- Configs integration —
wire also wires in the authorized memory namespaces (openviking memory + the injection hooks) so the agent reads the memory it was granted, same gesture.
- Demo + tests — update the wire demo to prove the agent uses a vault-fetched key (assert the agent's key == the master-authorized cred, NOT
$OPENROUTER_API_KEY); revoking the cred:<service> scope cuts the agent off.
Acceptance
- The sandbox agent runs Hermes on an LLM key fetched from the master's vault via its granted
cred:<service> scope — with no OPENROUTER_API_KEY in the operator env.
- The key + memory the agent uses are exactly what the master authorized at pairing; revoke the cred scope → the agent loses the key (next fetch denied).
- No-UI path: with no developer selection, the agent uses the master-designated default key.
- The wire demo asserts the above end-to-end (the real "surprise": the agent uses my authorized key, not the operator's env).
Out of scope
Effort
~L (agent-side wire integration: cred-fetch wiring + replace the env write + selection + configs integration + demo/tests). The cred-fetch cap, the cred worker, and the wire hooks already exist — this connects them.
References
Context
Today
agentkeys wireplants the agent's LLM key from the operator'sOPENROUTER_API_KEYenv var (harness/phase1-wire-demo.sh:1072writes it into~/.hermes/.env+hermes config set model.*). That's a demo shortcut, not the design. The real guarantee is: the agent uses the key the master authorized it to fetch from the master's vault — never an ambient operator env var. This issue builds that path.It's the agent-side complement to #214 (the master-side web pairing): #214 pairs + authorizes; this issue makes the agent actually fetch + use what it was authorized. Deferred from #207. Aligns with arch.md §10.2 +
docs/plan/web-flow/onboarding-classifier-distribution.md§1.1 (cred:<service>authorizes "fetch/use the credential").The agent-side sequence (this issue)
Scope
cred:<service>scope → cap-mint → STS → cred worker → S3), via the sharedagentkeys-backend-clientpath. No new broker/worker code (the cred-fetch cap + worker exist).wireplants the vault-fetched key into Hermes (~/.hermes/.env+hermes config set model.*), instead of reading the operator'sOPENROUTER_API_KEY. The operator env becomes a dev-only fallback, clearly labelled.--select 1(default = first / the master-set default).wirealso wires in the authorized memory namespaces (openviking memory + the injection hooks) so the agent reads the memory it was granted, same gesture.$OPENROUTER_API_KEY); revoking thecred:<service>scope cuts the agent off.Acceptance
cred:<service>scope — with noOPENROUTER_API_KEYin the operator env.Out of scope
Effort
~L (agent-side
wireintegration: cred-fetch wiring + replace the env write + selection + configs integration + demo/tests). The cred-fetch cap, the cred worker, and the wire hooks already exist — this connects them.References
onboarding-classifier-distribution.md§1.1 (cred = memory pattern;cred:<service>= fetch/use)harness/phase1-wire-demo.shPhase 4.0 (the current operator-env shortcut to replace)