diff --git a/doc/evolution.md b/doc/evolution.md index 8a2f7b9..5ff3468 100644 --- a/doc/evolution.md +++ b/doc/evolution.md @@ -95,6 +95,7 @@ gantt Markdown parsing + output cap :done, 2026-08-16, 1d Goals + conductor workflow :done, 2026-08-17, 1d Split session/agent indexes :done, 2026-08-17, 1d + Agent peers + consensus :done, 2026-08-19, 1d ``` ## Phase 1: Monorepo Bootstrap (Apr 11) Started as independent git repos unified under a monorepo with submodules. @@ -1861,3 +1862,69 @@ remote host, while `--yolo` remains the explicit way to disable enforcement. The project was also described more precisely as a distributed, integrating AI agent runtime: orchestration and model calls remain local while toolsrv, tools, and external systems can be composed locally or across remote hosts. + +## Phase 34: Agent Peers and Consensus Workflow (Aug 19) + +Inter-agent communication gained a first-class mechanism: **peer links**. +Previously, agents in the same session could only be addressed from external +scripts or through sub-agent spawn (which is transient). The peer system adds +persistent, topology-controlled messaging between agents within a session. + +### Peer mechanism + +Each agent exposes a `peer/` directory in its 9P namespace. Entries are +write-only files named after peer agents. Writing to `peer/{name}` delivers +the message to the named agent's prompt handler — identical semantics to +writing to that agent's `prompt` file, but scoped by the peer relationship. + +Peer links are **bidirectional**: `peeradd A` on agent B also adds B to A's +peer set. This is enforced in the `peeradd`/`peerdel` ctl commands. The +topology constrains who can talk to whom — if an agent has no peer link to +another, it has no `peer/{name}` file and cannot message it. This is the +access control surface. + +Implementation details: +- Agent struct: `peers map[string]struct{}` + RWMutex, lazy-init +- Methods: `AddPeer`, `RemovePeer`, `Peers` (sorted) +- `peer/` declared as a `virtfs.Each` node — dynamic directory rebuilt from peer set +- `peeradd`/`peerdel`/`peers` ctl commands with bidirectional enforcement +- Peer cleanup on agent removal: `RemoveAgent` strips the dead agent from all remaining peer sets +- Peers persisted in `PersistedAgent.Peers` field; restored after all agents are created +- `peeradd`/`peerdel` trigger immediate `s.Save()` for durability + +Total Go additions: ~55 lines in agent.go, ~50 lines in spec.go, ~15 lines in persist.go and session.go. + +### Consensus workflow + +The first workflow to use peers: `consensus`. Unlike the conductor (which +decomposes a goal into sequential/parallel subtasks), consensus runs the +**same task N times independently** and synthesizes agreement. + +The workflow creates: +- 1 **foreman** agent (profile: foreman, temp 0.3) — synthesis only, no investigation +- N **panelist** agents (profile: panelist, temp 0.7) — independent analysis + +Each panelist is linked as a peer of the foreman (bidirectional). Panelists +cannot message each other — the topology enforces the protocol. + +Flow: +1. Workflow script creates agents, establishes peer links, primes all +2. Each panelist investigates the goal from a different angle (correctness, simplicity, edge cases) +3. Panelists write findings to `peer/foreman` when done +4. Each delivery triggers a turn on the foreman +5. After receiving all N reports, the foreman synthesizes consensus in its chat output +6. Foreman writes "complete" to goalstatus + +The consensus output lives in the foreman's chat — the goal file is never +overwritten. This respects the separation: goal = what to do, chat = what +was learned. + +### Design insight + +Peers vs sub-agents is not a replacement — it's a complementary primitive: +- **Sub-agents** are stateless, transient, fire-and-forget. Good for decomposition. +- **Peers** are persistent, stateful, conversational. Good for deliberation. + +The conductor workflow uses sub-agents (decompose → delegate → collect). +The consensus workflow uses peers (investigate independently → report → synthesize). +Both are wiring over the same 9P primitives.