Design Philosophy
The Padded Cell
Clawker creates a “padded cell” for AI coding agents. Standard Docker gives users full control — dangerous for autonomous AI agents. Clawker wraps Docker-like commands with isolation that protects 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 byclawker.yaml and registered in the project registry (~/.local/clawker/projects.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 (
~/.local/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 init script blocks all outbound traffic by default, then allowlists specific domains. IP range sources fetch CIDR blocks from cloud provider APIs for services like GitHub.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, config check, monitor *, loop *, version
Management commands: container, volume, network, image, project, worktree
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