โ† Back to Clawdie PRD

๐Ÿ˜ˆ Clawdie on FreeBSD 15 exploration

Exploring alternatives to OpenClaw โ€” can Clawdie run on FreeBSD with bhyve, or even better, with native jails?

Author: Sam + Claude  ยท  Date: 06.03.2026  ยท  Status: Research phase

Why Clawdie?

While Clawdie is built on OpenClaw, Clawdie offers a compelling alternative: lightweight, containerized agent execution, skills engine for deterministic changes, and native multi-channel support. This document explores running it on FreeBSD 15.

Live instance: clawdie.si  ยท  Source: codeberg.org/Clawdie/clawdie

1. The Challenge

Clawdie uses Docker containers to isolate agent execution. Each agent runs in a Linux container with:

FreeBSD doesn't have native Docker. But we have bhyve โ€” the BSD hypervisor. Can we make it work?

2. Architecture Options

Option A: Full Linux VM

Run the entire Clawdie stack inside a Debian/Ubuntu bhyve VM.

Pros Cons
Zero code changes Resource overhead (separate kernel, init, etc.)
All features work out of box Managing two OS environments
Official Docker support More complexity for updates/backups

Option B: Hybrid (FreeBSD Host + Docker VM) recommended

Node.js runs natively on FreeBSD. Only Docker runs in a minimal Linux VM.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  FreeBSD 15 Host                                                โ”‚
โ”‚                                                                 โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  Node.js (Native)                                         โ”‚  โ”‚
โ”‚  โ”‚  โ”œโ”€โ”€ Clawdie main process                                โ”‚  โ”‚
โ”‚  โ”‚  โ”œโ”€โ”€ Telegram/WhatsApp channel                            โ”‚  โ”‚
โ”‚  โ”‚  โ”œโ”€โ”€ Message routing & IPC                                โ”‚  โ”‚
โ”‚  โ”‚  โ”œโ”€โ”€ SQLite database                                      โ”‚  โ”‚
โ”‚  โ”‚  โ””โ”€โ”€ tmux glass-pane                                      โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                        โ”‚                                        โ”‚
โ”‚                        โ”‚ DOCKER_HOST=tcp://10.0.0.2:2375        โ”‚
โ”‚                        โ–ผ                                        โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  bhyve Linux VM (Alpine or Debian minimal)               โ”‚  โ”‚
โ”‚  โ”‚  โ”œโ”€โ”€ Docker daemon only                                   โ”‚  โ”‚
โ”‚  โ”‚  โ”œโ”€โ”€ nanoclaw-agent images                                โ”‚  โ”‚
โ”‚  โ”‚  โ”œโ”€โ”€ ~512MB RAM, 1 vCPU                                   โ”‚  โ”‚
โ”‚  โ”‚  โ””โ”€โ”€ No SSH, no GUI, just Docker API                      โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
Pros Cons
FreeBSD stability, ZFS, jails ecosystem Need to maintain tiny Docker VM
Zero code changes to Clawdie Network bridge configuration
Lightweight (VM is ~200MB disk) TLS for Docker API (security)
Host benefits: pf, audit, snapshots Slight latency to Docker API

Option C: Abstract Runtime

Create a FreeBSD-specific container runtime abstraction (similar to the Apple Container skill).

Pros Cons
Native feel, no VM Significant development effort
Clean abstraction layer Linux containers won't work anyway
Would need FreeBSD jails + Linux compat

Option D: No Containers (Raw)

Run the agent directly on the FreeBSD host.

โš  Not Recommended

Agents would have full system access. No isolation. One bad prompt could delete everything. Only viable for fully trusted environments.

Option D+: Jail-Based Isolation native alternative

