6.5 KiB
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 <name> |
/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:
subagent_spawn [-name NAME] [-agent AGENT] [-backend BACKEND] [-model MODEL] [-cwd DIR] <prompt>
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.
Explicit Two-Step Creation
Session creation can be split into two phases for advanced orchestration scenarios:
- Create empty session:
echo "name=my-session" | ollie-9p rdwr session/new - 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)
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.
# 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
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.
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)
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.
# 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:
{
"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:
# 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.