A local-first issue board and knowledge base for AI coding agents: race-free claims, linked notes, and recorded decisions in one SQLite file.
Site · Install · Quickstart · Agents · Contributing · Changelog · Security
Part of Sothis, the local-first suite for running a fleet of AI coding agents on one repo (suite repo).
Think Linear + Obsidian in one SQLite file, driven by a single Rust binary (amt) that is
both a CLI and an MCP server. No cloud, no accounts, no embeddings.
Coding agents forget everything between sessions, and two agents working the same repo have no shared state: no backlog, no "who's doing what", no record of decisions already made. Ametrite gives every repo a shared workspace both humans and agents can read and write:
- Issues with race-free claims.
amt claimatomically leases the highest-priority open issue to one agent (BEGIN IMMEDIATE); two agents can never claim the same issue. Crashed agent? The lease expires and the issue becomes claimable again. - Knowledge that links. Issue and note bodies are markdown with
[[wikilinks]]and#tags, indexed into a bidirectional link graph with backlinks. - Decisions are first-class.
amt deciderecords an ADR-style decision (D-1) against the issue it resolves — searchable, linkable, supersedable. The "why" is one backlink hop from the "what". - Search without embeddings. SQLite FTS5 (BM25) + tags + link graph + structured filters.
- Everything is scriptable. Every command takes
--json;amt events --followstreams activity as NDJSON.
Prebuilt binaries for macOS (Intel + Apple Silicon), Linux (x86_64), and Windows are attached to each release.
# Homebrew. Recent versions refuse third-party taps until you trust them;
# if brew asks, run `brew trust Davidb3l/tap` and re-run the install.
brew install Davidb3l/tap/amt
# Shell installer (macOS / Linux)
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/Davidb3l/Ametrite/releases/latest/download/amt-installer.sh | sh
# From source (needs a Rust toolchain)
cargo install --git https://github.com/Davidb3l/Ametrite amt --locked# Windows (PowerShell)
irm https://github.com/Davidb3l/Ametrite/releases/latest/download/amt-installer.ps1 | iexamt upgrade updates in place, delegating to whichever of those installed it.
(If the board service is installed, follow up with amt serve --install so it
serves the new version.)
cd ~/code/your-project
amt init --name my-project # creates .ametrite/ (git-ignores itself); keys: MP-1, MP-2, …
# --prefix overrides the name-derived issue-key prefix
amt issue create --title "Fix login token refresh" --priority urgent --label bug
amt issue list
amt note create --title "Session Tokens" -b "Rotation affects [[AMT-1]]. #auth"
amt search token
amt backlinks AMT-1Representative output:
$ amt issue list
AMT-1 backlog urgent Fix login token refresh [bug]
AMT-2 backlog medium Write session-token docs
$ amt claim --agent worker-1
claimed AMT-1 in_progress urgent Fix login token refresh [bug] 🔒worker-1
$ amt release AMT-1 --agent worker-1 --status in_review -m "rotated refresh path"
released AMT-1 in_review urgent Fix login token refresh [bug]
$ amt doctor
workspace healthy ✓
Web UI (optional, requires Bun)
Run amt serve for a foreground board, or amt serve --install to register a
per-user login service (launchd on macOS, a logon Scheduled Task on Windows, a
systemd user unit on Linux — no sudo anywhere) so the board survives closing
your terminal, an agent session ending, and reboots. The web app ships inside
the binary: with no checkout around, serve extracts it to the per-user data
dir and serves that, so a brew/installer amt is a complete board setup. A
checkout, when present, wins — local edits show up live. amt serve --status says
whether the service is installed and whether the board is actually answering;
--uninstall removes it. Agents are unaffected either way: the CLI and MCP
open the workspace database directly, so the board is a viewport, not the
system.
On macOS, a login service that reads from ~/Documents, ~/Desktop, or
~/Downloads needs a privacy grant you have to approve once; --install
warns when your checkout is in one of those. The embedded copy extracts
outside those folders, so packaged installs skip the prompt for the app
itself (workspace databases living under protected folders still need it).
bun run web # → http://localhost:1776 (AMT_PORT to change)One kanban board across every registered workspace (amt ws list), live-updating via SSE
whenever any process writes — CLI, MCP agent, or another browser tab. The web app has zero
npm runtime dependencies and never writes the database directly: reads are direct SQLite,
mutations shell out to amt --json, so business logic lives in exactly one place.
MCP — amt mcp is a stdio MCP server exposing 25 tools (issues, claims, notes,
decisions, dependencies, search, context bundles, session briefs, stats, events, git
commits):
claude mcp add ametrite -- amt mcpClaude Code skill — this repo ships .claude/skills/ametrite/, picked up automatically
inside the repo (copy to ~/.claude/skills/ for global use). It teaches agents the claim
loop, decision recording, handoff notes, and wikilink etiquette. AGENTS.md
documents the same conventions for any agent.
Session continuity — a session ends by writing a handoff note (amt note create --tag handoff -b "where we stopped, the gotcha, the next step"); the next one starts with amt brief, which puts that note — plus your open claims, what's in flight, and recent
activity and decisions — in front of the agent in a single read-only call.
CLI loops — --json everywhere. Note that "nothing claimable" returns
{"claimed": false, ...} with exit code 0, so test the payload:
amt brief --agent worker-1 # where did the last session leave off? (read-only)
while id=$(amt --json claim --agent worker-1 | jq -r '.id // empty'); [ -n "$id" ]; do
amt context "$id" # issue + activity + decisions + backlinked docs + related hits
# … do the work …
amt release "$id" --agent worker-1 --status in_review -m "done, see [[Session Tokens]]"
doneClaims are leased (default 15 min; re-claim to renew) and have a cooldown so loops don't
re-serve an issue you just released. amt agents shows the live roster; amt stats reports
throughput, cycle time, and a claim-integrity audit.
| Command | Purpose |
|---|---|
amt init |
Create .ametrite/ametrite.db workspace in the current directory |
amt issue create/list/show/update/comment |
Issue CRUD (labels, projects, parents, due dates) |
amt comment <key> -m … |
Comment on an issue — top-level alias of amt issue comment (same flags, same --json) |
amt claim / amt release |
Atomic claim-loop primitives (--peek, --project, --label (repeatable: all must match), --not-label, --all-workspaces). Operator resets: release --force --no-cooldown. Only a lease's holder can change its issue's status (issue update --force overrides); leaving in_progress ends the lease |
amt dep add/rm/list |
Blocker → blocked dependencies (cycle-checked; blocked issues aren't claimable) |
amt decide / amt decision list/show |
Record ADR-style decisions against issues; supersede old ones |
amt note create/show/append/list |
Knowledge base (--dedupe warns on near-duplicate titles; list --tag) |
amt project create/list |
Projects (first-class, wikilinkable documents) |
amt search <terms> |
FTS5 full-text search (--type, --tag, --all-workspaces) |
amt context <key> |
One-bundle context read for an issue, with an optional char --budget |
amt brief |
Session-start orientation bundle for the whole workspace: your claims, what's in flight, recent activity + decisions, the latest handoff note, and what to claim next (--agent, --since, --budget) |
amt backlinks <id> |
Reverse link graph |
amt agents / amt stats / amt events |
Agent roster, throughput metrics, NDJSON activity stream |
amt branch <key> |
Create + check out a git branch named for an issue |
amt hook install |
git commit-msg hook that appends Refs: <KEY> from the branch name |
amt export <dir> / amt import <dir> |
Round-trip the workspace as an Obsidian-compatible markdown vault |
amt ws add/list/remove |
Global workspace registry (~/.ametrite/registry.json) |
amt doctor [--fix] |
Workspace health: unresolved links, stale claims, missing refs, malformed labels, closed issues still leased; --fix splits comma-joined labels and ends those leases |
amt serve [--install] |
Run the web board; --install registers a login service so it outlives your session (--status, --uninstall) |
amt seed --count N |
Bulk-insert N synthetic issues (benchmarking / demos) |
amt gc [--archive-older-than N] |
Compact the database; optionally archive activity of issues closed >N days to archive.db (stats stay exact) |
amt upgrade |
Update amt in place via brew / installer / cargo (--dry-run) |
amt mcp |
MCP stdio server |
Statuses: backlog → todo → in_progress → in_review → done (or canceled).
Priorities: urgent > high > medium > low > none.
.ametrite/ is git-ignored and branch-invariant: switch branches, same board — claim state
stays a single source of truth for agents on different branches. Code links back the other
way: amt branch AMT-7 names branches after issues, amt hook install stamps commits with
Refs: AMT-7, amt issue show lists referencing commits, and amt release appends the
branch's commits to the closing comment.
- SQLite (WAL) is the source of truth; only the Rust engine writes it.
[[AMT-12]],[[Note Title]], and[[note-slug]]all resolve; dangling links resolve automatically when the target is created later (amt doctorlists the ones that haven't).- The Rust engine's full dependency list: rusqlite, serde, serde_json, clap, regex.
Pre-1.0, early but functional — the engine is exercised by a Rust test suite and CI on Linux/macOS/Windows. MIT licensed (LICENSE). Contributions welcome: see CONTRIBUTING.md, and SUPPORT.md for where questions go.