Architecture
The in-front design. kaged is the long-lived parent. Everything else is a capability it supervises.
In front, not inside.
kaged sits in front of adjacent operator tooling — not inside it, not beside it. Adjacent tools are things kaged can call, install, or expose. Not bases. Not parents. Not peers.
┌─────────────────────────────┐ │ browser / mobile (web ui) │ └──────────────┬──────────────┘ │ [https/wss] │ ┌──────────────┴──────────────┐ │ cloudflare tunnel │ └──────────────┬──────────────┘ │ ┌──────────────┴──────────────┐ │ oauth2 sidecar (workspace)│ └──────────────┬──────────────┘ │ ╔══════════════════════════════════╧═══════════════════════════════════╗ ║ kaged daemon ║ ║ ┌──────────────────────────────────────────────────────────────────┐ ║ ║ │ http/ws api · session mgr · pty broker · dsl runtime │ ║ ║ │ primary agent orchestrator · subagent supervisor · plugins │ ║ ║ └──────────────────────────────────────────────────────────────────┘ ║ ╚════╤══════════╤══════════╤══════════╤══════════╤══════════╤══════════╝ │ │ │ │ │ │ [llm api] [pty] [sandbox] [plugin] [storage] [tunnel] claude/ bash/ bwrap/ oh-my-pi sqlite cloudflared openai/ tmux firejail ollama (postgres) api local podman custom
↳ Read top-to-bottom: operator → tunnel → auth → kaged → things kaged supervises.
Six moving parts.
Each component has a spec. Each spec was written before the code. The boundaries are intentional.
A real session, end to end.
One task, traced from the operator's phone through the daemon and back.
-
OPERATOR (PHONE)
"scrape the new bandcamp releases and prep a deploy" —
POST /api/projects/music-site/messages - DAEMON Routes to session "music-site/active". Persists message. Returns 202.
- SESSION MANAGER Primary agent loaded with project DSL context. Model + system prompt + subagent topology resolved.
-
PRIMARY AGENT
Decides: dispatch to
scrapersubagent. Calls subagent.invoke(name="scraper"). - SUPERVISOR Loads cage config from DSL. Spawns scraper in bwrap with allowlist. Streams stdout/stderr to daemon.
- SCRAPER SUBAGENT Hits bandcamp via cage's net allowlist. Writes results. Emits event "found_release".
-
DSL INTERCONNECT
scraper→deployeron found_release. Supervisor enqueues deployer invocation. - DEPLOYER SUBAGENT Spawned in its own cage. Network scoped to k3s.local:6443. Begins deploy prep.
- OPERATOR (LAPTOP) Reopens browser on laptop. Reattaches to session — full transcript replayed via WebSocket. Hits ⏸ to inspect. Edits the plan. Hits ▶ resume.
↳ The session survived the operator switching devices.
↳ The cage prevented scraper from touching anything outside its allowlist.
↳ The debug pause was operator-initiated, not model-initiated.
Concentric rings.
Each ring is a boundary. Crossing a ring requires explicit policy. Subagents do not get host-level capabilities.
The daemon does not directly expose itself to the internet — the tunnel and the OAuth sidecar mediate. Everything below kaged is a capability. Everything above is access.
Intentionally not in v0.
These are not oversights. They're explicitly deferred with significant access-control implications.