Choir is a single-node control plane for coordinating LLM-backed agents operating on exclusive workspaces, with explicit authority, file-backed configuration, and no hidden autonomy.
It is designed for personal or small-team use on a single VPS/bare-metal server, prioritizing correctness, debuggability, and operational sanity over scale or abstraction.
1. Core Design Principles (Non-Negotiable)
Authority is explicit
- Configuration defines capability
- Runtime only manages lifecycle
Agents are disposable
- No memory baked into images
- No long-lived authority
- Swappable without side effects
Workspaces are durable
- Agents never move between workspaces
- Workspaces are handed between agents
Configuration is file-backed
- No runtime config mutation
- No chat-based knobs
- Restart = convergence
Root compromise is game over
- Threat model assumes host integrity
- Security focuses on preventing accidents, not miracles
2. Components
choird (Go)
User-level daemon (non-root)
The only long-running service
Responsibilities:
- Load and validate config at startup
- Manage agent lifecycle
- Enforce workspace leases
- Allocate pooled resources
- Health checks
- Policy enforcement
choir-gateway (Go, embedded in)
Conceptually separate, not necessarily a separate binary
Handles Telegram ingress/egress
Strict allowlist enforcement
Only lifecycle commands
- start agent
- stop agent
- status / health
- attach task
No configuration
No secrets
No execution
choirctl (Python)
Only admin-facing tool
Used by the human operator
Responsibilities:
- Inspect system state
- Validate configuration
- Start/stop agents
- Debug / introspect
Does not replace config files
No secrets in arguments
choir-agent (Python)
The reasoning process (LLM-facing)
No direct OS privileges
No secrets
No control-plane access
Talks only to:
- gateway
- local execution broker
choir-member (Python)
- Per-agent tool broker
- Runs as root inside the container
- Holds secrets in memory only
- Executes tools on behalf of the agent
- Enforces capability boundaries
choir-exec (Python)
- CLI used by agents to request execution
- No direct shell access
- All execution goes through choir-member
3. Configuration Model (Pre-Start Only)
All configuration must exist before choird starts.
Pooled Configuration
- Agent templates
- Telegram channel secrets
- Providers + models
- TTS providers
Agent-Specific Configuration
- Notion API key
- Git identity (name/email)
- Git credentials
Configuration properties:
- File-backed
- Immutable at runtime
- Edited only by admin
- Loaded at daemon startup
- Failure → daemon refuses to start
4. Image Model
Agent images contain capabilities only:
Included
- System packages
- Tools
- Skills (markdown or executables)
- Personality files
- Boot logic
Excluded
- Memory
- Workspaces
- Secrets
- Runtime state
Registry Rules
- Private registry
- Timestamp-only tags
- Agents may update only their own images
- Activation is explicit and manual
- No latest
5. Workspace Model
- Workspace = durable filesystem state
- Exclusively leased to one agent at a time
- Bind-mounted into agent container
- Agents never switch workspaces
- Different agents operate on the same workspace sequentially
6. Secrets & Execution
- Secrets stored as plain text files on host
- Readable only by admin / control-plane user
- Injected into agent containers at startup
- Held in memory by choir-member
- Never exposed to agent language space
- No remote shell execution via Telegram
7. Interfaces & Authority
| Interface | Capability |
|---|---|
| Config files | Define identity & capability |
| choirctl | Full admin control |
| Telegram gateway | Lifecycle only (subset of choirctl) |
| Agents | Zero control-plane authority |
Telegram commands are a strict subset of choirctl.
8. Language Choice
Go: choird + embedded gateway
(correctness, concurrency, long-running stability)
Python: choirctl, choir-exec, agents
(UX, scripting, LLM ecosystem)
All authority decisions live in Go.
