Project structure
A Zooid project — sometimes called a workforce — is a directory on your disk. Everything zooid needs lives inside it: the configuration, secrets, and per-agent workspaces. This guide walks the layout and explains what each piece is for.
The layout
my-zooid/ zooid.yaml # workforce config: agents, transports, runtime .env # API keys and secrets (gitignored) .gitignore # ignores .env and data/ by default agents/ architect/ # one agent's workspace dev/ qa/ data/ # runtime state: homeserver db, sessions, logs (gitignored)The directory containing zooid.yaml is the workforce root. Run
zooid dev (or zooid start) from there. Agents are scoped to their
own subdirectory under agents/<name>/ — that’s the agent’s working
directory, the only place it can write files.
zooid.yaml
Workforce-as-code: the single source of truth for which agents exist, which rooms they join, what model they run on, and what runtime hosts them ([ZOD033]). See the Quickstart for a minimal example.
.env
Provider API keys (Anthropic, Vertex, OpenAI, …) and any other
secrets your agents need. zooid dev also writes the auto-generated
Matrix Application Service tokens here. Never bind-mounted into
agent containers — the runtime’s mount allowlist excludes it on
purpose.
agents/<name>/
Each agent’s working directory. The agent reads and writes files here
and nowhere else. Drop project files the agent needs into its own
folder; if multiple agents share files, see the shared/ reserved
namespace.
If you want to give an agent its own role prompt or project
conventions, the shim’s standard convention files work natively: a
CLAUDE.md in agents/architect/ is picked up by Claude Code via
upward-traversal, an AGENTS.md is picked up by opencode and codex,
and so on. These are not zooid-specific — zooid just makes sure they
reach the agent’s filesystem on both the local and docker runtimes.
The same applies to a CLAUDE.md / AGENTS.md at the workforce
root: optional, user-authored, inherited by every agent in the
workforce.
data/ — runtime state
Anything zooid generates while running goes into the persistent data root, which defaults to data/:
data/ matrix/ # tuwunel-mounted state (config, db, media, registrations) logs/ # daemon + tuwunel logs agents/ # per-agent daemon state <agent-id>/ sessions.jsonmatrix/contains the Tuwunel homeserver database and configurations.logs/acts as a unified log directory for the daemon and the Tuwunel container.agents/stores per-agent runtime state, such assessions.jsonholding active ACP sessions.
It’s recreated on demand, gitignored by default, and safe to delete between runs if you want a clean slate. You can override the root directory via the --data CLI flag.
.gitignore
zooid init seeds a .gitignore that excludes .env, data/, and
node_modules/ — the things you never want in version control. The
rest of the workforce (config, agent workspaces, anything project
context you author) is meant to be committed: that’s how you share
a workforce with collaborators or move it between machines.
What zooid creates for you
Running zooid dev (or zooid init) on a fresh directory seeds
zooid.yaml, .env, .gitignore, and the agents/ directory with
sensible defaults. It does not seed CLAUDE.md, AGENTS.md, or
any other shim convention file — those are entirely up to you, the
same way they would be in any other project. Everything zooid does
seed is user-editable and won’t be rewritten on subsequent runs.