PiClaw is a minimal Docker-based sandbox for running the Pi Coding Agent in an isolated Debian environment. It bundles piclaw — a web‑first orchestrator built on the Pi SDK with persistent sessions, a streaming web UI, and scheduled tasks. WhatsApp is optional. Inspired by agentbox and nanoclaw.
- Debian Bookworm (slim) base image
- Bun runtime + Homebrew package manager
- Pi Coding Agent installed globally (
piCLI) piclaworchestrator (web UI, WhatsApp optional)- Streaming Web UI with markdown, attachments, link previews, and SSE
- Persistent workspace & SQLite storage (messages, media, tasks, token usage)
- Token usage tracking + charts (token-chart skill)
- Built-in skills for setup, debugging, Playwright, charts, and scheduling
# Build the image
make build
# Start the container
make up
# Enter the container
make enter
# Inside the container, start piclaw (web UI + WhatsApp gateway)
piclawThe container starts idle — you need to exec into it and run piclaw manually (or set PICLAW_AUTOSTART=1 in your environment / .env to start it on boot).
Once piclaw is running, open the web UI at:
http://localhost:8080
To use pi interactively instead (no web UI):
cd /workspace
piWhatsApp pairing is optional; see docs/whatsapp.md.
The built-in UI is single-user, mobile-friendly, and streams updates over SSE:
- Real-time streaming with token-by-token updates
- Markdown rendering with syntax highlighting, KaTeX, and Mermaid
- Thought/Draft panels during streaming
- Live steering and follow‑ups while streaming
- File attachments with download links
- Link previews via server-side OpenGraph fetch
- Dark/Light themes (system preference)
- Mobile-first layout with webapp manifest
Web server settings:
PICLAW_WEB_PORT(default8080)PICLAW_WEB_HOST(default0.0.0.0)PICLAW_WEB_IDLE_TIMEOUT(seconds,0disables)PICLAW_WEB_MAX_CONTENT_CHARS(default262144/ 256 KB; oversized messages are truncated with metadata)
CLI overrides are also available: piclaw --port, --host, --idle-timeout.
Everything that should survive container recreation lives on two volumes:
| Mount | Container path | Contents |
|---|---|---|
| Home | /config |
Agent home persistence (.pi/, .gitconfig, .bashrc) |
| Workspace | /workspace |
Projects, piclaw state, and notes |
/workspace/
├── AGENTS.md # Pi system prompt (seeded from skeleton on first boot)
├── .pi/skills/ # Project-level skills (seeded from skel/)
├── .piclaw/ # `piclaw` state (auto-created, gitignored)
│ ├── store/messages.db # SQLite database (messages, media, tasks, token usage)
│ ├── data/sessions/ # Pi session history (per chat JID)
│ ├── data/ipc/ # IPC files (messages, tasks)
│ └── data/chats.json # Registered chat JIDs
├── notes/ # Agent memory (created by `pi` as needed)
└── <your projects>/
Never delete /workspace/.piclaw/store/messages.db. It contains all chat history, media, tasks, and token usage. Only repair/migrate it when needed.
By default, docker-compose.yml bind-mounts ./workspace. To use a different path or a named volume, set WORKSPACE_PATH in .env:
# Use a directory on an external drive
echo 'WORKSPACE_PATH=/mnt/data/piclaw-workspace' >> .env
make upOr override directly:
WORKSPACE_PATH=/mnt/data/piclaw-workspace docker compose up -d| Variable | Default | Purpose |
|---|---|---|
PICLAW_WORKSPACE |
/workspace |
Working directory for pi + piclaw |
PICLAW_STORE |
/workspace/.piclaw/store |
SQLite database location |
PICLAW_DATA |
/workspace/.piclaw/data |
Sessions, IPC, chats.json |
| Variable | Default | Purpose |
|---|---|---|
PICLAW_AUTOSTART |
0 |
Set to 1 to auto-start piclaw on container boot |
AGENT_TIMEOUT |
600000 |
Max pi invocation time (ms) |
ASSISTANT_NAME |
PiClaw |
Trigger name (@PiClaw) |
ASSISTANT_AVATAR |
(empty) | Avatar URL for web UI |
PICLAW_WEB_PORT |
8080 |
Web UI port |
PICLAW_WEB_HOST |
0.0.0.0 |
Web UI bind address |
PICLAW_WEB_IDLE_TIMEOUT |
0 |
Drop idle clients (seconds) |
PICLAW_WEB_MAX_CONTENT_CHARS |
262144 |
Max web message size |
PICLAW_TOOL_OUTPUT_RETENTION_DAYS |
30 |
Retain stored tool outputs |
PICLAW_TOOL_OUTPUT_CLEANUP_INTERVAL_MS |
43200000 |
Cleanup interval |
If QR pairing fails (headless/server environments), provide a phone number to request a pairing code:
WHATSAPP_PHONE=1234567890You can also store it in /workspace/.piclaw/config.json:
{ "whatsappPhone": "1234567890" }You can set the web UI name/avatar in .piclaw/config.json:
{
"assistant": {
"assistantName": "PiClaw",
"assistantAvatar": "https://example.com/avatar.png"
}
}piclaw can send proactive notifications for scheduled tasks or IPC messages:
PUSHOVER_APP_TOKEN=your-app-token
PUSHOVER_USER_KEY=your-user-key
PUSHOVER_DEVICE=myphone
PUSHOVER_PRIORITY=0
PUSHOVER_SOUND=pushoverOr via config:
{
"pushover": {
"appToken": "your-app-token",
"userKey": "your-user-key",
"device": "myphone",
"priority": 0,
"sound": "pushover"
}
}pi ships with the standard tools (read, bash, edit, write) plus piclaw extensions for message search, model control, and file attachments. They keep output lean, store messages and media in SQLite, and enable one‑shot operations without leaving the chat.
Skills live under .pi/skills and ~/.pi/agent/skills and are kept in sync. They cover setup, diagnostics, Playwright automation, hot‑reload, scheduling, messaging, and chart helpers. Each skill keeps its script alongside the SKILL.md so it can travel with the workspace.
cd piclaw
make build-piclaw # TypeScript compile + web asset copy
make lint # ESLint (flat config)
make test # Run all tests
make test-coverage # Tests with coverage reportTests use the Bun runner. For SQLite safety, tests default to sequential mode:
cd piclaw/piclaw
bun test # run all tests
bun test --max-concurrency=1 # sequential (recommended)
bun test test/extensions-model-control.test.ts # single filePiClaw is a standard OCI image and works with any compliant container runtime:
- Docker / Docker Desktop — primary development target
- Apple Containers (macOS 26+) — works natively
- Podman, nerdctl, etc. — standard
docker composeequivalents work
Multi-arch images (amd64 + arm64) are published to GHCR on every tag push.
Pushing a version tag triggers .github/workflows/publish.yml:
- Native multi-arch builds (amd64 + arm64)
- Manifest merge into
latest+ versioned tag - Artifact cleanup (keeps 5 most recent releases/tags/workflows/images)
make bump-patch # bumps VERSION, commits, creates git tag
make push # pushes commits + tag → triggers CIMIT
