New docs/guide/ tree — canonical home for operator-facing procedural docs. Starlight frontmatter added to all files. 0.12 alignment fixes applied: - v0.11.0 → v0.12.0 throughout - PI_TUI_PROVIDER/MODEL → DEEPSEEK_API_KEY - Headless Codex login → Agent runtime setup (zot + RPC mode) - /login and auth.json references removed - pi → zot in provider-fallback spawn reference - colibri-provider-verify (was pi-provider-smoke) - Language cleanup: smoke test → verification, fake → test, can't self-fix → requires operator intervention, broken → unresponsive, Fix anything broken → Verify all checks pass Two-tree model: docs/wiki/ (decisions) + docs/guide/ (procedural). Single source of truth in colibri. clawdie-ai docs/public/ to be retired.
181 lines
5.6 KiB
Markdown
181 lines
5.6 KiB
Markdown
---
|
||
title: 'Multi-Agent Deployment (Optional)'
|
||
---
|
||
|
||
Clawdie supports running multiple independent agents on the same FreeBSD host,
|
||
but the default path is **one agent per host or per bhyve VM**. Use this guide
|
||
only when you intentionally want a second agent later.
|
||
|
||
## Quick decision
|
||
|
||
- **Easiest isolation:** one agent per **bhyve VM** (each VM has its own `warden0`)
|
||
- **Same-host multi-agent:** one host `warden0` bridge carries **multiple /24 subnets**
|
||
|
||
## Concepts (what must stay unique)
|
||
|
||
Separate runtime names from portable agent identity. A host may run multiple
|
||
agents, and an agent may also carry a portable soul bundle (`SOUL.md`,
|
||
`USER.md`, `IDENTITY.md`, `AGENTS.md`) cloned from a dedicated repo. Runtime
|
||
names keep services, jails, datasets, and sockets from colliding; soul files
|
||
carry who the agent is and what context it may reuse across hosts or harnesses.
|
||
|
||
- `AGENT_NAME` is the runtime identity key:
|
||
- rc.d service name (`/usr/local/etc/rc.d/${AGENT_NAME}`)
|
||
- tmux session name
|
||
- jail name prefix (recommended)
|
||
- DB identifiers (users + databases)
|
||
- `AGENT_SUBNET_BASE` assigns a dedicated `/24` to that agent:
|
||
- pick any private `/24` that does not collide with another agent
|
||
- repo examples below use `10.0.1`
|
||
- live installs can also use `192.168.72`, `172.16.50`, etc
|
||
- you can also use `172.16.50`, `192.168.100`, etc — pick any private `/24` and stay consistent
|
||
- `warden0` is the canonical bridge name. A single `warden0` can host multiple
|
||
subnets; the host must own the `.1` gateway IP **for each subnet**.
|
||
- Prefer **VNET jails** (`bastille create -B ... warden0`) for cleaner isolation.
|
||
|
||
## Portable soul repos
|
||
|
||
For multi-host or multi-harness continuity, keep durable agent identity in a
|
||
small dedicated repository instead of baking it into one install. The same repo
|
||
can be pulled by Pi, Hermes, Codex, Claude Code, or Colibri and adapted into the
|
||
harness-specific prompt/config layer.
|
||
|
||
Recommended shape:
|
||
|
||
```text
|
||
SOUL.md # durable agent identity, values, voice, operating style
|
||
USER.md # operator/user context shared with this agent when allowed
|
||
IDENTITY.md # short runtime identity and boundaries
|
||
AGENTS.md # harness-facing rules when supported
|
||
manifest.json # schema version, provenance, sharing rules
|
||
```
|
||
|
||
Rules:
|
||
|
||
- keep secrets out of the soul repo;
|
||
- keep runtime state in `system_ops`, not in identity files;
|
||
- import long-lived memories into `system_brain` only when the operator allows;
|
||
- keep skills/reviewed procedures in `system_skills` or referenced skill repos.
|
||
|
||
## Same-host multi-agent (VNET path)
|
||
|
||
Example: add a second agent named `atlas` on `10.0.1.0/24`.
|
||
|
||
### 1) Create a second project directory
|
||
|
||
Use a separate clone so each agent has its own `.env`, `logs/`, and runtime state.
|
||
|
||
### 2) Configure `.env` for the second agent
|
||
|
||
Minimum keys to set (example values):
|
||
|
||
```env
|
||
AGENT_NAME=atlas
|
||
ASSISTANT_NAME=Atlas
|
||
|
||
AGENT_SUBNET_BASE=10.0.1
|
||
WARDEN_GATEWAY=10.0.1.1
|
||
WARDEN_SUBNET=10.0.1.0/24
|
||
|
||
WARDEN_GIT_IP=10.0.1.2
|
||
WARDEN_CMS_IP=10.0.1.3
|
||
WARDEN_OLLAMA_IP=10.0.1.4
|
||
WARDEN_LLAMA_CPP_IP=10.0.1.4
|
||
WARDEN_DB_IP=10.0.1.5
|
||
```
|
||
|
||
These are example values only. If your host already uses another private
|
||
subnet, keep that and stay consistent across the rest of the file.
|
||
|
||
Jail name overrides (avoid collisions with an existing agent’s jails):
|
||
|
||
```env
|
||
CMS_JAIL_NAME=atlas-cms
|
||
OLLAMA_JAIL_NAME=atlas-ollama
|
||
LLAMA_CPP_JAIL_NAME=atlas-llamacpp
|
||
```
|
||
|
||
Notes:
|
||
|
||
- `setup/git.ts` already defaults to `${AGENT_NAME}-git`, so `GIT_JAIL_NAME` is
|
||
usually not required.
|
||
- If you decide to share a local LLM jail across agents, keep a single `ollama`
|
||
jail and point both agents at the same IP instead of creating per-agent LLM jails.
|
||
|
||
### Locale per agent (optional but supported)
|
||
|
||
Each agent can display in its own language without changing the host locale.
|
||
Keep the host system locale stable (UTF-8), then set per-agent display/assistant
|
||
locales in that agent’s `.env`:
|
||
|
||
```env
|
||
DISPLAY_LOCALE=sl-SI
|
||
ASSISTANT_LOCALE=sl-SI
|
||
SYSTEM_LOCALE=sl_SI.UTF-8
|
||
```
|
||
|
||
For a different agent, choose different values (e.g. `de-DE`, `ru-RU`, `zh-CN`).
|
||
Do not use legacy encodings; `SYSTEM_LOCALE` must remain UTF-8.
|
||
|
||
If multiple agents share one tmux server, new panes inherit the server locale.
|
||
Either use separate tmux sessions per agent or set locale env vars inside each
|
||
agent’s rc.d service environment.
|
||
|
||
### 3) Add the new gateway IP to `warden0`
|
||
|
||
Runtime (immediate):
|
||
|
||
```sh
|
||
sudo ifconfig warden0 inet 10.0.1.1/24 alias
|
||
```
|
||
|
||
Persist across reboots (choose the next free alias index):
|
||
|
||
```sh
|
||
sudo sysrc ifconfig_warden0_alias0="inet 10.0.1.1/24"
|
||
```
|
||
|
||
### 4) Update PF NAT to include both subnets
|
||
|
||
If you use an include such as `/etc/pf.warden.conf`, the key idea is:
|
||
|
||
```pf
|
||
warden_net = "{ 10.0.1.0/24, 192.168.72.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
|
||
```
|
||
|
||
Reload PF:
|
||
|
||
```sh
|
||
sudo pfctl -nf /etc/pf.conf
|
||
sudo pfctl -f /etc/pf.conf
|
||
```
|
||
|
||
### 5) Provision the second agent’s service jails
|
||
|
||
From the second agent repo directory:
|
||
|
||
```sh
|
||
sudo just setup-db
|
||
sudo just setup-git
|
||
sudo just setup-cms
|
||
sudo just setup -- --step ollama # optional
|
||
sudo just setup -- --step llama-cpp # optional
|
||
```
|
||
|
||
Database provisioning can be done either via `just setup-db` (or `npm run setup -- --step db`) or via Ansible
|
||
playbooks in `infra/ansible/playbooks/`.
|
||
|
||
### 6) Install and start the second rc.d service
|
||
|
||
```sh
|
||
sudo just setup -- --step service
|
||
sudo service atlas onestart
|
||
```
|
||
|
||
## bhyve note
|
||
|
||
If you deploy one agent per **bhyve VM**, you typically do **not** need any of
|
||
the same-host subnet aliasing or multi-subnet PF rules. Each VM can keep a
|
||
single-agent `warden0` + single `/24` internally.
|