Architecture
A capsule (what the agent is) and an adapter (how to run it) combine through nix build into a deployable artifact. The artifact gets deployed with secrets injected, and the agent goes live.

Capsule
Section titled “Capsule”A capsule is a Git repo containing a single flake.nix. It declares the agent’s identity — name, system prompt, model, provider, transports — without knowing anything about how the agent will be run.
agent = { name = "Ada"; system-prompt = "You are Ada, a helpful assistant."; provider = "claude-code"; model = "sonnet"; transports.telegram = {};};The capsule imports an adapter as a flake input. It calls lib.mkAgent { agent = { ... }; } and the adapter produces a deployable artifact — a Docker image, a VPS service, or whatever the target platform needs.
Adapter
Section titled “Adapter”An adapter is a Nix flake that exports lib.mkAgent. It takes the universal agent config and translates it into whatever the target runtime needs — config files, environment variables, entrypoint scripts.
Each adapter lives in its own repo:
- adapter-claude — wraps Claude Code CLI with a bash Telegram long-poll loop
- adapter-zeroclaw — generates TOML config for the ZeroClaw Rust runtime
The adapter interface is simple: lib.mkAgent { agent } returns a Nix attribute set with deployable outputs.
Runtime
Section titled “Runtime”The runtime is the LLM backend that actually runs the agent. Reflection doesn’t implement runtimes — it integrates them. Current runtimes:
- Claude Code CLI — Anthropic’s CLI tool, used via
adapter-claude - ZeroClaw — open-source Rust binary with built-in tools, used via
adapter-zeroclaw
Runtimes are a replaceable detail. When a better runtime appears, you write a new adapter and switch with one line in flake.nix.
Data flow
Section titled “Data flow”The capsule and adapter combine at build time. Secrets are injected at deploy time:
nix build— capsule config + adapter logic → deployable artifact (e.g. Docker image)- Deploy — artifact runs with secrets injected (API keys, bot tokens via env vars or config generation)
- Runtime starts, connects to transports, answers messages
Secrets are never baked into the artifact. They’re injected at deploy time via environment variables or config file generation.
Switching adapters
Section titled “Switching adapters”Changing which runtime powers your agent is a one-line change in flake.nix:
# Before: Claude Code backendinputs.adapter.url = "github:reflection-network/adapter-claude";
# After: ZeroClaw backendinputs.adapter.url = "github:reflection-network/adapter-zeroclaw";Same agent identity, different plumbing.
Dev workflow
Section titled “Dev workflow”The dev launcher automates the build-deploy cycle:
- Launcher polls the capsule’s Git repo for changes
- On new commits, creates a worktree for the new revision
- Runs
nix buildto produce a Docker image - Stops the old container, starts the new one
- Agent is live with the updated config
Schema design
Section titled “Schema design”The agent config schema lives in agent.nix. Design principles:
- Required fields are minimal:
nameandsystem-promptonly - Optional fields grow from real needs:
provider,model, andtransportswere added when the second adapter needed them - Backward compatible: new optional fields don’t break existing capsules
- No speculative fields: nothing gets added until running code needs it