diff --git a/EVENTS.md b/EVENTS.md
index fa47d0e..26126cf 100644
--- a/EVENTS.md
+++ b/EVENTS.md
@@ -1,6 +1,12 @@
# Events System
-The events system provides a real-time text stream of all AnviLLM activity.
+The events system provides a real-time text stream of all AnviLLM activity using [github.com/simonfxr/pubsub](https://github.com/simonfxr/pubsub) as the event bus.
+
+## Architecture
+
+
+
+Multiple clients can read from `agent/events` simultaneously, each consuming the same event stream for different purposes: notifications (desktop, SMS, WhatsApp), logging/auditing, custom integrations, etc.
## Reading Events
diff --git a/README.md b/README.md
index 9b62ce5..73724ca 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,18 @@
# AnviLLM
-9P-based LLM orchestrator — Front-ends: Acme, Emacs, TUI, web
+LLM orchestrator using 9P — scriptable, multi-backend, crash-resilient
## Architecture
-**Core:** anvilsrv (9P daemon), anvilmcp (MCP server)
-**Clients:** Assist (Acme), anvillm.el (Emacs), anvillm (TUI), anvilweb (web)
-**Benefits:** Shared sessions, crash-resilient, scriptable via 9P, service integration, MCP support, **cross-backend agent communication**
+
+
+**Core:** anvilsrv (9P daemon), anvilmcp (MCP server), anvilwebgw (API proxy)
+**Clients:** Assist (Acme), anvillm.el (Emacs), anvillm (TUI), anvilweb (web)
+**Benefits:** Shared sessions, crash recovery, scriptable via 9P, cross-backend agent communication
## Why 9P?
-AnviLLM uses 9P because orchestration becomes file manipulation (`read`, `write`, `ls`, `stat`). Benefits: simplicity, universal access (shell, C, Go, Python, `cat`, `echo`), and composability (Unix pipes, `grep`, `awk`, `jq`). The only requirement is a 9P client (plan9port's `9p` or compatible).
+9P turns orchestration into file operations (`read`, `write`, `ls`, `stat`). Control agents with standard tools: `cat`, `echo`, shell scripts, or any language with file I/O. Compose workflows with Unix pipes, `grep`, `awk`, `jq`. Only requirement: a 9P client (plan9port's `9p` or compatible). Built with [9fans.net/go](https://9fans.net/go).
## Requirements
@@ -29,10 +31,12 @@ cp services/systemd/anvilsrv-user.service ~/.config/systemd/user/
systemctl --user enable --now anvilsrv
# systemd system
-sudo cp services/systemd/anvilsrv.service /etc/systemd/system/ && sudo systemctl enable --now anvilsrv
+sudo cp services/systemd/anvilsrv.service /etc/systemd/system/
+sudo systemctl enable --now anvilsrv
# runit
-sudo cp -r services/runit /etc/sv/anvilsrv && sudo ln -s /etc/sv/anvilsrv /var/service/
+sudo cp -r services/runit /etc/sv/anvilsrv
+sudo ln -s /etc/sv/anvilsrv /var/service/
```
## Usage
@@ -48,8 +52,8 @@ anvilsrv stop
**Namespaces:** Run multiple instances via `$NAMESPACE` (default: `/tmp/ns.$USER.:0`)
```sh
-NAMESPACE=/tmp/ns.$USER.:1 anvilsrv start # :1
-NAMESPACE=/tmp/ns.$USER.:1 Assist # connect
+NAMESPACE=/tmp/ns.$USER.:1 anvilsrv start
+NAMESPACE=/tmp/ns.$USER.:1 Assist
```
### Clients
@@ -60,7 +64,11 @@ NAMESPACE=/tmp/ns.$USER.:1 Assist # connect
**Web:** `anvilweb` (port :8080) — ⚠️ NO auth, localhost only — Remote: `ssh -L 8080:localhost:8080 user@remote`
-**Acme:** Type `Assist` and middle-click — Tag: `Get Attach Stop Restart Kill Alias Context Daemon Inbox Archive` — Right-click ID for prompt window, 2-1 chord for fire-and-forget
+**Acme:** Type `Assist` and middle-click
+
+**Tag commands:** `Get Attach Stop Restart Kill Alias Context Daemon Inbox Archive`
+
+**Interaction:** Right-click ID for prompt window, 2-1 chord for fire-and-forget
| Command | Action |
|---------|--------|
@@ -102,22 +110,54 @@ Available in sandbox YAML files (`~/.config/anvillm/`):
| `{XDG_STATE_HOME}` | XDG state | `$XDG_STATE_HOME` or `~/.local/state` |
| `{ANY_ENV_VAR}` | Environment variable | Any `$ENV_VAR` from the environment |
-**Note:** Templates use `{VARNAME}` syntax. Any environment variable can be referenced.
+Templates use `{VARNAME}` syntax. Any environment variable can be referenced.
## Backends & Sandboxing
-**Backends:** Claude (`npm install -g @anthropic-ai/claude-code`), Kiro ([kiro.dev](https://kiro.dev)), Ollama (local models via [ollie](https://github.com/lneely/ollie)) — Sandboxed with network access
+**Backends:** Claude (`npm install -g @anthropic-ai/claude-code`), Kiro ([kiro.dev](https://kiro.dev)), Ollama (local models via [ollie](https://github.com/lneely/ollie))
+
+**Sandbox:** [landrun](https://github.com/zouuup/landrun) (always enabled) — Defaults: CWD/`/tmp`/config (rw), `/usr`/`/lib`/`/bin` (ro+exec), no network
+
+**Config** (`~/.config/anvillm/`): Layered YAML files, most permissive wins:
+
+
+
+State transitions: `idle` ↔ `running` cycle via CLI hooks (`userPromptSubmit` when user sends prompt, `stop` when agent finishes). Crash → `error` → auto-restart → `starting`. Note: any state can transition to `stopped` or `killed` (not shown); `stopped` can restart → `starting`.
+
+**Self-healing:** Auto-restarts crashes every 5s (preserves context/alias/cwd), skips intentional stops
+
+
+
+Restored sessions automatically resume the latest conversation (kiro: `-r`, claude: `-c`).
+
+**Add backend:** Implement `CommandHandler`/`StateInspector` in `internal/backends/yourbackend.go`, register in `main.go`
### Ollama Backend
-Run local LLMs via Ollama:
+Run local LLMs via Ollama.
**Requirements:**
1. **Ollama:** Install from [ollama.com](https://ollama.com)
```sh
curl -fsSL https://ollama.com/install.sh | sh
- ollama serve # Start server (default: localhost:11434)
- ollama pull qwen2.5-coder:7b # Download a model
+ ollama serve
+ ollama pull qwen2.5-coder:7b
```
2. **Ollie CLI:** Install from [github.com/lneely/ollie](https://github.com/lneely/ollie)
@@ -130,28 +170,11 @@ Run local LLMs via Ollama:
echo 'new ollama /path/to/project' | 9p write agent/ctl
```
-**Configuration:** Set model via environment variable (default: `qwen3:8b`)
+**Configuration:** Set model via `ANVILLM_OLLAMA_MODEL` (default: `qwen3:8b`)
```sh
ANVILLM_OLLAMA_MODEL=llama3.2 echo 'new ollama /path' | 9p write agent/ctl
```
-**Add:** Implement `CommandHandler`/`StateInspector` in `internal/backends/yourbackend.go`, register in `main.go`
-
-**Sandbox:** [landrun](https://github.com/zouuup/landrun) (cannot disable) — Defaults: CWD/`/tmp`/config (rw), `/usr`/`/lib`/`/bin` (ro+exec), no network
-
-**Config** (`~/.config/anvillm/`): `global.yaml` → `backends/.yaml` → `roles/.yaml` (default: `roles/default.yaml`) → `tasks/.yaml` — Most permissive wins
-
-```yaml
-network: {enabled: true, unrestricted: true}
-filesystem: {rw: ["{CWD}", "{HOME}/.npm"]}
-```
-
-Templates: `{CWD}`, `{HOME}`, `{TMPDIR}`, `{XDG_*}` (see Configuration) — Tip: Make `roles/default.yaml` permissive
-
-**Kernel:** 5.13+ (Landlock v1), 6.7+ (v4), 6.10+ (v5 network) — Best-effort: `best_effort: true` (⚠️ unsandboxed if no Landlock)
-
-**Self-healing:** Auto-restarts crashes every 5s (preserves context/alias/cwd) — Skips intentional stops
-
## 9P Filesystem
`$NAMESPACE/agent`:
@@ -188,6 +211,12 @@ agent/
└── mail # Write messages (convenience)
```
+**Client Interactions:**
+
+
+
+Different clients interact with different parts of the filesystem: frontends read state, control files manage sessions, scripts consume events.
+
### Beads
Persistent task tracking via [beads](https://github.com/steveyegge/beads) — Dependency-aware graph
@@ -205,6 +234,14 @@ Config: `~/.beads/` (override: `ANVILLM_BEADS_PATH`) — Shared across namespace
### Events & Mailbox
+**Mailbox Flow:**
+
+
+
+Cross-backend communication: messages route between any participants (user, Claude agents, Kiro agents, Ollama agents) via the mailbox system.
+
+**Examples:**
+
```sh
# Events
9p read agent/events # {"type":"state_change","session_id":"...","state":"running",...}
@@ -223,7 +260,6 @@ echo 'new claude /home/user/project' | 9p write agent/ctl
# List sessions (newest first)
9p read agent/list
-# Output:
# Get most recent session ID
ID=$(9p read agent/list | head -1 | awk '{print $1}')
@@ -232,41 +268,43 @@ ID=$(9p read agent/list | head -1 | awk '{print $1}')
echo '{"to":"'$ID'","type":"PROMPT_REQUEST","subject":"User prompt","body":"Hello"}' | 9p write user/mail
# Check state
-9p read agent/$ID/state # "running" or "idle"
+9p read agent/$ID/state
# Read response from inbox
-9p read user/inbox # Lists message files
+9p read user/inbox
```
See `SECURITY.md`
-## Workflows
+## Bot Templates
-**Multi-Agent Communication:** Agents can communicate with each other **regardless of backend** (Claude, Kiro, etc.) via the built-in mailbox system. The `anvillm-communication` skill provides a convenient interface for agent messaging, enabling heterogeneous multi-agent workflows where different specialists use different backends while collaborating seamlessly.
+Bot templates provide pre-configured agents for common tasks. Templates are shell scripts that create sessions with specialized context and configuration.
-**Skills:** `anvillm-skills list`, `anvillm-skills load anvillm-communication`
-
-**Examples:** `./bot-templates/DevReview claude /path` (dev/reviewer loop), `./bot-templates/Planning kiro /path` (research/eng/editor)
-
-**Pattern:**
+**Available Templates:**
+- `Taskmaster` — Converts project plans into dependency-aware task graphs (beads)
+- `Conductor` — Orchestrates parallel execution by spawning and coordinating specialized agents
+**Usage:**
```sh
-echo "new claude /project" | 9p write agent/ctl
-ID=$(9p read agent/list | tail -1 | awk '{print $1}')
-echo "You are..." | 9p write agent/$ID/context
-echo '{"to":"...","type":"...","subject":"...","body":"..."}' | 9p write agent/$ID/mail
-echo 'new "Task"' | 9p write agent/beads/ctl
+./bot-templates/Taskmaster kiro /path/to/project
+./bot-templates/Conductor kiro /path/to/project
```
-See `bot-templates/`, `kiro-cli/SKILLS_PROMPT.md`
+Templates set up context, roles, and initial configuration. Interact via any client (Assist, TUI, Emacs, Web) or directly via 9P mailbox.
-## Automating Development
+**Creating Templates:** Shell scripts that write to `agent/ctl` and configure `context`, `role`, `tasks`. See existing templates for examples.
-Automate development workflows with Taskmaster and Conductor bots. Input a project plan → Taskmaster creates tasks with dependencies → Conductor orchestrates parallel execution.
+## Autonomous Workflows
+
+Automate workflows with Taskmaster and Conductor bots. Input project plan → Taskmaster creates tasks with dependencies → Conductor orchestrates parallel execution.
+
+
+
+Conductor receives the top-level bead ID, analyzes dependencies, and spawns agents to work in parallel. Agents notify Conductor when blocked; Conductor signals them to resume when dependencies resolve.
### Usage
-Examples below use raw 9P calls. These actions can also be performed from any front-end (Assist, TUI, Emacs, Web).
+Examples use raw 9P calls. These actions can also be performed from any front-end (Assist, TUI, Emacs, Web).
**1. Taskmaster: Create tasks from project plan**
@@ -291,13 +329,13 @@ CONDUCTOR_ID=$(9p read agent/list | head -1 | awk '{print $1}')
echo '{"to":"'$CONDUCTOR_ID'","type":"WORK_REQUEST","subject":"Execute","body":"Complete bead '$BEAD_ID'"}' | 9p write user/mail
```
-Conductor analyzes dependencies, spawns specialized bots (DevReview, Research, Docs), and delegates work in parallel.
+Conductor analyzes dependencies, spawns specialized bots, and delegates work in parallel.
**Monitoring:** Use any front-end (Assist, TUI, Emacs, Web). For custom integrations, see `EVENTS.md`.
## MCP Integration
-`anvilmcp` exposes AnviLLM via Model Context Protocol for Claude Desktop, Cline, etc
+`anvilmcp` exposes AnviLLM via Model Context Protocol for Claude Desktop, Cline, etc.
**Install:**
```sh
@@ -306,7 +344,7 @@ Conductor analyzes dependencies, spawns specialized bots (DevReview, Research, D
**Tools:** `read_inbox`, `send_message`, `list_sessions`, `set_state`
-Enables LLM clients to control AnviLLM sessions and communicate with agents
+Enables LLM clients to discover agents and communicate via the mailbox system.
## Troubleshooting
diff --git a/bot-templates/DevReview b/bot-templates/DevReview
deleted file mode 100755
index 366c74d..0000000
--- a/bot-templates/DevReview
+++ /dev/null
@@ -1,122 +0,0 @@
-#!/bin/bash
-# DevReview - Developer-Reviewer Workflow
-# Usage: ./scripts/DevReview
-
-set -e
-
-if [ $# -ne 2 ]; then
- echo "Usage: $0 "
- echo " backend: claude, kiro-cli"
- exit 1
-fi
-
-BACKEND="$1"
-PROJECT_PATH="$2"
-PROJECT_NAME=$(basename "$PROJECT_PATH")
-
-# Generate a random short identifier
-RANDOM_WORD=$(shuf -n1 -e alpha beta gamma delta zeta theta kappa sigma omega lambda)
-RANDOM_NUM=$(printf "%02d" $((RANDOM % 100)))
-ALIAS_NAME="${RANDOM_WORD}${RANDOM_NUM}"
-
-echo "Setting up Developer-Reviewer workflow for: $PROJECT_NAME"
-echo "Project path: $PROJECT_PATH"
-echo "Session alias: $ALIAS_NAME"
-
-NAMESPACE=$(namespace)
-if [ -z "$NAMESPACE" ]; then
- echo "Error: No namespace found. Is anvillm running?"
- exit 1
-fi
-
-AGENT_MOUNT="agent"
-
-echo "Creating developer session..."
-before=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-echo "new $BACKEND $PROJECT_PATH role=developer tasks=git,editor,go,rust,python,nodejs,docker,podman,maven,gradle,plan9,gpg,github-cli,agent-q" | 9p write $AGENT_MOUNT/ctl
-after=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-DEV_ID=$(comm -13 <(echo "$before") <(echo "$after") | head -1)
-echo "Developer session ID: $DEV_ID"
-
-echo "Creating reviewer session..."
-before=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-echo "new $BACKEND $PROJECT_PATH role=reviewer tasks=git,github-cli,plan9,agent-q" | 9p write $AGENT_MOUNT/ctl
-after=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-REVIEWER_ID=$(comm -13 <(echo "$before") <(echo "$after") | head -1)
-echo "Reviewer session ID: $REVIEWER_ID"
-
-# Set aliases
-echo "Setting aliases..."
-echo "${ALIAS_NAME}-dev" | 9p write $AGENT_MOUNT/$DEV_ID/alias
-echo "${ALIAS_NAME}-reviewer" | 9p write $AGENT_MOUNT/$REVIEWER_ID/alias
-
-# Set developer context
-cat <
-
-set -e
-
-if [ $# -ne 2 ]; then
- echo "Usage: $0 "
- echo " backend: claude, kiro-cli"
- exit 1
-fi
-
-BACKEND="$1"
-PROJECT_PATH="$2"
-PROJECT_NAME=$(basename "$PROJECT_PATH")
-
-# Generate a random short identifier
-RANDOM_WORD=$(shuf -n1 -e alpha beta gamma delta zeta theta kappa sigma omega lambda)
-RANDOM_NUM=$(printf "%02d" $((RANDOM % 100)))
-ALIAS_NAME="${RANDOM_WORD}${RANDOM_NUM}"
-
-echo "Setting up Developer-Reviewer workflow for: $PROJECT_NAME"
-echo "Project path: $PROJECT_PATH"
-echo "Session alias: $ALIAS_NAME"
-
-NAMESPACE=$(namespace)
-if [ -z "$NAMESPACE" ]; then
- echo "Error: No namespace found. Is anvillm running?"
- exit 1
-fi
-
-AGENT_MOUNT="agent"
-
-echo "Creating developer session..."
-before=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-echo "new $BACKEND $PROJECT_PATH role=developer tasks=git,editor,go,rust,python,nodejs,docker,podman,maven,gradle,plan9,gpg,github-cli,agent-q" | 9p write $AGENT_MOUNT/ctl
-after=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-DEV_ID=$(comm -13 <(echo "$before") <(echo "$after") | head -1)
-echo "Developer session ID: $DEV_ID"
-
-echo "Creating reviewer session..."
-before=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-echo "new $BACKEND $PROJECT_PATH role=reviewer tasks=git,github-cli,plan9,agent-q" | 9p write $AGENT_MOUNT/ctl
-after=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-REVIEWER_ID=$(comm -13 <(echo "$before") <(echo "$after") | head -1)
-echo "Reviewer session ID: $REVIEWER_ID"
-
-echo "Creating QA session..."
-before=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-echo "new $BACKEND $PROJECT_PATH role=tester tasks=git,github-cli,plan9,agent-q" | 9p write $AGENT_MOUNT/ctl
-after=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-QA_ID=$(comm -13 <(echo "$before") <(echo "$after") | head -1)
-echo "QA session ID: $QA_ID"
-
-# Set aliases
-echo "Setting aliases..."
-echo "${ALIAS_NAME}-dev" | 9p write $AGENT_MOUNT/$DEV_ID/alias
-echo "${ALIAS_NAME}-reviewer" | 9p write $AGENT_MOUNT/$REVIEWER_ID/alias
-echo "${ALIAS_NAME}-qa" | 9p write $AGENT_MOUNT/$QA_ID/alias
-
-# Set developer context
-cat <
-
-set -e
-
-if [ $# -ne 2 ]; then
- echo "Usage: $0 "
- echo " backend: claude, kiro-cli"
- exit 1
-fi
-
-BACKEND="$1"
-DOC_PATH="$2"
-
-RANDOM_WORD=$(shuf -n1 -e alpha beta gamma delta zeta theta kappa sigma omega lambda)
-RANDOM_NUM=$(printf "%02d" $((RANDOM % 100)))
-ALIAS_PREFIX="${RANDOM_WORD}${RANDOM_NUM}"
-
-NAMESPACE=$(namespace)
-if [ -z "$NAMESPACE" ]; then
- echo "Error: No namespace found. Is anvillm running?"
- exit 1
-fi
-
-AGENT_MOUNT="agent"
-
-echo "Creating writer session..."
-before=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-echo "new $BACKEND $DOC_PATH role=writer tasks=git,plan9,agent-q" | 9p write $AGENT_MOUNT/ctl
-after=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-WRITER_ID=$(comm -13 <(echo "$before") <(echo "$after") | head -1)
-
-echo "Creating techeditor session..."
-before=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-echo "new $BACKEND $DOC_PATH role=techeditor tasks=git,plan9,agent-q" | 9p write $AGENT_MOUNT/ctl
-after=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-EDITOR_ID=$(comm -13 <(echo "$before") <(echo "$after") | head -1)
-
-echo "${ALIAS_PREFIX}-writer" | 9p write $AGENT_MOUNT/$WRITER_ID/alias
-echo "${ALIAS_PREFIX}-techeditor" | 9p write $AGENT_MOUNT/$EDITOR_ID/alias
-
-cat <
-
-set -e
-
-if [ $# -ne 2 ]; then
- echo "Usage: $0 "
- echo " backend: claude, kiro-cli"
- exit 1
-fi
-
-BACKEND="$1"
-DOC_PATH="$2"
-
-# Generate random alias prefix
-RANDOM_WORD=$(shuf -n1 -e alpha beta gamma delta zeta theta kappa sigma omega lambda)
-RANDOM_NUM=$(printf "%02d" $((RANDOM % 100)))
-ALIAS_PREFIX="${RANDOM_WORD}${RANDOM_NUM}"
-
-NAMESPACE=$(namespace)
-if [ -z "$NAMESPACE" ]; then
- echo "Error: No namespace found. Is anvillm running?"
- exit 1
-fi
-
-AGENT_MOUNT="agent"
-
-echo "Creating research session..."
-before=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-echo "new $BACKEND $DOC_PATH role=research tasks=plan9,agent-q" | 9p write $AGENT_MOUNT/ctl
-after=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-RESEARCH_ID=$(comm -13 <(echo "$before") <(echo "$after") | head -1)
-echo " ID: $RESEARCH_ID"
-
-echo "Creating architect session..."
-before=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-echo "new $BACKEND $DOC_PATH role=architect tasks=git,plan9,agent-q" | 9p write $AGENT_MOUNT/ctl
-after=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-ARCH_ID=$(comm -13 <(echo "$before") <(echo "$after") | head -1)
-echo " ID: $ARCH_ID"
-
-echo "Creating techeditor session..."
-before=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-echo "new $BACKEND $DOC_PATH role=techeditor tasks=git,plan9,agent-q" | 9p write $AGENT_MOUNT/ctl
-after=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-EDITOR_ID=$(comm -13 <(echo "$before") <(echo "$after") | head -1)
-echo " ID: $EDITOR_ID"
-
-# Set aliases
-echo "${ALIAS_PREFIX}-research" | 9p write $AGENT_MOUNT/$RESEARCH_ID/alias
-echo "${ALIAS_PREFIX}-architect" | 9p write $AGENT_MOUNT/$ARCH_ID/alias
-echo "${ALIAS_PREFIX}-techeditor" | 9p write $AGENT_MOUNT/$EDITOR_ID/alias
-
-# Research context
-cat <
-
-set -e
-
-if [ $# -ne 2 ]; then
- echo "Usage: $0 "
- echo " backend: claude, kiro-cli"
- exit 1
-fi
-
-BACKEND="$1"
-WORKDIR="$2"
-
-RANDOM_WORD=$(shuf -n1 -e alpha beta gamma delta zeta theta kappa sigma omega lambda)
-RANDOM_NUM=$(printf "%02d" $((RANDOM % 100)))
-ALIAS_NAME="${RANDOM_WORD}${RANDOM_NUM}-research"
-
-NAMESPACE=$(namespace)
-if [ -z "$NAMESPACE" ]; then
- echo "Error: No namespace found. Is anvillm running?"
- exit 1
-fi
-
-AGENT_MOUNT="agent"
-
-echo "Creating research session..."
-before=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-echo "new $BACKEND $WORKDIR role=research tasks=plan9,agent-q" | 9p write $AGENT_MOUNT/ctl
-after=$(9p read $AGENT_MOUNT/list | awk '{print $1}' | sort)
-RESEARCH_ID=$(comm -13 <(echo "$before") <(echo "$after") | head -1)
-
-echo "$ALIAS_NAME" | 9p write $AGENT_MOUNT/$RESEARCH_ID/alias
-
-cat <(Acme)"]
+ TUI["TUI"]
+ Emacs["Emacs"]
+ Web["Web"]
+ end
+
+ subgraph Core["Core Services"]
+ anvilsrv["anvilsrv (9P daemon)"]
+ anvilmcp["anvilmcp (MCP server)"]
+ anvilwebgw["anvilwebgw (API proxy)"]
+ end
+
+ subgraph Backends
+ Claude["Claude"]
+ Kiro["Kiro"]
+ ollie["ollie"]
+ Ollama["Ollama"]
+ end
+
+ Assist -->|9P| anvilsrv
+ TUI -->|9P| anvilsrv
+ Emacs -->|9P| anvilsrv
+ Web -->|9P| anvilsrv
+
+ anvilsrv --> Claude
+ anvilsrv --> Kiro
+ anvilsrv --> ollie
+ ollie --> Ollama
diff --git a/docs/diagrams/architecture.svg b/docs/diagrams/architecture.svg
new file mode 100644
index 0000000..38de831
--- /dev/null
+++ b/docs/diagrams/architecture.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/diagrams/automation-workflow.mmd b/docs/diagrams/automation-workflow.mmd
new file mode 100644
index 0000000..0d1b82f
--- /dev/null
+++ b/docs/diagrams/automation-workflow.mmd
@@ -0,0 +1,36 @@
+sequenceDiagram
+ participant User
+ participant Taskmaster
+ participant Beads
+ participant Conductor
+ participant Bot1 as Bot 1
+ participant Bot2 as Bot 2
+ participant Bot3 as Bot 3
+
+ User->>Taskmaster: Project plan
+ Taskmaster->>Beads: Create task graph
+ Beads-->>Taskmaster: Top-level bead ID
+ Taskmaster-->>User: Tasks created
+
+ User->>Conductor: Top-level bead ID
+ Conductor->>Beads: Analyze dependencies
+
+ Conductor->>Bot1: Assign task (no blockers)
+ Conductor->>Bot2: Assign task (no blockers)
+
+ Bot1->>Bot1: Work on task
+ Bot1-->>Conductor: Task complete
+
+ Conductor->>Beads: Check dependencies
+ Conductor->>Bot3: Assign task (blockers resolved)
+
+ Bot2->>Bot2: Work on task
+ Bot2-->>Conductor: Task complete
+
+ Bot3->>Bot3: Work on task
+ Bot3-->>Conductor: Task complete
+
+ Conductor->>Beads: Check all child beads
+ Beads-->>Conductor: All complete
+ Conductor->>Beads: Mark top-level complete
+ Conductor-->>User: All work done
diff --git a/docs/diagrams/automation-workflow.svg b/docs/diagrams/automation-workflow.svg
new file mode 100644
index 0000000..8046175
--- /dev/null
+++ b/docs/diagrams/automation-workflow.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/diagrams/client-interactions.mmd b/docs/diagrams/client-interactions.mmd
new file mode 100644
index 0000000..0cff313
--- /dev/null
+++ b/docs/diagrams/client-interactions.mmd
@@ -0,0 +1,9 @@
+graph TB
+ Assist["Assist"]
+ TUI["TUI"]
+ Script["Script"]
+ FS["agent/ (9P filesystem)"]
+
+ Assist -->|9p read agent/list| FS
+ TUI -->|9p write agent/ctl| FS
+ Script -->|9p read agent/events| FS
diff --git a/docs/diagrams/client-interactions.svg b/docs/diagrams/client-interactions.svg
new file mode 100644
index 0000000..acab006
--- /dev/null
+++ b/docs/diagrams/client-interactions.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/diagrams/crash-recovery.mmd b/docs/diagrams/crash-recovery.mmd
new file mode 100644
index 0000000..7e5fd3b
--- /dev/null
+++ b/docs/diagrams/crash-recovery.mmd
@@ -0,0 +1,10 @@
+graph LR
+ running1[running]
+ error[error]
+ running2[running]
+ state[context alias cwd conversation]
+
+ running1 -->|crash| error
+ error -->|preserves| state
+ state -->|restored + auto-resume| running2
+ error -->|5s wait| running2
diff --git a/docs/diagrams/crash-recovery.svg b/docs/diagrams/crash-recovery.svg
new file mode 100644
index 0000000..adaa9d4
--- /dev/null
+++ b/docs/diagrams/crash-recovery.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/diagrams/events.mmd b/docs/diagrams/events.mmd
new file mode 100644
index 0000000..cb8c975
--- /dev/null
+++ b/docs/diagrams/events.mmd
@@ -0,0 +1,9 @@
+graph TB
+ events["agent/events (event stream)"]
+ notif["Notification"]
+ logger["Logger (audit)"]
+ etc["etc."]
+
+ events --> notif
+ events --> logger
+ events --> etc
diff --git a/docs/diagrams/events.svg b/docs/diagrams/events.svg
new file mode 100644
index 0000000..f0d8697
--- /dev/null
+++ b/docs/diagrams/events.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/diagrams/mailbox-flow.mmd b/docs/diagrams/mailbox-flow.mmd
new file mode 100644
index 0000000..c4e2140
--- /dev/null
+++ b/docs/diagrams/mailbox-flow.mmd
@@ -0,0 +1,17 @@
+sequenceDiagram
+ participant User
+ participant Mailbox as Mailbox System
+ participant AgentA as Agent A (Claude)
+ participant AgentB as Agent B (Kiro)
+
+ User->>Mailbox: write user/mail {"to":"agent-a",...}
+ Mailbox->>AgentA: agent-a/inbox
+
+ AgentA->>Mailbox: write agent/agent-a/mail {"to":"agent-b",...}
+ Mailbox->>AgentB: agent-b/inbox
+
+ AgentB->>Mailbox: write agent/agent-b/mail {"to":"agent-a",...}
+ Mailbox->>AgentA: agent-a/inbox
+
+ AgentB->>Mailbox: write agent/agent-b/mail {"to":"user",...}
+ Mailbox->>User: user/inbox
diff --git a/docs/diagrams/mailbox-flow.svg b/docs/diagrams/mailbox-flow.svg
new file mode 100644
index 0000000..a9aff11
--- /dev/null
+++ b/docs/diagrams/mailbox-flow.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/diagrams/sandbox-config.mmd b/docs/diagrams/sandbox-config.mmd
new file mode 100644
index 0000000..bc6a33d
--- /dev/null
+++ b/docs/diagrams/sandbox-config.mmd
@@ -0,0 +1,11 @@
+graph TB
+ global["global.yaml (Base configuration)"]
+ backends["backends/*.yaml (Backend-specific)"]
+ roles["roles/*.yaml (Role-specific) default: roles/default.yaml"]
+ tasks["tasks/*.yaml (Task-specific)"]
+ final["Final Config (most permissive wins)"]
+
+ global -->|override| backends
+ backends -->|override| roles
+ roles -->|override| tasks
+ tasks --> final
diff --git a/docs/diagrams/sandbox-config.svg b/docs/diagrams/sandbox-config.svg
new file mode 100644
index 0000000..ab1c949
--- /dev/null
+++ b/docs/diagrams/sandbox-config.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/diagrams/session-lifecycle.mmd b/docs/diagrams/session-lifecycle.mmd
new file mode 100644
index 0000000..c541ed2
--- /dev/null
+++ b/docs/diagrams/session-lifecycle.mmd
@@ -0,0 +1,16 @@
+stateDiagram-v2
+ [*] --> starting
+ starting --> idle
+ starting --> error
+
+ idle --> running: userPromptSubmit hook (user sends prompt)
+ running --> idle: stop hook (agent finishes)
+
+ running --> error: crash
+ error --> starting: restart
+
+ note right of idle
+ Any state can transition to
+ stopped or killed (not shown)
+ stopped can restart → starting
+ end note
diff --git a/docs/diagrams/session-lifecycle.svg b/docs/diagrams/session-lifecycle.svg
new file mode 100644
index 0000000..195e0b1
--- /dev/null
+++ b/docs/diagrams/session-lifecycle.svg
@@ -0,0 +1 @@
+
\ No newline at end of file