Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ openclaw/workspaces/*/logs/
# Misc local artifacts
*.log
*.tmp
.DS_Store
1 change: 0 additions & 1 deletion CLAUDE.md

This file was deleted.

29 changes: 29 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# CLAUDE.md

## What This Is

Clawdapus is infrastructure-layer governance for AI agent containers. The `claw` CLI (Go) treats agents as untrusted workloads — reproducible, inspectable, diffable, killable.

**Key documents:**
- `MANIFESTO.md` — vision, principles, full architecture (source of truth)
- `docs/plans/2026-02-18-clawdapus-architecture.md` — implementation plan and decisions

## Architecture (summary)

- **Clawfile** → extended Dockerfile. `claw build` transpiles to standard Dockerfile, calls `docker build`. Output is OCI image.
- **CLAW_TYPE** → selects a runtime **driver** that knows how to enforce directives for a specific runner. Not just a label.
- **Driver framework** → abstract enforcement ops (set, unset, mount_ro, env, cron_upsert, healthcheck, wake). Each driver translates Clawfile directives into runner-specific config injection. Fail-closed: preflight + post-apply verification.
- **claw-pod.yml** → extended docker-compose. `claw up` parses `x-claw` blocks, runs driver enforcement, optionally injects cllama sidecars, emits clean `compose.generated.yml`, calls `docker compose`.
- **cllama sidecar** → optional bidirectional LLM proxy per Claw. Intercepts prompts outbound and responses inbound. Runner never knows. Only injected when `CLLAMA` directive is present.
- **Config injection** → primary enforcement model. Surgically writes specific config branches using the runner's own tools (e.g. `openclaw config set` for JSON5-aware OpenClaw config). Works without cllama.
- **docker compose** is the sole lifecycle authority. Docker SDK is read-only (inspect, logs, events).

## Language & Build

- Go. Single binary. `cmd/claw/main.go` entrypoint.
- Key dependencies: `github.com/moby/buildkit` (Dockerfile parser), `github.com/docker/docker/client` (Docker SDK)

## Conventions

- Don't add signatures to commit messages
- Archive of prior OpenClaw runtime is in `archive/openclaw-runtime/` — reference only
608 changes: 608 additions & 0 deletions MANIFESTO.md

Large diffs are not rendered by default.

178 changes: 87 additions & 91 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,128 +1,124 @@
# Clawdapus

Docker-based runtime for running one or many autonomous [OpenClaw](https://docs.openclaw.ai) bots in parallel, each with isolated workspace and state.
Infrastructure-layer governance for AI agent containers.

## Features
Clawdapus is to agent bots what Docker is to applications — the layer below the framework, above the operating system, where deployment meets governance. It treats AI agents as untrusted workloads: reproducible, inspectable, diffable, and killable.

- Per-bot isolated OpenClaw container with cron-scheduled periodic tasks
- Immutable config — `openclaw.json` is generated on the host and bind-mounted read-only; the bot cannot change its own heartbeat frequency or model
- System heartbeat cron (`/etc/cron.d/`) fires at the operator-set interval regardless of bot behavior
- Bot-managed workspace crons for tasks the bot controls
- Workspace-backed memory and editable strategy files
- Tool/runtime execution inside the mounted workspace
> **Swarm is for agents that work *for* you. Clawdapus is for bots that work *as* you.**

## Quick Start
---

1. Create a bot env file:
## Status

```bash
cp openclaw/bots/example.env openclaw/bots/alpha.env
```
**Active development — pre-release.**

2. Edit at minimum:
The `claw` CLI is being built from scratch in Go. See the documents below for where we are and where we're going.

- `BOT_REPO_PATH` — host path to the bot workspace
- `AGENTS_FILE_PATH` — host path to the agent instructions file
- model/provider keys (`OPENROUTER_API_KEY`, `ANTHROPIC_API_KEY`, etc.)
- heartbeat/cycle settings you want enabled
| Document | Purpose |
|----------|---------|
| [`MANIFESTO.md`](./MANIFESTO.md) | Vision and principles — the source of truth |
| [`docs/plans/2026-02-18-clawdapus-architecture.md`](./docs/plans/2026-02-18-clawdapus-architecture.md) | Architecture plan and phased implementation |
| [`docs/decisions/001-cllama-transport.md`](./docs/decisions/001-cllama-transport.md) | ADR: cllama sidecar as bidirectional LLM proxy |
| [`docs/decisions/002-runtime-authority.md`](./docs/decisions/002-runtime-authority.md) | ADR: compose-only lifecycle, SDK read-only |

3. Start:
The prior OpenClaw-based runtime lives in [`archive/openclaw-runtime/`](./archive/openclaw-runtime/) for reference.

```bash
bash scripts/openclaw-up.sh alpha
```
---

4. Stop:
## What It Will Do

```bash
bash scripts/openclaw-down.sh alpha
```

## Run Multiple Bots

Create one env file per bot in `openclaw/bots/`, each with its own workspace/state paths.

Start all:

```bash
bash scripts/openclaw-up.sh
claw doctor # Check Docker, BuildKit, compose versions
claw build [path] # Clawfile → Dockerfile → docker build
claw inspect <image> # Show resolved Claw labels from built image
claw up [pod] # claw-pod.yml → compose.yml → docker compose up
claw down [pod] # Stop and remove pod containers
claw ps [pod] # Fleet status with drift scores and policy-layer health
claw logs <claw> # Stream logs from a running Claw
claw skillmap <claw> # Show assembled capability inventory
claw audit <claw> # Policy interventions (cllama when enabled) and drift events
claw recipe <claw> # Suggested recipe from mutation log
claw bake <claw> # Apply recipe to rebuild image
claw snapshot <claw> # Snapshot a running Claw as a new image
```

Stop all:

```bash
bash scripts/openclaw-down.sh
```
### The Clawfile

## Operate and Observe
An extended Dockerfile. Any valid Dockerfile is a valid Clawfile. Extended directives add bot-specific governance:

Run OpenClaw CLI in-container:
```dockerfile
FROM openclaw:latest

```bash
bash scripts/openclaw-cmd.sh alpha 'openclaw health --json'
```
CLAW_TYPE openclaw
AGENT AGENTS.md

Log streams:
MODEL primary anthropic/claude-sonnet-4-6
CLLAMA cllama-org-policy/anthropic/claude-haiku-4-5 purpose/on-mission tone/professional

```bash
bash scripts/openclaw-logs.sh alpha # docker compose logs
bash scripts/openclaw-tail-session.sh alpha --with-tools # live session JSONL stream
bash scripts/openclaw-console.sh alpha # health + heartbeat + live conversation
bash scripts/openclaw-last.sh alpha # health + balance + last assistant message
bash scripts/openclaw-live.sh alpha # combined session + cron job logs
```
INVOKE 0 */4 * * * run-cycle
INVOKE 0 9 * * 1-5 morning-brief

