Everything on by default — MCP, LSP, ACP, a Janet plugin system, tree-sitter code intelligence, and self-improving memory. Yet it's native Rust: ~8 MB RAM idle, ~36 MB binary, no runtime. And an agent loop built to keep even small, cheap models on the rails.
ctx [██░░░░░░░░] 1%
11.5k / 1.0M · cmp:0
edit voxel.cljs
read voxel.cljs
skill paren-check
bash cd …/voxel
<you> add FPS-style mouse-look + wheel height to voxel.cljs
<dirge> Here's the plan:
1. add :mouseX/:mouseY delta fields to input
2. mousemove + wheel listeners (pointer lock)
3. consume deltas in update-camera, reset per frame
<critic> deltas reset each frame ✓ — looks complete
CPU [██░░░░░░] 24%
MEM [████░░░░] 55%
● chiasmus
● rlm
● wavescope
● lattice
● clojure-lsp
✓ input delta fields
▸ pointer-lock listeners
○ minimap overlay
voxel.cljs
A dirge is a song to keep the dead from losing their way. It turns grief into something that is remembered. Agents are like mayflies awoken for a moment to work and to forget, with every new session effacing the old one. Dirge keeps watch over things said and done, always folding context into memory to carry past mistakes and preferences across the gulf between sessions. It sings the past forward, so that no grave need be dug twice. Dirge grieves for nothing, since nothing is truly buried under its care, and its lament is a promise that what was built here once will be remembered.
Native Rust, no runtime — and an agent loop engineered so cheaper models stay productive instead of derailing.
ratatui + crossterm. Live token streaming, a branching session tree, and configurable info panes via /display — all keyboard-driven.
Repairs malformed tool calls, validates every write through tree-sitter before it hits disk, trips circuit breakers on non-progressing loops, and escalates to a stronger model on repeated failure.
A single Policy Decision Point with four modes, op-based rules, and session allowlists. The /why command traces exactly which policy decided — and why.
Point the main loop, review, escalation, summarization, and subagent roles at different models. Mix DeepSeek, GLM, Anthropic, OpenAI, and Ollama in one session.
Persistent per-project memory plus a post-session orchestrator that extracts learnings, curates memory & skills, and promotes patterns recurring across sessions.
Tree-sitter semantic tools and inline LSP diagnostics for 10+ languages — surfaced in tool output so the agent fixes compile errors on the same turn.
A Janet plugin system hooks the full lifecycle — intercept tools, rewrite prompts, register commands — plus Claude-compatible skills loaded on demand.
Model Context Protocol for extra tools and servers. Agent Communication Protocol for editor integration with Zed.
Run every bash command inside an isolated bubblewrap environment with --sandbox — defense in depth on top of the permission engine.
An opt-in /plan workflow runs explore → plan → implement → review as context-isolated phases: a read-only agent maps the code, a second drafts the plan, then a write-disabled reviewer runs the code and feeds gaps back for a bounded retry.
Tree-sitter read_minified/edit_minified collapse files to their skeleton; a hard read-before-edit gate blocks blind edits; and oversized bash/webfetch output is relayed to disk with a head+tail summary so the context window stays lean.
A built-in Debug Adapter Protocol client drives real debuggers — set breakpoints, step, inspect stacks and variables — straight from the agent loop and Janet plugins (debug tool, dap/* bindings).
The crate is published as dirge-agent (the short name was taken);
the installed command is still dirge. Set an API key and start coding.
# Batteries included — MCP, LSP, ACP, plugins, and every # tree-sitter language are on by default. $ cargo install dirge-agent # Leaner build — opt out of defaults, pick what you need: $ cargo install dirge-agent --no-default-features \ --features "loop,git-worktree,mcp,lsp,semantic-rust"
Works with all major providers, and any OpenAI-compatible endpoint. OpenRouter is the default — no setup for most. Switch with /model.
GPT-4o · o-series
Claude Sonnet · Opus
V4 Pro · R1 · V3
2.5 Pro · 2.0 Flash
Llama · Qwen · Mistral
Default · 200+ models
GLM-4 · ZhipuAI
Any OpenAI-compatible endpoint
Everything the agent needs — files, shell, search, code intelligence, and delegation — with zero configuration.
read · write · edit · apply_patch · list_dir · find_files
bash · bash_output · kill_shell — foreground & background
grep · glob · session_search
webfetch · websearch
list_symbols · get_symbol_body · find_callers · find_callees · find_definition · lsp · repo_overview
task · plan · write_todo_list · memory · skill · question
Control the agent from the TUI — switch models, manage sessions, inspect decisions. Type /help for the full list.
Show or switch LLM model
List or activate system prompts
Set security permission mode
Trace the last permission decision
Configure visible info panes
Compact history for context
List, save, load sessions
Show session branch tree
Branch the conversation
Start an iterative coding loop
List MCP servers and tools
Create a git worktree
Manage the session allowlist
Toggle reasoning visibility
Quick question (no tools)
Show all commands
dirge embeds Janet as a plugin language. Plugins are small scripts that hook into the agent loop, intercept tools, rewrite prompts, register slash commands, gate execution, and drive session navigation — all from a few lines of Lisp.
Plugins live in ~/.config/dirge/plugins/ (global)
or ./.dirge/plugins/ (project-local).
A plugin is a single .janet file — no boilerplate, no exports required.
;; Every time the user sends a prompt, print a line (defn on-prompt [ctx] (harness/notify (string "user said: " (ctx :prompt)) :info))
That's it. Restart dirge, type a message, and the notification appears in chat. The plugin system is on by default.
Multi-file plugins: create a directory of .janet files that share
one Janet environment and load in alphabetical order. Name files
00-state.janet, 01-hooks.janet to control load order.
Switch between built-in themes or create your own with a simple JSON file. Override any color — the rest falls back to defaults.
80s CRT green on black. Errors red, warnings yellow. The default.
White assistant text, cyan accents, gray dim. Clean and modern.
{
"theme": "plain"
}
Configure providers, role routing, permissions, themes, MCP servers, and custom
prompts in ~/.config/dirge/config.json.
{
"provider": "openrouter",
"model": "deepseek/deepseek-v4-flash",
"theme": "phosphor",
"permissions": {
"mode": "standard",
"rules": [
{ "pattern": "git checkout *", "action": "allow" },
{ "pattern": "rm -rf **", "action": "deny" }
]
},
"roles": {
"escalation": "anthropic",
"review": "glm"
},
"mcp_servers": {
"lattice": {
"command": "lattice-mcp",
"args": []
},
"chiasmus": {
"command": "npx",
"args": ["-y", "chiasmus"]
},
"wavescope": {
"command": "wavescope-mcp",
"args": []
}
}
}
Four permission modes: standard (safe ops auto-approved),
restrictive (every tool prompts),
accept-all (auto-approve inside cwd),
yolo (auto-approve everything).
Pattern rules support glob matching, and the /why command explains any decision.
Common questions about dirge.
list_symbols,
get_symbol_body, find_callers, find_callees, and
find_definition, with LSP diagnostics surfaced inline.
/why
traces exactly which rule decided. Add --sandbox to isolate bash in bubblewrap.