# Jail Networking Strategy

This document describes the recommended networking path for Clawdie on FreeBSD.

## Current Host Network

The current host layout is:

- `vtnet0`: public internet
- `tailscale0`: host Tailscale interface
- `lo0`: host loopback

That is already enough for the first Clawdie jail milestone.

## Recommendation

Use the canonical Warden control-plane network from the start.

### Phase 1: Warden Control-Plane

- one native FreeBSD jail
- thick, persistent control-plane profile
- VNET-enabled control-plane attached to `warden0`
- host gateway `192.168.100.1`
- host forwarding enabled with `gateway_enable="YES"`
- jail IP `192.168.100.100`
- hostname `ai.clawdie.si`
- PI runs inside the jail
- Clawdie can invoke the jail worker with the same network shape used in deployment

This is the first thing to prove.

Treat `gateway_enable`, `sysctl net.inet.ip.forwarding`, and similar system-wide
changes as host admin work. Do not bury those changes inside jail-specific
playbooks.

For `pf`, the first usable baseline is:

```pf
ext_if = "vtnet0"
warden_net = "192.168.100.0/24"

nat on $ext_if from $warden_net to any -> ($ext_if)
pass quick on warden0 inet from $warden_net to any keep state
```

Without that, a VNET jail may start cleanly and still fail package installs,
Telegram access, and provider API access.

Do not copy the host Tailscale resolver file into Bastille jails blindly. A
host-side `nameserver 100.100.100.100` is valid for the host, not necessarily
for Warden VNET jails. Use a dedicated Bastille resolver file instead.

### Phase 2: Worker VNET Expansion

Once the control-plane is stable, expand the same subnet to worker classes.

That usually means:

- worker IP allocation from `192.168.100.101+`
- host-side forwarding/NAT
- Bastille VNET templates

In Warden terms, this maps to the future `networkedWorker` profile:

- provisioning: `thin`
- networking: `vnet`
- persistent: `false`

### Phase 3: Optional Tailscale Reachability

There are three ways to expose jail workloads to Tailscale later.

1. Host-only Tailscale
- simplest
- host has the tailnet identity
- jails remain internal

2. Subnet-routed jail network
- recommended next step
- host advertises the jail subnet to Tailscale
- jails are reachable through the host

3. Tailscale inside each jail
- highest complexity
- each jail becomes its own tailnet node
- only worth it when per-jail identity matters

## Recommended Naming

Use project-specific naming:

- loopback: `clawdie0`
- pf table: `clawdie_jails`
- bridge: `warden0`
- jail subnet: `192.168.100.0/24`
- host gateway on that subnet: `192.168.100.1`
- control-plane: `192.168.100.100`
- workers: `192.168.100.101+`

These names keep FreeBSD and Bastille defaults understandable while making project-owned objects obvious.

## Why Use VNET For The Control-Plane

You decided to encode the real production shape now rather than bootstrap on a
temporary loopback shortcut. That keeps the provisioning code and docs aligned
with the intended deployment:

1. `controlplane` is always the thick persistent control-plane jail ID
2. `warden0` is always the host bridge for Warden jails
3. `192.168.100.100` is always the control-plane address
4. workers always start at `192.168.100.101`

This adds host bridge work earlier, but it avoids baking a throwaway network
model into the codebase.

## Why Not Start With Tailscale Inside the Jail

Tailscale inside every jail is useful, but it solves a more advanced problem:

- per-jail reachability
- per-jail identity
- mesh exposure of internal services

Clawdie's first runtime requirement is much simpler:

- Telegram access
- provider API access
- jailed execution

Those do not require per-jail Tailscale.

## Future Browser/GUI Workloads

If you later want a full Linux desktop for browser automation, treat that as a separate executor.

Use:

- FreeBSD jail for PI/coding/CLI work
- `bhyve` Linux VM for GUI/browser tasks

Do not force the browser/desktop use case into the plain jail runtime path.

In Warden profile terms, that future executor is:

- runtime: `linux-vm`
- role: `browser-vm`
- provisioning: `image`
- networking: `vm-bridged` by default

The initial profile set for that VM class is:

- `base-tmux`
- `browser`
- `xfce`
- `i3`
- `kde`
