Documentation Index
Fetch the complete documentation index at: https://docs.clawker.dev/llms.txt
Use this file to discover all available pages before exploring further.
Architecture
System Overview
Clawker is a CLI tool plus two long-lived daemons — clawker-cp (the control plane, one per host) and clawkerd (one per agent container) — that together manage isolated Docker containers for AI coding agents. The CLI is the root of trust; the daemons hold the security boundary at runtime.
┌────────────────────────────────────────────────────────────────────────────┐
│ CLI Layer │
│ cmd/clawker → internal/clawker → internal/cmd/root │
│ 12 command groups, 50+ subcommands (Cobra, Factory DI) │
└──────┬──────────────────────────┬──────────────────────┬────────────────────┘
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌─────────────────────┐ ┌────────────────────────────┐
│ Container │ │ Configuration │ │ Control Plane │
│ Subsystem │ │ Subsystem │ │ (cmd/clawker-cp, PID 1 │
│ │ │ │ │ of clawker-controlplane) │
│ docker/ │ │ storage/ (engine) │ │ │
│ workspace/ │ │ config/ (project) │ │ AdminService gRPC (mTLS │
│ containerfs/ │ │ config/ (settings) │ │ + OAuth2): 13 firewall │
│ bundler/ │ │ project/ (registry) │ │ RPCs + ListAgents │
│ │ │ storeui/ (TUI edit) │ │ AgentService gRPC (mTLS): │
│ pkg/whail │ │ │ │ clawkerd Register + │
│ (engine lib) │ │ │ │ Session command channel │
└──────┬───────┘ └─────────────────────┘ │ Ory auth stack (Hydra, │
│ │ Kratos, Oathkeeper) │
▼ │ Agent sqlite registry │
moby/moby (Docker SDK) │ Overseer event bus │
│ Owns: firewall (Envoy + │
│ CoreDNS) + eBPF cgroup │
│ programs + dns_cache map │
└──────────┬─────────────────┘
│ mTLS Session
▼
┌────────────────────────────┐
│ clawkerd │
│ (PID 1 of every agent │
│ container; ENTRYPOINT) │
│ │
│ Inbound mTLS gRPC :7700 │
│ Forks user CMD with kernel-│
│ side privilege drop │
│ Two-phase orphan reaper │
│ Signal forwarding to child │
│ pgroup │
└────────────────────────────┘
The control plane is not the firewall — it is the supervisor that, among other things, owns the firewall lifecycle. See Control Plane for the user-facing CP guide and Firewall for the firewall guide.
CLI Command Structure
Commands are organized under internal/cmd/ with subpackages per subcommand:
| Command Group | Subcommands | Purpose |
|---|
container | list, run, start, stop, kill, exec, attach, logs, inspect, cp, pause, unpause, restart, rename, remove, stats, top, update, wait, create | Docker container management |
image | list, build, inspect, remove, prune | Image lifecycle |
volume | list, create, inspect, remove, prune | Volume management |
network | list, create, inspect, remove, prune | Network management |
project | init, register, list, info, edit, remove | Project registration and config |
worktree | add, list, prune, remove | Git worktree management |
firewall | status, list, add, remove, reload, up, down, enable, disable, bypass, rotate-ca | Egress firewall control (all RPCs route through f.AdminClient to the CP daemon) |
controlplane | up, down, status, agents | Break-glass control plane lifecycle + registered agent listing |
auth | rotate | CLI-side auth material (CA, server certs, OAuth2 signing key) |
monitor | init, up, down, status | Observability stack (OTel Collector, OpenSearch, OpenSearch Dashboards, Prometheus) |
settings | edit | User settings TUI editor |
skill | install, show, remove | Manage the clawker-support Claude Code plugin |
Top-level shortcuts: init → project init, build → image build, run/start → container run/start, generate, version
Shared domain logic (container creation) lives in shared/ subpackages within each command group — not in library packages.
Package Dependency Graph
Packages follow a strict DAG with no cycles. Verified via goda.
Leaf Packages (zero internal imports)
Importable by anyone. Depend only on stdlib or external libraries.
| Package | Purpose |
|---|
storage | Generic layered YAML store engine (Store[T]): discovery, merge, provenance, atomic write |
git | Git operations, worktree management (go-git) |
logger | Struct-based zerolog (file rotation + optional OTEL bridge) |
text | Pure ANSI-aware text utilities (Truncate, PadRight, StripANSI) |
term | Terminal capabilities + raw mode (sole x/term gateway) |
signals | OS signal utilities (SetupSignalContext, ResizeHandler) |
build | Build-time metadata (version, date via ldflags) |
update | Background GitHub release checker (24h cached) |
keyring | Credential storage service |
pkg/whail | Reusable Docker engine library with label-based isolation |
Foundation Packages (import leaves only)
Universally imported infrastructure. Their imports are leaf-only.
| Package | Imports | Purpose |
|---|
config | storage | Config loading/validation, schema types, path resolution. Composes Store[Project] + Store[Settings] |
iostreams | term, text | I/O streams, TTY detection, colors, styles, spinners, progress |
ebpf | logger | eBPF program loader/manager (cilium/ebpf) — pins maps and programs, attaches to container cgroups, SyncRoutes replaces the global route_map atomically |
Domain Packages (import leaves + foundation)
Core business logic. Import leaves and foundation packages only.
| Package | Imports | Purpose |
|---|
project | config, git, logger, storage, text | Project registration, worktree lifecycle, registry CRUD |
bundler | config + own subpkgs | Dockerfile generation, content hashing, semver, npm registry |
tui | iostreams, text | BubbleTea models, viewports, panels, progress display |
prompter | iostreams | Interactive prompts with TTY/CI awareness |
storeui | iostreams, storage, tui | Generic TUI editor for Store[T] instances |
controlplane | config, docker, logger, ory subprocess managers | CP daemon core: AdminService composition, Ory auth stack, startup orchestrator, agent watcher |
controlplane/agent | auth, consts, dockerevents, overseer, logger | CP-side agent surface: Dialer, sqlite Registry, Register handler, IdentityInterceptor, session/agent events |
controlplane/overseer | logger | Typed event bus + in-memory State worldview (containers + agents) |
controlplane/dockerevents | overseer, logger | Docker events feeder (reconnecting stream → typed events on overseer bus) |
controlplane/cpboot | config, docker, logger (+ embedded clawker-cp + ebpf-manager binaries) | Host-side CP lifecycle: EnsureRunning/Stop/CPRunning |
controlplane/adminclient | auth, consts | CLI-side AdminService gRPC dial (mTLS + auto-refreshing OAuth2 bearer) |
controlplane/firewall | config, docker, logger, storage, controlplane/firewall/ebpf | Firewall Handler (13 RPCs), Stack (Envoy+CoreDNS lifecycle), ActionQueue, config generators, certificate PKI, rules store |
controlplane/firewall/ebpf | logger | eBPF program loader/manager, SyncRoutes replaces global route_map atomically; break-glass ebpf-manager CLI under cmd/ |
dnsbpf | controlplane/firewall/ebpf | CoreDNS plugin that writes DNS resolutions to the BPF dns_cache map in real time (embedded in cmd/coredns-clawker) |
clawkerd | (embed only) | //go:embed assets/clawkerd — exports the per-container daemon binary; bundler drops it into every per-project image at /usr/local/bin/clawkerd |
hostproxy | config, logger | Host proxy for container-to-host communication |
socketbridge | config, logger | SSH/GPG agent forwarding via muxrpc |
containerfs | config, keyring, logger | Host config preparation for container init |
monitor | config | Observability stack templates (OTel Collector, OpenSearch, OpenSearch Dashboards, Prometheus) |
docs | config, storage | CLI documentation generation |
Composite Packages (import domain packages)
Higher-level subsystems that compose domain packages.
| Package | Key Imports | Purpose |
|---|
docker | bundler, config, pkg/whail, pkg/whail/buildkit | Clawker middleware wrapping whail with labels/naming |
workspace | config, docker, logger | Bind vs Snapshot strategies |
cmdutil | config, docker, iostreams, tui, + type imports for Factory | Factory struct (DI container), error types, arg validators |
Import Rules
OK: foundation → leaf (config → storage)
OK: domain → leaf (firewall → storage)
OK: domain → foundation (project → config)
OK: composite → domain (docker → bundler)
BAD: leaf → anything internal (storage must never import config)
BAD: foundation ↔ foundation (config must never import iostreams)
BAD: any cycle (A → B → A is always wrong)
Configuration and Storage
Three packages form the configuration subsystem:
storage (leaf) — Generic Store[T] engine. Handles file discovery (static paths + walk-up), YAML loading with migrations, N-way merge with provenance tracking, and atomic writes. Zero domain knowledge.
config — Thin domain wrapper composing Store[Project] + Store[Settings]. Exposes the Config interface with schema types, path helpers, and ~40 accessor methods.
project — Project domain layer. Owns projects.yaml registry via its own Store[ProjectRegistry]. Handles registration CRUD, path resolution, worktree lifecycle.
Commands access config through the Config interface and ProjectManager interface — never storage directly.
Dependency Injection: The Factory Pattern
Follows the GitHub CLI’s three-layer pattern:
-
Wiring (
internal/cmd/factory/) — Creates *cmdutil.Factory with all deps as sync.Once closures. Called once at entry point. Tests never import this.
-
Contract (
internal/cmdutil/) — Factory is a pure struct with closure fields. Eager: Version, IOStreams, TUI. Lazy: Config, Client, ProjectManager, GitManager, HostProxy, SocketBridge, Firewall, Logger, Prompter.
-
Consumers (
internal/cmd/*/) — Cherry-pick Factory closures into per-command Options structs. Run functions accept *Options only.
func NewCmdStop(f *cmdutil.Factory, runF func(*StopOptions) error) *cobra.Command {
opts := &StopOptions{
IOStreams: f.IOStreams,
Client: f.Client, // closure, not call
}
}
func stopRun(ctx context.Context, opts *StopOptions) error {
client, err := opts.Client(ctx) // resolved lazily here
}
Key Abstractions
| Abstraction | Package | Purpose |
|---|
storage.Store[T] | internal/storage | Generic layered YAML store with merge, provenance, and atomic write |
config.Config | internal/config | Typed config interface composing Store[Project] + Store[Settings] |
project.ProjectManager | internal/project | Project identity, registration CRUD, worktree orchestration |
whail.Engine | pkg/whail | Reusable Docker engine with label-based resource isolation |
docker.Client | internal/docker | Clawker middleware (labels, naming) wrapping whail |
cmdutil.Factory | internal/cmdutil | DI struct (closure fields); constructor in cmd/factory |
CreateContainer() | internal/cmd/container/shared | Single entry point for container creation |
adminclient.Dial | internal/controlplane/adminclient | CLI-side AdminService gRPC dial (mTLS + OAuth2) |
firewall.Handler | internal/controlplane/firewall | 13-method AdminService firewall surface inside the CP daemon |
firewall.Stack | internal/controlplane/firewall | Envoy + CoreDNS container lifecycle |
dnsbpf.Handler | internal/dnsbpf | CoreDNS plugin populating the BPF dns_cache map in real time |
ebpf.Manager | internal/controlplane/firewall/ebpf | BPF program loader; SyncRoutes replaces the global route_map atomically |
cpboot.Manager | internal/controlplane/cpboot | Host-side CP container lifecycle (EnsureRunning/Stop/CPRunning) |
agent.Registry | internal/controlplane/agent | sqlite-backed agent identity (CP is sole writer) |
overseer.Overseer | internal/controlplane/overseer | Typed event bus + worldview state inside CP |
cmd/clawker-cp | cmd/clawker-cp | CP daemon entry point — PID 1 of the clawker-controlplane container |
cmd/clawkerd | cmd/clawkerd | Per-container agent daemon — PID 1 of every agent container |
cmd/coredns-clawker | cmd/coredns-clawker | Custom CoreDNS entrypoint embedding dnsbpf; built into clawker-coredns:latest on demand |
tui.TUI | internal/tui | Factory noun for presentation layer |
Container Naming and Labels
Container names: clawker.project.agent (3-segment) or clawker.agent (2-segment when project is empty)
Volume names: clawker.project.agent-purpose (purposes: workspace, config, history)
Labels (all under dev.clawker.*):
| Label | Purpose |
|---|
managed | true — authoritative ownership marker |
project | Project name (omitted when empty) |
agent | Agent name |
version | Clawker version |
image | Source image reference |
Labels are authoritative for resource ownership. Names are for human readability. Clawker refuses to operate on resources without dev.clawker.managed=true.
Presentation Layer
Commands follow a 4-scenario output model:
| Scenario | Description | Packages |
|---|
| Static | Print and done | iostreams + fmt |
| Static-interactive | Output with y/n prompts | iostreams + prompter |
| Live-display | Continuous rendering, no input | iostreams + tui |
| Live-interactive | Full keyboard input, navigation | iostreams + tui |
Import boundaries (enforced):
- Only
iostreams imports lipgloss
- Only
tui imports bubbletea/bubbles
- Only
term imports golang.org/x/term