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.
Files changed (158) hide show
  1. {dctracker-1.0.0/dctracker.egg-info → dctracker-1.2.0}/PKG-INFO +42 -18
  2. {dctracker-1.0.0 → dctracker-1.2.0}/README.md +40 -17
  3. {dctracker-1.0.0 → dctracker-1.2.0}/dct/__init__.py +1 -1
  4. dctracker-1.2.0/dct/assets/__init__.py +19 -0
  5. {dctracker-1.0.0 → dctracker-1.2.0}/dct/cli.py +402 -35
  6. dctracker-1.2.0/dct/config.py +269 -0
  7. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/engine.py +8 -4
  8. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/plans/ingest.py +12 -3
  9. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/projects.py +15 -1
  10. dctracker-1.2.0/dct/core/provenance.py +58 -0
  11. {dctracker-1.0.0 → dctracker-1.2.0}/dct/db.py +80 -0
  12. dctracker-1.2.0/dct/hooks/check-changelog-on-stop.sh +112 -0
  13. {dctracker-1.0.0 → dctracker-1.2.0}/dct/hooks/dct-task-mirror.sh +15 -25
  14. dctracker-1.2.0/dct/integrations/__init__.py +5 -0
  15. dctracker-1.0.0/dct/setup.py → dctracker-1.2.0/dct/integrations/claude.py +94 -20
  16. dctracker-1.2.0/dct/mcp/__init__.py +3 -0
  17. {dctracker-1.0.0/dct → dctracker-1.2.0/dct/mcp}/server.py +372 -194
  18. dctracker-1.2.0/dct/migrate.py +597 -0
  19. dctracker-1.2.0/dct/paths.py +103 -0
  20. dctracker-1.2.0/dct/server.py +10 -0
  21. dctracker-1.2.0/dct/services/__init__.py +5 -0
  22. dctracker-1.2.0/dct/setup.py +19 -0
  23. {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/clog/SKILL.md +4 -9
  24. dctracker-1.2.0/dct/skills/commit/SKILL.md +114 -0
  25. {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/dct-import/SKILL.md +2 -1
  26. {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/dct-init/SKILL.md +3 -2
  27. dctracker-1.2.0/dct/skills/handoff/SKILL.md +129 -0
  28. dctracker-1.2.0/dct/skills/pickup/SKILL.md +110 -0
  29. {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/plan-resolve-uncertain/SKILL.md +2 -1
  30. {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/plan-status/SKILL.md +5 -6
  31. {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/release/SKILL.md +73 -60
  32. {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/track/SKILL.md +4 -8
  33. {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/track-list/SKILL.md +5 -6
  34. {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/track-resolve/SKILL.md +3 -4
  35. {dctracker-1.0.0 → dctracker-1.2.0}/dct/skills/track-update/SKILL.md +4 -7
  36. dctracker-1.2.0/dct/update.py +322 -0
  37. dctracker-1.2.0/dct/workflows/__init__.py +3 -0
  38. {dctracker-1.0.0 → dctracker-1.2.0/dctracker.egg-info}/PKG-INFO +42 -18
  39. {dctracker-1.0.0 → dctracker-1.2.0}/dctracker.egg-info/SOURCES.txt +21 -1
  40. {dctracker-1.0.0 → dctracker-1.2.0}/dctracker.egg-info/requires.txt +3 -0
  41. {dctracker-1.0.0 → dctracker-1.2.0}/pyproject.toml +8 -2
  42. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_adversarial.py +1 -1
  43. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_cli_web.py +76 -2
  44. dctracker-1.2.0/tests/test_config.py +300 -0
  45. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_engine.py +37 -0
  46. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_hook_bypass.py +1 -1
  47. dctracker-1.2.0/tests/test_hook_changelog_stop.py +241 -0
  48. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_hook_plan_autoscan.py +1 -1
  49. dctracker-1.2.0/tests/test_hook_task_mirror.py +213 -0
  50. dctracker-1.2.0/tests/test_migrate.py +679 -0
  51. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_packaging.py +1 -1
  52. dctracker-1.2.0/tests/test_paths.py +189 -0
  53. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_plan_classify.py +68 -6
  54. dctracker-1.2.0/tests/test_provenance.py +153 -0
  55. dctracker-1.2.0/tests/test_restructure.py +66 -0
  56. dctracker-1.2.0/tests/test_server_acks.py +425 -0
  57. dctracker-1.2.0/tests/test_server_alwaysload.py +71 -0
  58. dctracker-1.2.0/tests/test_server_handoff_view.py +111 -0
  59. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_setup.py +1 -1
  60. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_setup_wiring.py +1 -1
  61. dctracker-1.2.0/tests/test_update.py +573 -0
  62. dctracker-1.2.0/tests/test_windows_support.py +192 -0
  63. dctracker-1.0.0/dct/config.py +0 -150
  64. dctracker-1.0.0/dct/hooks/check-changelog-on-stop.sh +0 -49
  65. dctracker-1.0.0/dct/skills/commit/SKILL.md +0 -153
  66. dctracker-1.0.0/dct/skills/handoff/SKILL.md +0 -136
  67. dctracker-1.0.0/dct/skills/pickup/SKILL.md +0 -115
  68. dctracker-1.0.0/tests/test_config.py +0 -55
  69. dctracker-1.0.0/tests/test_hook_task_mirror.py +0 -101
  70. dctracker-1.0.0/tests/test_server_alwaysload.py +0 -47
  71. {dctracker-1.0.0 → dctracker-1.2.0}/LICENSE +0 -0
  72. {dctracker-1.0.0 → dctracker-1.2.0}/MANIFEST.in +0 -0
  73. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/__init__.py +0 -0
  74. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/analytics.py +0 -0
  75. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/changelog.py +0 -0
  76. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/checkpoints.py +0 -0
  77. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/decisions.py +0 -0
  78. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/handoff.py +0 -0
  79. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/ids.py +0 -0
  80. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/items.py +0 -0
  81. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/plans/__init__.py +0 -0
  82. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/plans/classify.py +0 -0
  83. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/plans/crud.py +0 -0
  84. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/plans/parser.py +0 -0
  85. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/sprint.py +0 -0
  86. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/sprints.py +0 -0
  87. {dctracker-1.0.0 → dctracker-1.2.0}/dct/core/version.py +0 -0
  88. {dctracker-1.0.0 → dctracker-1.2.0}/dct/export.py +0 -0
  89. {dctracker-1.0.0 → dctracker-1.2.0}/dct/hooks/check-changelog.sh +0 -0
  90. {dctracker-1.0.0 → dctracker-1.2.0}/dct/hooks/dct-plan-autoscan.sh +0 -0
  91. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/__init__.py +0 -0
  92. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/app.py +0 -0
  93. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/__init__.py +0 -0
  94. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/analytics.py +0 -0
  95. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/changelog.py +0 -0
  96. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/decisions.py +0 -0
  97. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/events.py +0 -0
  98. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/handoffs.py +0 -0
  99. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/home.py +0 -0
  100. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/items.py +0 -0
  101. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/plans.py +0 -0
  102. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/projects.py +0 -0
  103. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/blueprints/sprints.py +0 -0
  104. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/changes.py +0 -0
  105. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/serializers.py +0 -0
  106. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/static/app.css +0 -0
  107. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/static/app.js +0 -0
  108. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/static/vendor/SOURCES.txt +0 -0
  109. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/static/vendor/htmx.min.js +0 -0
  110. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/static/vendor/uPlot.iife.min.js +0 -0
  111. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/static/vendor/uPlot.min.css +0 -0
  112. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/analytics.html +0 -0
  113. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/base.html +0 -0
  114. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/changelog/list.html +0 -0
  115. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/decisions/list.html +0 -0
  116. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/handoffs/list.html +0 -0
  117. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/home.html +0 -0
  118. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/item_detail.html +0 -0
  119. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/items_list.html +0 -0
  120. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/partials/_bars.html +0 -0
  121. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/partials/_checkpoint_steps.html +0 -0
  122. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/partials/_items_table.html +0 -0
  123. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/partials/_plan_section.html +0 -0
  124. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/partials/_project_card.html +0 -0
  125. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/plans/detail.html +0 -0
  126. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/plans/list.html +0 -0
  127. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/project_home.html +0 -0
  128. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/sprints/detail.html +0 -0
  129. {dctracker-1.0.0 → dctracker-1.2.0}/dct/web/templates/sprints/list.html +0 -0
  130. {dctracker-1.0.0 → dctracker-1.2.0}/dctracker.egg-info/dependency_links.txt +0 -0
  131. {dctracker-1.0.0 → dctracker-1.2.0}/dctracker.egg-info/entry_points.txt +0 -0
  132. {dctracker-1.0.0 → dctracker-1.2.0}/dctracker.egg-info/top_level.txt +0 -0
  133. {dctracker-1.0.0 → dctracker-1.2.0}/setup.cfg +0 -0
  134. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_analytics.py +0 -0
  135. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_changelog.py +0 -0
  136. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_changes.py +0 -0
  137. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_checkpoints.py +0 -0
  138. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_cli_prompts.py +0 -0
  139. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_cli_sprints.py +0 -0
  140. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_decisions_crud.py +0 -0
  141. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_export.py +0 -0
  142. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_handoff.py +0 -0
  143. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_ids.py +0 -0
  144. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_ingest_dogfood.py +0 -0
  145. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_items.py +0 -0
  146. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_migration.py +0 -0
  147. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_plan_ingest.py +0 -0
  148. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_plan_parser.py +0 -0
  149. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_plans_crud.py +0 -0
  150. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_projects.py +0 -0
  151. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_sprint.py +0 -0
  152. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_sprints_crud.py +0 -0
  153. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_version.py +0 -0
  154. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_web_analytics.py +0 -0
  155. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_web_app.py +0 -0
  156. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_web_items.py +0 -0
  157. {dctracker-1.0.0 → dctracker-1.2.0}/tests/test_web_structural.py +0 -0
  158. {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.0.0
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
  [![CI](https://github.com/fotodeveloper/dct/actions/workflows/ci.yml/badge.svg)](https://github.com/fotodeveloper/dct/actions/workflows/ci.yml)
48
49
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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, 48 MCP tools); the MCP server and CLI work with any MCP-capable assistant.
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.1.0
108
+ 15 unreleased entries → stamped as 1.4.0
108
109
  changelog.md regenerated (Keep a Changelog format)
109
- release: v1.1.0 committed, project version bumped
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, 48 tools
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 `~/.claude/dct.db`) or `postgresql` (you supply the URL). It test-connects before saving.
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`, `~/.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
+ `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 **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:
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 48 tools: **[docs/mcp-tools.md](docs/mcp-tools.md)**.
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 `~/.claude/dct.toml`.
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
  ![dct web viewer — read-only dashboard over all registered projects](docs/assets/web-viewer.png)
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`. The minimal config is just the database URL:
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:////Users/you/.claude/dct.db"
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 (`[plans]`, `[mirror]`, `[web]` sections), the database schema, MCP scope precedence, and project auto-detection mechanics, see **[docs/architecture.md](docs/architecture.md)**.
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 (670)
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
  [![CI](https://github.com/fotodeveloper/dct/actions/workflows/ci.yml/badge.svg)](https://github.com/fotodeveloper/dct/actions/workflows/ci.yml)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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, 48 MCP tools); the MCP server and CLI work with any MCP-capable assistant.
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.1.0
65
+ 15 unreleased entries → stamped as 1.4.0
66
66
  changelog.md regenerated (Keep a Changelog format)
67
- release: v1.1.0 committed, project version bumped
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, 48 tools
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 `~/.claude/dct.db`) or `postgresql` (you supply the URL). It test-connects before saving.
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`, `~/.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.
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 **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:
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 48 tools: **[docs/mcp-tools.md](docs/mcp-tools.md)**.
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 `~/.claude/dct.toml`.
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
  ![dct web viewer — read-only dashboard over all registered projects](docs/assets/web-viewer.png)
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`. The minimal config is just the database URL:
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:////Users/you/.claude/dct.db"
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 (`[plans]`, `[mirror]`, `[web]` sections), the database schema, MCP scope precedence, and project auto-detection mechanics, see **[docs/architecture.md](docs/architecture.md)**.
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 (670)
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
 
@@ -3,4 +3,4 @@ from importlib.metadata import version, PackageNotFoundError
3
3
  try:
4
4
  __version__ = version("dctracker")
5
5
  except PackageNotFoundError:
6
- __version__ = "1.0.0"
6
+ __version__ = "1.2.0"
@@ -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"