AnviLLM was an experimental 9P interface for common CLI-based AI agents. It is no longer actively maintained, but kept for progeny.
This repository has been archived on 2026-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
Go to file
Levi Neely 4c83e0d2bf claim_bead: exit 1 on failed ctl write instead of printing success
9p write error was ignored; bots always printed "claimed" regardless
of whether the server rejected the claim with ErrAlreadyClaimed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15 07:54:38 +01:00
cfg sandbox: allow anvillm mail dir; remove scripts/mail_history.sh 2026-03-14 00:08:01 +01:00
claude anvillm-agent: prohibit sub-agents for single-tool operations 2026-03-14 21:57:18 +01:00
cmd Assist: remap bead prefixes, add open/defer; orphan: skip user-claimed 2026-03-14 21:21:25 +01:00
docs rename 9P endpoint from 'agent' to 'anvillm' 2026-03-12 12:13:40 +01:00
elisp Add frontend support for mountable beads and remove global mount state 2026-02-28 13:35:46 +01:00
internal beads,roles: emit BeadClaimed event; add bead loop to worker roles 2026-03-14 20:58:58 +01:00
kiro-cli rename 9P endpoint from 'agent' to 'anvillm' 2026-03-12 12:13:40 +01:00
mcptools claim_bead: exit 1 on failed ctl write instead of printing success 2026-03-15 07:54:38 +01:00
ollama minor fix 2026-02-21 21:05:18 +01:00
roles skills,roles: replace bash process substitution with list_mounts.sh tool 2026-03-14 21:11:49 +01:00
scripts Assist: remap bead prefixes, add open/defer; orphan: skip user-claimed 2026-03-14 21:21:25 +01:00
services rename 9P endpoint from 'agent' to 'anvillm' 2026-03-12 12:13:40 +01:00
skills beads: fix wait_for_bead description — no role filter 2026-03-14 21:39:11 +01:00
team-templates rename 9P endpoint from 'agent' to 'anvillm' 2026-03-12 12:13:40 +01:00
workflows session: reset initialPromptSent when context is set 2026-03-07 12:30:21 +01:00
.gitignore gitignore: ignore compiled test binaries (*.test) 2026-03-06 19:43:20 +01:00
BEADS.md beads: remove pending_approval/pending_review workflow 2026-03-14 17:24:46 +01:00
EVENTS.md beads,roles: emit BeadClaimed event; add bead loop to worker roles 2026-03-14 20:58:58 +01:00
LICENSE.md initial docs 2026-02-10 22:57:21 +01:00
OUTPUT_PROTOCOL.md working on a different approach for roles 2026-03-06 08:54:44 +01:00
README.md rename 9P endpoint from 'agent' to 'anvillm' 2026-03-12 12:13:40 +01:00
SECURITY.md Remove deprecated audit endpoint 2026-02-20 22:18:53 +01:00
SKILLS_PROMPT.md SKILLS_PROMPT: add sub-agent discipline section 2026-03-14 22:01:43 +01:00
WORKFLOW_DESIGN.md fileaddr; smart delegation 2026-03-12 18:44:40 +01:00
bookmarks.html hotfix: mkfile 2026-02-23 22:03:12 +01:00
go.mod Replace event queue with in-memory pub-sub event bus 2026-02-22 09:38:14 +01:00
go.sum Replace event queue with in-memory pub-sub event bus 2026-02-22 09:38:14 +01:00
mkfile anvillm: add orphan bead recovery via cron 2026-03-14 15:16:40 +01:00
test-code-execution.sh Implement MCP code execution pattern (#20) 2026-02-26 14:02:54 +01:00
test_beads.sh Add mountable beads projects with per-project databases 2026-02-28 11:35:19 +01:00

README.md

AnviLLM

LLM orchestrator using 9P — scriptable, multi-backend, crash-resilient

Architecture

Architecture

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?

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.

Requirements

Go 1.21+, plan9port, tmux, landrun (kernel 5.13+), backend (Claude Code, Kiro, or Ollama + ollie)

Installation

git clone https://github.com/lneely/anvillm && cd anvillm && mk

Service integration (optional, see services/*/README.md):

# systemd user
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

# runit
sudo cp -r services/runit /etc/sv/anvilsrv
sudo ln -s /etc/sv/anvilsrv /var/service/

Usage

anvilsrv start       # background
anvilsrv fgstart     # foreground
anvilsrv status
anvilsrv stop

Assist auto-starts if needed.

Namespaces: Run multiple instances via $NAMESPACE (default: /tmp/ns.$USER.:0)

NAMESPACE=/tmp/ns.$USER.:1 anvilsrv start
NAMESPACE=/tmp/ns.$USER.:1 Assist

Clients

TUI: anvillm — Keys: s start | p prompt | t stop | R restart | K kill | a alias | r refresh | d daemon | ? help | q quit

Emacs: (require 'anvillm) then M-x anvillm — Keys: s start | p prompt | P prompt (minibuffer) | t stop | R restart | K kill | a alias | r/g refresh | d daemon | ? help | q quit

Web: anvilweb (port :8080) — ⚠️ NO auth, localhost only — Remote: ssh -L 8080:localhost:8080 user@remote

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
Get Refresh session list
Kiro <dir> / Claude <dir> / Ollama <dir> Start session
Attach <id> Open tmux
Stop <id> / Restart <id> / Kill <id> Control session
Alias <id> <name> Name session
Context <id> Edit context
Daemon Manage daemon
Inbox [id] / Archive [id] View messages

Configuration

Environment Variables

Variable Default Description
NAMESPACE /tmp/ns.$USER.:0 9P namespace for server/client communication
ANVILLM_BEADS_PATH ~/.beads Beads database location (shared across namespaces)
ANVILLM_TERMINAL foot Terminal command for tmux attach (Assist)
ANTHROPIC_API_KEY — Claude API key (optional if using claude /login)
CLAUDE_AGENT_NAME anvillm-agent Claude agent configuration name
KIRO_API_KEY — Kiro API key (optional if using kiro-cli login)
ANVILLM_OLLAMA_MODEL qwen3:8b Ollama model to use for ollama backend
ANVILLM_SKILLS_DIR $CLAUDE_CONFIG_DIR/skills:~/.kiro/skills:~/.config/anvillm/skills Colon-separated skill directories (searched in order)

Skills System

Skills are loaded from multiple directories via the anvillm/skills 9pfs. By default, searches:

  1. $CLAUDE_CONFIG_DIR/skills (if CLAUDE_CONFIG_DIR set)
  2. ~/.kiro/skills
  3. ~/.config/anvillm/skills

Override with ANVILLM_SKILLS_DIR (colon-separated paths). Skills are organized by intent (virtual directories) and discovered via SKILL.md front-matter.

Usage:

9p ls anvillm/skills                    # list intents
9p read anvillm/skills/help             # search index
9p read anvillm/skills/tasks/beads/SKILL.md

Sandbox Config Templates

Available in sandbox YAML files (~/.config/anvillm/):

Template Expands To Description
{CWD} Current working directory Session's working directory
{HOME} User home directory $HOME
{TMPDIR} Temp directory $TMPDIR or /tmp
{XDG_CONFIG_HOME} XDG config $XDG_CONFIG_HOME or ~/.config
{XDG_DATA_HOME} XDG data $XDG_DATA_HOME or ~/.local/share
{XDG_CACHE_HOME} XDG cache $XDG_CACHE_HOME or ~/.cache
{XDG_STATE_HOME} XDG state $XDG_STATE_HOME or ~/.local/state
{ANY_ENV_VAR} Environment variable Any $ENV_VAR from the environment

Templates use {VARNAME} syntax. Any environment variable can be referenced.

Backends & Sandboxing

Backends: Claude (npm install -g @anthropic-ai/claude-code), Kiro (kiro.dev), Ollama (local models via ollie)

Sandbox: landrun (always enabled) — Defaults: CWD//tmp/config (rw), /usr//lib//bin (ro+exec), no network

Config (~/.config/anvillm/): Layered YAML files, most permissive wins:

  • Default role: roles/default.yaml
network: {enabled: true, unrestricted: true}
filesystem: {rw: ["{CWD}", "{HOME}/.npm"]}

Templates: {CWD}, {HOME}, {TMPDIR}, {XDG_*} (see Configuration)

Kernel requirements: 5.13+ (Landlock v1), 6.7+ (v4), 6.10+ (v5 network) Set best_effort: true for unsandboxed fallback (⚠️ if no Landlock support)

Session lifecycle:

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.

Requirements:

  1. Ollama: Install from ollama.com

    curl -fsSL https://ollama.com/install.sh | sh
    ollama serve
    ollama pull qwen2.5-coder:7b
    
  2. Ollie CLI: Install from github.com/lneely/ollie

    git clone https://github.com/lneely/ollie && cd ollie && go install
    

Usage:

echo 'new ollama /path/to/project' | 9p write anvillm/ctl

Configuration: Set model via ANVILLM_OLLAMA_MODEL (default: qwen3:8b)

ANVILLM_OLLAMA_MODEL=llama3.2 echo 'new ollama /path' | 9p write anvillm/ctl

9P Filesystem

$NAMESPACE/agent:

anvillm/
├── ctl             # "new <backend> <cwd>" creates session
├── list            # id, alias, state, pid, cwd
├── events          # Event stream (state changes, messages)
├── beads/          # Task tracking (persistent across namespaces)
│   ├── ctl         # Commands: init, new, claim, complete, fail, dep
│   ├── list        # All beads as JSON
│   ├── ready       # Ready beads (no blockers) as JSON
│   └── <bead-id>/
│       ├── status
│       ├── title
│       ├── description
│       ├── assignee
│       └── json
└── <id>/
    ├── ctl         # "stop", "restart", "kill"
    ├── state       # starting, idle, running, stopped, error, exited
    ├── context     # Prepended to prompts (r/w)
    ├── alias       # Session name (r/w)
    ├── pid         # Process ID
    ├── cwd         # Working directory
    ├── backend     # Backend name
    ├── role        # Role name
    ├── tasks       # Task names
    ├── tmux        # Tmux session name
    ├── inbox       # Incoming messages (JSON)
    ├── outbox      # Outgoing messages (JSON)
    ├── completed   # Archived messages (JSON, "Archive" in Assist)
    └── 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 — Dependency-aware graph

echo 'init' | 9p write anvillm/beads/ctl
echo 'new "Implement login" "Add JWT auth"' | 9p write anvillm/beads/ctl
echo 'claim bd-a1b2' | 9p write anvillm/beads/ctl
echo 'complete bd-a1b2' | 9p write anvillm/beads/ctl
echo 'dep bd-child bd-parent' | 9p write anvillm/beads/ctl  # child blocks parent
9p read anvillm/beads/ready | jq -r '.[] | "\(.id): \(.title)"'

Config: ~/.beads/ (override: ANVILLM_BEADS_PATH) — Shared across namespaces — See internal/beads/README.md

Events & Mailbox

Mailbox Flow:

Mailbox Flow

Cross-backend communication: messages route between any participants (user, Claude agents, Kiro agents, Ollama agents) via the mailbox system.

Examples:

# Events
9p read anvillm/events  # {"type":"state_change","session_id":"...","state":"running",...}

# Mailbox
echo '{"to":"a3f2b9d1","type":"REVIEW_REQUEST","subject":"...","body":"..."}' | 9p write anvillm/b4e3c8f2/mail
9p read anvillm/a3f2b9d1/inbox
9p read anvillm/a3f2b9d1/completed

Basic Session Example

# Create session
echo 'new claude /home/user/project' | 9p write anvillm/ctl

# List sessions (newest first)
9p read anvillm/list

# Get most recent session ID
ID=$(9p read anvillm/list | head -1 | awk '{print $1}')

# Send prompt via mailbox
echo '{"to":"'$ID'","type":"PROMPT_REQUEST","subject":"User prompt","body":"Hello"}' | 9p write user/mail

# Check state
9p read anvillm/$ID/state

# Read response from inbox
9p read user/inbox

See SECURITY.md

Bot Templates

Bot templates provide pre-configured agents for common tasks. Templates are shell scripts that create sessions with specialized context and configuration.

Available Templates:

  • Taskmaster — Converts project plans into dependency-aware task graphs (beads)
  • Conductor — Orchestrates parallel execution by spawning and coordinating specialized agents

Usage:

./bot-templates/Taskmaster kiro /path/to/project
./bot-templates/Conductor kiro /path/to/project

Templates set up context, roles, and initial configuration. Interact via any client (Assist, TUI, Emacs, Web) or directly via 9P mailbox.

Creating Templates: Shell scripts that write to anvillm/ctl and configure context, role, tasks. See existing templates for examples.

Autonomous Workflows

Automate workflows with Taskmaster and Conductor bots. Input project plan → Taskmaster creates tasks with dependencies → Conductor orchestrates parallel execution.

Autonomous Workflow

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

./bot-templates/Taskmaster kiro /path/to/project
TASKMASTER_ID=$(9p read anvillm/list | head -1 | awk '{print $1}')

# Send project plan
echo '{"to":"'$TASKMASTER_ID'","type":"PROMPT_REQUEST","subject":"Create tasks","body":"<your project plan>"}' | 9p write user/mail

# Get top-level bead ID
BEAD_ID=$(9p read anvillm/beads/list | jq -r '.[0].id')

2. Conductor: Execute work

./bot-templates/Conductor kiro /path/to/project
CONDUCTOR_ID=$(9p read anvillm/list | head -1 | awk '{print $1}')

# Send work request
echo '{"to":"'$CONDUCTOR_ID'","type":"WORK_REQUEST","subject":"Execute","body":"Complete bead '$BEAD_ID'"}' | 9p write user/mail

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.

Install:

./kiro-cli/install-mcp.sh  # Adds to ~/.kiro/settings/cli.json

Tool: execute_code - Execute bash scripts in isolated subprocess

Enables code execution pattern for 80-99% token reduction:

  • Progressive tool discovery via 9P filesystem
  • Data processing in subprocess (not in context)
  • Loops, conditionals, and complex workflows

See Code Execution User Guide for details.

Legacy tools removed: Direct tool calls (read_inbox, send_message, etc.) replaced by bash scripts accessible via 9p read anvillm/tools/anvilmcp/*.sh

Troubleshooting

Problem Solution
Can't connect anvilsrv status; try anvilsrv start
Session won't start Check stderr; verify backend installed
Landlock ABI error Set best_effort: true or upgrade kernel
Permission denied Add paths to layered config
Orphaned tmux tmux kill-session -t anvillm-0
9P not working 9p ls agent
Stale PID anvilsrv stop auto-cleans
Daemon won't stop anvilsrv fgstart for logs
anvilweb issues Check anvilsrv running, namespace matches

See Configuration section for environment variables.