Define a team
Guide (informative) · For: operators · Prereqs: Quickstart
The Quickstart gives you one agent. To run a specific team (your own
channels, your own agents, and the channel access for each agent), describe it once in a
cotal.yaml and launch it with a single command.
What a manifest is
Section titled “What a manifest is”A manifest (cotal.yaml, kind: Mesh) is the declarative form of what you’d otherwise do by
hand: start a broker, seed channels, spawn agents, and mint each agent creds scoped to the channels
it may use. It is a convenience over the CLI and adds no wire concepts. Today it is single-space
(one space: per file).
It is channel-centric: you list the channels, and under each one name the agents that may read and post. Cotal inverts that into one least-privilege credential per agent, so the file reads the way you think about a team (“who’s in #review?”), while each agent only gets the access you granted.
Quickstart
Section titled “Quickstart”A complete, runnable manifest (two agents, two channels, no separate files):
apiVersion: cotal/v1kind: Meshspace: main # the default space, runnable fresh or right after `cotal up`agent: claude # the harness that runs each agent
agents: # inline personas (no external files needed) planner: instructions: Break the work into steps and post the plan. builder: instructions: Implement the smallest change that works.
channels: general: subscribe: [planner, builder] # auto-listen at boot allowPublish: [planner, builder] # may post: default-deny, so list everyone who posts review: subscribe: [planner] # only planner auto-listens allowSubscribe: [planner, builder] # builder MAY read #review, but isn't auto-subscribed allowPublish: [planner, builder]Save it as cotal.yaml and launch:
cotal topology view -f cotal.yaml # validate + render the access graph (no broker needed)cotal up -f cotal.yaml # broker + channels + agents, all freshcotal ps --space main # see the agents the manager bootedcotal web --space main # ...or watch it in the browsercotal down # stop the whole meshThe manifest introduces no access model of its own; the three verbs are the same ones
Cotal uses everywhere: subscribe (auto-listen at boot, and implicitly may read),
allowSubscribe (read; defaults to subscribe, must be a superset of it), and
allowPublish (post; default-deny: an empty or omitted list means nobody posts).
Above, builder may read #review but doesn’t auto-listen to it. Every top-level key,
the three agents: forms, channel cards, and the resolution rules are in the
manifest reference.
The command lifecycle
Section titled “The command lifecycle”| Command | What it does |
|---|---|
cotal topology view -f <file> |
Validate the file and render its access graph. Read-only: needs no broker, mutates nothing. Run it before you launch. |
cotal up -f <file> |
Bring up a fresh mesh: broker + seeded channels + booted agents. |
cotal spawn -f <file> |
Deploy a manifest additively onto a mesh that is already running. |
cotal down [-f <file>] |
Tear down (see “Tearing down” below). |
up -f and spawn -f accept --dry-run (preview the plan, change nothing). up -f also takes
--server / --host / --space / --runtime / --open to override the file for one run.
If a Cotal mesh is already running at the manifest’s broker address (e.g. the default
127.0.0.1:4222fromcotal up),up -frefuses; it never re-seeds a live broker. The check is on the address, not thespace:name. Runcotal downfirst, point the manifest at another address (broker: { servers: nats://127.0.0.1:14999 }, or--server), or usecotal spawn -fto deploy onto the running mesh.
Tearing down. A fresh mesh from up -f is torn down with plain cotal down: it owns the
whole space. An additive deploy from spawn -f is torn down with cotal down -f <file> (or
cotal down -f <file> --run <id>), which removes only that run’s agents and channels.
Manifest ownership
Section titled “Manifest ownership”The rule: up -f owns the whole space; spawn -f owns only what it created. Cotal only ever
tears down what it owns; foreign actors on a shared mesh are never touched.
- A fresh mesh from
up -f→cotal downstops all of it. - An additive deploy from
spawn -frecords a creation-only ledger (.cotal/manifests/<runId>.json) of the channels and agents it added;cotal down -fremoves only those. The run id is printed byspawn -fand is the filename under.cotal/manifests/; pass it todown -f --run <id>when the file has changed since the deploy (an edited file no longer matches its ledger) or to finish a teardown that was retained.
down -f is deliberately conservative; it treats the ledger as untrusted and validates before
deleting: an owned agent is stopped only when the live agent’s recorded name and id match; an
owned channel is removed only when no other members remain; and if the broker is unreachable or
anything is uncertain, nothing remote is removed and the ledger is retained for a later
down -f --run <id>. It is local-only: run it from the checkout that created the run.
(.cotal/ holds creds, the ledger, and runtime artifacts: add it to your .gitignore; commit
your cotal.yaml and persona files, not what’s under it.)
Deploying onto a shared mesh (spawn -f)
Section titled “Deploying onto a shared mesh (spawn -f)”spawn -f is additive and never adopts or mutates anything it didn’t create. It classifies each
declared item against the live mesh:
| Item | Classification | Behaviour |
|---|---|---|
| Channel, brand-new | created + owned | Seeded and recorded in the ledger. |
| Channel, already present | exists-unmanaged |
Left untouched: card not mutated; the desired card is shown against the live one. |
| Agent, not yet created | will-create | Booted and recorded. |
| Agent, already created, unchanged | already-owned | No-op. |
| Agent, already created, policy changed | stale |
Exits non-zero unless --allow-stale <names> (then it restarts). |
Security. If an unmanaged actor already has read access to a channel you declare,
spawn -fprints a warning: an isolation conflict on a shared mesh. It is an explicit lower bound (presence plus the broker membership feed), not a guarantee that no other access exists.
Deploying to a remote manager. The mesh’s manager may live on another machine (or another
checkout): spawn -f detects that from the manager lease and pushes the resolved launch spec
inline over the control plane. The manager validates it as untrusted input and persists it under
its own .cotal/run/ before launching, so nothing changes downstream. Run the deploy from the
checkout the mesh is registered to on your machine (that’s where the ledger lands), and run
down -f from that same checkout; it stops remote agents over the control plane and treats a
locally-absent cred file as proven-absent. One residual: the agents’ cred files minted on the
manager’s host stay there until the mesh’s own cleanup, the same way it would after a crash.
Operating a manifest mesh
Section titled “Operating a manifest mesh”Every mesh-touching command resolves the broker from the mesh registry, so --space <name> is
enough; send, channels, console, web, the manifest verbs, and the manager control commands
(cotal ps / stop / attach, plus cotal spawn --detach) all reach a manifest mesh on any port
with no --server:
cotal ps --space research-team # finds research-team's broker via the registry--server remains an explicit override for an off-registry broker.
See manifest.md for the complete field reference and the resolution rules,
channels and permissions for the access model, and
agent files for the persona format the agents: entries point at.