Tirith
Tirith logo

Tirith

Coordination server for parallel coding agents.

File claims with leases, a task board, interface contracts, change notices, a decisions log, memory notes scoped to paths, and messages between agents, over MCP. One small daemon per repository. Works with Claude Code, Cursor, Codex, LangGraph, CrewAI, or a plain script.

CI status Latest release crates.io version MIT license
# macOS and Linux
curl -LsSf https://eabz.github.io/tirith/install.sh | sh
0.1.x. Every primitive is built and tested; tool schemas may still change until v1 ships.

Install

Tirith ships as a single static binary per platform and as the crate tirith-mcp on crates.io. The binary is always called tirith. Pick whichever fits.

curl -LsSf https://eabz.github.io/tirith/install.sh | sh

The shim fetches the installer attached to the latest GitHub release. It detects your OS and CPU, downloads the matching archive, verifies its checksum, installs tirith into $CARGO_HOME/bin (~/.cargo/bin by default, created if missing), and tells you if your PATH needs a line.

Pin a version with TIRITH_VERSION=v0.1.2 in front of the command. To skip the shim, the release asset itself is the same installer:

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/eabz/tirith/releases/latest/download/tirith-mcp-installer.sh | sh
irm https://eabz.github.io/tirith/install.ps1 | iex

Run it in PowerShell. It installs tirith.exe for x86_64 or ARM64 and adds it to your user PATH; open a new terminal afterwards so the change is picked up. Pin a version with $env:TIRITH_VERSION = "v0.1.3" first.

From cmd.exe, or if your execution policy blocks the one-liner:

powershell -ExecutionPolicy Bypass -c "irm https://eabz.github.io/tirith/install.ps1 | iex"
cargo install tirith-mcp

Compiles from crates.io and installs the tirith binary. Works on any platform with a stable Rust toolchain (1.90 or newer), including ones without prebuilt archives.

Mind the crate name. The crate tirith on crates.io belongs to an unrelated project, so cargo install tirith installs something else. Tirith's package is tirith-mcp; only the binary is named tirith.

cargo binstall tirith-mcp

cargo-binstall reads the crate metadata, finds the matching prebuilt archive on the GitHub release, and installs it without compiling.

git clone https://github.com/eabz/tirith
cd tirith
cargo install --path .

Needs a stable Rust toolchain (1.90 or newer). There are no C dependencies: Tirith speaks plain HTTP on localhost, so no TLS library is compiled in.

Every release carries an archive per target, named tirith-mcp-<target>.tar.xz (.zip on Windows), plus a sha256 file. Unpack and put tirith somewhere on your PATH.

PlatformTarget
macOS Apple Siliconaarch64-apple-darwin
macOS Intelx86_64-apple-darwin
Linux x86_64 (glibc)x86_64-unknown-linux-gnu
Linux ARM64 (glibc)aarch64-unknown-linux-gnu
Linux x86_64 (static, musl)x86_64-unknown-linux-musl
Linux ARM64 (static, musl)aarch64-unknown-linux-musl
Windows x86_64x86_64-pc-windows-msvc
Windows ARM64aarch64-pc-windows-msvc
Check the install
tirith --version

If the shell cannot find it, add ~/.cargo/bin to your PATH and open a new terminal.

Already installed? tirith update replaces the binary in place with the latest release; tirith update --check only reports.

Connect your agents

Register tirith stdio with your client the same way as any other stdio MCP server. It starts the repository's daemon the first time a session needs it, replaces a daemon left by an older version, and proxies to it after that, so nothing has to be started by hand. The daemon keeps running so every agent on the repo shares it.

Claude Code

Run from the repository root.

claude mcp add tirith -- tirith stdio

Cursor

Add to .cursor/mcp.json in the repository.

{
  "mcpServers": {
    "tirith": { "command": "tirith", "args": ["stdio"] }
  }
}

Codex CLI

One command, same shape.

