Deterministic Context Tracker (dct) — cross-project tracking, changelog, and release tooling for Claude Code.
Project description
dct — Deterministic Context Tracker
Persistent, queryable memory for AI coding assistants — your assistant reads facts from a database instead of guessing. One user-scoped database tracks issues, todos, changelog entries, plans, sprints, and decisions across all your projects. Built for Claude Code (skills, hooks, 48 MCP tools); the MCP server and CLI work with any MCP-capable assistant.
Part of the dc tools family (dctools.dev) — deterministic context for AI-assisted development.
Why dct?
You have a dozen side projects. Every Claude Code session starts cold — the assistant has no memory of what you decided last week, which bug you were mid-fix on, or why you picked SQLite over Postgres. So you re-explain, or it guesses.
The usual trackers don't fill the gap. GitHub Issues and Jira are per-repo, heavyweight, and live behind an API your assistant can't casually read or write. TODO.md files rot the moment you stop grooming them, and you can't query "every P1 across all my repos" from a pile of markdown.
dct is built for exactly this:
- One user-scoped database across all your projects — one place to ask "what's open everywhere?". Local-first: SQLite by default — nothing leaves your machine — with first-class PostgreSQL support when you want a server-grade backend.
- MCP-native — the assistant reads and writes tracking directly, no copy-paste, no context loss.
- Changelog-first releases — entries accumulate as you work (your assistant writes them); release day is one command, not an afternoon of
git logarchaeology. - Append-only ledger — notes, checkpoints, and handoffs are soft-deleted, never dropped. Nothing is lost.
- Session handoffs — end a session with a handoff prompt; the next one picks up exactly where you left off.
The session loop: /handoff → /pickup
The pair you will use most. AI coding sessions end; your context shouldn't.
Ending a session — /handoff flags the items you were working on as the
current sprint and stores a short prompt for whoever comes next (usually:
you, tomorrow). Starting a session — /pickup reads the newest unconsumed
handoff, shows the sprint with checkpoint progress, and proposes the first
action — so the session starts in the middle of the work, not from a cold
"what were we doing?". The sprint is the durable what's-in-flight-right-now
set: it survives between sessions and cleans itself up — resolving an item
drops it from the sprint automatically. Illustrative session start:
> /pickup
Handoff (2026-07-05, scope: sprint-15):
"Theme tokens are merged; wire the toggle into settings next.
The Safari session fix (#12) still awaits review."
Sprint: 3 items — #12 in_progress [2/4], #31 open, #7 open
Proposed first action: #12 — wire the theme toggle into settings.
Handoffs are database rows, not files: several can coexist per project
(scope tags disambiguate parallel workstreams), consuming one preserves it
in the ledger, and an unconsumed one can be amended in place. Available as
skills in Claude Code, MCP tools, and the CLI — full catalogue in
docs/mcp-tools.md.
The release loop: /clog → /commit → /release
The other daily loop. A changelog reconstructed from git log on release
day is archaeology — dct makes it a side effect of working. Each time a
change lands, your assistant records a one-line entry in the database (the
/clog skill, add_changelog over MCP, dct clog add in scripts); an
opt-in hook can even hold back git commit until the entry exists. By
release day the changelog is already written:
> /release
15 unreleased entries → stamped as 1.1.0
changelog.md regenerated (Keep a Changelog format)
release: v1.1.0 committed, project version bumped
One command stamps the version, exports Keep a Changelog markdown, and makes the release commit.
Features
- Centralized tracking — one database for all your projects
- Hybrid changelog — entries in DB, export to Keep a Changelog markdown at release; opt-in enforcement + per-project changelog location (repo root by default, or a subdir like
pkg/changelog.md) - Plans, specs, roadmaps, ADRs — index markdown plans with stable ULID anchors; state in DB, content stays in markdown
- First-class sprints — a named, goal-scoped current work set that survives across sessions and self-cleans as items resolve
- Decision records — ADRs, sprint amendments, inline plan decisions with multi-anchor linkage
- LLM-assisted classification — uncertain plan sections auto-resolved via
claude --print(haiku by default) - Passive autoscan hook — PostToolUse hook re-scans plan-like files in background on every edit
- MCP server — native Claude Code integration via FastMCP, 48 tools
- CLI — fast
dctcommand for hooks and scripts - Skills — Claude Code slash commands (
/track,/clog,/dct-import,/plan-status, …) - Soft deletes — ledger pattern, nothing is ever lost
- DB portable — SQLite (zero setup) or PostgreSQL
Installation
Pick one — whichever matches your Python workflow. The distribution is named dctracker (PyPI); the installed command is dct.
# Option A: uv tool (recommended — isolated, upgradable, editable for dev)
uv tool install dctracker --with 'mcp[cli]' --with 'psycopg[binary]'
# Or from source (dev):
uv tool install --editable /path/to/dct --with 'mcp[cli]' --with 'psycopg[binary]'
# Or straight from GitHub, no clone (e.g. to try main before a release):
uv tool install 'dctracker[mcp,pg] @ git+https://github.com/fotodeveloper/dct'
# Option B: pipx (classic isolated install)
pipx install 'dctracker[mcp,pg]'
# Option C: uvx (zero-install, fetches per-invocation)
# In ~/.claude.json: { "command": "uvx", "args": ["--from", "dctracker[mcp,pg]", "dct", "server"] }
# Option D: pip into your venv (not recommended for global CLI)
pip install 'dctracker[mcp,pg]'
After installation dct must be in PATH. Verify:
dct --version # -> dct <version>
dct server --help
dct plan --help # plan subcommands
First run
dct init
The interactive wizard walks through the one-time global bootstrap:
- Database backend —
sqlite(default, zero setup at~/.claude/dct.db) orpostgresql(you supply the URL). It test-connects before saving. - Register projects — for each project it asks slug / path / name, then auto-detects the version from
VERSION,pyproject.toml,package.json,Cargo.toml, orsrc-tauri/tauri.conf.json. If none matches, you get an interactive prompt (0.0.1/0.1.0/1.0.0shortcuts); in non-tty contexts it storescurrent_version=NULLand reminds you to set it later. Register more any time withdct project add. - MCP server — registered at user scope in
~/.claude.json(viaclaude mcp add --scope user, with a direct-edit fallback), so/track,/clog,/release, and the MCP tools are available in every Claude Code session, from any directory. - Skills + hooks — symlinks the skills into
~/.claude/skills/and the four hooks into~/.claude/hooks/. Both ship inside the package; with an editable/dev install the symlinks point at the repo, so a fix goes live without reinstall. - Hook wiring — with your consent, merges the hooks into
~/.claude/settings.json. The merge is idempotent, backs up the file before the first write, and never touches hooks you already have. Re-run any time withdct hooks wire.
dct init writes ~/.claude/dct.toml, ~/.claude.json (MCP entry), the skill/hook symlinks, and (opt-in) the settings.json wiring — see docs/architecture.md for the full config reference and scope model.
Your first session
With dct init done, open any registered project in Claude Code and just talk:
> track this: parser crashes on empty frontmatter
Created issue #12 in myproj (P2, open)
> I fixed the frontmatter crash
Changelog entry added (unreleased) — issue #12 resolved
> /handoff
Sprint set (1 item); handoff prompt stored for the next session
Tomorrow, /pickup resumes mid-work — that's the session loop
from the top of this page. When you're ready to ship, /release stamps the
accumulated changelog with a version. No forms, no context switch — tracking
happens in the conversation you're already having.
Troubleshooting
dct: command not foundafter install — the install location isn't on yourPATH. Foruv tool/pipx, run theirensurepathhelper (uv tool update-shellorpipx ensurepath) and restart the shell.- PostgreSQL connection fails at
dct init— either start your local Postgres and re-run, or just pick the SQLite default (the answer to the backend prompt) — it needs no server and works everywhere. - MCP tools don't show up in Claude Code — the MCP server is a per-session subprocess, so newly registered tools (or a reinstall) appear only after you restart the Claude Code session. Start a fresh session and they'll be there.
- Plans/decisions tools fail with
No module named 'ulid'— your installed tool environment predates thepython-uliddependency. Upgrade it:uv tool upgrade dctracker(or reinstall via your chosen option above).
Usage
CLI
# Items
dct add myproj todo "Fix parser crash" --priority P1 --tags "parser,crash"
dct list # All open items, all projects
dct list myproj --priority P1 # P1 items in myproj
dct show 42 # Full item details with notes
dct update 42 --status in_progress
dct note 42 "Found root cause in tokenizer"
dct resolve 42 --resolution "Fixed in commit abc123"
# Changelog (project auto-detected from CWD; --project overrides)
dct clog add added "New Python parser support" --project myproj
dct clog list --project myproj --unreleased
dct clog count --project myproj # Used by hooks
dct clog release 1.1 --project myproj # Stamp unreleased → 1.1
dct clog export --project myproj --output changelog.md
# Projects
dct project add myproj /path/to/myproj --name "My Project" # Version auto-detected
dct project list
dct project detect # Print current project slug (for hooks)
dct project rename myproj --slug myproj2 --name "Rebranded" # Rename in-place, project_id stable
dct project set-version myproj 1.1 # Post-factum version fix
dct project changelog myproj off # Opt out of dct changelog enforcement
dct project changelog-path myproj docs/changelog.md # Changelog outside repo root; default: changelog.md
# Plans
dct plan rescan /path/to/docs/plans/2026-04-17-feature.md # Idempotent rescan; hook entrypoint
dct plan rescan $FILE --quiet --resolve-uncertain # Hook-mode flags
# Checkpoints (item-level)
dct checkpoint add 42 "Write parser"
dct checkpoint list 42
dct checkpoint done 3 # Mark CP #3 as done
dct checkpoint reject 4 # Scope-change, keep in ledger
MCP Tools
dct ships 48 MCP tools, registered at user scope so they're callable from any Claude Code session as mcp__dct__<name>. Zero-arg calls auto-detect the project from the session's working directory; pass project=<slug> to override. The daily drivers:
| Tool | Purpose |
|---|---|
create_item |
Create a tracked item (issue / todo / feature / idea / improvement) |
list_items |
List / search items in compact {cols, rows} form |
update_item |
Update fields on an existing item |
resolve_item |
Close an item (terminal status), with gate-checkpoint guard |
add_checkpoint |
Add an acceptance criterion to an item |
complete_checkpoint |
Mark a checkpoint done (real-time, never batched) |
add_changelog |
Add an unreleased changelog entry |
release_changelog |
Stamp unreleased entries with a version + bump current_version |
set_sprint |
Atomically replace the current sprint's membership |
create_handoff |
Leave a handoff draft for the next session |
Full categorized catalogue of all 48 tools: docs/mcp-tools.md.
Plans, Roadmaps & Decisions
dct extends the flat items model with hierarchical plans: markdown plan/spec/roadmap/ADR files stay the source of truth for content, while dct indexes their structure (sections, checkpoints, decisions) with stable ULID anchors and owns their state (done/pending/rejected). A PostToolUse hook rescans plan-like files in the background on every edit, injecting ULIDs and syncing the DB; uncertain section headings are classified by a headless claude --print call (haiku).
Full guide — concepts, ULID anchors, ingest pipeline, classification rules, and promotion to items/sprints: docs/plans.md.
Web viewer
dct web runs a localhost-only, read-only browser dashboard over all registered projects (items, sprints, plans, changelog, decisions, handoffs, plus Radar / Backlog-Health / Velocity analytics) with live SSE refresh. It binds 127.0.0.1 only — no auth, single-user. Install the optional extra first:
uv tool install 'dctracker[web,mcp,pg]' # or: pipx install 'dctracker[web]' — adds flask + markdown
dct web start # start the daemon → prints http://localhost:8787
dct web start --open # open the browser after starting
dct web status # show pid + URL
dct web stop # SIGTERM the daemon
If the preferred port (default 8787) is busy, the daemon auto-selects the next free port (disable with --no-fallback). Configure defaults under [web] in ~/.claude/dct.toml.
Integration with Claude Code
dct is designed to be driven by Claude Code. To teach your assistant when to reach for each skill and MCP tool across every project, copy the ready-made snippet into your personal ~/.claude/CLAUDE.md: docs/CLAUDE.md-snippet.md.
Skills
| Skill | Purpose |
|---|---|
/track |
Create a tracked item |
/track-list |
List/search items |
/track-update |
Update item fields |
/track-resolve |
Resolve/close items |
/clog |
Add changelog entry |
/commit |
Conventional commit with version suffix + changelog gate |
/release |
Stamp changelog + bump version + generate changelog.md |
/pickup |
Session start — read handoff, show sprint, propose first action |
/handoff |
Session end — flag sprint items, write handoff prompt |
/dct-import |
Discover + multi-select + ingest plan-like markdown files |
/dct-init |
Bootstrap dct + register the current project (interactive) |
/plan-status |
Cross-plan progress dashboard |
/plan-resolve-uncertain |
Batch classify uncertain plan sections via haiku |
Global Hooks
dct init symlinks four hooks into ~/.claude/hooks/ (→ the packaged dct/hooks/; an editable/dev install keeps them live-editable from the repo) and — with your consent — wires them into ~/.claude/settings.json automatically. The wiring is an idempotent merge: hooks you already have (dct or your own, in any placement) are never touched, and the file is backed up before the first write. Re-run any time:
dct hooks wire # idempotent; safe after upgrades or manual edits
| Hook | Event | Purpose |
|---|---|---|
dct-check-changelog.sh |
PreToolUse (Bash) |
blocks git commit when app code changed but no unreleased changelog entry exists — opt-in per project via dct project changelog <slug> on|off |
dct-check-changelog-on-stop.sh |
Stop | session-end reminder about pending unreleased entries (same opt-in gate) |
dct-plan-autoscan.sh |
PostToolUse (Edit|Write|MultiEdit) |
background rescan of plan-like MD files; fire-and-forget |
dct-task-mirror.sh |
PreToolUse (TodoWrite|TaskCreate) |
mirrors Claude Code tasks into dct as cc-task checkpoints |
Manual wiring reference (full JSON) and the five rules every dct hook follows: docs/hooks.md.
Configuration
dct reads ~/.claude/dct.toml. The minimal config is just the database URL:
[database]
url = "sqlite:////Users/you/.claude/dct.db"
# or: url = "postgresql+psycopg://localhost:5432/dct"
The DCT_DATABASE_URL environment variable overrides [database].url. For the full reference ([plans], [mirror], [web] sections), the database schema, MCP scope precedence, and project auto-detection mechanics, see docs/architecture.md.
Testing
.venv/bin/pytest -q # All tests (670)
.venv/bin/pytest tests/test_plan_parser.py -v # Parser only
.venv/bin/pytest tests/test_plan_ingest.py -v # Ingest + sticky-resolved semantics
# MCP server smoke (boot + tool list)
uv run --no-project --with 'mcp[cli]' --with sqlalchemy --with 'psycopg[binary]' \
python -c "import asyncio; from dct.server import mcp; \
print(len(asyncio.run(mcp.list_tools())), 'tools')"
Contributing
Bug reports, feature ideas, and PRs are welcome — see CONTRIBUTING.md for dev setup (uv venv + pytest), commit conventions, and how to add MCP tools or skills.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dctracker-1.0.0.tar.gz.
File metadata
- Download URL: dctracker-1.0.0.tar.gz
- Upload date:
- Size: 263.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc29ccb60eedfa5ae6ce04a6bfd82bbaf2771e750344e83227c621d9808c89e1
|
|
| MD5 |
cd1420bfcf414ed284b40c4a949104a9
|
|
| BLAKE2b-256 |
e71c59192a1edbc6ebe59590eb934da2bcc35dc89bdbe3be4149552ee14c26d4
|
Provenance
The following attestation bundles were made for dctracker-1.0.0.tar.gz:
Publisher:
publish.yml on fotodeveloper/dct
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dctracker-1.0.0.tar.gz -
Subject digest:
dc29ccb60eedfa5ae6ce04a6bfd82bbaf2771e750344e83227c621d9808c89e1 - Sigstore transparency entry: 2139757453
- Sigstore integration time:
-
Permalink:
fotodeveloper/dct@2654ae7a4d468a05b4a0cf900468d17a90400a47 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/fotodeveloper
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2654ae7a4d468a05b4a0cf900468d17a90400a47 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dctracker-1.0.0-py3-none-any.whl.
File metadata
- Download URL: dctracker-1.0.0-py3-none-any.whl
- Upload date:
- Size: 225.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33328730414b8bdbbc0efc673ab691454eda2e7a111bdbd3020084ecdb873c2b
|
|
| MD5 |
3de51967147e0f97f48fe45cdd043978
|
|
| BLAKE2b-256 |
3b6cfe3e302365dabec2cdca8ed8a449436a23919927946b451982e564c8a61d
|
Provenance
The following attestation bundles were made for dctracker-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on fotodeveloper/dct
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dctracker-1.0.0-py3-none-any.whl -
Subject digest:
33328730414b8bdbbc0efc673ab691454eda2e7a111bdbd3020084ecdb873c2b - Sigstore transparency entry: 2139757464
- Sigstore integration time:
-
Permalink:
fotodeveloper/dct@2654ae7a4d468a05b4a0cf900468d17a90400a47 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/fotodeveloper
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2654ae7a4d468a05b4a0cf900468d17a90400a47 -
Trigger Event:
push
-
Statement type: