Persistent Coordination and Memory Layer for AI Coding Agents.
"Simple like Git. Persistent like Notion. AI-Native like Cursor."
Why not just a TODO.md? Text files have no locking, no claims, no session tracking β two agents editing one at the same time silently overwrite each other, and a crashed agent leaves a task looking claimed forever. Butler gives every write a version, every claim a lock, and every session a heartbeat. Full comparison β
π€ For AI agents: quick server summary (expand)
name: io.github.Teycir/butler
package: butler-mcp (.mcpb via GitHub Releases, no npm)
transport: stdio (MCP JSON-RPC)
storage: local SQLite (.butler/butler.db) β no cloud, cross-tool by design
install: download .mcpb from https://github.com/Teycir/Butler/releases/latest
core_loop: projectlist -> sessionregister -> read butler://projects/{id}/context ->
sessionheartbeat every 15s -> handoffcreate + sessiondisconnect on exit
tools:
session: [sessionregister, sessionheartbeat, sessiondisconnect]
tasks: [todoadd, todocomplete, todoupdate, tododelete, todolist]
coordination: [todoclaim, todounclaim, messagesend, broadcast, synccontext]
knowledge: [wikiupdate, ruleadd, ruleremove, decisionrecord, handoffcreate]
memory: [memorystore, memorysearch, memorydelete, projectlist]
observability: [eventsexport, butlerping]
resources:
- butler://projects/{id}/context # markdown packet: TODOs, rules, decisions, wiki, handoffs
- butler://projects/{id}/todos # JSON
- butler://projects/{id}/wiki # JSON
- butler://projects/{id}/sessions # JSON
- butler://projects/{id}/memories # JSON
- butler://projects/{id}/diff?since={eventId} # JSON changelog
- butler://projects/{id}/orchestration # LangGraph checkpoints, JSON
manifests:
- server.json # Official MCP Registry manifest
- .well-known/mcp/server-card.json # SEP-1649 server card
- .well-known/mcp.json # SEP-1960 discovery pointer
- llms.txt # plain-text agent summaryFull schemas: src/mcp/tools/*.tools.ts, or query tools/list over MCP. See Discovery & Registries for where this server is indexed.
Butler's core value isn't just that an agent remembers β it's that the memory is portable across completely different AI tools, because it lives in a shared local SQLite file rather than inside any one vendor's session. That's what makes cross-tool continuity possible in the first place.
| Scenario | What happens without Butler | What Butler does |
|---|---|---|
| Claude Code runs out of credits mid-task | You switch to Kiro CLI (or Cursor, or anything else) and it starts from zero β no idea what Claude Code already did | Kiro CLI registers a session, reads butler://projects/{id}/context, and picks up exactly where Claude Code left off: the same TODOs, rules, decisions, and the handoffcreate summary Claude Code recorded before running out |
| Planning in one tool, implementing in another (e.g. plan in Claude Desktop, implement in Cursor) | The implementing tool starts cold β no idea what was decided or done | The new session reads /context and instantly gets the prior session's handoff summary, open TODOs, and rules β regardless of which vendor built either tool |
| Two agents (possibly different tools) editing the same repo concurrently | Silent overwrites or duplicated work on the same task | todoclaim/todounclaim mark tasks as in-progress across tools; todocomplete/todoupdate use optimistic version locks and emit a TODO_CONFLICT event if two sessions touch the same TODO within seconds |
| An agent crashes or the terminal is closed | Its in-progress claims stay locked forever; no record of what it was doing | The lifecycle monitor marks the session stale after 60s, dead after 5 minutes, auto-releases its claims, and synthesizes an ungraceful handoff for whichever tool picks it up next |
| Coordinating a large refactor across sessions/tools | Agents don't know what their peers (on other tools) are touching | messagesend for direct heads-up between two sessions, broadcast for announcements to everyone, both surfaced in the next /context read regardless of client |
| Recording why a design decision was made | Rationale lives only in one tool's chat history and gets lost when the window closes or credits run out | decisionrecord logs an ADR (context + outcome) directly into the durable, tool-agnostic event log and project wiki |
| Onboarding a new agent/session into an existing project | Re-explaining architecture, constraints, and conventions from scratch every time β and again for every different tool you try | ruleadd persists coding guidelines every session must follow, on every client; wikiupdate builds a shared reference doc; both are pulled into /context automatically |
| Finding relevant past context without re-reading everything | Manually grepping chat logs or the whole codebase β and chat logs from other tools aren't even accessible | memorysearch runs hybrid TF-IDF + recency ranking over stored summaries, decisions, rules, and wiki pages, shared by every connected tool |
| Auditing what happened in a project over time | No structured history, just scattered chat transcripts split across whichever tools were used | eventsexport dumps the full append-only event log as JSON/NDJSON, filterable by session, type, or time range β one log, all tools |
| Multi-step agent orchestration (e.g. Plan β Implement β Verify β Commit, each stage potentially a different tool) | Each phase runs in isolation with no shared checkpoint state | The built-in LangGraph checkpointer (getLangGraphCheckpointer()) persists thread state in the same SQLite DB, and buildOrchestratorGraph coordinates hand-offs between planning/implementing/verifying agents |
| Watching a live multi-agent, multi-tool workspace | No visibility into who's doing what right now, especially across different clients | butler tui / butler dashboard show live sessions from every connected tool, claims, conflicts, and handoff quality in real time |
| π₯οΈ Live Orchestration Dashboard | π€ Active Session Topology & Status |
|---|---|
![]() |
![]() |
| β‘ Concurrency Mutation Conflicts | π€ Handoff Quality Scorecard & Coaching |
![]() |
![]() |
- π Butler
- π― Use Cases
- π Table of Contents
- β‘ Butler in 3 Minutes
- β±οΈ Quickstart in 30 Seconds (via GitHub Release)
- β±οΈ Quickstart from Source
- π The Core Vision
- π§ Core Terminology
- ποΈ System Architecture
- π Workflow Demo: cross-client session continuity
- β‘ Quickstart
- π API & Tool Surface
- π₯οΈ Developer CLI
- π§© Butler Workflow Skill
- π€ Zero-Intervention Automation
- π Context Freshness & Staleness
- π€ Multi-Agent Conflict Detection
- ποΈ Schema Migration
- π€ Multi-Agent Orchestration & LangGraph Integration
- π Repository Anatomy
- π Principles
- π Discovery & Registries
- Support Development
- π Related Projects
- πΌ Services Offered
- π License
- Author
Butler is a lightweight, local-first background coordination engine that registers active AI agents (e.g. Claude Desktop, Cursor, custom IDE tools) and maintains a shared, event-sourced memory space directly inside your project repository.
Butler features native LangGraph integration, providing a built-in SQLite checkpointer to save/restore multi-agent conversation threads and coordinate workflow graphs directly in the project database.
Coding agents are fundamentally amnesiac. When Cursor reloads or a process exits, active context (TODOs, architectural constraints, session differences) is completely lost. When multiple agents run concurrently, they operate in silos, generating race conditions and divergent branches. Butler bridges this gap.
- AI Pair Programmers: Developers working interchangeably across multiple LLM clients (e.g., planning in Claude, implementing in Cursor).
- Multi-Agent Workspaces: Teams running concurrent background AI workers on the same repository.
- Local-First Advocates: Engineers seeking zero network leakages and absolute privacy.
Unlike general-purpose agent memory platforms (which require hosted cloud APIs, external vector databases, or wrapping your code in framework SDKs), Butler is a local-first developer utility. It integrates directly with your existing workspace as a standard Model Context Protocol (MCP) server. A single .mcpb install (or the bundled install.sh/install.ps1 script) auto-configures your entire IDE stack (Cursor, Claude Desktop, VS Code, Zed) to instantly share project-level context, prevent concurrent file-editing conflicts, and persist active tasks directly within your repo's local SQLite databaseβwith zero network leakage, zero dependencies, and zero setup latency.
| Dimension | Butler | Mem0 | Letta (MemGPT) | LangMem | Zep |
|---|---|---|---|---|---|
| Primary Use Case | AI coding client memory & repo state coordination | General-purpose personalization APIs | Long-running autonomous OS-like agents | LangGraph-native agent prompt refinement | Temporal context & enterprise data graphs |
| Local Footprint | 0-Click Local SQLite (stored inside the repository) | Hybrid Cloud API or self-hosted vector database | Local/Cloud server (requires separate Docker/process) | Cloud-first managed service by LangChain | Cloud-first or heavy Docker dependencies |
| MCP Native | Yes (integrated in Claude Desktop, Cursor, VS Code, Zed) | No | No (uses custom REST/Websocket API) | No | No |
| IDE/CLI Auto-Install | Yes (.mcpb one-click, or install.sh/install.ps1 auto-configures clients) |
No | No | No | No |
| LangGraph Support | Yes (Built-in SQLite checkpointer for LangGraph JS) | No | No | Yes (native SDK integration) | No |
| Concurrency Control | Yes (Optimistic locking for parallel agents editing code) | No | No | No | No |
| Amnesia Prevention | Yes (Maintains context state across IDE reloads/restarts) | No (Focuses on user memory, not project state) | Yes (for its own custom agents) | Yes (primarily via API state stores) | Yes (via temporal memory logs) |
The obvious cheap alternative is a TODO.md or context.txt the agent reads and edits directly. It works, until more than one thing touches it:
- Concurrent writes silently clobber each other. If two agents (or two tabs of the same agent) both read the file, edit it, and write it back, the second write wins and the first agent's changes vanish β no error, no merge, just gone. Butler's SQLite event log gives every write a version number; a stale write is rejected instead of silently overwriting.
- A flat file has no session concept. There's no way to tell "who wrote this line and when," or to detect that the agent that claimed a task crashed 20 minutes ago and the task is actually free again. Butler tracks sessions with heartbeats, so dead agents don't hold a task forever.
- Context only grows. A markdown file accumulates every decision and TODO ever written, so agents either re-read a growing wall of text every turn (token cost climbs over the project's lifetime) or a human has to manually prune it. Butler materializes a current-state view from the event log β closed TODOs and superseded decisions drop out of what the agent reads, while the full history stays queryable if you ever need it.
- No structured handoff. Passing context from one tool to another means copy-pasting the relevant bit of the file into a prompt by hand. Butler's
handoffcreate/sessiondisconnectgives the next session a specific, structured summary to pick up from β not "here's the whole file, figure out where I left off." - Diffing a markdown file tells you what changed, not why or by whom. Butler's event log is append-only and attributes every change to a session, so
eventsexportgives you a real audit trail instead of a git diff on prose.
None of this means TODO.md is bad β for a single agent working alone, it's fine, and often simpler. Butler earns its keep specifically when more than one agent (or more than one tool) touches the same project.
"But what if every agent just re-reads TODO.md at the start of each session?" That genuinely solves amnesia for a single agent working sequentially β read the file, pick up where you left off, no dependency needed. It stops working the moment two agents can be active at overlapping times:
- Read-then-write races. Agent A reads
TODO.mdat t=0, starts a long task. Agent B reads the same file at t=1, also starts working, then finishes first and writes back its version β silently erasing whatever A was about to add. Re-reading at session start doesn't help if the write happens at session end; the race is on the write, not the read. - "Re-read at the start of each session" only works if sessions don't overlap. Two IDE windows open on the same repo right now, both mid-task, is the actual multi-agent case Butler targets β and no file-reread policy fixes a write collision between two sessions that are already both open.
- Nothing tells B that a TODO is claimed, only that it exists. A can mark a line "in progress," but there's no lock β B can start the same item five seconds later because the file doesn't enforce anything, it just describes. Butler's
todoclaimis an actual claim other agents are blocked from taking, not a note that can be ignored. - A crashed agent leaves a lie in the file. If A claims a TODO in the text and then dies, that TODO looks permanently claimed to every future reader β nothing expires it. Butler's session heartbeats detect the dead session and free the claim automatically.
So the re-read pattern is a real, valid simplification exactly when you can guarantee one agent at a time. Butler is for the case where you can't β or don't want to have to.
| Dimension | Butler | Plain Text Files (context.txt) |
Heavy DBs (Postgres/Redis) |
|---|---|---|---|
| Portability | 0-Click Local SQLite | Hard to version-control safely | Complex Docker setup |
| State Conflict | Optimistic Lock Versions | Prone to complete overrides | Manual locks required |
| Recovery | Ephemeral heartbeats & handoffs | None (static data) | Complex event logs |
| Context Size | Materialized incremental views | Massive raw token bloat | Ad-hoc query builds |
Butler is distributed as a single .mcpb bundle attached to each GitHub Release β no npm package, no registry account needed:
- Download
butler-mcp-linux-x64.mcpbfrom the latest release. - Double-click it (or drag into Claude Desktop's Settings β Extensions) to install with one click.
Currently Linux x64 only β see Discovery & Registries below for why, and for the source-build path on other platforms.
git clone https://github.com/Teycir/Butler.git
cd ButlerLinux / macOS:
bash install/install.shWindows (PowerShell):
.\install\install.ps1The installer will:
- Build Butler from source.
- Deploy the production bundle to
~/Mcp/butler-mcp/. - Automatically scan the host machine for active coding clients.
- Inject the Butler MCP configuration into all detected clients (supporting Claude Desktop, Claude Code, Cursor, VS Code, Windsurf, Zed, Gemini CLI, Kiro CLI, and Kilo Code).
- JSONC / Comment Safe: Safely parses configurations with comments and trailing commas without overwriting custom settings.
Custom DB path: Pass
--db-pathto use a custom SQLite file location:bash install/install.sh --db-path /your/path/butler.dbOr on Windows:.\install\install.ps1 -DbPath "C:\your\path\butler.db"
npm install
npm run buildThen add Butler to your AI client's MCP config manually:
{
"mcpServers": {
"butler": {
"command": "node",
"args": ["/absolute/path/to/Butler/dist/index.js"],
"env": {
"BUTLER_DB_PATH": "/absolute/path/to/butler.db"
}
}
}
}Config file locations:
- Claude Desktop (Linux):
~/.config/Claude/claude_desktop_config.json - Claude Desktop (macOS):
~/Library/Application Support/Claude/claude_desktop_config.json - Claude Desktop (Windows):
%APPDATA%\Claude\claude_desktop_config.json - VS Code / Cursor:
mcp.jsonin your user settings directory - Kiro CLI:
~/.config/kiro-cli/mcp.json - Kilo Code:
~/.config/Antigravity/User/globalStorage/kilocode.kilo-code/settings/mcp_settings.json
Example: Kiro CLI configuration (~/.config/kiro-cli/mcp.json)
{
"mcpServers": {
"butler": {
"command": "/home/user/.nvm/versions/node/v20.20.0/bin/node",
"args": [
"/home/user/Mcp/butler-mcp/dist/index.js"
],
"env": {
"BUTLER_DB_PATH": "/home/user/.butler/butler.db"
}
}
}
}Restart your AI clients and Butler is ready.
Coding agents today are incredibly powerful but fundamentally amnesiac. When your Cursor window reloads or Claude Desktop restarts, your active context, developer constraints, completed tasks, and architectural decisions are erased.
Even worse, when multiple agents work on the same codebase simultaneously, they operate in completely disjoint silos, causing race conditions, diverging implementations, and broken handoffs.
Butler bridges this gap by acting as a local, background Durable Project Memory Log:
π€ Agent A (Claude) π€ Agent B (Cursor)
\ /
\ /
[ Model Context Protocol stdio transport ]
β
===========================
β BUTLER β
β Durable Shared Memory β
===========================
/ β β \
/ β β \
βΌ βΌ βΌ βΌ
π― TODOs π Rules π‘ Decisions π Wiki
To understand Butler in under two minutes, here are our core conceptual models:
- Project: The permanent codebase workspace. Lives forever, anchored by a local-first SQLite file (
.butler/butler.db). - Session: An ephemeral window of activity by a specific AI client (e.g.
cursor-1,claude-desktop-2). Sessions send periodic heartbeats to prove presence. - Event: An append-only, immutable transaction log entry representing a discrete state change (e.g.
TODO_CREATED,RULE_ADDED,WIKI_UPDATED). Events are the ground truth. - State: A materialized cache of the project's current status (active tasks, wiki pages, rules) constructed incrementally by playing events. State is the cache.
- Handoff: A structured, context-rich handoff payload generated when a session disconnects, capturing exact achievements and pending blockers.
- Memory: Highly searchable semantic guidelines, observations, and design logs indexed locally using light, zero-click Term Frequency-Inverse Document Frequency (TF-IDF) sparse relevance algorithms.
Butler is designed to be operationally invisible and incredibly fast. It operates on an event-sourced, materialized-view model backed by SQLite in Write-Ahead Log (WAL) mode.
graph TD
subgraph AI_Clients["AI Clients"]
C1[π€ Claude Desktop]
C2[π€ Cursor Editor]
C3[π€ Kiro / Kilo / VSCode]
end
subgraph Dev_Tools["Developer Tools (local, no MCP)"]
CLI[π₯οΈ cli/status.ts Β· cli/tui.ts<br/>npm run status Β· npm run tui]
DASH[π cli/dashboard.ts<br/>npm run dashboard β :7888 SSE]
end
subgraph MCP_Layer["Transport Layer"]
MCP[π mcp/server.ts<br/>MCP stdio Β· JSON-RPC]
end
subgraph Tools["mcp/tools/"]
T_SES[session.tools.ts<br/>register Β· heartbeat Β· disconnect]
T_TODO[todo.tools.ts<br/>add Β· complete Β· update Β· delete Β· list]
T_KNOW[knowledge.tools.ts<br/>wiki Β· rule Β· decision Β· handoff]
T_MEM[memory.tools.ts<br/>store Β· search Β· delete Β· projectlist]
T_COORD[coordination.tools.ts<br/>claim Β· unclaim Β· message Β· broadcast Β· synccontext]
T_OBS[observability.tools.ts<br/>eventsexport Β· butlerping]
end
subgraph Resources["mcp/resources.ts Β· mcp/resources/"]
R_CTX[context Β· todos Β· wiki<br/>sessions Β· memories Β· diff Β· orchestration]
end
subgraph Coordinator["src/coordinator/"]
LIFE[lifecycle.ts<br/>session CRUD Β· heartbeat monitor<br/>stale/dead detection Β· ensureSession]
HAND[handoff.ts<br/>generateStructuredHandoff<br/>computeHandoffQualityScore]
DIFF[diff.ts<br/>getProjectDiff<br/>getContextStaleness]
SES[session.ts<br/>SessionRecord Β· low-level read helpers]
end
subgraph Events["src/events/"]
STORE[store.ts<br/>appendEvent Β· getEvents<br/>createSnapshot Β· getLatestSnapshot]
MAT[materializer.ts<br/>materializeProject Β· in-memory ProjectState cache]
PROJ[projections.ts<br/>projectEvent Β· per-event state transitions]
TYPES[types.ts<br/>EventRecord Β· event type definitions]
end
subgraph Vector["src/vector/"]
VEC[index.ts<br/>Pure-JS TF-IDF<br/>addMemory Β· searchMemories Β· deleteMemory]
SIM[similarity.ts<br/>cosine similarity Β· token scoring]
end
subgraph DB_Layer["src/db/"]
SCHEMA[schema.ts<br/>INIT_SCHEMA_SQL<br/>VERSIONED_MIGRATIONS v1βv8]
DATABASE[database.ts<br/>initDatabase Β· getDb Β· closeDatabase]
end
subgraph Storage["SQLite WAL .butler/butler.db"]
T1[(projects)]
T2[(sessions)]
T3[(events)]
T4[(sequences)]
T5[(snapshots)]
T6[(memories)]
T7[(butler_migrations)]
T8[(checkpoints)]
T9[(writes)]
end
C1 & C2 & C3 -->|JSON-RPC stdio| MCP
MCP --> T_SES & T_TODO & T_KNOW & T_MEM & T_COORD & T_OBS
MCP --> R_CTX
T_SES & T_TODO & T_KNOW & T_MEM & T_COORD --> LIFE
T_SES --> HAND
T_KNOW --> HAND
R_CTX --> MAT & LIFE & DIFF & VEC
LIFE --> STORE & HAND & DIFF
LIFE --> SES
HAND --> SES
STORE --> DATABASE
MAT --> STORE & PROJ & TYPES
PROJ --> TYPES
VEC --> SIM
VEC --> DATABASE
DATABASE --> SCHEMA
DATABASE --> T1 & T2 & T3 & T4 & T5 & T6 & T7 & T8 & T9
CLI --> DATABASE
DASH --> DATABASE
Imagine this workflow:
- Start in Cursor: You ask Cursor to plan a database migration. Cursor registers a session, creates 3 TODOs, and records a design decision (
ADR-001). - Cursor Window Reloads / Crashes: The Cursor session terminates. Butler detects the disconnection, automatically materializes a structured handoff marker, and updates the event log.
- Resume in Claude Desktop: You open Claude Desktop. Claude registers its session.
- Instant Rehydration: Claude reads the
butler://projects/{id}/contextresource. It instantly receives:- The structured handoff summarizing Cursor's accomplishments.
- The exact pending TODO list.
- The active project rules and architectural constraints. Claude immediately resumes work with zero lost context.
git clone https://github.com/Teycir/Butler.git
cd ButlerLinux / macOS:
bash install/install.shWindows (PowerShell):
.\install\install.ps1The installer builds Butler, deploys the release to ~/Mcp/butler-mcp/, and auto-configures detected clients (including Claude Desktop, Claude Code, Cursor, VS Code, Windsurf, Zed, Gemini CLI, Kiro CLI, and Kilo Code) safely. Restart your AI clients and Butler is ready.
Custom DB path: Pass
--db-pathto specify a custom database location:bash install/install.sh --db-path /your/path/butler.dbOr on Windows:.\install\install.ps1 -DbPath "C:\your\path\butler.db"
Open your AI client (Claude Desktop, Cursor, etc.) and ask:
"Can you call the
butlerpingtool?"
Expected response:
{
"status": "ok",
"db_path": "/home/user/.butler/butler.db",
"db_size_kb": 142,
"schema_version": 8,
"project_count": 3,
"uptime_seconds": 3621
}Drop a .butler/project.json in your repo root to set a default project for all tool calls:
{ "project_id": "my-project" }Butler walks up the directory tree to find this file automatically. Once set, every tool call in that workspace resolves project_id without you passing it explicitly.
npm test| URI | Description |
|---|---|
butler://projects/{id}/context |
Unified markdown context packet: TODOs, rules, decisions, wiki, sessions, handoffs, messages, broadcasts, and auto-surfaced relevant memories. Includes a π’/π΄ freshness badge and staleness metadata. |
butler://projects/{id}/todos |
Materialized active task list (JSON). |
butler://projects/{id}/wiki |
Shared wiki and reference documents (JSON). |
butler://projects/{id}/sessions |
Active and stale session registry (JSON). |
butler://projects/{id}/memories |
Complete project memory log (JSON). |
butler://projects/{id}/diff?since={eventId} |
Compact changelog of all state changes since a given event ID, grouped by type. |
butler://projects/{id}/orchestration |
LangGraph orchestration checkpoints and execution state stored for the project (JSON). |
| Tool | Description |
|---|---|
sessionregister |
Bind an active client session. Idempotent β reconnecting agents reuse their session. |
sessionheartbeat |
Signal presence every 15 seconds to stay alive in shared context. |
sessiondisconnect |
Gracefully disconnect and broadcast a structured continuity handoff. |
| Tool | Description |
|---|---|
todoadd |
Create a task with priority (low/medium/high) and optimistic version locking. |
todocomplete |
Mark a task done with conflict detection against concurrent mutations. |
todoupdate |
Update a TODO's title, priority, or status with version checking. |
tododelete |
Delete a TODO with optimistic version checking. |
todolist |
List all TODOs for a project (filterable by pending/completed/all). |
| Tool | Description |
|---|---|
todoclaim |
Claim a TODO as actively being worked. Other agents see it as π in-progress. Claims expire when the session goes stale. |
todounclaim |
Release a claim, making the TODO available again. |
messagesend |
Send a direct message to another active session (stored in event log; delivered on reconnect). |
broadcast |
Announce something to all active sessions β visible in every agent's next context read under π’ Broadcasts. |
synccontext |
Force an immediate context sync across all peer sessions, surfacing the latest shared state without waiting for the next heartbeat cycle. |
| Tool | Description |
|---|---|
wikiupdate |
Create or update a wiki knowledge base page. |
ruleadd |
Add a persistent coding guideline all agents must follow. |
ruleremove |
Remove a persistent guideline by ID. |
decisionrecord |
Log an architectural decision record (ADR) with context and outcome. |
handoffcreate |
Explicitly broadcast a session handoff. Includes quality scoring (0β100%) with inline coaching feedback. |
memorystore |
Store a semantic project memory (type: summary, decision, rule, wiki). |
memorysearch |
Search project memory using hybrid TF-IDF keyword + recency ranking. |
memorydelete |
Delete a memory by ID to remove stale or incorrect information. |
projectlist |
List all projects in the Butler database. |
| Tool | Description |
|---|---|
eventsexport |
Export the raw event log as json (array) or ndjson (newline-delimited). Supports since, until, session_id, event_type, and limit filters. Default 500, max 5000 events. |
butlerping |
Lightweight health-check returning DB path, size, schema version, project count, and uptime. |
Butler ships with a local command line interface (CLI) to configure, manage, and monitor your multi-agent workspaces β no MCP server connection required to run diagnostics or status checks.
Manages the opt-in registry of AI client config files Butler installs into (persisted to ~/.butler/clients.json).
$ butler clients list
π Known AI clients
β
claude-desktop
/home/user/.config/Claude/claude_desktop_config.json
cursor
vscode
windsurf
zed
kiro-cli
kilo-code
...
1 client(s) registered. Run `butler install` to apply.
butler clients listβ show all known client slugs plus which ones are currently registered.butler clients add <slug>β register a known slug (resolves its default path automatically), or pass--path /path/to/config.jsonto register a custom/unknown tool under that slug.butler clients remove <slug>β unregister a slug.
Note: once at least one client has been registered (manually or via auto-detect on the very first butler install run), butler install only injects into the registered set β it does not re-scan for newly installed IDEs on subsequent runs. Use butler clients add <slug> to pick up a new client later.
Deploys the Butler production bundle to ~/Mcp/butler-mcp and injects the Butler MCP server configuration into your registered AI client configuration files. If no clients are registered yet (i.e. this is the first run), it scans your system once to auto-detect and register active clients; on subsequent runs it only touches whatever is already registered in ~/.butler/clients.json (see butler clients above). It supports comments (JSONC) and trailing commas safely.
$ butler install
π¨ Building from source...
π Syncing to /home/user/Mcp/butler-mcp...
π§ Injecting Butler into registered AI clients...
β
/home/user/.config/Claude/claude_desktop_config.json
β
/home/user/.config/Cursor/User/mcp.json
β
/home/user/.config/zed/settings.json
...
π Done! Restart your AI clients to activate Butler.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π SYSTEM PROMPT SNIPPET β paste this into your AI client once:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
On startup: call projectlist, then sessionregister (project_id from .butler/project.json or ask the user, session_id = "<client>-<4 random chars>", client_type = your tool name). Heartbeat every 15 seconds. Before exit: call handoffcreate with a summary of what you did, then sessiondisconnect.
π§ͺ Verifying setup...
Open any registered client and ask: 'Can you call the butlerping tool?'
Expected response: status: ok, schema_version: 8
Interactively initializes a new project configuration inside your local workspace. This creates .butler/project.json and adds it to your .gitignore so your agents can automatically identify the correct project database namespace.
$ butler init
π Butler β Project Setup
? Project ID [default: my-project]: my-project
? Project name (optional): My Project Workspace
? Default client [default: Claude Desktop]: Claude Desktop
β
Created .butler/project.json
β
Added .butler/ to .gitignore
β
Ready! Open your AI client and start coding.
Reads the global SQLite database (~/.butler/butler.db) directly and outputs a comprehensive diagnostic summary of the workspace's projects, sessions, active/completed tasks, and recent handoffs.
$ butler status
π€΅ Butler Status 15/06/2026 20:08:12
Database: /home/user/.butler/butler.db
Projects: 4
βββββββββββββββββββββββββββββββββββββ
β π Butler β Butler β
β π΄ INACTIVE | 0 live sessions β
βββββββββββββββββββββββββββββββββββββ
SESSIONS
No active sessions
β« 1 dead session(s) hidden
TODOS (0 open, 0 completed)
No open TODOs
π€ RECENT HANDOFFS (last 3)
[system] claude-r4x (127h ago)
"Session claude-r4x lost connection (missed heartbeat). Auto-generated cβ¦"
[system] claude-r4x (127h ago)
"Session claude-r4x lost connection (missed heartbeat). Auto-generated cβ¦"
HANDOFF QUALITY SCORE ββββββββββ 49% (last: claude-r4x)
Event log: 19 events | last: 127h ago
Snapshot: no snapshot yet
Supports --project <id>, --db <path>, --json, and --help flags.
Launches a live split-screen Terminal User Interface (TUI) that refreshes every 2 seconds, displaying real-time agent presence, broadcast events, active tasks, version conflicts, and handoff quality metrics.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π€΅ BUTLER ORCHESTRATOR β Project: api-hunter β 20:13:57 β
β DB: ~/.butler/butler.db (128 KB) β Schema: v8 β Projects: 4 β Status: π’ HEALTHY β
ββββββββββββββββββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββ€
β π€ Topology Sessions (2) β π― Shared Task Space (3 open) β
β β cursor-main-1 cursor 12s ago β Progress: [ββββββββββββββββ] 37% (6/16 done) β
β β claude-desk-2 claude 45s ago β β HGH [#1] Implement JWT signatβ¦ β π cursor-mβ¦ β
β β β MED [#2] Add OAuth tests β unclaimed β
β π’ Broadcast Stream (2) β β LOW [#3] Verify README typos β unclaimed β
β 10s ago [cursor-m]: refactored auth.ts β β
β 45s ago [claude-d]: pulling main branch β β‘ Mutation Conflicts (1) β
β β β οΈ Task #1 β concurrent_update β 8s ago β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β π€ RECENT WORKSPACE HANDOFFS β
β [agent] cursor-main-1 (10m ago) - "Refactored JWT signature checking and fixed algorithm bypass."β
β [system] claude-desk-2 (25m ago) - "Session claude-desk-2 disconnected gracefully." β
β Quality Rating: [βββββββββββββββ] 73% (latest: cursor-main-1) β Words: 24 β Struct: β β Verbs: ββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Events: 142 β Last Event: TODO_COMPLETED (12s ago) [Q] Quit β [R] Refresh β Auto-Refresh: 2s β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Interactive controls: Press q to quit, r to force a manual refresh.
Starts a local web dashboard with SSE (Server-Sent Events) live pushing every 5 seconds to show active sessions, TODOs, conflict lists, and event trails. Runs read-only by default.
$ butler dashboard
π Serving Butler dashboard at http://localhost:7888
Pass --dev to start it in writable mode instead, which lets you complete, edit, or delete TODOs and send broadcasts directly from the dashboard UI (in addition to the read-only view):
npx tsx src/cli/dashboard.ts --dev
# Mode: dev-writableSupports --port <n>, --host <addr>, --db <path>, and --dev flags.
Outputs structured database size and schema metrics as JSON. Perfect for piping to jq or integrating into external status monitoring tools.
{
"status": "ok",
"db_path": "/home/user/.butler/butler.db",
"db_size_kb": 128,
"schema_version": 8,
"project_count": 4
}Runs environmental diagnostics to ensure Node.js compatibility, built output validity, database state, and client MCP configurations are set up correctly.
$ butler doctor
π©Ί Butler Doctor Diagnostics
β
Node.js v20.20.0 β OK
β
Butler build β OK (dist/index.js exists)
β
Database β OK (/home/user/.butler/butler.db, schema v8)
β
Claude Desktop config β OK (butler entry found)
β οΈ Cursor config β NOT FOUND (missing file)
β
Kiro CLI config β OK (butler entry found)
β
VS Code config β OK (butler entry found)
β
Kilo Code config β OK (butler entry found)
Fix: Run `butler install` to repair configuration files.
Butler includes a portable skill package that teaches AI agents how to use Butler's coordination features effectively. The skill is available in skills/butler-workflow/.
For Kiro CLI / Kilo Code / Claude Code:
cp -r skills/butler-workflow ~/.kiro/skills/
# or
cp -r skills/butler-workflow ~/.agents/skills/For other agents: Copy the skill to your agent's skill directory and it will be auto-loaded on startup.
The butler-workflow skill provides comprehensive patterns for:
- Session Lifecycle: Register β heartbeat β handoff β disconnect
- TODO Workflow: Create β claim β work β complete with conflict prevention
- Memory Management: Store decisions, search context, clean up stale data
- Multi-Agent Coordination: Messages, broadcasts, conflict detection
- Best Practices: When to register, how to handoff, what to persist
Once installed, agents automatically learn Butler patterns. The skill teaches agents to:
- Register sessions at startup with unique session IDs
- Send heartbeats every 15-30 seconds during active work
- Claim TODOs before starting to prevent conflicts
- Store important decisions with appropriate importance scores
- Create quality handoffs when switching contexts
- Coordinate with other active sessions via messages
See skills/butler-workflow/SKILL.md for full documentation and examples.
Butler is designed to run completely in the background. All you need to do is install the MCP server and copy the skill package to your agent folder. Butler handles the rest automatically.
When you open any directory to work:
- Butler automatically configures the project by creating
.butler/project.json(derived from the directory name). - The agent automatically joins and heartbeats in the background.
- The agent automatically records context and leaves a handoff on exit.
You do not need to run any initialization commands or setup scripts. It just works.
To make onboarding effortless, Butler automatically handles project configuration:
- Automatic Setup: If a connecting agent runs inside a workspace that does not contain a
.butler/project.jsonfile, Butler will automatically:- Create the
.butler/directory. - Normalize the current working directory's folder name to generate a clean, kebab-case
project_id(e.g.some-cool-project). - Write a default
project.jsoncontaining that ID.
- Create the
- Manual Override: You can change or override the default ID at any time by editing the
"project_id"field in.butler/project.json. - Result: Zero configuration or manual creation steps are required when opening new directories.
Deploy the butler-workflow skill package to your agent's skill directory:
# For Agy / Claude Code / Antigravity
cp -r skills/butler-workflow ~/.agents/skills/
# For OpenCode
cp -r skills/butler-workflow ~/.config/opencode/skill/
# For Kiro CLI / Kilo Code
cp -r skills/butler-workflow ~/.kiro/skills/- Result: Connecting agents load this skill on startup and execute the session lifecycle autonomously:
- Registers the session on startup.
- Starts a silent background timer emitting heartbeats every 15s.
- Automatically fetches context and reads tasks.
- Generates a structured handoff and disconnects gracefully on exit.
If using standard LLM clients (Claude Desktop, Cursor, VS Code, ChatGPT) without a skill loader, append this directive to your agent's global System Prompt instructions:
On startup, call
projectlistor check.butler/project.jsonto find the active project. Callsessionregister(generate a uniquesession_id). Fetchbutler://projects/{id}/contextto catch up. Send heartbeats every 15 seconds. Before exit, runhandoffcreateand callsessiondisconnect.
If an agent crashes or the terminal is closed abruptly, Butler automatically self-heals:
- The background lifecycle monitor sweeps active heartbeats every 15 seconds.
- If a session misses heartbeats for 60 seconds, it is marked
stale. - After 5 minutes, it is marked
dead, its task claims/locks are automatically released for other sessions, and an ungraceful continuity handoff is synthesized to record what was left behind.
Every /context read opens with a freshness badge:
π’β at least one session is alive and actively heartbeatingπ΄β no live sessions; context was last updated some time ago
The raw JSON payload (second content block on /context) also includes a staleness object:
{
"last_live_heartbeat": 1716900000,
"has_live_session": false,
"events_since_last_read": 12,
"context_age_seconds": 720
}Agents reconnecting after a gap can use last_event_id + the /diff resource to fetch only what changed, rather than re-reading the full context.
When two sessions complete or update the same TODO within a 10-second window, Butler appends a TODO_CONFLICT event alongside the mutation. These conflicts surface in the /context resource under β‘ Recent Coordination Conflicts, letting all agents see where parallel writes collided and coordinate resolution.
Butler uses a versioned migration runner backed by a butler_migrations tracking table. Each migration:
- Runs inside a transaction β failure rolls back cleanly
- Is idempotent β applied exactly once, never re-run
- Records version number, description, and
applied_attimestamp
The VERSIONED_MIGRATIONS array in schema.ts is the single source of truth. Pre-existing databases are automatically brought up to date on startup.
Butler features first-class integration with LangGraph to support complex, multi-step agent orchestration workflows (such as Planning β Implementing β Verifying β Committing).
Butler provides a custom LangGraph checkpointer (getLangGraphCheckpointer()) that utilizes your existing better-sqlite3 database to save and restore agent checkpoint states and conversation threads. This avoids the need to maintain a separate SQLite checkpointer file for LangGraph.
To fetch the checkpointer instance:
import { getLangGraphCheckpointer } from './dist/langgraph/checkpointer.js';
const checkpointer = getLangGraphCheckpointer();The checkpointer stores thread state in the checkpoints and writes tables, automatically managed under the same WAL-journaled database as the event log.
Butler includes a built-in multi-agent state graph definition (OrchestratorState / buildOrchestratorGraph) to coordinate actions between different developer agents (e.g. Antigravity/Agy planning, Kiro CLI implementing, OpenCode verifying). The orchestrator uses LangGraph interrupts to pause execution until tasks are completed and marked complete in the Butler event log.
Butler/
βββ src/
β βββ db/ # SQLite connection pool, WAL mode, versioned schema migrations (v1βv8), Zod schemas (zod.ts)
β βββ events/ # Event store (append-only log), materializer, projections, type definitions
β βββ coordinator/ # Heartbeat registry, session lifecycle, handoff quality scoring, session helpers
β βββ vector/ # Pure-JS TF-IDF sparse memory indexer + cosine similarity
β βββ langgraph/ # LangGraph checkpointer, orchestrator graph, builder utilities
β βββ lib/ # Shared formatting utilities
β βββ mcp/
β β βββ server.ts # MCP stdio transport, routing, auto-registration
β β βββ resources.ts # context, todos, wiki, sessions, memories, diff, checkpoints
β β βββ resources/ # Resource handler modules (context.ts, diff.ts)
β β βββ tools/
β β βββ session.tools.ts # sessionregister, sessionheartbeat, sessiondisconnect
β β βββ todo.tools.ts # todoadd, todocomplete, todoupdate, tododelete, todolist
β β βββ knowledge.tools.ts # wikiupdate, ruleadd, ruleremove, decisionrecord, handoffcreate
β β βββ memory.tools.ts # memorystore, memorysearch, memorydelete, projectlist
β β βββ coordination.tools.ts # todoclaim, todounclaim, messagesend, broadcast, synccontext
β β βββ coordination/ # Coordination sub-handlers (sync.ts)
β β βββ observability.tools.ts # eventsexport, butlerping
β βββ cli/
β β βββ main.ts # CLI entry point and command router (install, init, clients, ping, doctor)
β β βββ clientConfigs.ts # Known AI client config paths + opt-in client registry (~/.butler/clients.json)
β β βββ status.ts # `npm run status` β terminal project summary
β β βββ tui.ts # `npm run tui` β live split-screen terminal UI
β β βββ tuiRenderer.ts # TUI rendering logic
β β βββ tuiTheme.ts # TUI color and styling constants
β β βββ dashboard.ts # `npm run dashboard` β local SSE web dashboard
β β βββ dashboardServer.ts # SSE server and HTTP handler
β β βββ dashboardHandlers.ts # Dashboard data handlers
β β βββ dashboardRenderer.ts # Dashboard HTML rendering
β βββ constants.ts # Shared constants (TTLs, limits, timing values)
β βββ project-config.ts # .butler/project.json discovery (walks up directory tree)
β βββ validation.ts
β βββ index.ts # Application entry point
βββ tests/
β βββ integration.test.ts
βββ skills/ # Portable agent skill packages
β βββ butler-workflow/ # Butler coordination patterns for AI agents
βββ docs/ # Workflows, best practices, troubleshooting, architecture, concepts, changelog, recovery guides
βββ install/ # install.sh / install.ps1 β build + multi-client auto-config
βββ .well-known/
β βββ mcp.json # SEP-1960 discovery pointer
β βββ mcp/server-card.json # SEP-1649 server card
βββ server.json # Official MCP Registry manifest
βββ llms.txt # Plain-text agent-readable summary
βββ package.json
βββ tsconfig.json
- Events are Truth, State is Cache: We reconstruct project models deterministically by replaying event logs.
- 0-Clicks Portability: Vector indexers run on pure JavaScript TF-IDF token matching, eliminating the need for Python packages, heavy vector databases, or paid API keys.
- Invisible Ergonomics: The user never manages memory. The system simply remembers.
- Active Contribution, Not Passive Reading: Butler's server instructions coach every agent to write decisions, TODOs, rules, and handoffs β not just consume them. The shared brain only works if everyone feeds it.
Butler ships machine-readable manifests so AI agents and registry crawlers can find and evaluate it without parsing the full README:
| File | Purpose |
|---|---|
llms.txt |
Plain-text summary for LLMs/agents: what it's for, core loop, tool/resource list, doc links |
server.json |
Official MCP Registry manifest under namespace io.github.Teycir/butler, pointing at a GitHub Release-hosted .mcpb bundle (no npm package involved) |
.well-known/mcp/server-card.json |
Full server card (tools, resources, compatible clients, categories) per the SEP-1649 draft convention |
.well-known/mcp.json |
Discovery pointer per the SEP-1960 draft convention |
<!-- mcp-name: io.github.Teycir/butler --> (top of this README) |
Ownership-verification marker required by the Official MCP Registry |
manifest.json |
MCPB bundle manifest β packs Butler into a single .mcpb file attached to each GitHub Release for one-click desktop install |
Butler is distributed entirely through GitHub β no npm package, no PyPI, no external registry account required. Each release attaches a butler-mcp-linux-x64.mcpb asset (built via npx @anthropic-ai/mcpb pack), and server.json's packages[0].identifier points directly at that release asset URL with a fileSha256 for integrity verification. Currently Linux x64 only, since better-sqlite3 ships a platform-specific native binary; cross-platform bundles would need to be built on macOS/Windows separately.
Publishing/updating the registry listing (maintainer-only, requires mcp-publisher):
# Authenticate once via GitHub (namespace io.github.Teycir/*)
mcp-publisher login github
# Publish/update the listing from server.json at the repo root
mcp-publisher publish server.jsonOn every release: bump version in manifest.json and server.json, rebuild the .mcpb (npx @anthropic-ai/mcpb pack . butler-mcp-linux-x64.mcpb), attach it to the new GitHub Release, update fileSha256 and the release-tag path in server.json, then re-run mcp-publisher publish server.json β the registry does not auto-detect new releases.
Butler is also discoverable through general-purpose MCP directories (mcp.so, Smithery, Glama, the punkpeye/awesome-mcp-servers GitHub list) once listed in the Official Registry, since several of them auto-ingest from it.
If this project helps your work, support ongoing maintenance and new features.
ETH Donation Wallet
0x11282eE5726B3370c8B480e321b3B2aA13686582
Scan the QR code or copy the wallet address above.
Explore more privacy-first and security tools:
- Timeseal - Time-locked encryption vault with Dead Man's Switch. AES-256 split-key crypto, ephemeral seals.
- Sanctum - Zero-trust encrypted vault with cryptographic plausible deniability. XChaCha20-Poly1305, Argon2id.
- GhostChat - True P2P encrypted chat via WebRTC. No servers, no storage, self-destructing messages.
- xmrproof - Monero payment verification, 100% client-side.
- GhostReceipt - Anonymous receipt generation with zero-knowledge proofs.
- BurpAPISecuritySuite - Burp Suite extension for API security testing. 15 attack types, 108+ payloads, BOLA/IDOR detection.
- Mcpwn - Automated security scanner for Model Context Protocol servers. Detects RCE, path traversal, prompt injection.
- DiffCatcher - Git repo discovery, diff capture, code element extraction.
- HoneypotScan - Honeypot detection service for security research.
- CheckAPI - LLM API key validator for multiple providers. Privacy-first, client-side validation.
- SeekYou - Host intelligence aggregator β unified OSINT across 15 sources for IPs, domains, and ASNs.
- burp-mcp-server - MCP server for Burp Suite Professional. Vulnerability scanning via AI assistants.
- nuclei-mcp - MCP server for Nuclei. Multi-target scanning, severity filtering.
- nmap-mcp - MCP server for Nmap. Stealth recon, vuln/NSE scanning.
- frida-mcp - MCP server for Frida. Dynamic instrumentation, SSL pinning bypass.
- π Privacy-First Development - P2P applications, encrypted communication, zero-knowledge systems
- π Web Application Development - Full-stack development with Next.js, React, TypeScript
- π§ Edge Computing Solutions - Cloudflare Workers, Pages, D1, KV, Durable Objects
- π‘οΈ Security Tool Development - Burp extensions, penetration testing tools, automation frameworks
- π€ AI Integration - LLM-powered applications, intelligent automation, custom AI solutions
- π OSINT & Threat Intelligence - Custom reconnaissance tools, threat feed aggregation, IOC correlation
Get in Touch: teycirbensoltane.tn | Available for freelance projects and consulting
MIT License
Copyright (c) 2026 Teycir Ben Soltane
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Teycir Ben Soltane
Email: teycir@pxdmail.net
GitHub: @Teycir
Built with π by Teycir Ben Soltane




