A CLI, written in Rust, for recording technical debt you intentionally leave
behind — outside the repo. The techdebt mcp subcommand exposes the store as an
MCP server over stdio; a bare techdebt
prints help. Entries live in a SQLite database under XDG local data
(${XDG_DATA_HOME:-~/.local/share}/techdebt-mcp/techdebt.db), so no debt files
land in your tree.
The database is opened in WAL mode with a busy timeout, so several server processes — one per agent — can read and write the same log concurrently without losing each other's writes. Each entry carries an append-only event history, so an agent can revisit a piece of debt later and see how it was addressed and whether it is still open.
A legacy entries.json from older versions is imported automatically on first
run against a fresh database.
The MCP server is built on
rmcp, the official Rust
SDK, and communicates over stdio with newline-delimited JSON-RPC.
Requires a Rust toolchain with edition 2024 support (rustc 1.85+).
cargo build --release # -> target/release/techdebt
cargo test # unit tests
cargo run -- mcp # run the server on stdionix build # -> result/bin/techdebt
nix run -- mcp # run the server on stdioThe flake also exposes overlays.default, which adds a techdebt-cli
attribute to nixpkgs for consumers that import it.
These are served by techdebt mcp.
| Tool | Purpose |
|---|---|
record |
Log a piece of debt. Required: title, context, impact, resolution_condition, severity (low/medium/high/critical), paths (≥1). Optional global for workspace-wide debt; otherwise scope is the git repository owning each path (submodule-aware). |
list |
List entries. Optional scope (current/global/all, default current), root (override the current scope), severity filter, include_resolved (default false), limit, compact. The default current scope covers the current repo, repos nested under it, and all global debt. Open and in_progress entries are shown by default. |
scopes |
List the repos that own recorded debt, each with open/total counts, plus a global bucket. Use it to discover a root to pass to list/search. |
get |
Fetch one entry by id with its full event history. Timestamps render as RFC3339 UTC. |
search |
Full-text search debt by topic or filename. Required query; optional scope (default current), root, include_resolved (default false), limit, compact. Results are ranked by relevance. |
edit |
Amend an entry's title, context, impact, resolution_condition, severity or paths by id. Scope and status are untouched. |
update |
Change an entry's status (open/in_progress/resolved/wontfix/superseded) and/or attach a note to its history. |
resolve |
Mark an entry resolved by id once its resolution condition is met. Optional note records how it was addressed. |
delete |
Soft-delete a mistaken or duplicate entry by id. It leaves all listings but stays recoverable (restore by update-ing it back to open). Genuinely closed debt belongs in resolve/wontfix/superseded. |
Per-path scope is resolved against the git repository owning each path. The
current list scope defaults to the git toplevel of the server process's
working directory and covers that repo, the repos nested under it, and all
global debt. To inspect a repo the server was not launched from, discover it
with scopes and pass its path as root to list/search.
{
"mcpServers": {
"techdebt": {
"command": "/absolute/path/to/target/release/techdebt",
"args": ["mcp"]
}
}
}The store can be versioned in a git repo that lives in the data directory,
modelled on pass: once the directory is under
git, every write auto-commits, and you drive remotes and pushes yourself.
techdebt backup # init the repo (first run) + commit a snapshot
techdebt git remote add origin <url> # any git command, run inside the data dir
techdebt git push -u origin main
techdebt git log --oneline # inspect the backup historyEach MCP write (record, update, resolve, edit, delete) auto-commits the
database once the repo exists, so the history mirrors how the debt evolved. Only
techdebt.db is committed — a wal_checkpoint runs first so the snapshot is
complete, and the WAL/SHM sidecars are git-ignored. Backups are best-effort: a
git failure warns on stderr but never fails the underlying operation. Pushing is
never automatic; run techdebt git push (or a hook/cron) when you want it
off-machine.