## Directory Layout
SURFACE volume://shared-cache read-write
SURFACE service://company-crm read-write

```
openclaw/
compose.yml # Docker Compose stack definition
bots/*.env # per-bot configuration
workspaces/<bot>/ # bot workspace (strategy files, scripts, state)
runner/ # Dockerfile + entrypoint
runtime/<bot>/ # persisted runtime state (gitignored)
scripts/openclaw-*.sh # lifecycle and observability helpers
TRACK apt pip npm
PRIVILEGE runtime claw-user
```

Container mounts:

- `BOT_REPO_PATH -> /workspace` (read/write)
- `AGENTS_FILE_PATH -> /workspace/AGENTS.md` (read-only)
- `BOT_STATE_PATH -> /state` (read/write)
`claw build` compiles this to a standard Dockerfile and calls `docker build`. Output is an ordinary OCI image — runnable on any Docker host.
Directives express intent, not runner-specific mutation commands. At runtime, `CLAW_TYPE` selects a driver that enforces those intents using runner-native mechanisms (for example JSON/JSON5 config writes, env pins, and read-only mounts).

### The claw-pod.yml

An extended docker-compose file. The `x-claw` extension namespace is already ignored by Docker natively. Mixed clusters of Claws and plain containers:

```yaml
x-claw:
pod: my-ops
master: fleet-master

services:
my-claw:
build:
context: .
dockerfile: Clawfile
x-claw:
agent: ./AGENTS.md
count: 3
surfaces:
- volume://shared-cache: read-write
- service://company-crm: read-write

company-crm:
image: custom/crm-mcp-bridge:latest
x-claw:
expose:
protocol: mcp
port: 3100
require_cllama:
- policy/pii-gate
```

