A Red workflow that turns one colors.yml into a running Agent Network
demo: OpenTofu for the machine, its provider firewall and two Cloudflare records
(the base name and its wildcard); Ansible for Traefik, the combined
netbird-server, the dashboard in agent-network-only mode, the NetBird
reverse proxy in private mode, the control plane (provider, guardrail,
policy, global limit), and the isolated agent container.
The demo's claim: the agent has no internet path — two independent boundaries, an internal Docker network and DOCKER-USER rules — and its only route to an LLM is the keyless agent-network endpoint over the WireGuard tunnel, where every request carries the peer's identity, passes the policy, and is metered. Convergence proves the claim (positive and negative space both) or fails.
Compute library boundary
All three implementations depend directly on colors-compute at
ae28ea74962bb1897fa6365c143c1d43ac1fe095. ONCE at
a1fe1be7a427dd2e406ff7befd1c43a53e7c3618 supplies application domain helpers only.
The library owns provider selection, required options, credentials, OpenTofu
VM/firewall/key resources, remote R2/S3 state, identity checks, leases, and
managed key cleanup. Do not add provider registries or VM templates here.
A library version bump supplies additional compatible providers; unsupported
requested capabilities fail before compute mutation.
This package requests one public node, IPv6 disabled, TCP 22 from SSH
sources, TCP 80/443 from HTTP sources, and its STUN UDP port from STUN sources.
The library reads neutral agent-network-ssh-sources,
agent-network-http-sources, and agent-network-stun-sources, falling back to
the selected provider's source keys. SSH sources cannot be empty. Empty HTTP
or STUN sources keep those ports closed. The public-only singleton needs no
owned private network by default; DigitalOcean may assign its provider default
VPC. Existing Vultr and DigitalOcean fixtures cover both key modes.
build writes library JSON under compute/shared and compute/nodes/0, with
library-produced remote backend documents. It performs no cloud calls or key
reads. Runtime creation acquires owned state before compute credentials or keys;
unknown, unreadable, mismatched, and legacy combined compute state are refused.
The old <profile>/agent-network-infrastructure.tfstate requires an explicit
migration procedure; absence must never be inferred from a failed read.
Create runs compute, canonical SSH alias, DNS, application, then acceptance.
Delete inspects owned state, tears down the application, removes DNS and alias,
then destroys library compute and removes its managed key. The profile alias
contains the actual node user/address; only managed mode adds IdentityFile.
An explicitly selected external private path reaches Ansible and acceptance SSH.
The package owns its locked SSH updater; existing profile-only markers are
recognized. Generated credentials, STUN, tunnel-only policy, and all isolation
acceptance gates remain application-owned.
Verbs
./red build # render .colors/<profile>/ — no provider calls, no credentials
./red create --dry-run # walk the workflow, skip every side effect
./red create # converge for real
./red delete # guarded; needs a one-run override
Exit code 2 is validation or usage failure and lists every problem at once. The
launcher walks up from the working directory to find colors.yml.
Before you converge
- The hostname and its wildcard must be free in the Cloudflare zone. The DNS stage creates both and never adopts a foreign record.
- Five credentials must be set in
.envrc.private— the selected compute provider's, Cloudflare's, the two R2 keys and the Anthropic key; seereferences/configuration.md. Never exportCOLORS_PAR_PROFILE. - A deliberately fake
COLORS_PAR_ANTHROPIC_API_KEYis a supported mode: the acceptance suite then expects Anthropic's own 401 relayed through the proxy, which still proves isolation, tunnel, policy and key injection while never producing a billable completion. Swap in a real key and re-run create to upgrade the demo to real completions.
Disposability
This deployment is disposable by design: no backups, and recovery is a
guarded delete followed by create. The endpoint hostname and every peer
identity are regenerated by the next create; nothing on the box is worth
outliving it.
Operating
agent-network-status, agent-network-smoke, agent-network-bootstrap on
the host. The dashboard admin password is generated on the host:
/etc/agent-network/secrets/admin_password.
Rules
colors.ymlis the only file to edit..colors/is generated: never edit it, read it as source, or commit it.- Credentials are
COLORS_PAR_<UPPER_SNAKE_KEY>variables in the gitignored.envrc.private, never incolors.ymlor documentation. - Never weaken
compute-prevent-destroyin committed desired state. - The installed launcher is a copy, not a symlink. After
npx skills update -p, copy.agents/skills/package-agent-network-red/redover the root./red.
Validated retired compute prevents remote Ansible during delete even when caller input retains a stale IP or private-key path. Remaining application and local cleanup keeps its existing ordering. Normal creation still converges the application.