Skip to content

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.

  • 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

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.

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:

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.

Example: add a second agent named atlas on 10.0.1.0/24.

Use a separate clone so each agent has its own .env, logs/, and runtime state.

Minimum keys to set (example values):

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):

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.

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:

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.

Runtime (immediate):

Terminal window
sudo ifconfig warden0 inet 10.0.1.1/24 alias

Persist across reboots (choose the next free alias index):

Terminal window
sudo sysrc ifconfig_warden0_alias0="inet 10.0.1.1/24"

If you use an include such as /etc/pf.warden.conf, the key idea is:

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:

Terminal window
sudo pfctl -nf /etc/pf.conf
sudo pfctl -f /etc/pf.conf

5) Provision the second agent’s service jails

Section titled “5) Provision the second agent’s service jails”

From the second agent repo directory:

Terminal window
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

Section titled “6) Install and start the second rc.d service”
Terminal window
sudo just setup -- --step service
sudo service atlas onestart

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.