Replace ASCII diagrams with SVG images

- Create Mermaid source files for all diagrams
- Generate SVGs using mermaid-cli
- Replace all ASCII art with embedded SVG images
- Diagrams: architecture, sandbox-config, session-lifecycle, crash-recovery, client-interactions, mailbox-flow, automation-workflow, events
- Fixes alignment issues with ASCII box drawing characters
This commit is contained in:
Levi Neely 2026-02-22 12:08:12 +01:00
parent d3267d8771
commit 41acc805d1
18 changed files with 135 additions and 179 deletions

View File

@ -4,20 +4,7 @@ The events system provides a real-time text stream of all AnviLLM activity using
## Architecture
```
┌─────────────────┐
│ agent/events │
│ (event stream) │
└────────┬────────┘
│
┌──────────────┼──────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────┐ ┌────────────┐
│ Notification │ │ Logger │ │ etc. │
│ │ │ (audit) │ │ │
└──────────────┘ └──────────┘ └────────────┘
```
![Events System](diagrams/events.svg)
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.

172
README.md
View File

@ -4,38 +4,7 @@ LLM orchestrator using 9P — scriptable, multi-backend, crash-resilient
## Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ Clients │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ Assist │ │ TUI │ │ Emacs │ │ Web │ │
│ │ (Acme) │ │ │ │ │ │ │ │
│ └───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘ │
└──────┼───────────┼───────────┼───────────┼────────────────┘
│ │ │ │
└───────────┴───────────┴───────────┘
│ 9P
┌───────────────┴───────────────┐
│ │
┌──────▼──────────────────────────────────────────────────────┐
│ Core Services │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ anvilsrv │ │ anvilmcp │ │anvilwebgw│ │
│ │(9P daemon) │(MCP server) │(API proxy)│ │
│ └─────┬────┘ └──────────┘ └──────────┘ │
└────────┼───────────────────────────────────────────────────┘
│
┌────┴────┬────────┐
│ │ │
┌───▼───┐ ┌──▼────┐ ┌─▼─────┐
│ Claude│ │ Kiro │ │ ollie │
└───────┘ └───────┘ └───┬───┘
│
┌───▼────┐
│ Ollama │
└────────┘
Backends
```
![Architecture](docs/diagrams/architecture.svg)
**Core:** anvilsrv (9P daemon), anvilmcp (MCP server), anvilwebgw (API proxy)
**Clients:** Assist (Acme), anvillm.el (Emacs), anvillm (TUI), anvilweb (web)
@ -151,26 +120,7 @@ Templates use `{VARNAME}` syntax. Any environment variable can be referenced.
**Config** (`~/.config/anvillm/`): Layered YAML files, most permissive wins:
```
┌─────────────────┐
│ global.yaml │ Base configuration
└────────┬────────┘
│ (override)
┌────────▼────────┐
│ backends/*.yaml │ Backend-specific
└────────┬────────┘
│ (override)
┌────────▼────────┐
│ roles/*.yaml │ Role-specific (default: roles/default.yaml)
└────────┬────────┘
│ (override)
┌────────▼────────┐
│ tasks/*.yaml │ Task-specific
└────────┬────────┘
│
▼
Final Config (most permissive wins)
```
![Sandbox Config Layering](docs/diagrams/sandbox-config.svg)
- Default role: `roles/default.yaml`
@ -186,43 +136,13 @@ Set `best_effort: true` for unsandboxed fallback (⚠️ if no Landlock support)
**Session lifecycle:**
```
┌─────────────────────────┐
│ │
│ ┌──────────┐ │
│ │ starting │ │
│ └─────┬────┘ │
│ │ │
│ ▼ │
│ ┌─────────┐ │
└────►│ idle │◄────┐ │
└────┬────┘ │ │
│ │ │
│ userPromptSubmit hook
│ (user sends prompt)
│ │ │
▼ │ │
┌─────────┐ │ │
│ running │ │ │
└────┬────┘ │ │
│ │ │
│ stop hook│ │
│ (agent finishes)
│ │ │
└──────────┘ │
│ │
│ crash │
▼ │
┌───────┐ restart │
│ error │───────────┘
└───────┘
```
![Session Lifecycle](docs/diagrams/session-lifecycle.svg)
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
```
![Crash Recovery](docs/diagrams/crash-recovery.svg)
┌─────────┐ crash ┌─────────┐ 5s wait ┌─────────┐
│ running │─────────►│ error │──────────►│ running │
└─────────┘ └─────────┘ └─────────┘
@ -308,21 +228,7 @@ agent/
**Client Interactions:**
```
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Assist │ │ TUI │ │ Script │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
│ 9p read │ 9p write │ 9p read
│ agent/list │ agent/ctl │ agent/events
│ │ │
└───────────────────┴───────────────────┘
│
┌────▼────┐
│ agent/ │
│ (9P fs) │
└─────────┘
```
![Client Interactions](docs/diagrams/client-interactions.svg)
Different clients interact with different parts of the filesystem: frontends read state, control files manage sessions, scripts consume events.
@ -345,43 +251,7 @@ Config: `~/.beads/` (override: `ANVILLM_BEADS_PATH`) — Shared across namespace
**Mailbox Flow:**
```
User writes to Agent A:
echo '{"to":"agent-a",...}' | 9p write user/mail
│
▼
[mailbox system]
│
▼
agent-a/inbox (Agent A reads)
Agent A writes to Agent B:
echo '{"to":"agent-b",...}' | 9p write agent/agent-a/mail
│
▼
[mailbox system]
│
▼
agent-b/inbox (Agent B reads)
Agent B replies to Agent A:
echo '{"to":"agent-a",...}' | 9p write agent/agent-b/mail
│
▼
[mailbox system]
│
▼
agent-a/inbox (Agent A reads)
Agent B replies to User:
echo '{"to":"user",...}' | 9p write agent/agent-b/mail
│
▼
[mailbox system]
│
▼
user/inbox (User reads)
```
![Mailbox Flow](docs/diagrams/mailbox-flow.svg)
Cross-backend communication: messages route between any participants (user, Claude agents, Kiro agents, Ollama agents) via the mailbox system.
@ -443,35 +313,7 @@ Templates set up context, roles, and initial configuration. Interact via any cli
Automate workflows with Taskmaster and Conductor bots. Input project plan → Taskmaster creates tasks with dependencies → Conductor orchestrates parallel execution.
```
┌──────────────┐
│ Project Plan │
└──────┬───────┘
│
▼
┌──────────────┐ ┌─────────────────────────────┐
│ Taskmaster │────►│ Beads (dependency graph) │
└──────────────┘ │ ┌─────────────────────┐ │
│ │ Top-level bead ID │ │
│ │ (represents project)│ │
│ └──────────┬──────────┘ │
└─────────────┼────────────────┘
│
▼
┌──────────────────┐
│ Conductor │
│ (coordinates │
│ dependencies) │
└────────┬─────────┘
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Agent 1 │ │ Agent 2 │ │ Agent 3 │
│ │ │ │ │ │
└──────────┘ └──────────┘ └──────────┘
```
![Automation Workflow](docs/diagrams/automation-workflow.svg)
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.

View File

@ -0,0 +1,30 @@
graph TB
subgraph Clients
Assist["Assist<br/>(Acme)"]
TUI["TUI"]
Emacs["Emacs"]
Web["Web"]
end
subgraph Core["Core Services"]
anvilsrv["anvilsrv<br/>(9P daemon)"]
anvilmcp["anvilmcp<br/>(MCP server)"]
anvilwebgw["anvilwebgw<br/>(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

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,17 @@
graph TB
Plan["Project Plan"]
Taskmaster["Taskmaster"]
Beads["Beads<br/>(dependency graph)"]
TopBead["Top-level bead ID<br/>(represents project)"]
Conductor["Conductor<br/>(coordinates dependencies)"]
Agent1["Agent 1"]
Agent2["Agent 2"]
Agent3["Agent 3"]
Plan --> Taskmaster
Taskmaster --> Beads
Beads --> TopBead
TopBead --> Conductor
Conductor --> Agent1
Conductor --> Agent2
Conductor --> Agent3

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,9 @@
graph TB
Assist["Assist"]
TUI["TUI"]
Script["Script"]
FS["agent/<br/>(9P filesystem)"]
Assist -->|9p read<br/>agent/list| FS
TUI -->|9p write<br/>agent/ctl| FS
Script -->|9p read<br/>agent/events| FS

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,10 @@
graph LR
running1[running]
error[error]
running2[running]
state[context<br/>alias<br/>cwd<br/>conversation]
running1 -->|crash| error
error -->|preserves| state
state -->|restored +<br/>auto-resume| running2
error -->|5s wait| running2

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

9
docs/diagrams/events.mmd Normal file
View File

@ -0,0 +1,9 @@
graph TB
events["agent/events<br/>(event stream)"]
notif["Notification"]
logger["Logger<br/>(audit)"]
etc["etc."]
events --> notif
events --> logger
events --> etc

1
docs/diagrams/events.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -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<br/>{"to":"agent-a",...}
Mailbox->>AgentA: agent-a/inbox
AgentA->>Mailbox: write agent/agent-a/mail<br/>{"to":"agent-b",...}
Mailbox->>AgentB: agent-b/inbox
AgentB->>Mailbox: write agent/agent-b/mail<br/>{"to":"agent-a",...}
Mailbox->>AgentA: agent-a/inbox
AgentB->>Mailbox: write agent/agent-b/mail<br/>{"to":"user",...}
Mailbox->>User: user/inbox

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -0,0 +1,11 @@
graph TB
global["global.yaml<br/>(Base configuration)"]
backends["backends/*.yaml<br/>(Backend-specific)"]
roles["roles/*.yaml<br/>(Role-specific)<br/>default: roles/default.yaml"]
tasks["tasks/*.yaml<br/>(Task-specific)"]
final["Final Config<br/>(most permissive wins)"]
global -->|override| backends
backends -->|override| roles
roles -->|override| tasks
tasks --> final

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,16 @@
stateDiagram-v2
[*] --> starting
starting --> idle
starting --> error
idle --> running: userPromptSubmit hook<br/>(user sends prompt)
running --> idle: stop hook<br/>(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

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 148 KiB