## Configuration
---

Core:
## Core Concepts

- `OPENCLAW_MODEL_PRIMARY` — model identifier (e.g. `openrouter/anthropic/claude-sonnet-4`)
- `OPENCLAW_HEARTBEAT_EVERY` — heartbeat interval (e.g. `30m`)
- `OPENCLAW_HEARTBEAT_TARGET` — heartbeat target (e.g. `none`)
**Behavioral Contract** — A read-only bind-mounted file (AGENTS.md, CLAUDE.md, etc.) defining purpose. Lives on the host. Even a root-compromised container cannot rewrite its mission.

Credentials (as needed):
**Persona** — Mutable workspace of identity, memory, and interaction history. Versionable and forkable as OCI artifacts.

- `OPENROUTER_API_KEY` / `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `GEMINI_API_KEY`
- venue credentials required by your strategy
**Claw Type Driver** — `CLAW_TYPE` selects the runtime driver for a runner family. Drivers translate abstract directive intent into runner-specific enforcement actions.

Cron-scheduled tasks (configured via workspace `crontab`):
**cllama** — Optional LLM-powered judgment proxy layer between the Claw and the world. When enabled, the runner never sees cllama's evaluation.

- Balance sync: `POLYMARKET_SYNC_*`
- Opportunity scan: `POLY_SCAN_*`
**Surfaces** — Declared communication channels. Give operators topology visibility; give bots capability discovery via assembled skill maps.

See `openclaw/API_KEYS.md` for full key setup guide.
**Drift scoring** — Independent audit of outputs against contract and configured policy layers (including cllama where enabled). Triggers capability restriction or quarantine.

## Adding a New Bot
See [`MANIFESTO.md`](./MANIFESTO.md) for the full architecture.

```bash
cp openclaw/bots/example.env openclaw/bots/mybot.env
# Edit: set BOT_REPO_PATH, AGENTS_FILE_PATH, model/provider keys
# Create workspace:
mkdir -p openclaw/workspaces/mybot
cp openclaw/workspaces/default/AGENTS.md openclaw/workspaces/mybot/
bash scripts/openclaw-up.sh mybot
```
---

## Publishing Notes
## Contributing

- Remove secrets from all `*.env` files before publishing.
- Keep `openclaw/bots/example.env` as template-only.
- Avoid committing runtime state under `openclaw/workspaces/*/state` unless intentional.
The project is pre-release. The best place to engage is the [architecture plan PR](https://github.com/mostlydev/clawdapus/pull/2).
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
54 changes: 54 additions & 0 deletions docs/decisions/001-cllama-transport.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# ADR-001: cllama Transport

**Date:** 2026-02-18
**Status:** Accepted
**Decided during:** 3-agent deliberation (arch-review room)

## Context

cllama is a bidirectional LLM proxy — it intercepts both outbound prompts (runner → LLM) and inbound responses (LLM → runner). The runner must never know cllama exists. The transport mechanism determines how interception works and what runners are supported.

## Decision

**Primary mode: HTTP sidecar proxy (built first).**

Each Claw gets a `<name>-cllama` sidecar container injected into the generated compose file by `claw up`. The sidecar:

- Exposes an OpenAI-compatible API endpoint on a pod-internal network
- Receives the runner's LLM calls (runner's `*_API_BASE` env vars are rewritten to point at the sidecar)
- Holds the real LLM provider API keys (runner never sees them)
- Applies the cllama pipeline bidirectionally (purpose → policy → tone → obfuscation)
- Logs all requests and responses for drift scoring and audit
- Enforces `require_cllama` policy modules on tool calls routed to services

**Secondary mode: adapter (documented, not built yet).**

For runners that use local models or embedded SDK clients that don't make HTTP calls to an LLM base URL, a runner-specific adapter would be needed. This is documented as a known gap. No concrete runner currently requires it — all four target runners (OpenClaw, Nanobot, Claude Code, custom scripts) use HTTP-based LLM calls.

Adapter mode will be designed and built when a concrete runner requires it.

## Consequences

**Positive:**
- Works with any runner that makes HTTP calls to an LLM endpoint — no runner integration needed
- Key isolation is free — runner never holds provider API keys
- Logging and audit are centralized at the sidecar
- Sidecar failure = LLM calls fail = fail-closed (runner can't bypass to direct provider)

**Negative:**
- One extra container per Claw (resource overhead)
- Latency added to every LLM call (proxy hop)
- Runners using local/embedded models are not covered until adapter mode is built
- Streaming responses require the sidecar to handle SSE correctly

**Risks:**
- If a runner uses a non-standard LLM API format (not OpenAI-compatible), the sidecar needs format adapters
- Sidecar must handle all LLM provider quirks (rate limits, retries, error formats) transparently

## Alternatives Considered

1. **Transparent network proxy** — intercept at the network layer (iptables/eBPF). More invisible but much harder to implement, debug, and handle streaming. Rejected: too complex for Phase 2.

2. **Runner SDK hooks** — instrument each runner to call cllama before/after LLM calls. Maximally flexible but requires per-runner integration and doesn't work for opaque runners. Rejected as default: too coupled.

3. **Shared volume FIFO** — runner writes intent to a FIFO, sidecar reads, evaluates, writes response. Simple but doesn't support streaming and adds latency. Rejected: poor UX for streaming-heavy runners.
44 changes: 44 additions & 0 deletions docs/decisions/002-runtime-authority.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# ADR-002: Runtime Authority

**Date:** 2026-02-18
**Status:** Accepted
**Decided during:** 3-agent deliberation (arch-review room)

## Context

Clawdapus needs to manage container lifecycle (start, stop, restart) and also inspect running containers (status, logs, events). Docker provides two interfaces: the `docker compose` CLI and the Docker Go SDK (`github.com/docker/docker/client`). Using both for lifecycle operations creates a dual-write problem — compose and SDK can disagree about container state.

## Decision

**`docker compose` is the sole lifecycle authority. Docker SDK is read-only.**

- **Lifecycle operations** (start, stop, restart, scale, remove): always via `docker compose` CLI, operating on the generated `compose.generated.yml`
- **Read operations** (inspect, logs, events, status): via Docker Go SDK for structured data and streaming
- **Never** use Docker SDK for start/stop/restart/remove

`claw up` emits `compose.generated.yml` and runs `docker compose up`. `claw down` runs `docker compose down`. `claw ps` uses Docker SDK to inspect running containers. There is exactly one source of truth for "what should be running" (the generated compose file) and one authority for making it so (`docker compose`).

## Consequences

**Positive:**
- Single source of truth eliminates state drift
- Compose handles networking, volume mounts, dependency ordering, health checks — no reimplementation
- Generated compose file is inspectable and debuggable
- Users can run `docker compose` directly against the generated file in emergencies

**Negative:**
- Shelling out to `docker compose` is slower than SDK calls for lifecycle ops
- Error handling requires parsing compose CLI output (structured JSON output helps but isn't perfect)
- Some advanced lifecycle operations (rolling restarts, canary deploys) may be awkward through compose

**Risks:**
- Compose CLI breaking changes could affect `claw` (mitigated by pinning minimum compose version via `claw doctor`)
- If Clawdapus ever needs sub-second lifecycle operations, the compose CLI overhead may become a bottleneck (unlikely for agent workloads)

## Alternatives Considered

1. **SDK-only** — use Docker Go SDK for everything. Eliminates compose dependency but means reimplementing networking, volume mounts, dependency ordering, and every compose feature we rely on. Rejected: too much reimplementation.

2. **Dual authority** — compose for initial deploy, SDK for runtime adjustments. Creates state drift between what compose thinks is running and what SDK has done. Rejected: the exact problem this ADR prevents.

3. **Compose as a library** — import compose's Go packages directly instead of shelling out. More tightly coupled, version-locked to compose internals, and compose's library API is not stable. Rejected: fragile coupling.
Loading