Use FreeBSD jails with nullfs mounts to isolate agents โ€” no Docker, no Linux VM, pure FreeBSD.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  FreeBSD 15 Host                                                โ”‚
โ”‚                                                                โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚  Jail: nanoclaw                                         โ”‚   โ”‚
โ”‚  โ”‚                                                         โ”‚   โ”‚
โ”‚  โ”‚  /home/nanoclaw/     โ† nullfs RO (host:/home/nanoclaw) โ”‚   โ”‚
โ”‚  โ”‚  /groups/            โ† nullfs RW (host:/path/groups)   โ”‚   โ”‚
โ”‚  โ”‚  /data/              โ† nullfs RW (host:/path/data)     โ”‚   โ”‚
โ”‚  โ”‚  /workspace/ipc/     โ† nullfs RW (host:/path/ipc)      โ”‚   โ”‚
โ”‚  โ”‚                                                         โ”‚   โ”‚
โ”‚  โ”‚  โ”œโ”€โ”€ Node.js 22 (installed in jail)                   โ”‚   โ”‚
โ”‚  โ”‚  โ”œโ”€โ”€ Chromium (installed in jail)                     โ”‚   โ”‚
โ”‚  โ”‚  โ”œโ”€โ”€ claude-code CLI (installed in jail)              โ”‚   โ”‚
โ”‚  โ”‚  โ””โ”€โ”€ Agent runs here, can ONLY see jail filesystem    โ”‚   โ”‚
โ”‚  โ”‚                                                         โ”‚   โ”‚
โ”‚  โ”‚  Even "rm -rf /" only destroys the jail, not host     โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚                                                                โ”‚
โ”‚  Host is protected โ€” jail has no access to /etc, /root, etc.  โ”‚
โ”‚                                                                โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
Pros Cons
Native FreeBSD (no Linux emulation) Small code changes needed (~5 path env vars)
Real isolation (jail can't escape) Need to install Chromium in jail
Lower overhead than bhyve VM bastille or ezjail setup required
ZFS snapshots of jail dataset No Linux container compatibility
Same kernel = faster agent spawn Agent-runner paths need configuration
Why this works

The agent-runner has only 5 hardcoded paths (/workspace/group, /workspace/ipc, etc.). Making these configurable via environment variables enables jail execution with zero architectural changes.

3. Option B vs Option D+

Two viable approaches emerged from this exploration:

Option B (Docker VM) โ€” Zero Code Changes

The container-runtime.ts file in Clawdie is already an abstraction layer โ€” only 87 lines, designed to be swappable. The only change needed:

# In .env on FreeBSD host:
DOCKER_HOST=tcp://10.0.0.2:2375

That's it. The Node.js process thinks it's talking to local Docker, but it's actually talking to Docker inside the VM.

Option D+ (Jail) โ€” Native FreeBSD Performance

For a small code change (5 environment variables), you get native FreeBSD performance with real isolation. The agent-runner's hardcoded paths become configurable:

# Environment variables for jail mode:
NANOCLAW_IPC_DIR=/workspace/ipc/input
NANOCLAW_WORKSPACE=/groups/main
NANOCLAW_CONVERSATIONS_DIR=/groups/main/conversations
NANOCLAW_GLOBAL_MD=/workspace/global/CLAUDE.md
NANOCLAW_EXTRA_DIR=/workspace/extra

Key insight

Clawdie's architecture already separates concerns:

Component Runs Where Why
Channel (Telegram/WhatsApp) FreeBSD host Native Node.js, no Linux deps
Message routing FreeBSD host Pure JavaScript
SQLite database FreeBSD host Native better-sqlite3 works
Agent execution Docker VM or Jail Needs isolation + Chromium

4. Setup Guide (Option B)

Prerequisites

Step 1: Create the Docker VM

# Install vm-bhyve (VM manager)
pkg install vm-bhyve

# Create ZFS dataset for VMs
zfs create -o mountpoint=/vms zroot/vms

# Initialize vm-bhyve
sysrc vm_enable="YES"
sysrc vm_dir="zfs:zroot/vms"
vm init

# Download Alpine Linux (minimal, ~50MB)
vm iso https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/x86_64/alpine-virt-3.20.0-x86_64.iso

# Create VM (512MB RAM, 1 vCPU, 4GB disk)
vm create -t alpine -s 4G -m 512M -c 1 docker-vm

# Install Alpine
vm install docker-vm alpine-virt-3.20.0-x86_64.iso

Step 2: Configure Alpine for Docker

# Inside the VM console:
vm console docker-vm

# Setup Alpine
setup-alpine  # Choose "sys" mode for disk install

# After reboot, install Docker
apk add docker
rc-update add docker boot
service docker start

# Enable TCP API (edit /etc/init.d/docker or use override)
# Create /etc/docker/daemon.json:
{
  "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"]
}

