Skip to content

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.json
  • matrix/ 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 as sessions.json holding 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.