Problem
Two related issues with daemon session storage:
1. No keychain support on capable machines
The daemon (agentkeys-daemon) always stores its child session as a plain file at ~/.agentkeys/session (mode 0600). The CLI (agentkeys-cli) uses the OS keychain by default with file fallback.
The spec assumes "daemon = Docker/cloud sandbox = no keychain," but daemons also run on:
- Mac mini (macOS Keychain available)
- Another MacBook (macOS Keychain available)
- Raspberry Pi (Linux secret-service / gnome-keyring available)
In these cases, plain file storage is unnecessarily weak.
2. Multiple daemons on one machine collide
All daemons write to the same path: ~/.agentkeys/session. Running two agent daemons on the same Mac mini means the second daemon overwrites the first's session token. This breaks the multi-agent isolation use case the spec explicitly requires:
"explicit (needed if multiple agents are attached to the same machine)" -- 1-step-analysis.md:221
"Multi-agent isolation E2E: two agents, each with different credentials, scope enforcement verified" -- development-stages.md:623
The multi-agent demo (Demo 1) requires N agents on one host, each with independent sessions and scoped credentials.
Current behavior
| Binary |
Session storage |
Keychain |
Multi-instance |
agentkeys-cli |
Keychain-first, file fallback |
Yes (keyring crate, 2s timeout) |
N/A (single master) |
agentkeys-daemon |
Plain file only |
No |
Broken (all write to same path) |
Proposed fix
Wallet-based session isolation
Use the wallet address to namespace sessions. Each daemon gets its own storage slot:
| Role |
Keychain entry |
File fallback |
| Master (CLI) |
service=agentkeys, account=master |
~/.agentkeys/master/session.json |
| Daemon (per agent) |
service=agentkeys, account=daemon-<wallet> |
~/.agentkeys/daemon-<wallet>/session.json |
This supports:
- One master + one daemon on a laptop (current use case)
- One master + N daemons on a Mac mini (multi-agent use case)
- N daemons, no master on a cloud VM (headless multi-agent)
Step 1: Move session_store to agentkeys-core
Move session_store.rs from agentkeys-cli to agentkeys-core so both CLI and daemon share the same keychain-first, file-fallback logic.
The shared module should accept a session_id: &str parameter to distinguish entries:
pub fn save_session(session: &Session, session_id: &str) -> Result<()>
pub fn load_session(session_id: &str) -> Result<Session>
Keychain entry: service=agentkeys, account=<session_id>
File fallback: ~/.agentkeys/<session_id>/session.json
Step 2: Update CLI to use named session
session_store::save_session(&session, "master")?;
session_store::load_session("master")?;
Step 3: Update daemon to use wallet-based session
The daemon learns its wallet after pairing/recovery. Before that, it uses a temp session ID, then renames after wallet is known:
// After pair/recover completes and wallet is known:
session_store::save_session(&session, &format!("daemon-{}", wallet.0))?;
For --recover <identity>, the daemon can pre-resolve the wallet via identity lookup and use it from the start.
Step 4: Env var override
The AGENTKEYS_SESSION_STORE=file env var continues to force file-only mode for CI/Docker/headless environments.
Affected deployment environments
| Environment |
Keychain available |
Multi-daemon |
Expected behavior |
| macOS (MacBook, Mac mini) |
Yes (macOS Keychain) |
Yes |
Keychain with wallet-based accounts |
| Linux desktop (Raspberry Pi with GUI) |
Yes (gnome-keyring / KDE Wallet) |
Yes |
secret-service via keyring crate |
| Linux server (headless) |
No |
Yes |
File fallback with wallet-based paths |
| Docker container |
No |
One per container |
File fallback |
| Cloud LLM sandbox |
No |
One per sandbox |
File fallback |
| CI (GitHub Actions) |
No |
N/A |
File fallback via AGENTKEYS_SESSION_STORE=file |
Documentation updates
docs/spec/architecture.md -- update daemon session storage to reflect keychain-first + wallet-based isolation
wiki/key-security.md -- update storage table, document session naming scheme
docs/manual-test-stage4.md -- add test cases: (1) daemon keychain on macOS, (2) master + daemon coexistence, (3) two daemons on same machine
docs/spec/plans/development-stages.md -- note as Stage 4 hardening item
Context
- CLI session store:
crates/agentkeys-cli/src/session_store.rs (keychain-first pattern to reuse)
- Daemon session store:
crates/agentkeys-daemon/src/session.rs (file-only, needs upgrade)
- Security spec:
wiki/key-security.md
- Multi-agent isolation:
docs/spec/1-step-analysis.md:221, docs/spec/plans/development-stages.md:623
Problem
Two related issues with daemon session storage:
1. No keychain support on capable machines
The daemon (
agentkeys-daemon) always stores its child session as a plain file at~/.agentkeys/session(mode 0600). The CLI (agentkeys-cli) uses the OS keychain by default with file fallback.The spec assumes "daemon = Docker/cloud sandbox = no keychain," but daemons also run on:
In these cases, plain file storage is unnecessarily weak.
2. Multiple daemons on one machine collide
All daemons write to the same path:
~/.agentkeys/session. Running two agent daemons on the same Mac mini means the second daemon overwrites the first's session token. This breaks the multi-agent isolation use case the spec explicitly requires:The multi-agent demo (Demo 1) requires N agents on one host, each with independent sessions and scoped credentials.
Current behavior
agentkeys-clikeyringcrate, 2s timeout)agentkeys-daemonProposed fix
Wallet-based session isolation
Use the wallet address to namespace sessions. Each daemon gets its own storage slot:
service=agentkeys, account=master~/.agentkeys/master/session.jsonservice=agentkeys, account=daemon-<wallet>~/.agentkeys/daemon-<wallet>/session.jsonThis supports:
Step 1: Move session_store to agentkeys-core
Move
session_store.rsfromagentkeys-clitoagentkeys-coreso both CLI and daemon share the same keychain-first, file-fallback logic.The shared module should accept a
session_id: &strparameter to distinguish entries:Keychain entry:
service=agentkeys, account=<session_id>File fallback:
~/.agentkeys/<session_id>/session.jsonStep 2: Update CLI to use named session
Step 3: Update daemon to use wallet-based session
The daemon learns its wallet after pairing/recovery. Before that, it uses a temp session ID, then renames after wallet is known:
For
--recover <identity>, the daemon can pre-resolve the wallet via identity lookup and use it from the start.Step 4: Env var override
The
AGENTKEYS_SESSION_STORE=fileenv var continues to force file-only mode for CI/Docker/headless environments.Affected deployment environments
keyringcrateAGENTKEYS_SESSION_STORE=fileDocumentation updates
docs/spec/architecture.md-- update daemon session storage to reflect keychain-first + wallet-based isolationwiki/key-security.md-- update storage table, document session naming schemedocs/manual-test-stage4.md-- add test cases: (1) daemon keychain on macOS, (2) master + daemon coexistence, (3) two daemons on same machinedocs/spec/plans/development-stages.md-- note as Stage 4 hardening itemContext
crates/agentkeys-cli/src/session_store.rs(keychain-first pattern to reuse)crates/agentkeys-daemon/src/session.rs(file-only, needs upgrade)wiki/key-security.mddocs/spec/1-step-analysis.md:221,docs/spec/plans/development-stages.md:623