# Restart Docker
service docker restart

Step 3: Network Bridge

# On FreeBSD host, create bridge for VM communication
# Add to /etc/rc.conf:
cloned_interfaces="bridge0"
ifconfig_bridge0="addm em0"  # Replace em0 with your NIC

# Configure VM with static IP (edit /vms/docker-vm/vm.conf)
# Add network config to get 10.0.0.2 or use DHCP

Step 4: Install Clawdie on FreeBSD

# Install Node.js 22
pkg install node22 npm

# Clone Clawdie
git clone https://codeberg.org/Clawdie/nanoclaw.git /home/nanoclaw
cd /home/nanoclaw

# Install dependencies
npm install

# Build
npm run build

# Configure Docker host
echo "DOCKER_HOST=tcp://10.0.0.2:2375" >> .env

Step 5: Build Agent Image

# On FreeBSD host, tell Docker (in VM) to build the image
DOCKER_HOST=tcp://10.0.0.2:2375 docker build -t nanoclaw-agent:latest container/

# Verify
DOCKER_HOST=tcp://10.0.0.2:2375 docker images

Step 6: Configure Telegram

Use the /add-telegram skill to add Telegram support (replaces WhatsApp):

# Create bot with @BotFather, get token
# Add to .env:
TELEGRAM_BOT_TOKEN=123456:ABC-DEF...
TELEGRAM_ONLY=true

4.5 Setup Guide (Option D+ โ€” Jail-Based)

This approach uses FreeBSD's native jail system instead of Docker. The agent runs isolated but shares the host kernel โ€” no VM overhead.

Code Changes Required

The agent-runner has 5 hardcoded paths. Make them configurable:

// In container/agent-runner/src/index.ts, change:

// Before (hardcoded):
const IPC_INPUT_DIR = '/workspace/ipc/input';
const conversationsDir = '/workspace/group/conversations';
const globalClaudeMdPath = '/workspace/global/CLAUDE.md';
const extraBase = '/workspace/extra';
cwd: '/workspace/group'

// After (configurable):
const IPC_INPUT_DIR = process.env.NANOCLAW_IPC_DIR || '/workspace/ipc/input';
const conversationsDir = process.env.NANOCLAW_CONVERSATIONS_DIR || '/workspace/group/conversations';
const globalClaudeMdPath = process.env.NANOCLAW_GLOBAL_MD || '/workspace/global/CLAUDE.md';
const extraBase = process.env.NANOCLAW_EXTRA_DIR || '/workspace/extra';
// cwd becomes: process.env.NANOCLAW_WORKSPACE || '/workspace/group'

Step 1: Install bastille (Jail Manager)

# bastille is the modern FreeBSD jail manager
pkg install bastille

# Enable it
sysrc bastille_enable="YES"

# Initialize with ZFS
bastille bootstrap zfs

Step 2: Create the Jail

# Create a thin jail (uses ZFS snapshots, minimal disk)
bastille create nanoclaw 15.0-RELEASE 10.0.0.10

# Or use a base template for faster creation:
bastille create -T nanoclaw 15.0-RELEASE 10.0.0.10

Step 3: Install Dependencies in Jail

# Enter the jail
bastille console nanoclaw

# Inside jail:
pkg install node22 npm chromium

# Install claude-code globally
npm install -g @anthropic-ai/claude-code

# Verify Chromium works
chromium --version

Step 4: Configure nullfs Mounts

# On HOST, edit /etc/jail.conf.d/nanoclaw.conf or bastille config:
# Mount Clawdie code (read-only for safety)

# Create mount points in jail first:
bastille exec nanoclaw mkdir -p /home/nanoclaw /groups /data /workspace/ipc

# Add to /etc/fstab (host):
/home/nanoclaw  /jails/nanoclaw/root/home/nanoclaw  nullfs  ro   0 0
/home/nanoclaw/groups/main  /jails/nanoclaw/root/groups/main  nullfs  rw  0 0
/home/nanoclaw/data  /jails/nanoclaw/root/data  nullfs  rw  0 0
/home/nanoclaw/data/ipc  /jails/nanoclaw/root/workspace/ipc  nullfs  rw  0 0

# Or use bastille's mount command:
bastille mount nanoclaw /home/nanoclaw /home/nanoclaw nullfs ro
bastille mount nanoclaw /home/nanoclaw/groups/main /groups/main nullfs rw
bastille mount nanoclaw /home/nanoclaw/data /data nullfs rw

Step 5: Create Jail Runner Script

Replace Docker container spawn with jail exec:

#!/bin/sh
# run-agent-in-jail.sh

JAIL_NAME="nanoclaw"
GROUP_FOLDER="$1"
PROMPT="$2"

# Environment for agent-runner
export NANOCLAW_IPC_DIR="/workspace/ipc/input"
export NANOCLAW_CONVERSATIONS_DIR="/groups/${GROUP_FOLDER}/conversations"
export NANOCLAW_WORKSPACE="/groups/${GROUP_FOLDER}"
export NANOCLAW_GLOBAL_MD="/workspace/global/CLAUDE.md"
export NANOCLAW_EXTRA_DIR="/workspace/extra"

# Run agent inside jail
echo "{\"prompt\":\"${PROMPT}\",\"groupFolder\":\"${GROUP_FOLDER}\"}" | \
  bastille exec $JAIL_NAME node /home/nanoclaw/container/agent-runner/dist/index.js

Step 6: Modify container-runner.ts

// In src/container-runner.ts, add jail mode:

const USE_JAIL = process.env.NANOCLAW_USE_JAIL === 'true';

if (USE_JAIL) {
  // Spawn process in jail instead of Docker container
  const jail = spawn('bastille', [
    'exec', 'nanoclaw',
    'node', '/home/nanoclaw/container/agent-runner/dist/index.js'
  ], { stdio: ['pipe', 'pipe', 'pipe'] });
  
  // Rest is same โ€” stdin JSON, stdout parsing, etc.
} else {
  // Existing Docker code...
}

Step 7: Jail Security Hardening

# In jail.conf, add restrictions:
nanoclaw {
  host.hostname = nanoclaw;
  ip4.addr = 10.0.0.10;
  path = /jails/nanoclaw/root;
  
  # Security settings
  securelevel = 2;
  enforce_statfs = 2;
  children.max = 0;
  allow.raw_sockets = 0;
  allow.sysvipc = 0;
  allow.mount = 0;
  allow.mount.devfs = 0;
  allow.quotas = 0;
  
  # Network restrictions (optional)
  interface = lo1;
}

# Create loopback interface for jail isolation:
cloned_interfaces="lo1"
ifconfig_lo1_name="jail0"

Architecture Comparison

Aspect Docker (Option B) Jail (Option D+)
Isolation level Container (namespaces) Jail (chroot + syscall filter)
Kernel Linux (in VM) FreeBSD (shared)
Memory overhead ~512MB (VM) + container ~0 (shared kernel)
Startup time ~2-5s (VM always on) ~0.1s (process spawn)
Code changes None ~5 env vars + spawn logic
Chromium In container In jail
ZFS snapshots VM disk image Jail dataset directly
โœ“ Jail advantages
  • Instant agent spawn (no container startup)
  • Native FreeBSD performance
  • ZFS snapshots for instant rollback
  • Proven security model (20+ years)

5. tmux Glass-Pane for Clawdie adaptable

The tmux glass-pane concept from Clawdie adapts perfectly to Clawdie. Instead of watching an OpenClaw gateway, you watch Clawdie's main process + container logs.

3-Pane Layout

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    tmux session: nanoclaw                       โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                            โ”‚                                    โ”‚
โ”‚   Clawdie main process    โ”‚         Interactive shell          โ”‚
โ”‚   (npm start / dev)        โ”‚      (for debugging, tests)        โ”‚
โ”‚                            โ”‚                                    โ”‚
โ”‚   [agent spawning logs]    โ”‚      $ sqlite3 store/messages.db   โ”‚
โ”‚   [message routing]        โ”‚      $ tail -f logs/nanoclaw.log   โ”‚
โ”‚   [IPC activity]           โ”‚                                    โ”‚
โ”‚                            โ”‚                                    โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                 โ”‚
โ”‚   btop / htop (system monitoring)                               โ”‚
โ”‚   - Container CPU/RAM usage                                     โ”‚
โ”‚   - FreeBSD host resources                                      โ”‚
โ”‚                                                                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Start Script: start-nanoclaw.sh

#!/bin/sh
# start-nanoclaw.sh โ€” tmux glass-pane launcher for FreeBSD

SESSION="nanoclaw"
PROJECT="/home/nanoclaw"

# Kill existing session if any
tmux kill-session -t $SESSION 2>/dev/null

# Create new session with main process
tmux new-session -d -s $SESSION -c $PROJECT

# Split horizontally (shell on right)
tmux split-window -h -t $SESSION

# Split bottom (monitor)
tmux split-window -v -t $SESSION:0.0

# Pane 0: Clawdie main process
tmux send-keys -t $SESSION:0.0 'cd /home/nanoclaw && DOCKER_HOST=tcp://10.0.0.2:2375 npm start' Enter

# Pane 1: Shell
tmux send-keys -t $SESSION:0.1 'cd /home/nanoclaw' Enter

# Pane 2: btop (or htop)
tmux send-keys -t $SESSION:0.2 'btop' Enter

# Set layout
tmux select-layout -t $SESSION main-horizontal

# Attach
tmux attach -t $SESSION

Access Patterns

From Command
Local (FreeBSD console) tmux attach -t nanoclaw
SSH from laptop ssh user@freebsd-host -t "tmux attach -t nanoclaw"
Read-only monitor tmux attach -t nanoclaw -r
Check Docker VM vm console docker-vm

6. Stripe Integration preinstalled

This instance comes with Stripe Agents toolkit preconfigured for payment processing. The agent can handle customer lookups, payment links, subscriptions, and billing operations.

Integration Paths

Path Use Case Status
MCP Server Claude Desktop, Cursor, existing MCP setups โœ“ Ready
Python Toolkit Custom agents, LangChain, CrewAI โœ“ Ready
TypeScript Toolkit Node.js apps, Vercel AI SDK โœ“ Ready

Configuration

# In .env (NOT committed to repo):
STRIPE_SECRET_KEY=rk_test_...   # Restricted API Key (test mode)
STRIPE_WEBHOOK_SECRET=whsec_... # For webhook verification

# MCP config (for Claude/Cursor integration):
# See .claude/mcp-servers.json.example
โš  Security
  • Use Restricted API Keys (RAK) with minimum permissions
  • Start with read-only, add write ops as needed
  • Never commit .env or real keys
  • Implement approval flows for refunds/cancellations

Available Operations

Category Operations
Payments Create/retrieve charges, Payment Links, refunds
Customers Create/list/update customers, payment methods
Products CRUD products and prices
Billing Subscriptions, invoices, credit notes
Balance Retrieve balance, transactions

Example: Customer Lookup

# Via Telegram to Clawdie:
"Look up customer john@example.com in Stripe"

# Agent will:
# 1. Search Stripe customers by email
# 2. Return payment history, subscription status
# 3. Offer actions (update, refund, etc.)

Resources

7. Security Considerations

Docker TCP API

โš  Plain TCP is insecure

Exposing Docker API on TCP without TLS allows anyone on the network to run containers as root. Use TLS or restrict to internal network only.

TLS Setup (Recommended)

# On Docker VM, generate certs
apk add openssl
mkdir -p /etc/docker/certs
cd /etc/docker/certs

# Generate CA
openssl genrsa -out ca-key.pem 4096
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem

# Generate server cert
openssl genrsa -out server-key.pem 4096
openssl req -new -key server-key.pem -out server.csr
openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem

# Generate client cert (for FreeBSD host)
openssl genrsa -out key.pem 4096
openssl req -new -key key.pem -out client.csr
openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem

# Update /etc/docker/daemon.json:
{
  "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"],
  "tls": true,
  "tlscacert": "/etc/docker/certs/ca.pem",
  "tlscert": "/etc/docker/certs/server-cert.pem",
  "tlskey": "/etc/docker/certs/server-key.pem"
}

