From c25e2e708c8237ed330c400ab1a9569ba9d662f0 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Fri, 14 Aug 2026 15:09:02 +0200 Subject: [PATCH] doc: add sub-agents to evolution.md and README --- README.md | 1 + doc/evolution.md | 101 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/README.md b/README.md index 53db148..edff930 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ Everything lives under `$XDG_CONFIG_HOME/ollie/` (default: `~/.config/ollie/`) | **Remote execution** | Set `remote=user@host` in session config | | **Background processes** | Pass `"background": true` to any tool — runs with no timeout, output pushed to agent prompt on completion | | **Parallel execution** | Non-conflicting tool calls within a turn run in parallel (scope-based conflict scheduling) | +| **Sub-agents** | `subagent_spawn` — delegate work to a transient agent, block until done, get the reply. Multiple spawns run in parallel. | | **Agents** | Write a JSON config in `~/.config/ollie/agents/` with agent prompt in `~/.config/ollie/prompts/` | | **Tools** | Drop an executable + `.meta` in `~/.config/ollie/tools/` — load at runtime via `tool_load` | | **Tool definitions** | Define tools with `.meta` files only — no wrapper script needed ([doc](doc/tool-definitions.md)) | diff --git a/doc/evolution.md b/doc/evolution.md index fda219d..81f5ffc 100644 --- a/doc/evolution.md +++ b/doc/evolution.md @@ -54,6 +54,7 @@ gantt fs/ flattening :done, 2026-08-11, 1d Feed + observer agents :done, 2026-08-13, 1d BlockOnce/Stream refactor :done, 2026-08-13, 1d + Sub-agents via 9P rdwr :done, 2026-08-14, 1d ``` ## Phase 1: Monorepo Bootstrap (Apr 11) Started as independent git repos unified under a monorepo with submodules. @@ -1449,3 +1450,103 @@ Three related changes in one session. Net **+278 SLOC** across 21 files. | `BlockOnceRaw` as primary API | Forced handlers to implement blocking themselves | | Concurrent-by-default tool execution | Rejected: turns one reasoning step into N generation cycles with partial info — sequential but slower and more expensive | +## Sub-Agents via 9P rdwr (Aug 14) + +Sub-agents implemented in **42 net lines of code**. The entire feature is +wiring — no new infrastructure, no new concepts, no new processes. + +### The mechanism + +`session/{sname}/agent/new` is an `Rdwr` file. Without `prompt=`, it creates +a persistent agent and returns its ID (existing behavior). With `prompt=`, it +enters sub-agent mode: creates a transient agent, submits the prompt, blocks +until the agent finishes, returns the reply, and destroys the agent. + +``` +printf 'cwd=%s\nprompt=fix the tests\n' "$PWD" \ + | ollie-9p rdwr session/$OLLIE_SESSION_ID/agent/new +``` + +### Why it works in 42 lines + +The infrastructure was already there: +- **`Rdwr` file primitive** (née `Request`) — atomic write-then-read, per-open isolation +- **`Agent.Submit()`** — already blocks through the full turn +- **`Agent.Reply()`** — already captures the final response +- **`Session.RemoveAgent()`** — already handles cleanup +- **Event bus** — normal agent lifecycle events fire (GUI sees sub-agents appear/disappear) + +The handler is just: parse params → create agent → submit → read reply → destroy → return. + +### Path-based lock table + +Prerequisite: moved conflict serialization from the agent loop into toolsrv +itself. All foreground tool calls now acquire a path-based lock before execution: + +- `scope "read"` — no lock (never conflicts) +- `scope "write"` — exclusive lock on the file path +- `scope "global"` — exclusive global lock + +This ensures sub-agents writing to the same file serialize correctly regardless +of which agent initiated the call. The agent loop's batching remains as a +performance optimization; correctness is enforced at the execution layer. + +### Parallel dispatch + +`subagent_spawn` is declared `scope: "read"` — multiple spawn calls in the same +turn run in parallel automatically. The calling agent blocks until all results +return. No shell backgrounding, no polling, no coordination code. + +```mermaid +sequenceDiagram + participant P as Parent Agent + participant S1 as Sub-Agent 1 + participant S2 as Sub-Agent 2 + + P->>S1: subagent_spawn(prompt="task A") + P->>S2: subagent_spawn(prompt="task B") + Note over P: blocked (parallel tool calls) + S1-->>P: reply A + S2-->>P: reply B + Note over P: resumes with both results +``` + +### What was killed + +- **`subagent_generate`** — JIT agent profile generation tool. Obsolete: sub-agents + use existing profiles directly. +- **D-Bus spawn path** — `subagent_spawn` previously used `dbus-send` to create + sessions. Replaced by a 3-line `ollie-9p rdwr` call. + +### Framework rename: `Request` → `Rdwr` + +The three atomic 9P operations are now named for what they are: +- `Read` — non-blocking read +- `Write` — non-blocking write (fire-and-forget) +- `Rdwr` — atomic write-then-read (blocking, produces result) + +`BlockOnce` and `Stream` are special cases of `Read`. +`Rdwr` is its own primitive — not a variant of either. + +### Architecture validation + +This feature is evidence that the "everything is a file" architecture works at +scale. A major capability (parallel sub-agents with automatic serialization) +landed as pure wiring because: + +1. The 9P namespace already exposes `agent/new` as an rdwr file +2. The agent loop already blocks and produces results +3. The tool server already serializes conflicting writes by path +4. The batching algorithm already parallelizes non-conflicting calls + +No new abstractions. No new processes. No new protocols. Just connecting +existing pieces with 42 lines of glue. + +### Future work + +- **Shared toolsrv per host** — currently each session spawns its own toolsrv. + Cross-session path serialization requires sessions to share a single toolsrv + instance per host. +- **Budget/depth controls** — token limits, step limits, and recursion depth + caps for sub-agents. +