Skip to content

kortiene/claw

Repository files navigation

claw

Project status (2026-05-11): research prototype, frozen as a product. After reconnoitring the actual OpenClaw project (370K+ stars, MIT, active TS codebase with its own Gateway, multi-agent routing, Telegram pairing, and Docker sandbox), the strategic decision is to stop developing claw as a standalone CLI and instead contribute rootless Podman sandboxing upstream to OpenClaw alongside its existing Docker / SSH / OpenShell backends. The v0.2.x line (v0.2.0 → v0.2.8) ships as-is and remains usable as a research prototype; no v0.3 is planned in this repo. The architectural rationale is documented in docs/V0_3_OPENCLAW_FIT.md (Frame δ); the upstream contribution plan lives in docs/UPSTREAM_OPENCLAW_RECON.md.

claw is a local CLI and supervisor for creating, managing, isolating, and governing OpenClaw agents as rootless Podman containers.

OpenClaw owns agent semantics: tools, skills, plugins, channels, sessions, model configuration, and approvals. Claw owns lifecycle, template compilation, container enforcement, local access approval, and auditability.

Claw template
  → policy compiler
  → openclaw.json
  → container-spec.json
  → policy.lock.json
  → rootless isolated OpenClaw agent container

Architecture

   ┌─────────────┐ ┌────────────────┐ ┌─────────────┐
   │  claw CLI   │ │  Telegram Bot  │ │ TUI (exec)  │
   └──────┬──────┘ └────────┬───────┘ └──────┬──────┘
          │                 │                │
          └─────────────────┼────────────────┘
                            ▼
   ┌────────────────────────────────────────────────────┐
   │                  CLAW SUPERVISOR                   │
   │                                                    │
   │  ┌──────────┐  ┌──────────┐  ┌──────────┐ ┌──────┐ │
   │  │Templates │  │ Compiler │  │  State   │ │Access│ │
   │  │ (coder,  │→ │ (policy →│→ │ Manager  │ │  +   │ │
   │  │reviewer…)│  │ lock+sign│  │ (agents/)│ │Pair- │ │
   │  └──────────┘  └────┬─────┘  └──────────┘ │ ing  │ │
   │                     │                     └──────┘ │
   │                     ▼                              │
   │  ┌──────────────────────────────────────────────┐  │
   │  │  AUDIT LOG (JSONL)                           │  │
   │  │  lifecycle · policy · access · egress events │  │
   │  └──────────────────────────────────────────────┘  │
   └──────────────────────┬─────────────────────────────┘
                          ▼
   ┌────────────────────────────────────────────────────┐
   │                  PODMAN BACKEND                    │
   │                                                    │
   │  ┌────────────┐  ┌────────────┐  ┌────────────┐    │
   │  │Agent Pod A │  │Agent Pod B │  │Agent Pod C │    │
   │  │            │  │            │  │            │    │
   │  │ ┌────────┐ │  │ ┌────────┐ │  │ ┌────────┐ │    │
   │  │ │OpenClaw│ │  │ │OpenClaw│ │  │ │OpenClaw│ │    │
   │  │ │Runtime │ │  │ │Runtime │ │  │ │Runtime │ │    │
   │  │ └────────┘ │  │ └────────┘ │  │ └────────┘ │    │
   │  │ workspace/ │  │ workspace/ │  │ workspace/ │    │
   │  │ state/     │  │ state/     │  │ state/     │    │
   │  └────────────┘  └────────────┘  └────────────┘    │
   │                                                    │
   │  rootless · userns=keep-id · resource-limited      │
   │  · net-profiled                                    │
   └────────────────────────────────────────────────────┘

Three operator surfaces (CLI, Telegram bot, TUI) drive one supervisor. The supervisor compiles templates into signed policy locks, manages per-agent state, brokers Telegram pairing, and appends every lifecycle / policy / access / egress event to an audit log. The Podman backend runs each agent as a rootless pod with userns=keep-id, resource limits, and a network profile; the OpenClaw runtime is the agent process inside the pod. The strategic relationship to OpenClaw upstream is covered in docs/PODMAN_PLUGIN_PLAN.md; deeper architecture notes (incl. a Mermaid rendering of the same diagram) are in docs/ARCHITECTURE.md.

Status

Frozen as prototype at v0.2.8 (2026-05-11). The full unit-test suite passes on macOS Python 3.12.2 (1 environmental skip), ruff clean, ~99% coverage (CI floor: 95%). Live-bot pairing was smoke-tested end-to-end on macOS + podman machine against a real BotFather bot (HANDOVER.md §-12). Full host e2e (scripts/e2e.sh) remains a Linux-host operator step — see docs/TELEGRAM_RUNBOOK.md and scripts/e2e.sh. No new feature work is planned in this repo; the next chapter is upstream in openclaw/openclaw — see the banner above. The v0.2.x line is still installable and runnable if you want to inspect the patterns (signed policy lock, audit log, rootless Podman backend, Telegram pairing flow, etc.).

Working today:

  • Typer CLI, ~/.claw state initialization, claw doctor
  • Built-in templates: coder, reviewer, security, devops
  • Disk-loaded user templates at ~/.claw/templates/*.yaml (override built-ins)
  • Agent creation → agent.yaml, template.yaml (snapshot), openclaw.json, container-spec.json, policy.lock.json (Ed25519-signed, ADR-0006)
  • JSONL audit events for every lifecycle, policy, and access event
  • podman-py backend with real resource limits, userns=keep-id, tmpfs:/tmp, network-profile mapping, stale-container reconcile, claw.network label on every container
  • Real interactive claw exec --tty and claw tui via podman exec -it
  • claw image build builds + tags localhost/claw-openclaw-agent:latest, with the openclaw stub binary baked in for the bootstrap shim's happy path
  • Bootstrap shim (claw-agent-init) execs the openclaw binary and only falls back to keep-alive if missing
  • Policy lock with templateHash, imageDigest, Ed25519 signature, drift detection, --force override that re-locks + re-signs + audits
  • claw delete (archives to ~/.claw/trash/), claw inspect, claw restart, claw status reconciled with live container state
  • Telegram pairing core: SQLite store at ~/.claw/claw.db, secure token issuance, in-terminal QR, local-confirmation handshake over Unix socket, claw access pair / confirm / list / revoke / serve telegram. PTB handler wiring covered by in-process tests; live-bot runbook in docs/TELEGRAM_RUNBOOK.md
  • Egress-enforcer seam (src/claw/egress.py) with a noop default and a Protocol-typed extension point; profile label always emitted, a future enforcer swap is a one-liner
  • Full unit-test suite passes, ruff clean, ~99% coverage (CI floor: 95%), GitHub Actions CI on Python 3.11/3.12 (pytest -q
    • ruff check . with a 60s per-test timeout; make all reproduces the gate locally)

Known limitations (deferred — no v0.3 is planned in this repo; see the pivot banner above):

  • Real network-egress filtering beyond none vs slirp4netns flavours. The v0.2 release ships the architectural seam (EgressEnforcer Protocol, claw.network label, apply/teardown hooks) but the default NoopEnforcer enforces nothing. claw policy explain says so out loud.
  • Telegram bot loop (claw access serve telegram) requires the optional claw[telegram] extras and a ~/.claw/secrets/telegram.toml. The bot handlers themselves are covered by 14 in-process tests; the live-Telegram end-to-end was smoke-tested against a real BotFather bot on macOS + podman machine in session 14 (see HANDOVER.md §-12) and remains a manual runbook step in CI (see docs/TELEGRAM_RUNBOOK.md).
  • The default openclaw binary inside the agent image is a stub (bootstrap/openclaw-stub). It exposes the --self-test, --version, gateway, and tui surface the real OpenClaw runtime is expected to honour, so a derived image can replace it without claw-side changes. A real OpenClaw runtime drop-in is no longer planned in this repo — the upstream contribution path (docs/UPSTREAM_OPENCLAW_RECON.md) supersedes it.
  • HSM/KMS-backed signing key storage. The v0.2 host key is a raw 32-byte seed under ~/.claw/secrets/ (0o600). The empty [signing] extra in pyproject.toml was originally reserved for v0.3 backends and is left in place as an extension point; no implementation is planned in this repo.

Install for development

python -m venv .venv
. .venv/bin/activate
pip install -e '.[podman,dev]'

Or, after creating .venv, use the top-level Makefile:

make install   # pip install -e '.[dev]'
make all       # ruff check . + pytest with coverage (mirrors CI)
make lint      # ruff only
make test      # pytest only
make cov       # pytest with --cov-fail-under=95
make clean     # purge .pytest_cache, .ruff_cache, .coverage, __pycache__

macOS quick-start (Podman Machine)

Rootless Podman on macOS runs inside a Linux VM (podman machine). The podman-py library claw uses talks to that VM over a Unix socket — but the default socket path it probes (/run/user/<uid>/podman/podman.sock) is the Linux-host path, not the macOS-host path. Without help, claw's backend falls back to the CLI and you'll see "Podman backend unavailable" in claw doctor.

Fix: export CONTAINER_HOST so claw points at the macOS-side socket the machine publishes.

brew install podman
podman machine init
podman machine start
export CONTAINER_HOST="$(podman info --format '{{.Host.RemoteSocket.Path}}')"
claw doctor   # should now show "Podman backend OK"

The CONTAINER_HOST env var is honoured by PodmanBackend at startup (src/claw/backend.py). To make it stick across shells, add the export to ~/.zshrc (or wherever your podman machine start env hook lives). Linux hosts and rootful Podman do not need this — the default socket path works as-is.

Basic workflow

claw init
claw templates list
claw create coder backend-agent
claw policy explain backend-agent
claw start backend-agent
claw exec backend-agent -- pwd
claw openclaw backend-agent -- --help
claw tui backend-agent

Primary commands:

claw init
claw doctor
claw templates list
claw templates show coder
claw create <template> <agent-name>
claw list
claw status [agent-name]
claw start <agent-name>
claw stop <agent-name>
claw logs <agent-name>
claw exec <agent-name> -- <command>
claw openclaw <agent-name> -- <openclaw-args>
claw tui <agent-name>
claw policy show <agent-name>
claw policy explain <agent-name>
claw policy validate <agent-name>
claw access pair    telegram <agent-name> [--role operator] [--expires 60]
claw access list    telegram [<agent-name>]
claw access revoke  telegram <agent-name> <telegram-user-id>
claw access confirm telegram <agent-name> <token> --telegram-user-id <id>
claw access serve   telegram   # requires claw[telegram] extras
claw image build [--tag TAG] [--no-cache]
claw inspect <agent-name>
claw restart <agent-name>
claw delete <agent-name> [--force]

Local state layout

~/.claw/
  config.yaml
  agents/
    backend-agent/
      agent.yaml
      openclaw.json
      container-spec.json
      policy.lock.json
      audit.jsonl
      workspace/
      state/
      logs/
  templates/
  plugin-cache/
  secrets/
  logs/audit.jsonl

Security model

Claw uses two policy layers:

  1. OpenClaw policy controls semantic permissions: tools, skills, plugins, channels, and approvals.
  2. Claw/Podman policy controls physical access: mounts, network, privileges, resource limits, and secrets.

Safe defaults include rootless Podman, no privileged containers, no host home mount, no SSH mount, no Podman/Docker socket mount, and per-agent workspaces.

Documentation

About

Research prototype: local OpenClaw agent supervisor in rootless Podman containers, with Telegram pairing and Ed25519-signed policy locks. Frozen at v0.2.7 — next chapter is upstream at openclaw/openclaw.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors