---
name: setup
description: Run initial Clawdie control-plane setup on FreeBSD. Use when installing dependencies, configuring Telegram, bootstrapping the Warden jail runtime, or first-time setup. Triggers on "setup", "install", "configure clawdie", or first-time setup requests.
---

# Clawdie Setup

Run setup steps automatically on FreeBSD 15. Only pause when user action is required (creating a Telegram bot, pasting a token, configuration choices). Verbose logs go to `logs/clawdie.log`.

**Principle:** When something is broken or missing, fix it. Don't tell the user to go fix it themselves unless it genuinely requires their manual action (e.g. creating a Telegram bot token). If a dependency is missing, install it. If a service won't start, diagnose and repair. Ask the user for permission when needed, then do the work.

**UX Note:** Use `AskUserQuestion` for all user-facing questions.

**Attribution:** Clawdie is a fork of [NanoClaw](https://github.com/openclaw/nanoclaw) by [Gavriel](https://github.com/openclaw), built on the [OpenClaw](https://github.com/openclaw/openclaw) ecosystem created by [Peter Steinberger](https://github.com/steipete). The skills engine and upstream update mechanism originate from NanoClaw.

## 1. Preflight

### Check FreeBSD version

```bash
freebsd-version
```

Must be 15.0-RELEASE or later.

### Check ZFS pool

```bash
zpool status zroot
```

Pool must be healthy (state: ONLINE). Note available space with `zfs list -o name,used,avail,mountpoint`.

### Check user access

```bash
id
```

Need wheel group membership or root access for jail management.

### Check Node.js

```bash
node --version
```

Must be v20+ (v24 recommended). If missing or too old:

```bash
sudo pkg install node24 npm git
```

### Check Python

```bash
python3 --version
```

Must be 3.12+. If missing:

```bash
sudo pkg install python312 py312-uv
```

### Check PI coding agent

```bash
pi --version 2>/dev/null || echo "NOT_INSTALLED"
```

If missing:

```bash
npm install -g @mariozechner/pi-coding-agent
```

### Record preflight state

Note: NODE_OK, PYTHON_OK, ZFS_OK, PI_OK for later steps.

## 2. ZFS Dataset Layout

Delegate to `/warden-zfs` skill if `clawdie-runtime` dataset does not exist:

```bash
zfs list zroot/clawdie-runtime 2>/dev/null && echo "EXISTS" || echo "NEEDS_CREATION"
```

If NEEDS_CREATION, run the `/warden-zfs` skill to create the dataset hierarchy under `zroot/clawdie-runtime`.

Verify the expected layout:

```bash
zfs list -r zroot/clawdie-runtime
```

Expected:
- `zroot/clawdie-runtime`
- `zroot/clawdie-runtime/jails/controlplane`
- `zroot/clawdie-runtime/jails/db`

## 3. Host Networking

Delegate to `/bastille-network` and `/warden-pf` skills.

### Check bridge

```bash
ifconfig warden0 2>/dev/null && echo "BRIDGE_OK" || echo "NEEDS_BRIDGE"
```

If NEEDS_BRIDGE, run `/bastille-network` to create the persistent `warden0` bridge at `192.168.100.1/24`.

### Check PF NAT

```bash
sudo pfctl -sr 2>/dev/null | grep "192.168.100" && echo "NAT_OK" || echo "NEEDS_NAT"
```

If NEEDS_NAT, run `/warden-pf` to configure NAT rules for jail egress.

### Check forwarding

```bash
sysctl net.inet.ip.forwarding
```

Must be `1`. If not:

```bash
sudo sysrc gateway_enable="YES"
sudo sysctl net.inet.ip.forwarding=1
```

## 4. Warden Bootstrap

Delegate to `/warden-bootstrap` skill for the control-plane jail.

### Check if controlplane jail exists

```bash
bastille list 2>/dev/null | grep controlplane && echo "JAIL_EXISTS" || echo "NEEDS_JAIL"
```

If NEEDS_JAIL, run `/warden-bootstrap` to create the thick VNET `controlplane` jail at `192.168.100.100` with hostname `ai.clawdie.si`.

### Verify jail health

```bash
jls
jexec controlplane hostname
```

Should show `ai.clawdie.si`.

## 5. Database Jail

### Check if db jail exists

```bash
bastille list 2>/dev/null | grep "db" && echo "DB_EXISTS" || echo "NEEDS_DB"
```

If NEEDS_DB, delegate to `/postgres-memory` skill to provision the `db` jail at `192.168.100.2` with PostgreSQL 18.

## 6. Sanoid Snapshot Policy

Delegate to `/sanoid` skill.

### Check if Sanoid is installed

```bash
sanoid --version 2>/dev/null && echo "SANOID_OK" || echo "NEEDS_SANOID"
```

If NEEDS_SANOID:

```bash
sudo pkg install -y sanoid
```

### Check if policies exist

```bash
test -f /usr/local/etc/sanoid/sanoid.conf && echo "CONF_EXISTS" || echo "NEEDS_CONF"
```

If NEEDS_CONF, run `/sanoid` to generate snapshot policies for `controlplane` and `db` datasets.

## 7. Clawdie Code Deployment

### Check if codebase exists

```bash
test -d /home/clawdie/clawdie-ai/src && echo "CODE_OK" || echo "NEEDS_CLONE"
```

If NEEDS_CLONE:

```bash
git clone https://codeberg.org/Clawdie/Clawdie-AI.git /home/clawdie/clawdie-ai
cd /home/clawdie/clawdie-ai
```

### Install dependencies

```bash
cd /home/clawdie/clawdie-ai
npm install
```

### Build

```bash
npm run build
```

If build fails on `better-sqlite3`:

```bash
sudo pkg install -y gmake pkgconf
npm rebuild better-sqlite3
npm run build
```

## 8. Environment Configuration

### Copy template

```bash
cp .env.example .env
```

### Configure provider

AskUserQuestion: Which AI provider? Options:
- OpenRouter (default, recommended)
- Anthropic API key
- Claude subscription (Pro/Max)

**OpenRouter:** Add `OPENROUTER_API_KEY=<key>` to `.env`.

**Anthropic API:** Add `ANTHROPIC_API_KEY=<key>` to `.env`.

**Claude subscription:** Tell user to run `claude setup-token` in another terminal, copy the token, add `CLAUDE_CODE_OAUTH_TOKEN=<token>` to `.env`. Do NOT collect the token in chat.

## 9. Telegram Bot Setup

AskUserQuestion: Do you have a Telegram bot token, or do you need to create one?

If they need to create one:

> 1. Open Telegram and search for `@BotFather`
> 2. Send `/newbot` and follow prompts
> 3. Bot name: Something friendly (e.g., "Clawdie Assistant")
> 4. Bot username: Must end with "bot" (e.g., "clawdie_ai_bot")
> 5. Copy the bot token

Wait for the user to provide the token.

### Add to environment

Add `TELEGRAM_BOT_TOKEN=<token>` to `.env`.

### Run auth setup

```bash
npm run auth
```

### Disable Group Privacy (for group chats)

> **Optional for group chats**: By default, Telegram bots only see @mentions in groups. To see all messages:
> 1. Open `@BotFather` > `/mybots` > select bot
> 2. **Bot Settings** > **Group Privacy** > **Turn off**

## 10. Channel Registration

### Start temporarily to get chat ID

```bash
npm run dev
```

Tell the user to send a message to the bot to discover the chat ID from logs.

### Register main channel

```bash
npm run setup
```

Follow the interactive setup to register the main Telegram channel.

## 11. FreeBSD Service Setup

### Create rc.d script

```bash
sudo tee /usr/local/etc/rc.d/clawdie << 'RCEOF'
#!/bin/sh

# PROVIDE: clawdie
# REQUIRE: LOGIN DAEMON NETWORKING
# KEYWORD: shutdown

. /etc/rc.subr

name="clawdie"
rcvar="clawdie_enable"
command="/usr/local/bin/node"
command_args="/home/clawdie/clawdie-ai/dist/index.js"
pidfile="/var/run/clawdie.pid"
clawdie_chdir="/home/clawdie/clawdie-ai"
clawdie_user="clawdie"

load_rc_config $name
run_rc_command "$1"
RCEOF
sudo chmod +x /usr/local/etc/rc.d/clawdie
```

### Enable and start

```bash
sudo sysrc clawdie_enable=YES
sudo service clawdie start
```

## 12. ZFS Snapshot (Post-Setup Milestone)

Take a named milestone snapshot after successful setup:

```bash
sudo zfs snapshot zroot/clawdie-runtime/jails/controlplane@setup-complete-$(date +%d-%b-%Y | tr '[:upper:]' '[:lower:]')
```

This provides a clean rollback point.

## 13. Verification

### Run doctor

```bash
npm run doctor
```

### Check service

```bash
service clawdie status
```

### Check logs

```bash
tail -f logs/clawdie.log
```

### Check jails

```bash
jls
```

### Check snapshots

```bash
zfs list -t snapshot -r zroot/clawdie-runtime
```

### Test Telegram

Tell the user:

> Send a message to your bot in Telegram. For main chat, any message works. For groups, use `@Clawdie hello`.

## Troubleshooting

**Jail won't start:** Check `bastille list`, verify bridge with `ifconfig warden0`, check PF rules with `sudo pfctl -sr`.

**Service fails to start:** Check `logs/clawdie.error.log`. Common: missing `.env`, missing Telegram token, permission issues.

**Telegram bot not responding:** Verify token in `.env`, check chat registration in SQLite, check service status, check logs.

**Build fails:** Install build tools (`gmake`, `pkgconf`), rebuild native modules, retry build.

**Network issues in jail:** Run `/warden-health` to diagnose. Check bridge, PF NAT, and forwarding state.