codex mcp add tirith -- tirith stdio

LangGraph, CrewAI, curl

Python frameworks and plain scripts connect to the daemon over HTTP.

"tirith": {
  "url": "http://127.0.0.1:7477/mcp",
  "transport": "streamable_http"
}

Client setup for every framework

Tell your agents the rule. Add this to the project's CLAUDE.md, AGENTS.md, or Cursor rules: Before editing files, call the tirith claim tool with a stable agent name. If the result is a conflict, do not edit those files. Every agent passes a stable agent name with each call; that is the only convention it has to follow.

Alternative: run the daemon yourself and connect over HTTP

The stdio shim ships in Tirith 0.1.3 and later. With an older binary, or when you want the daemon under your own supervision, start it from the repository root and point clients at its URL.

cd /path/to/your/repo
tirith serve
# MCP at http://127.0.0.1:7477/mcp, dashboard at http://127.0.0.1:7477/
# Claude Code
claude mcp add --transport http tirith http://127.0.0.1:7477/mcp
# Codex
codex mcp add tirith --url http://127.0.0.1:7477/mcp
# Cursor, .cursor/mcp.json
{ "mcpServers": { "tirith": { "url": "http://127.0.0.1:7477/mcp" } } }

To keep it running across terminal sessions: nohup tirith serve > .tirith/runtime/serve.log 2>&1 &. The address is recorded in .tirith/runtime/daemon.json, so the CLI run from the same repo finds it without flags.

Verify

The CLI goes through the same MCP path agents use, so it doubles as a way to watch or nudge a running swarm.

tirith status
# tirith 0.1.3 up 42s  seq 0  claims 0  tasks 0 open / 0 done  contracts 0  notices 0  decisions 0
# no active agents

Open http://127.0.0.1:7477/ for the live dashboard: agents, claims, tasks, contracts, notices, decisions, and memory notes, updating as they change.

Commit the right files

Tirith writes .tirith/.gitignore itself, ignoring .tirith/runtime/: claims, tasks, notice deliveries, and messages are runtime state. Everything else under .tirith/, the contracts, notices, decisions, and memory notes, is meant to be committed so the next session inherits it.

What it does

Claims and the task board are table stakes. Contracts and change notices are the reason Tirith exists. Memory notes are what makes the rest worth keeping after the session ends.

Claims

Lease files or directories before editing. Overlaps are refused with the owner, reason, and expiry. Leases expire if the agent dies.

Task board

Tasks with priority, owner, and dependencies. Agents pull the next unblocked task.

Contracts

Interface shapes published and versioned before implementation. A new version notifies its consumers automatically.

Change notices

"Renamed X to Y, these paths are affected." Dependents get them in the brief that comes back with a claim, once each.

Decisions log

Settled choices with rationale, so nothing is decided twice.

Memory notes

Lessons, traps, and handoffs scoped to repository paths. Committed Markdown, searchable, and delivered to whoever claims the paths a note is about.

Messages

Short notes between agents, delivered on the recipient's next call, so any MCP client can take part. Runtime only, never committed.

Two agents, one directory

tirith claim --agent alice --reason "refactor session handling" src/auth/
# ok       alice  src/auth  expires 04:14:34Z

tirith claim --agent bob --reason "fix login redirect" src/auth/login.rs
# conflict src/auth/login.rs overlaps src/auth (alice: "refactor session handling", expires 04:14:34Z)

Over MCP the same refusal is structured JSON, so agents branch on status instead of parsing text. The full two-agent walkthrough is in examples/demo.sh.

Documentation

InstallationEvery install path in detail, including pinning and offline archives
Client setupClaude Code, Cursor, Codex, LangGraph, CrewAI, and raw JSON-RPC
Tool referenceAll 22 MCP tools, their inputs, and their response shapes
ArchitectureHow the daemon, state, and persistence fit together
Decision recordsWhy Rust, why one daemon over HTTP, why JSON files
All docsThe full index