# Multi-Agent Coordination ollie exposes agents as filesystem objects via the 9P protocol. This means multi-agent coordination requires no framework, SDK, or message bus — it is ordinary shell scripting against a mounted filesystem. ## The Namespace Every session lives under `/session/{name}/` where `{name}` is the session's **mutable human-readable name** (not the immutable UUID — see `id` and `name` files). Session directories are keyed by Name; renaming a session via writing to its `name` file moves the entire directory subtree. | Path | Purpose | |------|---------| | `/session/new` | Create an empty session (write `name=...`, read back name) | | `/session/{name}/agent/new` | Create an agent within a session (write `cwd=... backend=...`) | | `/session/{name}/env` | Session environment variables | | `/session/{name}/id` | Immutable session UUID | | `/session/{name}/name` | Mutable session name (write to rename) | | `/session/{name}/agent/{aname}/prompt` | Submit a prompt | | `/session/{name}/agent/{aname}/chat` | Streaming chat (filtered text) | | `/session/{name}/agent/{aname}/plan` | Agent-scoped markdown checklist | | `/session/{name}/agent/{aname}/cfg` | Agent config KV: backend, model, agent, cwd, params | | `/session/{name}/agent/{aname}/statewait` | **Blocking read** — returns when state changes | | `/session/{name}/agent/{aname}/ctl` | Control commands: `stop`, `kill`, `compact`, `rn ` | | `/session/{name}/agent/{aname}/id` | Immutable agent ID (uname) | | `/session/{name}/agent/{aname}/name` | Mutable display name (write to rename) | Global request-response files provide stateless operations without sessions: | File | Purpose | |------|---------| | `/generate` | Write prompt, read response (one-shot generation) | Global namespaces are shared across all sessions: | Path | Purpose | |------|---------| | `/session/idx` | Session index (id, state, cwd, backend, model) | | `/session/{name}/agent/{aname}/plan` | Agent checklist | | `/session/{name}/agent/{aname}/chat` | Streaming filtered text | ## Spawning Agents From within an agent session, use `subagent_spawn`: ```sh subagent_spawn [-name NAME] [-agent AGENT] [-backend BACKEND] [-model MODEL] [-cwd DIR] ``` This creates a child session + agent atomically, writes the prompt, and returns the session path (e.g. `session/my-session`). Child sessions carry the parent session ID in their name, so the spawning tree is recoverable from session IDs alone. For transient `subagent_spawn` calls, the child gets its own context window and runtime state. It receives a one-time snapshot of the parent's conversation history, not a live shared context. The child cannot mutate the parent's history, and the parent receives only the child's final reply. The parent explicitly decides how to incorporate that reply. Workspace changes and other shared resources are coordinated separately through toolsrv locks. ### Explicit Two-Step Creation Session creation can be split into two phases for advanced orchestration scenarios: 1. **Create empty session**: `echo "name=my-session" | ollie-9p rdwr session/new` 2. **Add agent**: `echo "cwd=$HOME agent=default backend=openai model=gpt-4o" | ollie-9p rdwr session/my-session/agent/new` Empty sessions (`Core=nil`) are valid — they appear in `session/idx`, have no running agent, and can be killed or renamed. This enables pre-provisioning session directories before the agent environment is ready. ## Coordination Patterns ### Hub-and-Spoke (Conductor) ```mermaid flowchart TB ROOT["Root Agent\n(reasoning)"] W1["Worker A\n(cheap model)"] W2["Worker B\n(cheap model)"] ROOT -- "subagent_spawn" --> W1 ROOT -- "subagent_spawn" --> W2 W1 -- "statewait → read chat" --> ROOT W2 -- "statewait → read chat" --> ROOT ``` A root agent reasons about a task and delegates subtasks to workers. Workers report back via their log; the conductor reads `/session/{name}/agent/{aname}/log` after `statewait` unblocks. ```sh # Conductor spawns two workers worker_a=$(subagent_spawn -model haiku "analyse /src/a.go") worker_b=$(subagent_spawn -model haiku "analyse /src/b.go") # Wait for both until [ "$(cat $worker_a/state)" = "idle" ]; do cat $worker_a/statewait; done until [ "$(cat $worker_b/state)" = "idle" ]; do cat $worker_b/statewait; done # Collect results cat $worker_a/chat $worker_b/chat ``` The conductor and workers can run on different models. Mechanical analysis goes to cheaper models; reasoning stays on the expensive one. ### Pipeline ```mermaid flowchart LR A["Step 1\nExtract TODOs"] B["Step 2\nPrioritise"] A -->|"/tmp/todos.txt"| B ``` Agent A produces output; agent B consumes it. Composition via `/tmp/` or direct path passing. ```sh step1=$(subagent_spawn "extract all TODOs from /src/ and write to /tmp/todos.txt") until [ "$(cat $step1/state)" = "idle" ]; do cat $step1/statewait; done subagent_spawn "prioritise the TODOs in /tmp/todos.txt and produce a plan" ``` ### Scatter-Gather (Swarm) ```mermaid flowchart TB P["Parent"] S1["Worker 1"] S2["Worker 2"] S3["Worker N"] P --> S1 P --> S2 P --> S3 S1 --> P S2 --> P S3 --> P ``` Spawn N workers in parallel, collect when all reach `idle`. Because `statewait` blocks until state changes, no polling loop is needed. ```sh # Scatter for f in /src/*.go; do subagent_spawn "review $f for security issues" & done wait # wait for all subagent_spawn calls to return session paths ``` Or from within `shell`: ```json { "steps": [ { "parallel": [ { "code": "subagent_spawn 'task A'" }, { "code": "subagent_spawn 'task B'" }, { "code": "subagent_spawn 'task C'" } ]} ] } ``` ### Peer-to-Peer Any agent can read any other agent's session directory. There is no privileged orchestrator role — agents coordinate by reading each other's `chat` and `state` files directly. A peer can wait on another peer's `statewait`, then act on what it reads in `chat`. ### Reactive / Event-Driven `statewait` is a proper synchronization primitive. A shell script (or another agent) blocks on it and wakes exactly when the target agent transitions state. This enables event-driven pipelines without polling: ```sh # Block until agent finishes, then trigger downstream work cat /session/worker-123/statewait # agent is now idle — proceed ``` ### Self-Directed Spawning Agents can spawn sub-agents mid-task without human direction. If an agent determines that parallelism or specialization would help, it calls `subagent_spawn` on its own. No human prompt is required to initiate a multi-agent workflow — the model decides. ## Design Principle ollie imposes no coordination model. There is no built-in conductor, swarm layer, or workflow engine. Orchestration is handled by the surrounding environment — shell scripts, cron, systemd, containers, or another agent. This is intentional. The filesystem namespace is the API. Any tool that can read and write files can participate in a multi-agent workflow, which means the full Unix toolchain is available as an orchestration layer.