# FreeBSD Jail Implementation Guide

## Overview

This document describes the FreeBSD jail implementation for NanoClaw/Clawdie, replacing Docker with native FreeBSD jails for better performance and security.

## Why Jails Instead of Docker?

| Aspect      | Docker on FreeBSD         | FreeBSD Jails      |
| ----------- | ------------------------- | ------------------ |
| Performance | Good (emulation overhead) | Excellent (native) |
| Layers      | FreeBSD → Linux → Docker  | FreeBSD → Jail     |
| Security    | Good                      | Excellent          |
| Networking  | Docker bridge             | Bastille VNET      |
| Complexity  | High                      | Low                |

## Architecture

```
FreeBSD Host
├── Jail: clawdie-cp
│   ├── IP: 192.168.100.100
│   ├── Path: /usr/local/bastille/jails/clawdie-cp/root
│   ├── Mounts:
│   │   ├── /home/clawdie/nanoclaw (ro)
│   │   └── /home/clawdie/.config/nanoclaw (rw)
│   └── Resources:
│       ├── Memory: 2G max
│       ├── CPU: 2 cores
│       └── Processes: 1000 max
└── NanoClaw running inside jail
```

## Files

### Runtime Detection

- `src/jail-runtime.ts` - Detects jail environment and provides runtime utilities
- `src/jail-runtime.test.ts` - Tests for jail detection

### Configuration

- `src/jail-config.ts` - Jail configuration generation and validation
- `src/jail-config.test.ts` - Tests for configuration

### FreeBSD-specific Tests

- `src/freebsd-jail.test.ts` - Comprehensive jail validation tests

## Usage

### Detect Jail Runtime

```typescript
import { JailRuntime, useJailRuntime } from './jail-runtime';

// Check if running in jail
const runtime = JailRuntime.getInstance();
if (runtime.isInJail()) {
  const info = runtime.getJailInfo();
  console.log(`Running in jail: ${info?.name}`);
}

// Validate environment
const validation = JailRuntime.validateJailEnvironment();
if (!validation.valid) {
  console.error('Errors:', validation.errors);
}
```

### Generate Jail Configuration

```typescript
import { generateJailConfig, DEFAULT_JAIL_CONFIG } from './jail-config';

// Use defaults
const config = generateJailConfig();

// Or customize
const customConfig = generateJailConfig({
  name: 'myjail',
  ip: '192.168.1.50',
  resources: {
    memoryMax: '4G',
    cpuLimit: 4,
  },
});

console.log(config);
```

### Validate Configuration

```typescript
import { validateJailConfig, DEFAULT_JAIL_CONFIG } from './jail-config';

const errors = validateJailConfig(DEFAULT_JAIL_CONFIG);
if (errors.length > 0) {
  console.error('Configuration errors:', errors);
}
```

## Running Tests

```bash
# Run jail-specific tests
npm test src/freebsd-jail.test.ts
npm test src/jail-runtime.test.ts
npm test src/jail-config.test.ts

# Run all tests
npm test
```

## Setup

### 1. Create Jail

```bash
# Create jail directory
mkdir -p /usr/local/bastille/jails/clawdie-cp/root

# Create jail configuration
cat > /etc/jail.conf.d/clawdie-cp.conf << 'EOF'
clawdie-cp {
  host.hostname = "ai.clawdie.si";
  ip4.addr = 192.168.100.100;
  path = "/usr/local/bastille/jails/clawdie-cp/root";
  mount.fstab = "/etc/fstab.clawdie-cp";
  mount.devfs;
  devfs_ruleset = 4;
  memoryuse = "max:2G";
  cpuset.cpus = "0-1";
  maxproc = 1000;
  exec.start = "/bin/sh /etc/rc";
  exec.stop = "/bin/sh /etc/rc.shutdown";
}
EOF
```

### 2. Create Mount Points

```bash
# Create fstab for jail
cat > /etc/fstab.clawdie-cp << 'EOF'
/home/clawdie/nanoclaw  /usr/local/bastille/jails/clawdie-cp/root/home/clawdie/nanoclaw  nullfs  ro  0  0
/home/clawdie/.config/nanoclaw  /usr/local/bastille/jails/clawdie-cp/root/home/clawdie/.config/nanoclaw  nullfs  rw  0  0
EOF
```

### 3. Install FreeBSD Base

```bash
# Download and extract FreeBSD base
fetch http://ftp.freebsd.org/pub/FreeBSD/releases/amd64/15.0-RELEASE/base.txz
tar -xpf base.txz -C /usr/local/bastille/jails/clawdie-cp/root
```

### 4. Configure Jail

```bash
# Start jail
service jail start clawdie-cp

# Install packages in jail
pkg -j clawdie-cp install node20 npm git

# Enter jail
jexec clawdie-cp /bin/sh

# Inside jail
cd /home/clawdie/nanoclaw
npm install
npm run setup
```

## Security

### Devfs Ruleset

Jail uses devfs ruleset 4 (basic) which provides:

- `/dev/null`, `/dev/zero`, `/dev/random`
- No access to disks, network devices, or privileged devices

### Resource Limits

- Memory: 2GB maximum
- CPU: 2 cores
- Processes: 1000 maximum

### Network Isolation

- Jail has its own IP address
- No access to host network stack
- Can be further isolated with VNET

## Troubleshooting

### Check Jail Status

```bash
# List running jails
jls

# Check jail details
jls -n -j clawdie-cp

# Check jail logs
tail -f /var/log/jail_clawdie.log
```

### Common Issues

**Jail won't start:**

```bash
# Check configuration
jail -c clawdie-cp -v

# Check mount points
mount | grep clawdie
```

**Can't access files:**

```bash
# Verify mount points
cat /etc/fstab.clawdie

# Check permissions
ls -la /home/clawdie/nanoclaw
```

**Network not working:**

```bash
# Check IP configuration
ifconfig | grep 192.168.100.100

# Verify network access from jail
jexec clawdie ping -c 3 google.com
```

## Migration from Docker

If migrating from Docker:

1. **Remove Docker:**

   ```bash
   pkg delete docker
   ```

2. **Disable Linux emulation:**

   ```bash
   sysrc linux_enable=NO
   service linux stop
   ```

3. **Create jail** (see Setup section)

4. **Transfer data:**

   ```bash
   # Copy configuration
   cp -r ~/.config/nanoclaw /home/clawdie/.config/nanoclaw

   # Clone repository
   git clone https://github.com/openclaw/nanoclaw.git /home/clawdie/nanoclaw
   ```

5. **Update environment:**
   ```bash
   export CONTAINER_RUNTIME=jail
   export JAIL_NAME=clawdie
   export JAIL_PATH=/jails/clawdie
   ```

## References

- [FreeBSD Handbook: Jails](https://docs.freebsd.org/en/books/handbook/jails/)
- [jail(8)](<https://man.freebsd.org/cgi/man.cgi?jail(8)>)
- [jls(8)](<https://man.freebsd.org/cgi/man.cgi?jls(8)>)
- [nullfs(5)](<https://man.freebsd.org/cgi/man.cgi?mount_nullfs(8)>)