# Copy ca.pem, cert.pem, key.pem to FreeBSD host
# Set DOCKER_HOST and DOCKER_TLS_VERIFY:
export DOCKER_HOST=tcp://10.0.0.2:2376
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH=/home/nanoclaw/docker-certs

FreeBSD Firewall (pf)

# /etc/pf.conf
# Block Docker API from external access
block in on egress proto tcp from any to any port 2375:2376

# Allow only from localhost and internal bridge
pass in on bridge0 proto tcp from 10.0.0.0/24 to any port 2375:2376

8. Comparison: All Options

Aspect OpenClaw Clawdie + Docker VM Clawdie + Jail
Isolation None (shared process) Full container isolation Jail isolation
FreeBSD native โœ“ Yes โœ— Needs Linux VM โœ“ Yes
Code changes None None ~5 env vars
Agent spawn time ~0.5s ~2-5s ~0.1s
Memory overhead ~200MB ~700MB (VM + container) ~200MB
Skills system Custom Deterministic engine Deterministic engine
Browser automation Remote CDP Built-in (container) Built-in (jail)
Setup complexity Low Medium Medium
ZFS snapshots User dataset VM disk image Jail dataset directly

When to choose each option

Choose When
OpenClaw (Clawdie) Maximum simplicity, native FreeBSD, no isolation needed, already have CDP browser
Clawdie + Docker VM Want container isolation, zero code changes, okay with VM overhead
Clawdie + Jail Want isolation + native FreeBSD performance, okay with small code changes

9. Open Questions

  1. Jail vs Docker VM performance โ€” Benchmark agent spawn time and memory usage for both approaches.
  2. Chromium in jail โ€” Does Chromium require special permissions or sysctls inside a jail?
  3. bastille vs ezjail vs iocage โ€” Which jail manager is best for this use case?
  4. nullfs performance โ€” Any I/O penalty for nullfs mounts vs native?
  5. VNET jails โ€” Should the jail have its own network stack (VNET) for additional isolation?
  6. Agent-runner refactor โ€” Should we upstream the configurable paths to Clawdie?

10. Next Steps

Option B (Docker VM)

Option D+ (Jail)

Shared

11. Forking This Repo

This document and the associated configuration are open source. Fork it, adapt it, run your own instance.

Repository

git clone https://codeberg.org/Clawdie/clawdie.git
cd clawdie

What's Included

File Purpose
docs/nanoclaw-on-freebsd.html This document
.env.example Template for environment variables
.claude/mcp-servers.json.example MCP config template (Stripe, etc.)
scripts/start-clawdie.sh tmux glass-pane launcher
skills/freebsd-jail/ Jail setup skill (planned)

What's NOT Included (Sensitive)

โš  Never commit these
  • .env โ€” Contains API keys, tokens
  • credentials/ โ€” Telegram session, OAuth tokens
  • data/ โ€” SQLite database, user data
  • store/ โ€” Message history
  • Any file matching *.pem, *.key

Quick Start After Fork

# 1. Copy environment template
cp .env.example .env

# 2. Edit with your values
vim .env
# Required:
#   - TELEGRAM_BOT_TOKEN (from @BotFather)
#   - ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN
# Optional:
#   - STRIPE_SECRET_KEY (for payments)
#   - DOCKER_HOST (if using Docker VM)

# 3. Install dependencies
npm install

# 4. Build
npm run build

# 5. Start (choose one)
./scripts/start-clawdie.sh    # tmux glass-pane
npm start                      # direct

# 6. Register your Telegram chat
# Send /chatid to your bot, then register via IPC

Customization Points

File Customize
groups/main/CLAUDE.md Agent personality, instructions
groups/main/IDENTITY.md Who the agent is
groups/main/USER.md About you (the operator)
.env ASSISTANT_NAME, timezone, etc.

Branches

Branch Purpose
main Production-ready, stable
dev Work in progress, experiments
freebsd-jail Jail-based isolation (experimental)
๐Ÿ“‹ Before Pushing
# Check for accidental secrets:
grep -r "sk_live\|rk_live\|whsec_\|TOKEN=" . --include="*.ts" --include="*.js" --include="*.env"

# Verify .gitignore is working:
git status --porcelain | grep -E "\.env|credentials|\.pem|\.key"

# Should return nothing!