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
15
EVENTS.md
|
|
@ -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) │ │ │
|
||||
└──────────────┘ └──────────┘ └────────────┘
|
||||
```
|
||||

|
||||
|
||||
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
|
|
@ -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
|
||||
```
|
||||

|
||||
|
||||
**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)
|
||||
```
|
||||

|
||||
|
||||
- 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 │───────────┘
|
||||
└───────┘
|
||||
```
|
||||

|
||||
|
||||
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 ┌─────────┐ 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) │
|
||||
└─────────┘
|
||||
```
|
||||

|
||||
|
||||
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)
|
||||
```
|
||||

|
||||
|
||||
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 │
|
||||
│ │ │ │ │ │
|
||||
└──────────┘ └──────────┘ └──────────┘
|
||||
```
|
||||

|
||||
|
||||
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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
After Width: | Height: | Size: 20 KiB |
|
|
@ -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
|
||||
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -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
|
||||
|
After Width: | Height: | Size: 10 KiB |
|
|
@ -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
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
|
@ -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
|
||||
|
After Width: | Height: | Size: 10 KiB |
|
|
@ -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
|
||||
|
After Width: | Height: | Size: 24 KiB |
|
|
@ -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
|
||||
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -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
|
||||
|
After Width: | Height: | Size: 148 KiB |