ollie/doc/resources/multi-agent.md

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:

  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)

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.