Design Philosophy
The Padded Cell
Clawker creates a “padded cell” for AI coding agents. Clawker uses Docker-like commands to build, bootstrap, and orchestrate infrastructure and isolated devcontainers that protect everything outside the container from what happens inside.What We Protect
- Host filesystem — from container writes (bind mounts controlled)
- Host network — via firewall (outbound controlled, inbound open)
- Other Docker resources — via label-based isolation
- The container itself — is disposable; a new one can always be created
Core Concepts
Project
A project is defined by.clawker.yaml and registered in the project registry (registry.yaml in the data dir, e.g. ~/.local/share/clawker/registry.yaml). Every Clawker command requires project context, resolved via longest-prefix path matching against the registry.
Configuration precedence (highest to lowest):
- CLI flags
- Environment variables
- Project config (
./.clawker.yaml) - User settings (
~/.config/clawker/settings.yaml)
Agent
An agent is a named container instance. One project can have multiple agents, each running in its own isolated container. Naming convention:clawker.<project>.<agent> (e.g., clawker.myapp.dev)
Resource Identification
| Mechanism | Purpose | Authority |
|---|---|---|
| Labels | Filtering, ownership verification | Authoritative source of truth |
| Naming | Human readability | Secondary |
| Network | Container communication, isolation | Functional |
dev.clawker.managed=true, even if they have the clawker. name prefix.
Security Model
Defaults
| Setting | Default | Rationale |
|---|---|---|
| Firewall | Enabled | Blocks outbound except allowlisted domains |
| Docker socket | Disabled | Container cannot control Docker |
| Git credentials | Forwarded | Agent access only — keys stay on host |
Credential Handling
- API keys passed via environment variables
- Subscription users authenticate via the host proxy (OAuth callback interception)
- Git HTTPS credentials forwarded through the host proxy
- SSH keys forwarded via agent socket (never copied)
Firewall
The firewall is deny-by-default. Outbound TCP is redirected to an Envoy egress proxy via eBPF cgroup programs (attached to each agent container’s cgroup from outside, by the clawker control plane). DNS is redirected to a custom CoreDNS that returns NXDOMAIN for any domain not in the allowlist. Allowed domains are configured per project (security.firewall in .clawker.yaml) and merged with a minimal hardcoded system list (Anthropic API, OAuth, telemetry). See the Firewall guide for the full design.
Control Plane
The clawker control plane (cmd/clawker-cp, PID 1 of the clawker-controlplane container) is the authoritative supervisor. It owns the firewall lifecycle, eBPF program lifetime, agent identity registry, and the mTLS Session over which it dispatches in-container commands to clawkerd. CP is not the firewall — it is the host-level daemon that, among other things, manages the firewall. The Ory stack (Hydra, Kratos, Oathkeeper) runs as subprocesses inside CP; the CLI exchanges OAuth2 tokens with Hydra and calls AdminService gRPC over mTLS for every privileged operation. See Control Plane for the user-facing guide and Container Internals → clawkerd for the in-container counterpart.
Egress Observability
Every firewall decision —allowed, denied, or bypassed — emits a structured OTLP log record from the netlogger subsystem. Records carry container attribution, the destination 4-tuple, and the resolved domain when available; they land in the clawker-ebpf-egress OpenSearch index (service.name=ebpf-egress) on the trusted infra OTLP lane. The headline guarantee is that bypass mode (clawker firewall bypass) is no longer a forensic blind spot — bypassed traffic still produces a per-decision record even though it skips Envoy and CoreDNS enforcement. See Egress Observability for the record shape and per-attribute reference.
Key Design Decisions
- All Docker SDK calls go through
pkg/whail— never bypass this isolation layer - Labels are authoritative —
dev.clawker.managed=truedetermines ownership, not names - stdout for data, stderr for status — enables scripting and composability
- Factory DI pattern — pure struct in
cmdutil, constructor incmd/factory, Options in commands - Stateless CLI — all state lives in Docker (containers, labels, volumes); no local state files
config.Configis a gateway — lazy accessor for Project, Settings, Resolution, Registry- zerolog is file-only — user-visible output uses
fmt.Fprintfto IOStreams
State Management
Clawker stores no local state. All state lives in Docker:- Container state (running, stopped)
- Labels (project, agent, metadata)
- Volumes (workspace, config, history)
Command Taxonomy
Commands mirror Docker’s CLI structure:| Pattern | Examples |
|---|---|
clawker <verb> | run, stop, build |
clawker <noun> <verb> | container ls, volume rm, image build |
init, build, run, start, generate, monitor *, version
Management commands: container, volume, network, image, project, worktree, firewall, controlplane, auth, settings, skill
Multi-Agent Operations
- One project has many agents
- Many agents can share one image
- Race condition resolution: second process attaches to existing container (no error, no duplicate)
Error Handling
Errors return typed values toMain() for centralized rendering:
fmt.Errorf(...)— general errorscmdutil.FlagError— triggers usage displaycmdutil.SilentError— already displayed, just exit non-zero