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 d07315a772 Reorganize README for logical flow
New section order:
1. Architecture/Requirements/Installation/Usage (getting started)
2. Configuration (env vars, templates) - before backends
3. Backends & Sandboxing (references Configuration templates)
4. 9P Filesystem (understand backend first, then filesystem)
5. Workflows (uses 9P concepts)
6. MCP Integration (alternative integration method)
7. Troubleshooting (end)

Improves flow: config before use, concepts before advanced features
2026-02-19 23:42:04 +01:00
cfg Reload sandbox config on Restart for hot-reload of YAML changes 2026-02-19 16:24:57 +01:00
claude Replace all 9p command references with MCP tools 2026-02-18 21:49:35 +01:00
cmd Add beads task tracking integration via 9P filesystem 2026-02-19 23:08:50 +01:00
elisp Remove deprecated endpoints and fix mailbox auto-completion 2026-02-17 23:06:07 +01:00
internal Tech editing pass on beads README 2026-02-19 23:38:06 +01:00
kiro-cli Make skills command conditional: use agent-prompt/agent-skills if available 2026-02-19 15:30:56 +01:00
scripts Make skills command conditional: use agent-prompt/agent-skills if available 2026-02-19 15:30:56 +01:00
services feat: split monolith into anvilsrv daemon and Assist client 2026-02-14 11:30:57 +01:00
skills Add explicit guidance on responding to messages 2026-02-18 22:08:38 +01:00
workflows improve messaging 2026-02-17 18:58:06 +01:00
.gitignore Fix 9p-read-inbox to strip .json extension when marking messages complete 2026-02-17 14:37:46 +01:00
IDEAS.md Add beads task tracking integration via 9P filesystem 2026-02-19 23:08:50 +01:00
LICENSE.md initial docs 2026-02-10 22:57:21 +01:00
README.md Reorganize README for logical flow 2026-02-19 23:42:04 +01:00
SECURITY.md feat: split monolith into anvilsrv daemon and Assist client 2026-02-14 11:30:57 +01:00
go.mod Add beads task tracking integration via 9P filesystem 2026-02-19 23:08:50 +01:00
go.sum Add beads task tracking integration via 9P filesystem 2026-02-19 23:08:50 +01:00
mkfile Make skills command conditional: use agent-prompt/agent-skills if available 2026-02-19 15:30:56 +01:00

README.md

AnviLLM

9P-based LLM orchestrator — Front-ends: Acme, Emacs, TUI, web

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

Requirements

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

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  # :1
NAMESPACE=/tmp/ns.$USER.:1 Assist          # connect

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: Get Attach Stop Restart Kill Alias Context Daemon Inbox Archive — Right-click ID for prompt window, 2-1 chord for fire-and-forget

Command Action
Get Refresh session list
Kiro <dir> / Claude <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 (required for Claude backend)
CLAUDE_AGENT_NAME anvillm-agent Claude agent configuration name
KIRO_API_KEY — Kiro API key (required for Kiro backend)

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

Backends & Sandboxing

Backends: Claude (npm install -g @anthropic-ai/claude-code), Kiro (kiro.dev) — Sandboxed with network access

Add: Implement CommandHandler/StateInspector in internal/backends/yourbackend.go, register in main.go

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

Config (~/.config/anvillm/): global.yaml → backends/<name>.yaml → roles/<name>.yaml (default: roles/default.yaml) → tasks/<name>.yaml — Most permissive wins

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:

agent/
├── 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>/
    ├── in          # Write prompts
    ├── out         # Read responses
    ├── 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
    ├── inbox       # Incoming messages (JSON)
    ├── outbox      # Outgoing messages (JSON)
    ├── completed   # Archived messages (JSON, "Archive" in Assist)
    └── mail        # Write messages (convenience)

Beads

Persistent task tracking via beads — Dependency-aware graph

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

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

Events & Mailbox

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

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

Example

echo 'new claude /home/user/project' | 9p write agent/ctl
echo 'Hello' | 9p write agent/a3f2b9d1/in
9p read agent/a3f2b9d1/state  # "running"

See SECURITY.md

Workflows

Skills: anvillm-skills list, anvillm-skills load anvillm-communication

Examples: ./workflows/DevReview claude /path (dev/reviewer loop), ./workflows/Planning kiro /path (research/eng/editor)

Pattern:

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

See workflows/, kiro-cli/SKILLS_PROMPT.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

Tools: read_inbox, send_message, list_sessions, set_state

Enables LLM clients to control AnviLLM sessions and communicate with agents

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.