dctracker 1.0.0__tar.gz → 1.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dctracker-1.0.0/dctracker.egg-info → dctracker-1.2.0}/PKG-INFO +42 -18
- {dctracker-1.0.0 → dctracker-1.2.0}/README.md +40 -17
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/__init__.py +1 -1
- dctracker-1.2.0/dct/assets/__init__.py +19 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/cli.py +402 -35
- dctracker-1.2.0/dct/config.py +269 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/engine.py +8 -4
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/plans/ingest.py +12 -3
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/projects.py +15 -1
- dctracker-1.2.0/dct/core/provenance.py +58 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/db.py +80 -0
- dctracker-1.2.0/dct/hooks/check-changelog-on-stop.sh +112 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/hooks/dct-task-mirror.sh +15 -25
- dctracker-1.2.0/dct/integrations/__init__.py +5 -0
- dctracker-1.0.0/dct/setup.py → dctracker-1.2.0/dct/integrations/claude.py +94 -20
- dctracker-1.2.0/dct/mcp/__init__.py +3 -0
- {dctracker-1.0.0/dct → dctracker-1.2.0/dct/mcp}/server.py +372 -194
- dctracker-1.2.0/dct/migrate.py +597 -0
- dctracker-1.2.0/dct/paths.py +103 -0
- dctracker-1.2.0/dct/server.py +10 -0
- dctracker-1.2.0/dct/services/__init__.py +5 -0
- dctracker-1.2.0/dct/setup.py +19 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/clog/SKILL.md +4 -9
- dctracker-1.2.0/dct/skills/commit/SKILL.md +114 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/dct-import/SKILL.md +2 -1
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/dct-init/SKILL.md +3 -2
- dctracker-1.2.0/dct/skills/handoff/SKILL.md +129 -0
- dctracker-1.2.0/dct/skills/pickup/SKILL.md +110 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/plan-resolve-uncertain/SKILL.md +2 -1
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/plan-status/SKILL.md +5 -6
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/release/SKILL.md +73 -60
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/track/SKILL.md +4 -8
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/track-list/SKILL.md +5 -6
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/track-resolve/SKILL.md +3 -4
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/track-update/SKILL.md +4 -7
- dctracker-1.2.0/dct/update.py +322 -0
- dctracker-1.2.0/dct/workflows/__init__.py +3 -0
- {dctracker-1.0.0 → dctracker-1.2.0/dctracker.egg-info}/PKG-INFO +42 -18
- {dctracker-1.0.0 → dctracker-1.2.0}/dctracker.egg-info/SOURCES.txt +21 -1
- {dctracker-1.0.0 → dctracker-1.2.0}/dctracker.egg-info/requires.txt +3 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/pyproject.toml +8 -2
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_adversarial.py +1 -1
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_cli_web.py +76 -2
- dctracker-1.2.0/tests/test_config.py +300 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_engine.py +37 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_hook_bypass.py +1 -1
- dctracker-1.2.0/tests/test_hook_changelog_stop.py +241 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_hook_plan_autoscan.py +1 -1
- dctracker-1.2.0/tests/test_hook_task_mirror.py +213 -0
- dctracker-1.2.0/tests/test_migrate.py +679 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_packaging.py +1 -1
- dctracker-1.2.0/tests/test_paths.py +189 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_plan_classify.py +68 -6
- dctracker-1.2.0/tests/test_provenance.py +153 -0
- dctracker-1.2.0/tests/test_restructure.py +66 -0
- dctracker-1.2.0/tests/test_server_acks.py +425 -0
- dctracker-1.2.0/tests/test_server_alwaysload.py +71 -0
- dctracker-1.2.0/tests/test_server_handoff_view.py +111 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_setup.py +1 -1
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_setup_wiring.py +1 -1
- dctracker-1.2.0/tests/test_update.py +573 -0
- dctracker-1.2.0/tests/test_windows_support.py +192 -0
- dctracker-1.0.0/dct/config.py +0 -150
- dctracker-1.0.0/dct/hooks/check-changelog-on-stop.sh +0 -49
- dctracker-1.0.0/dct/skills/commit/SKILL.md +0 -153
- dctracker-1.0.0/dct/skills/handoff/SKILL.md +0 -136
- dctracker-1.0.0/dct/skills/pickup/SKILL.md +0 -115
- dctracker-1.0.0/tests/test_config.py +0 -55
- dctracker-1.0.0/tests/test_hook_task_mirror.py +0 -101
- dctracker-1.0.0/tests/test_server_alwaysload.py +0 -47
- {dctracker-1.0.0 → dctracker-1.2.0}/LICENSE +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/MANIFEST.in +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/__init__.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/analytics.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/changelog.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/checkpoints.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/decisions.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/handoff.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/ids.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/items.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/plans/__init__.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/plans/classify.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/plans/crud.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/plans/parser.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/sprint.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/sprints.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/version.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/export.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/hooks/check-changelog.sh +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/hooks/dct-plan-autoscan.sh +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/__init__.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/app.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/__init__.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/analytics.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/changelog.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/decisions.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/events.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/handoffs.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/home.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/items.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/plans.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/projects.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/sprints.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/changes.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/serializers.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/static/app.css +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/static/app.js +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/static/vendor/SOURCES.txt +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/static/vendor/htmx.min.js +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/static/vendor/uPlot.iife.min.js +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/static/vendor/uPlot.min.css +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/analytics.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/base.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/changelog/list.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/decisions/list.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/handoffs/list.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/home.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/item_detail.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/items_list.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/partials/_bars.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/partials/_checkpoint_steps.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/partials/_items_table.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/partials/_plan_section.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/partials/_project_card.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/plans/detail.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/plans/list.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/project_home.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/sprints/detail.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/sprints/list.html +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dctracker.egg-info/dependency_links.txt +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dctracker.egg-info/entry_points.txt +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/dctracker.egg-info/top_level.txt +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/setup.cfg +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_analytics.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_changelog.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_changes.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_checkpoints.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_cli_prompts.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_cli_sprints.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_decisions_crud.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_export.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_handoff.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_ids.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_ingest_dogfood.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_items.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_migration.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_plan_ingest.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_plan_parser.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_plans_crud.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_projects.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_sprint.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_sprints_crud.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_version.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_web_analytics.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_web_app.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_web_items.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_web_structural.py +0 -0
- {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_web_views.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dctracker
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Deterministic Context Tracker (dct) — cross-project tracking, changelog, and release tooling for Claude Code.
|
|
5
5
|
Author-email: fotodeveloper <dev@fotodeveloper.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -21,6 +21,7 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Requires-Dist: sqlalchemy>=2.0
|
|
23
23
|
Requires-Dist: python-ulid>=2.0
|
|
24
|
+
Requires-Dist: platformdirs>=4.9.6; sys_platform == "win32"
|
|
24
25
|
Provides-Extra: pg
|
|
25
26
|
Requires-Dist: psycopg[binary]; extra == "pg"
|
|
26
27
|
Provides-Extra: mcp
|
|
@@ -47,7 +48,7 @@ Dynamic: license-file
|
|
|
47
48
|
[](https://github.com/fotodeveloper/dct/actions/workflows/ci.yml)
|
|
48
49
|
[](LICENSE)
|
|
49
50
|
|
|
50
|
-
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](https://claude.com/claude-code) (skills, hooks,
|
|
51
|
+
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](https://claude.com/claude-code) (skills, hooks, 49 MCP tools); the MCP server and CLI work with any MCP-capable assistant.
|
|
51
52
|
|
|
52
53
|
Part of the **dc tools** family ([dctools.dev](https://dctools.dev)) — *deterministic context* for AI-assisted development.
|
|
53
54
|
|
|
@@ -104,9 +105,9 @@ release day the changelog is already written:
|
|
|
104
105
|
|
|
105
106
|
```text
|
|
106
107
|
> /release
|
|
107
|
-
15 unreleased entries → stamped as 1.
|
|
108
|
+
15 unreleased entries → stamped as 1.4.0
|
|
108
109
|
changelog.md regenerated (Keep a Changelog format)
|
|
109
|
-
release: v1.
|
|
110
|
+
release: v1.4.0 committed, project version bumped
|
|
110
111
|
```
|
|
111
112
|
|
|
112
113
|
One command stamps the version, exports [Keep a Changelog](https://keepachangelog.com)
|
|
@@ -121,7 +122,7 @@ markdown, and makes the release commit.
|
|
|
121
122
|
- **Decision records** — ADRs, sprint amendments, inline plan decisions with multi-anchor linkage
|
|
122
123
|
- **LLM-assisted classification** — uncertain plan sections auto-resolved via `claude --print` (haiku by default)
|
|
123
124
|
- **Passive autoscan hook** — PostToolUse hook re-scans plan-like files in background on every edit
|
|
124
|
-
- **MCP server** — native Claude Code integration via FastMCP,
|
|
125
|
+
- **MCP server** — native Claude Code integration via FastMCP, 49 tools
|
|
125
126
|
- **CLI** — fast `dct` command for hooks and scripts
|
|
126
127
|
- **Skills** — Claude Code slash commands (`/track`, `/clog`, `/dct-import`, `/plan-status`, …)
|
|
127
128
|
- **Soft deletes** — ledger pattern, nothing is ever lost
|
|
@@ -165,13 +166,13 @@ dct init
|
|
|
165
166
|
|
|
166
167
|
The interactive wizard walks through the one-time global bootstrap:
|
|
167
168
|
|
|
168
|
-
1. **Database backend** — `sqlite` (default, zero setup at `~/.
|
|
169
|
+
1. **Database backend** — `sqlite` (default, zero setup at the platform data dir, e.g. `~/.local/share/dctools/dct.db`) or `postgresql` (you supply the URL). It test-connects before saving.
|
|
169
170
|
2. **Register projects** — for each project it asks slug / path / name, then **auto-detects the version** from `VERSION`, `pyproject.toml`, `package.json`, `Cargo.toml`, or `src-tauri/tauri.conf.json`. If none matches, you get an interactive prompt (`0.0.1` / `0.1.0` / `1.0.0` shortcuts); in non-tty contexts it stores `current_version=NULL` and reminds you to set it later. Register more any time with `dct project add`.
|
|
170
171
|
3. **MCP server** — registered at **user scope** in `~/.claude.json` (via `claude 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.
|
|
171
172
|
4. **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.
|
|
172
173
|
5. **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 with `dct hooks wire`.
|
|
173
174
|
|
|
174
|
-
`dct init` writes `~/.claude/dct.toml
|
|
175
|
+
`dct init` writes the config to the platform config dir (`~/.config/dctools/dct.toml`; existing `~/.claude/dct.toml` installs keep working — `dct migrate-home` moves them), `~/.claude.json` (MCP entry), the skill/hook symlinks, and (opt-in) the settings.json wiring — see [docs/architecture.md](docs/architecture.md) for the full config reference and scope model.
|
|
175
176
|
|
|
176
177
|
### Your first session
|
|
177
178
|
|
|
@@ -200,6 +201,16 @@ happens in the conversation you're already having.
|
|
|
200
201
|
- **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.
|
|
201
202
|
- **Plans/decisions tools fail with `No module named 'ulid'`** — your installed tool environment predates the `python-ulid` dependency. Upgrade it: `uv tool upgrade dctracker` (or reinstall via your chosen option above).
|
|
202
203
|
|
|
204
|
+
### Updating
|
|
205
|
+
|
|
206
|
+
dct runs a passive, offline-safe update check — a cached PyPI probe (refreshed at most once a day, never blocking) surfaces a one-line "newer release available" nudge on the CLI and in the MCP server instructions. Opt out with `[update] check = false` in the dct config file (`dct config path` shows where it lives). When a newer version exists:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
dct upgrade # detects install method (uv tool / pipx / pip), upgrades, re-links skills + hooks
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
`dct upgrade` refreshes the skill/hook symlinks and prunes any that the new package dropped. Editable/dev checkouts print `git pull` guidance instead (no package to upgrade). Run it at a session boundary — skill descriptions and the MCP server pick up the new code on the next session, migrations on the next engine bootstrap.
|
|
213
|
+
|
|
203
214
|
## Usage
|
|
204
215
|
|
|
205
216
|
### CLI
|
|
@@ -239,26 +250,39 @@ dct checkpoint add 42 "Write parser"
|
|
|
239
250
|
dct checkpoint list 42
|
|
240
251
|
dct checkpoint done 3 # Mark CP #3 as done
|
|
241
252
|
dct checkpoint reject 4 # Scope-change, keep in ledger
|
|
253
|
+
|
|
254
|
+
# Sprints (first-class, named units of work; /handoff manages the current-sprint set)
|
|
255
|
+
dct sprint list --status active
|
|
256
|
+
dct sprint create "Payments hardening" --code pay-1 --goal "Close the P1 backlog"
|
|
257
|
+
dct sprint show 3 # Details + linked items
|
|
258
|
+
dct sprint activate 3 # Shortcuts: activate / complete / defer
|
|
259
|
+
|
|
260
|
+
# Handoffs (amend an unconsumed handoff in place; creation is /handoff or MCP)
|
|
261
|
+
dct handoff update 12 --prompt "Wire the toggle into settings next"
|
|
262
|
+
|
|
263
|
+
# Config
|
|
264
|
+
dct config get integrations.claude.task_mirror # Read a dotted config key
|
|
265
|
+
dct config path # Show resolved config/data locations
|
|
242
266
|
```
|
|
243
267
|
|
|
244
268
|
## MCP Tools
|
|
245
269
|
|
|
246
|
-
dct ships **
|
|
270
|
+
dct ships **49 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. Write ops return a minimal ack (id + a few post-state scalars); fetch full context with `get_item(id)` / `get_handoff(id)`. Ten mid-session daily drivers are always resident (`alwaysLoad`); the rest of the catalogue loads on demand via ToolSearch:
|
|
247
271
|
|
|
248
272
|
| Tool | Purpose |
|
|
249
273
|
|---|---|
|
|
250
274
|
| `create_item` | Create a tracked item (issue / todo / feature / idea / improvement) |
|
|
275
|
+
| `get_item` | Full item dict — fields, notes, checkpoints, progress |
|
|
251
276
|
| `list_items` | List / search items in compact `{cols, rows}` form |
|
|
252
277
|
| `update_item` | Update fields on an existing item |
|
|
253
278
|
| `resolve_item` | Close an item (terminal status), with gate-checkpoint guard |
|
|
279
|
+
| `add_note` | Append a note to an item (append-only ledger) |
|
|
254
280
|
| `add_checkpoint` | Add an acceptance criterion to an item |
|
|
255
281
|
| `complete_checkpoint` | Mark a checkpoint done (real-time, never batched) |
|
|
282
|
+
| `reject_checkpoint` | Mark a checkpoint rejected (scope change) — ledger-preserving |
|
|
256
283
|
| `add_changelog` | Add an unreleased changelog entry |
|
|
257
|
-
| `release_changelog` | Stamp unreleased entries with a version + bump `current_version` |
|
|
258
|
-
| `set_sprint` | Atomically replace the current sprint's membership |
|
|
259
|
-
| `create_handoff` | Leave a handoff draft for the next session |
|
|
260
284
|
|
|
261
|
-
Full categorized catalogue of all
|
|
285
|
+
Session-edge tools stay deferred: `get_handoff` (full handoff dict — untruncated prompt + context_summary), `create_handoff`, `set_sprint`, `release_changelog`, and more. Full categorized catalogue of all 49 tools: **[docs/mcp-tools.md](docs/mcp-tools.md)**.
|
|
262
286
|
|
|
263
287
|
## Plans, Roadmaps & Decisions
|
|
264
288
|
|
|
@@ -278,7 +302,7 @@ dct web status # show pid + URL
|
|
|
278
302
|
dct web stop # SIGTERM the daemon
|
|
279
303
|
```
|
|
280
304
|
|
|
281
|
-
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
|
|
305
|
+
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 the dct config file.
|
|
282
306
|
|
|
283
307
|

|
|
284
308
|
|
|
@@ -323,26 +347,26 @@ Manual wiring reference (full JSON) and the five rules every dct hook follows: [
|
|
|
323
347
|
|
|
324
348
|
## Configuration
|
|
325
349
|
|
|
326
|
-
dct reads `~/.claude/dct.toml
|
|
350
|
+
dct reads its config from the platform config dir — `~/.config/dctools/dct.toml` on Linux and macOS, `%LOCALAPPDATA%\dctools\dct.toml` on Windows — with a permanent fallback to a legacy `~/.claude/dct.toml` (run `dct migrate-home` to move an old install). The minimal config is just the database URL:
|
|
327
351
|
|
|
328
352
|
```toml
|
|
329
353
|
[database]
|
|
330
|
-
url = "sqlite:////
|
|
354
|
+
url = "sqlite:////home/you/.local/share/dctools/dct.db"
|
|
331
355
|
# or: url = "postgresql+psycopg://localhost:5432/dct"
|
|
332
356
|
```
|
|
333
357
|
|
|
334
|
-
The `DCT_DATABASE_URL` environment variable overrides `[database].url`. For the full reference (`[
|
|
358
|
+
The `DCT_DATABASE_URL` environment variable overrides `[database].url`. For the full reference (`[classification]`, `[integrations.claude]`, `[web]` sections), the database schema, MCP scope precedence, and project auto-detection mechanics, see **[docs/architecture.md](docs/architecture.md)**.
|
|
335
359
|
|
|
336
360
|
## Testing
|
|
337
361
|
|
|
338
362
|
```bash
|
|
339
|
-
.venv/bin/pytest -q # All tests (
|
|
363
|
+
.venv/bin/pytest -q # All tests (938)
|
|
340
364
|
.venv/bin/pytest tests/test_plan_parser.py -v # Parser only
|
|
341
365
|
.venv/bin/pytest tests/test_plan_ingest.py -v # Ingest + sticky-resolved semantics
|
|
342
366
|
|
|
343
367
|
# MCP server smoke (boot + tool list)
|
|
344
368
|
uv run --no-project --with 'mcp[cli]' --with sqlalchemy --with 'psycopg[binary]' \
|
|
345
|
-
python -c "import asyncio; from dct.server import mcp; \
|
|
369
|
+
python -c "import asyncio; from dct.mcp.server import mcp; \
|
|
346
370
|
print(len(asyncio.run(mcp.list_tools())), 'tools')"
|
|
347
371
|
```
|
|
348
372
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://github.com/fotodeveloper/dct/actions/workflows/ci.yml)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
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](https://claude.com/claude-code) (skills, hooks,
|
|
8
|
+
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](https://claude.com/claude-code) (skills, hooks, 49 MCP tools); the MCP server and CLI work with any MCP-capable assistant.
|
|
9
9
|
|
|
10
10
|
Part of the **dc tools** family ([dctools.dev](https://dctools.dev)) — *deterministic context* for AI-assisted development.
|
|
11
11
|
|
|
@@ -62,9 +62,9 @@ release day the changelog is already written:
|
|
|
62
62
|
|
|
63
63
|
```text
|
|
64
64
|
> /release
|
|
65
|
-
15 unreleased entries → stamped as 1.
|
|
65
|
+
15 unreleased entries → stamped as 1.4.0
|
|
66
66
|
changelog.md regenerated (Keep a Changelog format)
|
|
67
|
-
release: v1.
|
|
67
|
+
release: v1.4.0 committed, project version bumped
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
One command stamps the version, exports [Keep a Changelog](https://keepachangelog.com)
|
|
@@ -79,7 +79,7 @@ markdown, and makes the release commit.
|
|
|
79
79
|
- **Decision records** — ADRs, sprint amendments, inline plan decisions with multi-anchor linkage
|
|
80
80
|
- **LLM-assisted classification** — uncertain plan sections auto-resolved via `claude --print` (haiku by default)
|
|
81
81
|
- **Passive autoscan hook** — PostToolUse hook re-scans plan-like files in background on every edit
|
|
82
|
-
- **MCP server** — native Claude Code integration via FastMCP,
|
|
82
|
+
- **MCP server** — native Claude Code integration via FastMCP, 49 tools
|
|
83
83
|
- **CLI** — fast `dct` command for hooks and scripts
|
|
84
84
|
- **Skills** — Claude Code slash commands (`/track`, `/clog`, `/dct-import`, `/plan-status`, …)
|
|
85
85
|
- **Soft deletes** — ledger pattern, nothing is ever lost
|
|
@@ -123,13 +123,13 @@ dct init
|
|
|
123
123
|
|
|
124
124
|
The interactive wizard walks through the one-time global bootstrap:
|
|
125
125
|
|
|
126
|
-
1. **Database backend** — `sqlite` (default, zero setup at `~/.
|
|
126
|
+
1. **Database backend** — `sqlite` (default, zero setup at the platform data dir, e.g. `~/.local/share/dctools/dct.db`) or `postgresql` (you supply the URL). It test-connects before saving.
|
|
127
127
|
2. **Register projects** — for each project it asks slug / path / name, then **auto-detects the version** from `VERSION`, `pyproject.toml`, `package.json`, `Cargo.toml`, or `src-tauri/tauri.conf.json`. If none matches, you get an interactive prompt (`0.0.1` / `0.1.0` / `1.0.0` shortcuts); in non-tty contexts it stores `current_version=NULL` and reminds you to set it later. Register more any time with `dct project add`.
|
|
128
128
|
3. **MCP server** — registered at **user scope** in `~/.claude.json` (via `claude 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.
|
|
129
129
|
4. **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.
|
|
130
130
|
5. **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 with `dct hooks wire`.
|
|
131
131
|
|
|
132
|
-
`dct init` writes `~/.claude/dct.toml
|
|
132
|
+
`dct init` writes the config to the platform config dir (`~/.config/dctools/dct.toml`; existing `~/.claude/dct.toml` installs keep working — `dct migrate-home` moves them), `~/.claude.json` (MCP entry), the skill/hook symlinks, and (opt-in) the settings.json wiring — see [docs/architecture.md](docs/architecture.md) for the full config reference and scope model.
|
|
133
133
|
|
|
134
134
|
### Your first session
|
|
135
135
|
|
|
@@ -158,6 +158,16 @@ happens in the conversation you're already having.
|
|
|
158
158
|
- **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.
|
|
159
159
|
- **Plans/decisions tools fail with `No module named 'ulid'`** — your installed tool environment predates the `python-ulid` dependency. Upgrade it: `uv tool upgrade dctracker` (or reinstall via your chosen option above).
|
|
160
160
|
|
|
161
|
+
### Updating
|
|
162
|
+
|
|
163
|
+
dct runs a passive, offline-safe update check — a cached PyPI probe (refreshed at most once a day, never blocking) surfaces a one-line "newer release available" nudge on the CLI and in the MCP server instructions. Opt out with `[update] check = false` in the dct config file (`dct config path` shows where it lives). When a newer version exists:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
dct upgrade # detects install method (uv tool / pipx / pip), upgrades, re-links skills + hooks
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
`dct upgrade` refreshes the skill/hook symlinks and prunes any that the new package dropped. Editable/dev checkouts print `git pull` guidance instead (no package to upgrade). Run it at a session boundary — skill descriptions and the MCP server pick up the new code on the next session, migrations on the next engine bootstrap.
|
|
170
|
+
|
|
161
171
|
## Usage
|
|
162
172
|
|
|
163
173
|
### CLI
|
|
@@ -197,26 +207,39 @@ dct checkpoint add 42 "Write parser"
|
|
|
197
207
|
dct checkpoint list 42
|
|
198
208
|
dct checkpoint done 3 # Mark CP #3 as done
|
|
199
209
|
dct checkpoint reject 4 # Scope-change, keep in ledger
|
|
210
|
+
|
|
211
|
+
# Sprints (first-class, named units of work; /handoff manages the current-sprint set)
|
|
212
|
+
dct sprint list --status active
|
|
213
|
+
dct sprint create "Payments hardening" --code pay-1 --goal "Close the P1 backlog"
|
|
214
|
+
dct sprint show 3 # Details + linked items
|
|
215
|
+
dct sprint activate 3 # Shortcuts: activate / complete / defer
|
|
216
|
+
|
|
217
|
+
# Handoffs (amend an unconsumed handoff in place; creation is /handoff or MCP)
|
|
218
|
+
dct handoff update 12 --prompt "Wire the toggle into settings next"
|
|
219
|
+
|
|
220
|
+
# Config
|
|
221
|
+
dct config get integrations.claude.task_mirror # Read a dotted config key
|
|
222
|
+
dct config path # Show resolved config/data locations
|
|
200
223
|
```
|
|
201
224
|
|
|
202
225
|
## MCP Tools
|
|
203
226
|
|
|
204
|
-
dct ships **
|
|
227
|
+
dct ships **49 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. Write ops return a minimal ack (id + a few post-state scalars); fetch full context with `get_item(id)` / `get_handoff(id)`. Ten mid-session daily drivers are always resident (`alwaysLoad`); the rest of the catalogue loads on demand via ToolSearch:
|
|
205
228
|
|
|
206
229
|
| Tool | Purpose |
|
|
207
230
|
|---|---|
|
|
208
231
|
| `create_item` | Create a tracked item (issue / todo / feature / idea / improvement) |
|
|
232
|
+
| `get_item` | Full item dict — fields, notes, checkpoints, progress |
|
|
209
233
|
| `list_items` | List / search items in compact `{cols, rows}` form |
|
|
210
234
|
| `update_item` | Update fields on an existing item |
|
|
211
235
|
| `resolve_item` | Close an item (terminal status), with gate-checkpoint guard |
|
|
236
|
+
| `add_note` | Append a note to an item (append-only ledger) |
|
|
212
237
|
| `add_checkpoint` | Add an acceptance criterion to an item |
|
|
213
238
|
| `complete_checkpoint` | Mark a checkpoint done (real-time, never batched) |
|
|
239
|
+
| `reject_checkpoint` | Mark a checkpoint rejected (scope change) — ledger-preserving |
|
|
214
240
|
| `add_changelog` | Add an unreleased changelog entry |
|
|
215
|
-
| `release_changelog` | Stamp unreleased entries with a version + bump `current_version` |
|
|
216
|
-
| `set_sprint` | Atomically replace the current sprint's membership |
|
|
217
|
-
| `create_handoff` | Leave a handoff draft for the next session |
|
|
218
241
|
|
|
219
|
-
Full categorized catalogue of all
|
|
242
|
+
Session-edge tools stay deferred: `get_handoff` (full handoff dict — untruncated prompt + context_summary), `create_handoff`, `set_sprint`, `release_changelog`, and more. Full categorized catalogue of all 49 tools: **[docs/mcp-tools.md](docs/mcp-tools.md)**.
|
|
220
243
|
|
|
221
244
|
## Plans, Roadmaps & Decisions
|
|
222
245
|
|
|
@@ -236,7 +259,7 @@ dct web status # show pid + URL
|
|
|
236
259
|
dct web stop # SIGTERM the daemon
|
|
237
260
|
```
|
|
238
261
|
|
|
239
|
-
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
|
|
262
|
+
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 the dct config file.
|
|
240
263
|
|
|
241
264
|

|
|
242
265
|
|
|
@@ -281,26 +304,26 @@ Manual wiring reference (full JSON) and the five rules every dct hook follows: [
|
|
|
281
304
|
|
|
282
305
|
## Configuration
|
|
283
306
|
|
|
284
|
-
dct reads `~/.claude/dct.toml
|
|
307
|
+
dct reads its config from the platform config dir — `~/.config/dctools/dct.toml` on Linux and macOS, `%LOCALAPPDATA%\dctools\dct.toml` on Windows — with a permanent fallback to a legacy `~/.claude/dct.toml` (run `dct migrate-home` to move an old install). The minimal config is just the database URL:
|
|
285
308
|
|
|
286
309
|
```toml
|
|
287
310
|
[database]
|
|
288
|
-
url = "sqlite:////
|
|
311
|
+
url = "sqlite:////home/you/.local/share/dctools/dct.db"
|
|
289
312
|
# or: url = "postgresql+psycopg://localhost:5432/dct"
|
|
290
313
|
```
|
|
291
314
|
|
|
292
|
-
The `DCT_DATABASE_URL` environment variable overrides `[database].url`. For the full reference (`[
|
|
315
|
+
The `DCT_DATABASE_URL` environment variable overrides `[database].url`. For the full reference (`[classification]`, `[integrations.claude]`, `[web]` sections), the database schema, MCP scope precedence, and project auto-detection mechanics, see **[docs/architecture.md](docs/architecture.md)**.
|
|
293
316
|
|
|
294
317
|
## Testing
|
|
295
318
|
|
|
296
319
|
```bash
|
|
297
|
-
.venv/bin/pytest -q # All tests (
|
|
320
|
+
.venv/bin/pytest -q # All tests (938)
|
|
298
321
|
.venv/bin/pytest tests/test_plan_parser.py -v # Parser only
|
|
299
322
|
.venv/bin/pytest tests/test_plan_ingest.py -v # Ingest + sticky-resolved semantics
|
|
300
323
|
|
|
301
324
|
# MCP server smoke (boot + tool list)
|
|
302
325
|
uv run --no-project --with 'mcp[cli]' --with sqlalchemy --with 'psycopg[binary]' \
|
|
303
|
-
python -c "import asyncio; from dct.server import mcp; \
|
|
326
|
+
python -c "import asyncio; from dct.mcp.server import mcp; \
|
|
304
327
|
print(len(asyncio.run(mcp.list_tools())), 'tools')"
|
|
305
328
|
```
|
|
306
329
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Packaged asset locations — the single indirection for skill/hook dirs.
|
|
2
|
+
|
|
3
|
+
The PHYSICAL directories stay at dct/skills and dct/hooks: the host's
|
|
4
|
+
~/.claude symlinks point into them, so moving them is a breaking change
|
|
5
|
+
reserved for 2.0.0 (ADR #52 froze every public surface for 1.2.0). When
|
|
6
|
+
that window opens, this module is the one place that changes.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
_PKG_ROOT = Path(__file__).resolve().parent.parent
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def skills_dir() -> Path:
|
|
15
|
+
return _PKG_ROOT / "skills"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def hooks_dir() -> Path:
|
|
19
|
+
return _PKG_ROOT / "hooks"
|