@unbrained/pm-cli 2026.3.9 → 2026.5.1-2

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 (288) hide show
  1. package/.agents/pm/extensions/.managed-extensions.json +42 -0
  2. package/.agents/pm/extensions/beads/index.js +109 -0
  3. package/.agents/pm/extensions/beads/manifest.json +7 -0
  4. package/{dist/cli/commands/beads.js → .agents/pm/extensions/beads/runtime.js} +167 -56
  5. package/.agents/pm/extensions/beads/runtime.ts +702 -0
  6. package/.agents/pm/extensions/todos/index.js +126 -0
  7. package/.agents/pm/extensions/todos/manifest.json +7 -0
  8. package/{dist/extensions/builtins/todos/import-export.js → .agents/pm/extensions/todos/runtime.js} +39 -29
  9. package/.agents/pm/extensions/todos/runtime.ts +568 -0
  10. package/AGENTS.md +212 -94
  11. package/CHANGELOG.md +404 -0
  12. package/CODE_OF_CONDUCT.md +42 -0
  13. package/CONTRIBUTING.md +144 -0
  14. package/PRD.md +522 -173
  15. package/README.md +996 -495
  16. package/SECURITY.md +51 -0
  17. package/dist/cli/commands/activity.d.ts +5 -0
  18. package/dist/cli/commands/activity.js +66 -3
  19. package/dist/cli/commands/activity.js.map +1 -1
  20. package/dist/cli/commands/aggregate.d.ts +54 -0
  21. package/dist/cli/commands/aggregate.js +181 -0
  22. package/dist/cli/commands/aggregate.js.map +1 -0
  23. package/dist/cli/commands/append.js +4 -1
  24. package/dist/cli/commands/append.js.map +1 -1
  25. package/dist/cli/commands/calendar.d.ts +109 -0
  26. package/dist/cli/commands/calendar.js +797 -0
  27. package/dist/cli/commands/calendar.js.map +1 -0
  28. package/dist/cli/commands/claim.d.ts +5 -1
  29. package/dist/cli/commands/claim.js +42 -21
  30. package/dist/cli/commands/claim.js.map +1 -1
  31. package/dist/cli/commands/close.d.ts +1 -0
  32. package/dist/cli/commands/close.js +54 -5
  33. package/dist/cli/commands/close.js.map +1 -1
  34. package/dist/cli/commands/comments-audit.d.ts +91 -0
  35. package/dist/cli/commands/comments-audit.js +195 -0
  36. package/dist/cli/commands/comments-audit.js.map +1 -0
  37. package/dist/cli/commands/comments.d.ts +1 -0
  38. package/dist/cli/commands/comments.js +70 -21
  39. package/dist/cli/commands/comments.js.map +1 -1
  40. package/dist/cli/commands/completion.d.ts +10 -4
  41. package/dist/cli/commands/completion.js +1240 -193
  42. package/dist/cli/commands/completion.js.map +1 -1
  43. package/dist/cli/commands/config.d.ts +35 -3
  44. package/dist/cli/commands/config.js +968 -13
  45. package/dist/cli/commands/config.js.map +1 -1
  46. package/dist/cli/commands/context.d.ts +86 -0
  47. package/dist/cli/commands/context.js +299 -0
  48. package/dist/cli/commands/context.js.map +1 -0
  49. package/dist/cli/commands/contracts.d.ts +78 -0
  50. package/dist/cli/commands/contracts.js +920 -0
  51. package/dist/cli/commands/contracts.js.map +1 -0
  52. package/dist/cli/commands/create.d.ts +48 -14
  53. package/dist/cli/commands/create.js +1331 -160
  54. package/dist/cli/commands/create.js.map +1 -1
  55. package/dist/cli/commands/dedupe-audit.d.ts +81 -0
  56. package/dist/cli/commands/dedupe-audit.js +330 -0
  57. package/dist/cli/commands/dedupe-audit.js.map +1 -0
  58. package/dist/cli/commands/deps.d.ts +52 -0
  59. package/dist/cli/commands/deps.js +204 -0
  60. package/dist/cli/commands/deps.js.map +1 -0
  61. package/dist/cli/commands/docs.d.ts +19 -0
  62. package/dist/cli/commands/docs.js +212 -13
  63. package/dist/cli/commands/docs.js.map +1 -1
  64. package/dist/cli/commands/extension.d.ts +122 -0
  65. package/dist/cli/commands/extension.js +1850 -0
  66. package/dist/cli/commands/extension.js.map +1 -0
  67. package/dist/cli/commands/files.d.ts +52 -1
  68. package/dist/cli/commands/files.js +455 -13
  69. package/dist/cli/commands/files.js.map +1 -1
  70. package/dist/cli/commands/gc.d.ts +11 -1
  71. package/dist/cli/commands/gc.js +89 -11
  72. package/dist/cli/commands/gc.js.map +1 -1
  73. package/dist/cli/commands/get.d.ts +13 -0
  74. package/dist/cli/commands/get.js +35 -3
  75. package/dist/cli/commands/get.js.map +1 -1
  76. package/dist/cli/commands/health.d.ts +10 -2
  77. package/dist/cli/commands/health.js +774 -23
  78. package/dist/cli/commands/health.js.map +1 -1
  79. package/dist/cli/commands/history.d.ts +20 -0
  80. package/dist/cli/commands/history.js +152 -6
  81. package/dist/cli/commands/history.js.map +1 -1
  82. package/dist/cli/commands/index.d.ts +16 -3
  83. package/dist/cli/commands/index.js +16 -3
  84. package/dist/cli/commands/index.js.map +1 -1
  85. package/dist/cli/commands/init.d.ts +7 -2
  86. package/dist/cli/commands/init.js +137 -5
  87. package/dist/cli/commands/init.js.map +1 -1
  88. package/dist/cli/commands/learnings.d.ts +17 -0
  89. package/dist/cli/commands/learnings.js +129 -0
  90. package/dist/cli/commands/learnings.js.map +1 -0
  91. package/dist/cli/commands/list.d.ts +29 -1
  92. package/dist/cli/commands/list.js +292 -56
  93. package/dist/cli/commands/list.js.map +1 -1
  94. package/dist/cli/commands/normalize.d.ts +51 -0
  95. package/dist/cli/commands/normalize.js +298 -0
  96. package/dist/cli/commands/normalize.js.map +1 -0
  97. package/dist/cli/commands/notes.d.ts +17 -0
  98. package/dist/cli/commands/notes.js +129 -0
  99. package/dist/cli/commands/notes.js.map +1 -0
  100. package/dist/cli/commands/reindex.d.ts +1 -0
  101. package/dist/cli/commands/reindex.js +208 -32
  102. package/dist/cli/commands/reindex.js.map +1 -1
  103. package/dist/cli/commands/restore.js +164 -30
  104. package/dist/cli/commands/restore.js.map +1 -1
  105. package/dist/cli/commands/search.d.ts +14 -1
  106. package/dist/cli/commands/search.js +479 -85
  107. package/dist/cli/commands/search.js.map +1 -1
  108. package/dist/cli/commands/stats.js +26 -10
  109. package/dist/cli/commands/stats.js.map +1 -1
  110. package/dist/cli/commands/templates.d.ts +26 -0
  111. package/dist/cli/commands/templates.js +179 -0
  112. package/dist/cli/commands/templates.js.map +1 -0
  113. package/dist/cli/commands/test-all.d.ts +19 -1
  114. package/dist/cli/commands/test-all.js +161 -13
  115. package/dist/cli/commands/test-all.js.map +1 -1
  116. package/dist/cli/commands/test-runs.d.ts +63 -0
  117. package/dist/cli/commands/test-runs.js +179 -0
  118. package/dist/cli/commands/test-runs.js.map +1 -0
  119. package/dist/cli/commands/test.d.ts +75 -1
  120. package/dist/cli/commands/test.js +1360 -41
  121. package/dist/cli/commands/test.js.map +1 -1
  122. package/dist/cli/commands/update-many.d.ts +57 -0
  123. package/dist/cli/commands/update-many.js +631 -0
  124. package/dist/cli/commands/update-many.js.map +1 -0
  125. package/dist/cli/commands/update.d.ts +30 -0
  126. package/dist/cli/commands/update.js +1393 -84
  127. package/dist/cli/commands/update.js.map +1 -1
  128. package/dist/cli/commands/validate.d.ts +30 -0
  129. package/dist/cli/commands/validate.js +1151 -0
  130. package/dist/cli/commands/validate.js.map +1 -0
  131. package/dist/cli/error-guidance.d.ts +33 -0
  132. package/dist/cli/error-guidance.js +337 -0
  133. package/dist/cli/error-guidance.js.map +1 -0
  134. package/dist/cli/extension-command-options.d.ts +1 -0
  135. package/dist/cli/extension-command-options.js +92 -0
  136. package/dist/cli/extension-command-options.js.map +1 -1
  137. package/dist/cli/help-content.d.ts +20 -0
  138. package/dist/cli/help-content.js +543 -0
  139. package/dist/cli/help-content.js.map +1 -0
  140. package/dist/cli/main.js +3648 -467
  141. package/dist/cli/main.js.map +1 -1
  142. package/dist/core/extensions/index.d.ts +13 -1
  143. package/dist/core/extensions/index.js +108 -1
  144. package/dist/core/extensions/index.js.map +1 -1
  145. package/dist/core/extensions/item-fields.d.ts +2 -0
  146. package/dist/core/extensions/item-fields.js +79 -0
  147. package/dist/core/extensions/item-fields.js.map +1 -0
  148. package/dist/core/extensions/loader.d.ts +322 -9
  149. package/dist/core/extensions/loader.js +911 -20
  150. package/dist/core/extensions/loader.js.map +1 -1
  151. package/dist/core/extensions/runtime-registrations.d.ts +5 -0
  152. package/dist/core/extensions/runtime-registrations.js +51 -0
  153. package/dist/core/extensions/runtime-registrations.js.map +1 -0
  154. package/dist/core/history/history-stream-policy.d.ts +20 -0
  155. package/dist/core/history/history-stream-policy.js +53 -0
  156. package/dist/core/history/history-stream-policy.js.map +1 -0
  157. package/dist/core/history/history.js +90 -1
  158. package/dist/core/history/history.js.map +1 -1
  159. package/dist/core/item/id.d.ts +1 -0
  160. package/dist/core/item/id.js +10 -3
  161. package/dist/core/item/id.js.map +1 -1
  162. package/dist/core/item/index.d.ts +1 -0
  163. package/dist/core/item/index.js +1 -0
  164. package/dist/core/item/index.js.map +1 -1
  165. package/dist/core/item/item-format.d.ts +11 -5
  166. package/dist/core/item/item-format.js +532 -28
  167. package/dist/core/item/item-format.js.map +1 -1
  168. package/dist/core/item/parent-reference-policy.d.ts +6 -0
  169. package/dist/core/item/parent-reference-policy.js +32 -0
  170. package/dist/core/item/parent-reference-policy.js.map +1 -0
  171. package/dist/core/item/parse.d.ts +5 -0
  172. package/dist/core/item/parse.js +216 -19
  173. package/dist/core/item/parse.js.map +1 -1
  174. package/dist/core/item/sprint-release-format.d.ts +6 -0
  175. package/dist/core/item/sprint-release-format.js +33 -0
  176. package/dist/core/item/sprint-release-format.js.map +1 -0
  177. package/dist/core/item/status.d.ts +3 -0
  178. package/dist/core/item/status.js +24 -0
  179. package/dist/core/item/status.js.map +1 -0
  180. package/dist/core/item/type-registry.d.ts +37 -0
  181. package/dist/core/item/type-registry.js +706 -0
  182. package/dist/core/item/type-registry.js.map +1 -0
  183. package/dist/core/lock/lock.d.ts +1 -1
  184. package/dist/core/lock/lock.js +101 -12
  185. package/dist/core/lock/lock.js.map +1 -1
  186. package/dist/core/output/command-aware.d.ts +1 -0
  187. package/dist/core/output/command-aware.js +394 -0
  188. package/dist/core/output/command-aware.js.map +1 -0
  189. package/dist/core/output/output.d.ts +3 -0
  190. package/dist/core/output/output.js +124 -6
  191. package/dist/core/output/output.js.map +1 -1
  192. package/dist/core/schema/runtime-field-filters.d.ts +3 -0
  193. package/dist/core/schema/runtime-field-filters.js +39 -0
  194. package/dist/core/schema/runtime-field-filters.js.map +1 -0
  195. package/dist/core/schema/runtime-field-values.d.ts +8 -0
  196. package/dist/core/schema/runtime-field-values.js +154 -0
  197. package/dist/core/schema/runtime-field-values.js.map +1 -0
  198. package/dist/core/schema/runtime-schema.d.ts +68 -0
  199. package/dist/core/schema/runtime-schema.js +554 -0
  200. package/dist/core/schema/runtime-schema.js.map +1 -0
  201. package/dist/core/search/cache.d.ts +13 -1
  202. package/dist/core/search/cache.js +123 -14
  203. package/dist/core/search/cache.js.map +1 -1
  204. package/dist/core/search/semantic-defaults.d.ts +6 -0
  205. package/dist/core/search/semantic-defaults.js +120 -0
  206. package/dist/core/search/semantic-defaults.js.map +1 -0
  207. package/dist/core/search/vector-stores.js +3 -1
  208. package/dist/core/search/vector-stores.js.map +1 -1
  209. package/dist/core/shared/command-types.d.ts +2 -0
  210. package/dist/core/shared/conflict-markers.d.ts +7 -0
  211. package/dist/core/shared/conflict-markers.js +27 -0
  212. package/dist/core/shared/conflict-markers.js.map +1 -0
  213. package/dist/core/shared/constants.d.ts +15 -4
  214. package/dist/core/shared/constants.js +146 -1
  215. package/dist/core/shared/constants.js.map +1 -1
  216. package/dist/core/shared/errors.d.ts +10 -1
  217. package/dist/core/shared/errors.js +3 -1
  218. package/dist/core/shared/errors.js.map +1 -1
  219. package/dist/core/shared/text-normalization.d.ts +4 -0
  220. package/dist/core/shared/text-normalization.js +33 -0
  221. package/dist/core/shared/text-normalization.js.map +1 -0
  222. package/dist/core/shared/time.d.ts +3 -2
  223. package/dist/core/shared/time.js +109 -11
  224. package/dist/core/shared/time.js.map +1 -1
  225. package/dist/core/store/index.d.ts +1 -0
  226. package/dist/core/store/index.js +1 -0
  227. package/dist/core/store/index.js.map +1 -1
  228. package/dist/core/store/item-format-migration.d.ts +9 -0
  229. package/dist/core/store/item-format-migration.js +87 -0
  230. package/dist/core/store/item-format-migration.js.map +1 -0
  231. package/dist/core/store/item-store.d.ts +13 -4
  232. package/dist/core/store/item-store.js +243 -52
  233. package/dist/core/store/item-store.js.map +1 -1
  234. package/dist/core/store/paths.d.ts +21 -3
  235. package/dist/core/store/paths.js +59 -4
  236. package/dist/core/store/paths.js.map +1 -1
  237. package/dist/core/store/settings.d.ts +14 -1
  238. package/dist/core/store/settings.js +463 -7
  239. package/dist/core/store/settings.js.map +1 -1
  240. package/dist/core/telemetry/consent.d.ts +2 -0
  241. package/dist/core/telemetry/consent.js +79 -0
  242. package/dist/core/telemetry/consent.js.map +1 -0
  243. package/dist/core/telemetry/runtime.d.ts +38 -0
  244. package/dist/core/telemetry/runtime.js +733 -0
  245. package/dist/core/telemetry/runtime.js.map +1 -0
  246. package/dist/core/test/background-runs.d.ts +117 -0
  247. package/dist/core/test/background-runs.js +760 -0
  248. package/dist/core/test/background-runs.js.map +1 -0
  249. package/dist/core/test/item-test-run-tracking.d.ts +9 -0
  250. package/dist/core/test/item-test-run-tracking.js +50 -0
  251. package/dist/core/test/item-test-run-tracking.js.map +1 -0
  252. package/dist/sdk/cli-contracts.d.ts +92 -0
  253. package/dist/sdk/cli-contracts.js +2357 -0
  254. package/dist/sdk/cli-contracts.js.map +1 -0
  255. package/dist/sdk/index.d.ts +34 -0
  256. package/dist/sdk/index.js +23 -0
  257. package/dist/sdk/index.js.map +1 -0
  258. package/dist/types.d.ts +204 -4
  259. package/dist/types.js +56 -1
  260. package/dist/types.js.map +1 -1
  261. package/docs/ARCHITECTURE.md +369 -40
  262. package/docs/EXTENSIONS.md +454 -49
  263. package/docs/RELEASING.md +70 -19
  264. package/docs/SDK.md +123 -0
  265. package/docs/examples/starter-extension/README.md +48 -0
  266. package/docs/examples/starter-extension/index.js +191 -0
  267. package/docs/examples/starter-extension/manifest.json +17 -0
  268. package/docs/examples/starter-extension/package.json +10 -0
  269. package/package.json +41 -14
  270. package/scripts/install.ps1 +2 -1
  271. package/scripts/install.sh +2 -1
  272. package/.pi/extensions/pm-cli/index.ts +0 -778
  273. package/dist/cli/commands/beads.d.ts +0 -15
  274. package/dist/cli/commands/beads.js.map +0 -1
  275. package/dist/cli/commands/install.d.ts +0 -18
  276. package/dist/cli/commands/install.js +0 -87
  277. package/dist/cli/commands/install.js.map +0 -1
  278. package/dist/core/extensions/builtins.d.ts +0 -3
  279. package/dist/core/extensions/builtins.js +0 -47
  280. package/dist/core/extensions/builtins.js.map +0 -1
  281. package/dist/extensions/builtins/beads/index.d.ts +0 -8
  282. package/dist/extensions/builtins/beads/index.js +0 -29
  283. package/dist/extensions/builtins/beads/index.js.map +0 -1
  284. package/dist/extensions/builtins/todos/import-export.d.ts +0 -26
  285. package/dist/extensions/builtins/todos/import-export.js.map +0 -1
  286. package/dist/extensions/builtins/todos/index.d.ts +0 -8
  287. package/dist/extensions/builtins/todos/index.js +0 -38
  288. package/dist/extensions/builtins/todos/index.js.map +0 -1
package/README.md CHANGED
@@ -5,651 +5,1152 @@
5
5
  [![Node >=20](https://img.shields.io/node/v/%40unbrained%2Fpm-cli)](https://nodejs.org)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
7
 
8
- Agent-friendly, git-native project management for humans and coding agents.
8
+ `pm` is a git-native project management CLI for humans and coding agents. It stores items as TOON (`.toon`) by default with full first-class JSON-front-matter Markdown (`.md`) support, keeps append-only JSONL history, and supports safe collaboration.
9
+
10
+ ## Highlights
11
+
12
+ - Git-native items that stay reviewable in diffs
13
+ - Safe multi-agent workflows with claims, locks, and restore
14
+ - Deterministic output with TOON by default and `--json` when needed
15
+ - Layered command help: compact default (`Intent` + one example) and deep explainability via `--explain`
16
+ - Machine-readable help payloads via `pm <command> --help --json` (also `pm help <command> --json`)
17
+ - Structured diagnostics with machine-readable JSON error envelopes when `--json` is active
18
+ - Dedicated machine contract surface via `pm contracts` (`--action`, `--command`, `--schema-only`, `--runtime-only`, `--active-only`)
19
+ - Sparse TOON default output that omits null/undefined/empty fields for token-efficient agent workflows
20
+ - Agent-friendly calendar views (`pm calendar` / `pm cal`) with markdown default output
21
+ - Agent-first context snapshot command (`pm context` / `pm ctx`) for critical work + agenda triage
22
+ - Reusable create templates (`pm templates save/list/show` + `pm create --template`)
23
+ - First-class dual item storage formats: TOON (`.toon`) and JSON-front-matter Markdown (`.md`)
24
+ - Compact TOON documents that are easier to review in terminal and GitHub web UI
25
+ - Automatic item format migration when `item-format` config changes
26
+ - Deterministic canonical normalization and atomic writes for parallel git/worktree workflows
27
+ - Warning-first/strict validation policies for sprint/release and parent references
28
+ - Additive history diff/verify diagnostics (`pm history --diff --verify`)
29
+ - Linked path hygiene for files/docs (`--add-glob`, `--migrate`, `--validate-paths`, `--audit`)
30
+ - Dependency topology inspection via `pm deps --format tree|graph`
31
+ - Deterministic `--tag` completion suggestions from tracked item metadata
32
+ - Additive large-list controls via projection (`--compact` / `--fields`), configurable sorting (`--sort` + `--order`), pagination (`--offset`), and opt-in JSON streaming (`--stream` with `--json`)
33
+ - Governance-focused corpus analysis commands: `pm aggregate` default grouped counts and `pm dedupe-audit` duplicate clustering
34
+ - Standalone `pm validate` command for metadata, resolution, lifecycle, linked-file, linked-command reference, and history-drift audits
35
+ - Opt-in non-interactive progress output for long-running operations (`pm test`, `pm test-all`, `pm reindex` with `--progress`)
36
+ - Managed background linked-test orchestration (`pm test --run --background`, `pm test-all --background`, and `pm test-runs` lifecycle controls; bare `pm test-runs` defaults to list output)
37
+ - Linked-test context preflight and auto-remediation controls (`pm test`/`pm test-all` with `--check-context` and `--auto-pm-context`)
38
+ - Safer cache cleanup controls via `pm gc --dry-run` and scoped cleanup with `--scope index|embeddings|runtime`
39
+ - Pager-safe help output in automation (help requests auto-disable paging on non-TTY stdout, with explicit global `--no-pager` override)
40
+ - Settings-gated item-level test result tracking (`pm config ... test-result-tracking --policy enabled|disabled`)
41
+ - Optional search and extension support for more advanced setups
42
+
43
+ ## Unified Command Contracts
44
+
45
+ `pm` now centralizes command/action contract metadata in `src/sdk/cli-contracts.ts` and uses it across:
46
+
47
+ - CLI option normalization in `src/cli/main.ts`
48
+ - Shell completion generation in `src/cli/commands/completion.ts`
49
+ - Pi wrapper tool actions, JSON Schema, and arg mapping in `.pi/extensions/pm-cli/index.ts`
50
+
51
+ Compatibility policy for command contracts:
52
+
53
+ - Existing commands/flags and aliases remain valid.
54
+ - Pi tool schema now uses strict action-scoped branches (schema v4); callers should send only action-relevant fields.
55
+ - `--json` remains machine-contract stable; search projection defaults are command-specific (`pm search` defaults to compact rows unless `--full` is requested).
56
+ - `pm contracts --json` is the canonical runtime contract introspection surface for agents, including active extension command/action metadata.
57
+ - Contract payloads include runtime action availability metadata (`action_availability`) and optional runtime-filtered views (`--runtime-only`, `--active-only`) so automation can avoid non-invocable actions.
58
+ - `pm contracts --command <name>` scopes output to the selected command for lower-noise machine payloads; omit `--command` for the full contract corpus.
59
+ - `pm contracts` supports lightweight projection modes for automation pipelines: `--flags-only` (command flag surface) and `--availability-only` (runtime invocability metadata); the projection flags are mutually exclusive.
60
+ - When `--action` is provided without `--command`, `pm contracts --flags-only` now scopes `command_flags` to the action-mapped command surface (for example `test-runs-list` resolves to `test-runs`).
61
+ - Contract payloads include canonical flag + alias metadata (`command_flags` plus `commander_aliases`) so machine clients can expose accepted hyphen/underscore variants deterministically.
62
+ - `pm completion` scripts are generated from the same normalized command-contract registry used by parser/contracts, keeping runtime, contract, and completion parity aligned.
63
+ - `pm completion` now defaults to lazy tag expansion through runtime `pm completion-tags` lookup in generated scripts; pass `--eager-tags` to embed static tags in the script (legacy eager mode).
64
+
65
+ ## Item Storage Formats
66
+
67
+ - Default item format is TOON (`.toon`) using root-object field storage (`id`, `title`, ..., `body`).
68
+ - JSON front matter + markdown body (`.md`) is a fully supported alternative format.
69
+ - `front_matter` is an internal TypeScript field name (`ItemDocument.front_matter`) for item metadata; TOON files store the same metadata as top-level keys, not YAML front matter.
70
+ - History files always remain JSONL (`history/<id>.jsonl`).
71
+ - Set project item storage format with:
9
72
 
10
- `pm` stores work items as plain markdown files with JSON front-matter, keeps append-only history, supports safe concurrent mutation with lock + claim semantics, and defaults to token-efficient TOON output.
73
+ ```bash
74
+ pm config project set item-format --format toon
75
+ # or
76
+ pm config project set item-format --format json_markdown
77
+ ```
11
78
 
12
- ## Why `pm`
79
+ Changing `item-format` automatically migrates item files to the configured format.
13
80
 
14
- - Git-native: every item is file-backed and reviewable in diffs.
15
- - Deterministic: stable output schema, key ordering, and filtering behavior.
16
- - Agent-optimized: claim/release ownership, append-only history, restore by version/timestamp.
17
- - Extensible: project + global extension loading with predictable precedence.
18
- - Search-ready: keyword search built-in, semantic/hybrid search optional.
81
+ ## Parallel Git and Worktree Robustness
19
82
 
20
- ## Installation
83
+ - TOON and JSON/Markdown are equally supported item formats; teams can choose either format per repository.
84
+ - Canonical normalization (stable field ordering and deterministic serialization) reduces diff churn and helps keep merges predictable.
85
+ - Item writes are atomic (temp file + rename), which prevents partial writes and corruption during concurrent local operations.
86
+ - Item history remains append-only JSONL with before/after hashes, so changes are auditable and recoverable with `pm history` and `pm restore`.
87
+ - When both `.toon` and `.md` exist for one item ID, configured `item_format` is the source of truth and automatic migration removes split-format drift.
88
+ - Concurrent edits to the exact same content can still require normal git conflict resolution; the storage model is designed to avoid silent data loss and make reconciliation explicit.
21
89
 
22
- `pm-cli` targets Node.js 20+ and ships a `pm` executable via npm `bin`.
90
+ ## Install
23
91
 
24
- ### npm (recommended)
92
+ `pm-cli` requires Node.js 20 or newer.
25
93
 
26
94
  ```bash
27
- npm i -g @unbrained/pm-cli
28
- pm --help
95
+ npm install -g @unbrained/pm-cli
29
96
  pm --version
97
+ pm --help
30
98
  ```
31
99
 
32
- Update to latest:
100
+ For project-local use:
33
101
 
34
102
  ```bash
35
- npm i -g @unbrained/pm-cli@latest
103
+ npx @unbrained/pm-cli --help
36
104
  ```
37
105
 
38
- ### Project-local invocation
106
+ ## Quick Start
39
107
 
40
108
  ```bash
41
- npx @unbrained/pm-cli --help
109
+ pm init
110
+
111
+ pm create \
112
+ --title "Fix Windows restore failure after stale lock cleanup" \
113
+ --description "Restore can fail on Windows when a stale lock is cleaned up during retry." \
114
+ --type Issue \
115
+ --status open \
116
+ --priority 1 \
117
+ --tags "windows,locks,restore,release" \
118
+ --body "Users can reproduce this on Windows after an interrupted restore. Add retry logging and verify restore succeeds after stale lock cleanup." \
119
+ --deadline +3d \
120
+ --estimate 180 \
121
+ --acceptance-criteria "Restore succeeds after stale lock cleanup on Windows and regression coverage is added." \
122
+ --definition-of-ready "Owner, reproduction steps, and affected files are identified." \
123
+ --order 7 \
124
+ --goal "Release readiness" \
125
+ --objective "Stabilize restore under lock contention" \
126
+ --value "Reduces failed recovery workflows during real incidents" \
127
+ --impact "Fewer blocked releases and clearer operator recovery steps" \
128
+ --outcome "Restore completes reliably after stale lock cleanup" \
129
+ --why-now "The bug affects recovery flows and can block release work." \
130
+ --author "alex-maintainer" \
131
+ --message "Create restore failure issue with full metadata" \
132
+ --assignee "alex-maintainer" \
133
+ --parent "pm-release" \
134
+ --reviewer "sam-reviewer" \
135
+ --risk high \
136
+ --confidence medium \
137
+ --sprint "2026-W11" \
138
+ --release "v2026.3" \
139
+ --blocked-by "pm-locks" \
140
+ --blocked-reason "Need the lock cleanup refactor merged first" \
141
+ --unblock-note "Rebase once the lock cleanup patch lands" \
142
+ --reporter "qa-bot" \
143
+ --severity high \
144
+ --environment "windows-11 node-25 npm-global-install" \
145
+ --repro-steps "1) Interrupt restore after lock creation 2) Retry restore 3) Observe stale-lock cleanup fail on Windows" \
146
+ --resolution "Add a retry after stale-lock cleanup and log the recovery path" \
147
+ --expected-result "Restore retries cleanly and completes after stale-lock cleanup." \
148
+ --actual-result "Restore exits with a lock error after cleanup on Windows." \
149
+ --affected-version "2026.3.9" \
150
+ --fixed-version "2026.3.10" \
151
+ --component "core/locks" \
152
+ --regression true \
153
+ --customer-impact "Maintainers can be blocked from recovering work during release prep." \
154
+ --dep "id=pm-locks,kind=blocks,author=alex-maintainer,created_at=now" \
155
+ --comment "author=alex-maintainer,created_at=now,text=Initial triage confirms the Windows-only stale-lock recovery failure." \
156
+ --note "author=alex-maintainer,created_at=now,text=Investigate lock cleanup timing in the restore retry path." \
157
+ --learning "author=alex-maintainer,created_at=now,text=Windows file-handle timing needs a retry window after stale-lock cleanup." \
158
+ --file "path=src/core/lock/lock-store.ts,scope=project,note=likely stale-lock retry fix" \
159
+ --test "command=node scripts/run-tests.mjs test -- tests/integration/cli.integration.spec.ts,scope=project,timeout_seconds=900,note=restore lock regression coverage" \
160
+ --doc "path=docs/ARCHITECTURE.md,scope=project,note=lock and restore design context"
161
+
162
+ pm list-open --limit 10
163
+ pm claim <item-id>
42
164
  ```
43
165
 
44
- ### Installer scripts
166
+ From there, use `pm update`, `pm comments`, `pm notes`, `pm learnings`, `pm files`, `pm docs`, `pm test`, `pm search`, and `pm close` as work progresses.
167
+
168
+ Claim behavior note:
169
+
170
+ - `pm claim <ID>` can take over non-terminal items even when currently assigned to someone else.
171
+ - Use `--force` for claim/release only when overriding terminal-state or lock conflicts.
172
+ - For non-owner release handoffs that only clear assignee metadata, prefer `pm release <ID> --allow-audit-release --author <you>` before `--force`.
173
+ - For ownership-conflict mutations, `--force` is intended for coordinated PM audits, lead-maintainer metadata corrections, or explicit ownership handoff cleanup.
174
+ - `pm get <ID> --json` now includes `claim_state` with current assignee plus latest claim/release history context.
175
+ - `pm get <ID> --json` returns body at top-level key `body` (not `item.body`) alongside `item`, `linked`, and `claim_state`.
176
+
177
+ Create policy mode note:
178
+
179
+ - `pm create` defaults to strict required-option enforcement.
180
+ - Use `--create-mode progressive` for staged governance triage when you need to defer non-critical metadata/linkage fields without placeholder `none` entries.
45
181
 
46
182
  ```bash
47
- # Linux/macOS
48
- bash scripts/install.sh
183
+ pm create --title "Triage seed" --description "Capture scope first, enrich later" --type Task --create-mode progressive
184
+ ```
49
185
 
50
- # Windows PowerShell
51
- pwsh scripts/install.ps1
186
+ ## Reusable Create Templates
187
+
188
+ Use templates to save recurring create metadata (including repeatable seeds) and apply them with explicit override precedence:
189
+
190
+ Template names are positional arguments (`pm templates save <name>` / `pm templates show <name>`); `--name` is not a valid flag.
191
+
192
+ ```bash
193
+ pm templates save release-issue \
194
+ --type Issue \
195
+ --status open \
196
+ --priority 1 \
197
+ --tags "release,incident" \
198
+ --dep "id=pm-release,kind=related,created_at=now" \
199
+ --file "path=src/cli/main.ts,scope=project"
200
+
201
+ pm templates list
202
+ pm templates show release-issue --json
203
+
204
+ # Explicit flags override template defaults deterministically.
205
+ pm create \
206
+ --title "Follow-up issue" \
207
+ --description "Investigate release incident follow-up." \
208
+ --type Issue \
209
+ --template release-issue \
210
+ --status blocked
52
211
  ```
53
212
 
54
- Both installers are idempotent for update flows; rerun them to move to a newer version.
55
- Each installer verifies post-install CLI availability by resolving `pm` and running `pm --version` before reporting success.
56
- Installer default package target is `@unbrained/pm-cli`.
57
- Set `PM_CLI_PACKAGE` to override the package source when smoke-testing installer flows.
58
- Scoped package names such as `@scope/pkg` still honor `--version`, while literal specs (`file:`, URLs, local paths/tarballs, or already versioned package specs) are passed to npm unchanged.
213
+ ## Semantic Search Defaults (Ollama)
214
+
215
+ `pm search` now auto-enables semantic-capable defaults on hosts where local Ollama is installed, without requiring manual semantic provider/vector configuration in `settings.json`.
59
216
 
60
- One-line bootstrap patterns (use with normal script-review caution):
217
+ - Auto-defaults only apply when semantic settings are otherwise unset (no explicit `settings.search.provider`, `settings.vector_store.adapter`, `providers.*`, or `vector_store.*` semantic config).
218
+ - Resolved defaults are:
219
+ - embedding provider: Ollama (`http://localhost:11434`)
220
+ - embedding model: `PM_OLLAMA_MODEL` (if set), otherwise first model from `ollama list` (preferring names containing `embed`/`embedding`), otherwise `qwen3-embedding:0.6b`
221
+ - vector store: local LanceDB path `.agents/pm/search/lancedb/`
222
+ - Explicit user/project configuration always takes precedence over auto-defaults.
223
+ - If implicit auto-defaulted semantic execution fails at runtime, `pm search` falls back to keyword mode to avoid breaking existing users.
224
+ - Implicit hybrid auto-default execution now uses bounded semantic timeouts and adds deterministic fallback warnings (for example `search_implicit_semantic_fallback:timeout:using_keyword_mode`) when switching to keyword mode.
225
+ - For strict low-latency loops, use `--mode keyword` explicitly.
226
+ - Disable this behavior with `PM_DISABLE_OLLAMA_AUTO_DEFAULTS=1`.
227
+
228
+ To (re)build semantic artifacts explicitly:
61
229
 
62
230
  ```bash
63
- curl -fsSL https://raw.githubusercontent.com/unbraind/pm-cli/main/scripts/install.sh | bash
231
+ pm reindex --mode hybrid
64
232
  ```
65
233
 
66
- ```powershell
67
- # safer PowerShell flow: download, inspect, then execute
68
- Invoke-WebRequest -Uri "https://raw.githubusercontent.com/unbraind/pm-cli/main/scripts/install.ps1" -OutFile "install.ps1"
69
- pwsh -File .\install.ps1
234
+ ## Search Projection Modes
235
+
236
+ `pm search` now supports explicit projection controls and defaults to compact rows in both TOON and JSON output modes:
237
+
238
+ - default projection: compact (`id`, `title`, `status`, `type`, `priority`, `updated_at`, `score`, `matched_fields`)
239
+ - `--full`: return full hit rows (including nested `item` payload)
240
+ - `--fields <csv>`: return only specific fields (for example `--fields id,title,score,item.updated_at`)
241
+ - projection flags are mutually exclusive (`--compact`, `--full`, `--fields`)
242
+
243
+ Unquoted multi-word queries are accepted directly:
244
+
245
+ ```bash
246
+ pm search performance mobile gpu --limit 5
70
247
  ```
71
248
 
72
- During development in this repo:
249
+ ## Hierarchical List Filtering
250
+
251
+ All list-family commands now support parent-scoped filtering:
73
252
 
74
253
  ```bash
75
- pnpm install
76
- pnpm build
77
- node dist/cli.js --help
254
+ pm list-open --parent pm-epic01 --limit 20
255
+ pm list-in-progress --parent pm-feature02 --json
78
256
  ```
79
257
 
80
- ## Maintainer Bootstrap (Dogfooding Runs)
258
+ ## List Projection and Sorting
259
+
260
+ List-family commands support explicit projection and deterministic sort controls:
81
261
 
82
262
  ```bash
83
- # maintainer identity for mutation history
84
- export PM_AUTHOR="maintainer-agent"
263
+ # Compact default projection fields for list rows
264
+ pm list-open --compact --limit 20
85
265
 
86
- # refresh global pm from this repository and verify availability
87
- npm install -g .
88
- pm --version
266
+ # Custom projected fields
267
+ pm list-all --fields id,title,parent,type --limit 50
268
+
269
+ # Configurable sort field + order
270
+ pm list-open --sort deadline --order asc --limit 20
271
+ pm list-open --sort priority --order desc --limit 20
272
+ ```
273
+
274
+ Projection flags are mutually exclusive for list-family commands (`--compact`, `--fields`, `--include-body` remains additive for body projection).
275
+
276
+ ## Ownership-Safe Metadata Updates and Bulk Mutation
277
+
278
+ Governance workflows now include explicit non-owner metadata mutation and bulk update planning surfaces:
279
+
280
+ - `pm update --allow-audit-update` allows non-owner metadata updates without broad `--force` semantics.
281
+ - `--allow-audit-update` is intentionally scoped: lifecycle/ownership/linkage mutations remain disallowed in this mode (for example assignee/parent and other lifecycle-governing fields).
282
+ - `pm update --allow-audit-dep-update` enables non-owner append-only dependency additions via `--dep` without broad `--force` semantics.
283
+ - `--allow-audit-update` and `--allow-audit-dep-update` are mutually exclusive by design.
284
+ - `pm update-many` provides native bulk mutation with deterministic filter targeting, dry-run planning, optional checkpoint capture, and rollback.
285
+ - `pm update-many` supports linked-array payload parity with `pm update` (repeatable `--dep/--comment/--note/--learning/--file/--test/--doc/--reminder/--event` plus `--clear-*`, `--replace-deps`, and `--replace-tests`).
286
+ - `pm update-many --rollback <checkpoint-id>` restores every item in a prior checkpoint (ownership-safe restore path included).
287
+ - `pm normalize` provides deterministic lifecycle metadata hygiene with default dry-run planning and explicit `--apply` mode.
288
+ - `pm normalize` reuses list-style filter targeting (`--filter-status`, `--filter-type`, `--filter-tag`, assignee/parent/sprint/release, `--limit`, `--offset`) and supports ownership-safe apply controls (`--allow-audit-update`, `--force`).
89
289
 
90
- # choose invocation based on whether global pm resolves to this build
91
- export PM_CMD="pm"
92
- # export PM_CMD="node dist/cli.js"
290
+ ```bash
291
+ # Ownership-safe metadata audit update (non-owner, metadata-only scope)
292
+ pm update pm-a1b2 --description "Clarified acceptance boundaries" --allow-audit-update --author audit-maintainer
293
+
294
+ # Ownership-safe dependency-only audit update (append-only --dep)
295
+ pm update pm-a1b2 --dep "id=pm-epic01,kind=related,author=audit-maintainer,created_at=now" --allow-audit-dep-update --author audit-maintainer
296
+
297
+ # Bulk apply mode with deterministic targeting
298
+ pm update-many --filter-status open --filter-tag governance --status in_progress --author maintainer --message "Governance sweep"
299
+
300
+ # Bulk linked-test replacement across matched items (single transaction per item)
301
+ pm update-many --filter-tag wave:7 --replace-tests --test "command=node scripts/run-tests.mjs test -- tests/core/history.spec.ts,scope=project,timeout_seconds=240" --message "Normalize linked test assertions"
302
+
303
+ # Dry-run planning mode (no mutations)
304
+ pm update-many --filter-status in_progress --priority 1 --deadline +2d --dry-run --json
305
+
306
+ # Roll back a previously captured checkpoint
307
+ pm update-many --rollback 20260406T102455Z-7xq9 --author maintainer --message "Rollback governance batch"
93
308
 
94
- # verify command surface before mutation work
95
- $PM_CMD --version
96
- $PM_CMD --help
309
+ # Preview lifecycle metadata normalization plans (default mode is dry-run)
310
+ pm normalize --filter-status in_progress --dry-run --json
311
+
312
+ # Apply lifecycle metadata normalization with audit-safe ownership controls
313
+ pm normalize --filter-tag governance --apply --allow-audit-update --author maintainer --message "Normalize lifecycle metadata"
97
314
  ```
98
315
 
99
- Use repository-default tracking for maintainer runs (do not set `PM_PATH`).
100
- For test runs only, always use sandboxed paths via `node scripts/run-tests.mjs <test|coverage>` so both `PM_PATH` and `PM_GLOBAL_PATH` are isolated.
316
+ ## Duplicate and Decomposition Audits
101
317
 
102
- ## Quickstart
318
+ Governance workflows now have dedicated audit commands:
103
319
 
104
320
  ```bash
105
- # 1) initialize project tracker storage
106
- pm init
321
+ # Group child counts by parent/type for decomposition checks
322
+ pm aggregate --group-by parent,type --status open --json
107
323
 
108
- # 2) create work item
109
- pm create \
110
- --title "Implement restore command" \
111
- --description "Rebuild item state from history replay." \
112
- --type Task \
113
- --status open \
114
- --priority 1 \
115
- --tags "history,reliability" \
116
- --body "" \
117
- --deadline +1d \
118
- --estimate 90 \
119
- --acceptance-criteria "Restore reproduces canonical target bytes." \
120
- --author "steve" \
121
- --message "Seed restore task" \
122
- --assignee none \
123
- --dep "none" \
124
- --comment "author=steve,created_at=now,text=Seed restore workflow" \
125
- --note "author=steve,created_at=now,text=Implement replay and hash verification" \
126
- --learning "none" \
127
- --file "path=src/core/history/store.ts,scope=project,note=restore logic target" \
128
- --test "command=node scripts/run-tests.mjs test,scope=project,timeout_seconds=240,note=sandbox-safe regression" \
129
- --doc "path=PRD.md,scope=project,note=authoritative contract"
324
+ # Include rows that do not have a parent when grouping by parent
325
+ pm aggregate --group-by parent,type --include-unparented --json
326
+
327
+ # Group by operational triage dimensions
328
+ pm aggregate --group-by type,status --json
329
+
330
+ # Detect likely duplicates by exact title, fuzzy title, or parent-scoped title collisions
331
+ pm dedupe-audit --mode title_exact --limit 25 --json
332
+ pm dedupe-audit --mode title_fuzzy --threshold 0.75 --limit 25 --json
333
+ pm dedupe-audit --mode parent_scope --limit 25 --json
334
+ ```
130
335
 
131
- # 3) list open work
132
- pm list-open --limit 20
336
+ `pm aggregate --group-by` supports `parent,type,priority,status,assignee,tags,sprint,release`.
133
337
 
134
- # 4) claim ownership
135
- pm claim pm-a1b2
338
+ ## GC Safety Controls
136
339
 
137
- # 5) update + attach context
138
- pm update pm-a1b2 --status in_progress --acceptance-criteria "Exact replay by version/timestamp"
139
- pm files pm-a1b2 --add path=src/history.ts,scope=project
140
- pm test pm-a1b2 --add command="node scripts/run-tests.mjs test",scope=project,timeout_seconds=240
340
+ `pm gc` now supports no-side-effect previews and targeted cleanup scopes:
141
341
 
142
- # 6) close with evidence
143
- pm comments pm-a1b2 --add "Evidence: replay tests passed"
144
- pm close pm-a1b2 "Replay tests passed" --author "steve" --message "Close: replay tests passed"
342
+ ```bash
343
+ # Preview what would be removed (no deletes)
344
+ pm gc --dry-run --json
345
+
346
+ # Clean only index + embeddings cache artifacts
347
+ pm gc --scope index,embeddings --json
145
348
 
146
- # 7) release ownership
147
- pm release pm-a1b2
349
+ # Repeatable scope flags are also supported
350
+ pm gc --scope runtime --scope embeddings --json
148
351
  ```
149
352
 
150
- ## Storage Layout
353
+ `pm gc` output now includes `dry_run`, resolved `scope`, and `guidance` fields. When search artifacts are removed, guidance includes reindex recommendations.
354
+
355
+ ## Health Drift, Integrity, and Vectorization Checks
356
+
357
+ `pm health` includes deterministic checks for item/history integrity and semantic vector freshness:
358
+
359
+ - `directories`
360
+ - distinguishes required tracker directories from optional built-in item-type directories
361
+ - reports `missing_required` and `missing_optional` separately in check details
362
+ - treats missing optional built-in type directories (`events`, `reminders`, `milestones`, `meetings`) as informational by default
363
+ - supports `--strict-directories` to treat missing optional directories as health warnings/failures
364
+ - supports `--strict-exit` (alias `--fail-on-warn`) to return non-zero exit (`1`) when health warnings are present (`ok=false`)
365
+ - `integrity`
366
+ - scans item and history files for merge-conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`)
367
+ - reports invalid item parses and invalid JSONL lines in history streams with deterministic warning codes
368
+ - `history_drift`
369
+ - scans current items and compares each canonical item hash against the latest history `after_hash`
370
+ - reports missing history streams, unreadable/corrupt history streams, and hash mismatches
371
+ - `vectorization`
372
+ - compares current item `updated_at` values against a local vectorization ledger at `search/vectorization-status.json`
373
+ - identifies stale/missing vector entries and (by default) performs targeted semantic refresh for stale item IDs when semantic runtime is available
374
+ - avoids forcing a full rebuild (`pm reindex`) for routine health checks
375
+ - supports explicit refresh policy controls:
376
+ - `--check-only` / `--no-refresh` for read-only diagnostics
377
+ - `--refresh-vectors` to force refresh intent explicitly
378
+
379
+ The vectorization ledger is also refreshed during `pm reindex --mode semantic|hybrid` to keep health diagnostics aligned with the latest indexed corpus.
380
+
381
+ ## Standalone Validation Checks
382
+
383
+ `pm validate` provides a dedicated audit surface for project metadata quality and integrity checks:
384
+
385
+ - Runs all validation checks by default (`metadata`, `resolution`, `lifecycle`, `files`, `command_references`, `history_drift`).
386
+ - Runs linked-command PM reference checks by default (`command_references`) to catch stale `pm-<id>` references before execution-time failures.
387
+ - Supports scoped checks with `--check-metadata`, `--check-resolution`, `--check-lifecycle`, `--check-stale-blockers`, `--check-files`, `--check-command-references`, and `--check-history-drift`.
388
+ - `--check-metadata` supports `--metadata-profile core|strict|custom` for deterministic required-field policy selection.
389
+ - `--metadata-profile custom` reads `settings.validation.metadata_required_fields`; if the configured list is empty, validation falls back to core requirements and emits `validate_metadata_custom_profile_missing_required_fields:0`.
390
+ - `--check-lifecycle` audits active-item governance drift for terminal-parent lineage and closure-like metadata on non-terminal items.
391
+ - `--check-stale-blockers` adds optional blocker-consistency diagnostics to lifecycle checks, surfacing stale `blocked_by`/`blocked_reason` patterns without enabling those heuristics by default.
392
+ - Lifecycle-check details include effective closure/stale pattern lists and deterministic per-field pattern sources (`default` vs `settings`).
393
+ - `--check-files` supports `--scan-mode default|tracked-all|tracked-all-strict`; tracked modes use git-tracked candidates when available.
394
+ - `tracked-all` excludes PM internals by default for higher-signal orphaned results; pass `--include-pm-internals` for full internal-audit scans.
395
+ - `tracked-all-strict` forces full tracked coverage (including PM internals) and bypasses internal exclusion filtering.
396
+ - `tracked-all-strict` emits explicit strict-coverage visibility fields in file-check details (`strict_mode_forces_pm_internals`, `strict_mode_forces_pm_internals_notice`) and warning `validate_files_tracked_all_strict_forces_pm_internals` when internals were force-enabled.
397
+ - File-check details report filtered candidate counts (`candidate_total`, `candidate_scanned`) plus raw pre-filter counts (`candidate_total_raw`, `candidate_scanned_raw`), `pm_internal_excluded_count`, and structured `excluded_by_reason` summaries when paths are filtered.
398
+ - Command-reference details report referenced PM IDs and stale-reference rows; stale rows emit `validate_command_references_stale_pm_ids:<count>` warnings.
399
+ - Resolution-check details now include default remediation hint templates (`pm update <id> ...`) for missing `resolution`/`expected_result`/`actual_result` fields.
400
+ - `--strict-exit` (alias `--fail-on-warn`) returns non-zero exit (`1`) when validation warnings are present (`ok=false`).
401
+ - Returns deterministic TOON/JSON output suitable for review or automation pipelines.
402
+ - Output writers treat broken pipes (`EPIPE`) as expected shell behavior: stdout `EPIPE` exits successfully (for pipeline-friendly reads) while stderr `EPIPE` remains non-zero.
403
+
404
+ ## Missing History Stream Policy
405
+
406
+ `settings.history.missing_stream` controls behavior when an item's `history/<id>.jsonl` stream is missing:
407
+
408
+ - `auto_create` (default)
409
+ - missing streams for existing items are created automatically before history-touching command paths continue
410
+ - `strict_error`
411
+ - history-touching command paths fail with a deterministic error instead of creating missing streams
412
+
413
+ Configure policy with:
151
414
 
152
- Default root: `.agents/pm` (override with `PM_PATH` or `--path`)
153
- Global extension root: `~/.pm-cli` (override with `PM_GLOBAL_PATH`)
415
+ ```bash
416
+ pm config project set history-missing-stream-policy --policy auto_create
417
+ pm config project set history-missing-stream-policy --policy strict_error
418
+ pm config project get history-missing-stream-policy --json
419
+ ```
154
420
 
155
- ```text
156
- .agents/pm/
157
- settings.json
158
- epics/
159
- features/
160
- tasks/
161
- chores/
162
- issues/
163
- history/
164
- index/
165
- search/
166
- extensions/
167
- locks/
168
- ```
169
-
170
- ## Repository Structure
421
+ Policy enforcement applies to `pm history`, `pm activity`, `pm stats`, `pm health`, restore, and existing-item mutation paths.
171
422
 
172
- ```text
173
- src/
174
- cli/
175
- main.ts
176
- commands/
177
- core/
178
- fs/
179
- history/
180
- item/
181
- lock/
182
- output/
183
- store/
184
- types/
185
- tests/
186
- unit/
187
- integration/
188
- scripts/
189
- install.sh
190
- install.ps1
191
- run-tests.mjs
192
- docs/
193
- ARCHITECTURE.md
194
- EXTENSIONS.md
195
- .pi/
196
- extensions/
197
- pm-cli/
198
- .github/workflows/
199
- ci.yml
200
- nightly.yml
201
- ```
202
-
203
- ## Developer Docs
204
-
205
- - [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) — Internal architecture, source layout, mutation contract, history/restore, search, and testing.
206
- - [docs/EXTENSIONS.md](docs/EXTENSIONS.md) — Extension development guide: manifest format, API reference, hook lifecycle, built-in extensions.
207
- - [docs/RELEASING.md](docs/RELEASING.md) — Maintainer release runbook for calendar versioning, CI gates, npm publish, and GitHub Releases.
208
-
209
- ## Item File Format
210
-
211
- Each item is stored as `<id>.md` under the folder matching its type:
212
-
213
- - `Epic` -> `epics/`
214
- - `Feature` -> `features/`
215
- - `Task` -> `tasks/`
216
- - `Chore` -> `chores/`
217
- - `Issue` -> `issues/`
218
-
219
- Format:
220
-
221
- 1. JSON front-matter object (not YAML)
222
- 2. blank line
223
- 3. optional markdown body
224
-
225
- ## Commands
226
-
227
- ### Core (implemented in v0.1)
228
-
229
- - `pm init [PREFIX]`
230
- - `pm install pi [--project|--global]` (install bundled Pi extension to `<project-root>/.pi/extensions/pm-cli/index.ts`, where `project-root` is derived from `--path` when provided, otherwise current working directory; global scope uses `PI_CODING_AGENT_DIR/extensions/pm-cli/index.ts`)
231
- - `pm list` (excludes terminal statuses `closed`/`canceled` by default — the active working-set view), `pm list-all` (all statuses including terminal)
232
- - `pm list-draft`, `pm list-open`, `pm list-in-progress`, `pm list-blocked`, `pm list-closed`, `pm list-canceled`
233
- - `pm get <ID>`
234
- - `pm search <keywords>` (keyword + semantic + hybrid modes; `--include-linked` expands keyword/hybrid lexical scoring with linked content)
235
- - `pm search` shared filters enforce canonical values: `--type` must be `Epic|Feature|Task|Chore|Issue` and `--priority` must be an integer `0..4`
236
- - `pm search --limit 0` returns a deterministic empty result set (after mode/config validation) without embedding/vector query execution
237
- - `pm reindex` (keyword/semantic/hybrid cache artifact rebuild; semantic/hybrid perform provider embedding generation + vector upsert)
238
- - `pm history <ID>`, `pm activity [--limit]`
239
- - `pm restore <ID> <TIMESTAMP|VERSION>`
240
- - `pm config <project|global> set definition-of-done --criterion <text>`
241
- - `pm config <project|global> get definition-of-done`
242
- - `pm create`, `pm update <ID>`, `pm append <ID>`, `pm close <ID> <TEXT>`, `pm delete <ID>`
243
- - `pm claim <ID>`, `pm release <ID>`
244
- - `pm comments <ID>`
245
- - `pm files <ID>`, `pm test <ID>`, `pm docs <ID>`
246
- - `pm test-all`
247
- - `pm stats`
248
- - `pm health`
249
- - `pm gc`
250
- - `pm beads import [--file <path>]` (built-in Beads extension command, import-only)
251
- - `pm todos import [--folder <path>]` (built-in todos extension command)
252
- - `pm todos export [--folder <path>]` (built-in todos extension command)
253
- - `pm completion <bash|zsh|fish>` (generate shell tab-completion script)
254
- - extension-only command paths return not-found when no handler is registered, and generic failure when a matched handler throws; profile diagnostics include deterministic warning codes like `extension_command_handler_failed:<layer>:<name>:<command>`
255
- - extension command names are canonicalized (trimmed, lowercased, repeated internal whitespace collapsed) before registration and dispatch so equivalent command paths resolve deterministically
256
- - `pm test <ID> --add` rejects linked commands that invoke `pm test-all` (including global-flag and package-spec launcher forms like `pm --json test-all`, `npx @unbrained/pm-cli@latest --json test-all`, `pnpm dlx @unbrained/pm-cli@latest --json test-all`, and `npm exec -- @unbrained/pm-cli@latest --json test-all`) to prevent recursive orchestration
257
- - `pm test <ID> --run` skips legacy linked commands that invoke `pm test-all` (including global-flag and package-spec launcher forms such as `npx`, `pnpm dlx`, and `npm exec` launcher variants) and reports deterministic skip diagnostics
258
- - `pm test <ID> --add` rejects sandbox-unsafe test-runner commands (for example `pnpm test`, `pnpm test:coverage`, `npm test`, `npm run test`, `pnpm run test`, `yarn run test`, `bun run test`, `vitest`) unless they use `node scripts/run-tests.mjs ...` or explicitly set both `PM_PATH` and `PM_GLOBAL_PATH`; chained direct test-runner segments are validated independently, so each direct runner segment must be explicitly sandboxed
259
- - `pm test-all` deduplicates identical linked command/path entries per invocation (keyed by scope+normalized command or scope+path), reports duplicates as skipped, and uses the maximum `timeout_seconds` when duplicate keys disagree on timeout metadata
260
-
261
- ### `pm list` vs `pm list-all`
262
-
263
- - `pm list` — active working-set view: excludes `closed` and `canceled` items by default. Useful for day-to-day use to see what needs attention.
264
- - `pm list-all` — full inventory: includes all items regardless of status. Useful for auditing and historical review.
265
-
266
- Both commands accept the same filter flags; `pm list` applies the terminal-status exclusion before any other filters.
267
-
268
- ### `pm list` filters
269
-
270
- All `list*` commands accept these filter flags:
271
-
272
- - `--type <value>` — `Epic|Feature|Task|Chore|Issue`
273
- - `--tag <value>` — exact tag match (case-insensitive)
274
- - `--priority <value>` — integer `0..4`
275
- - `--deadline-before <value>` — ISO or relative deadline upper bound
276
- - `--deadline-after <value>` — ISO or relative deadline lower bound
277
- - `--assignee <value>` — exact match on `assignee` field; use `none` to filter for unassigned items
278
- - `--sprint <value>` — exact match on `sprint` field
279
- - `--release <value>` — exact match on `release` field
280
- - `--limit <n>` — max items returned
281
-
282
- ### Roadmap (post-v0.1 / partial areas)
283
-
284
- - semantic/hybrid search enhancements (advanced hybrid relevance tuning, incremental embedding refresh, adapter optimizations)
285
- - Pi agent extension advanced ergonomics (higher-level workflow presets and additional tooling integrations)
286
-
287
- ### Global flags
288
-
289
- - `--json` output JSON instead of TOON
290
- - `--quiet` suppress stdout (errors still on stderr)
291
- - `--path <dir>` override PM path for invocation
292
- - `--no-extensions` disable extension loading
293
- - `--profile` print timing diagnostics
294
- - `--version` print CLI version
295
-
296
- ### `pm create` explicit-field contract
297
-
298
- `pm create` accepts explicit flags for all schema fields (including optional ones) so callers can always pass complete intent:
299
-
300
- - required scalar flags:
301
- - `--title/-t`
302
- - `--description/-d` (explicit empty allowed)
303
- - `--type`
304
- - `--status/-s`
305
- - `--priority/-p` (`0..4`)
306
- - `--tags` (explicit empty allowed)
307
- - `--body/-b` (explicit empty allowed)
308
- - `--deadline` (ISO, relative, or none)
309
- - `--estimate/--estimated-minutes/--estimated_minutes` (supports `0`)
310
- - `--acceptance-criteria`, `--acceptance_criteria`, `--ac` (explicit empty allowed)
311
- - `--author` (fallbacks still exist, but explicit is recommended)
312
- - `--message`
313
- - `--assignee` (explicit; use `none` to clear)
314
- - optional scalar flags (use `none` to unset):
315
- - `--parent` (item ID reference)
316
- - `--reviewer`
317
- - `--risk` (`low|med|medium|high|critical`; `med` persists as `medium`)
318
- - `--confidence` (`0..100|low|med|medium|high`; `med` persists as `medium`)
319
- - `--sprint`
320
- - `--release`
321
- - `--blocked-by/--blocked_by` (item ID or free-text)
322
- - `--blocked-reason/--blocked_reason`
323
- - `--unblock-note/--unblock_note` (unblock rationale note)
324
- - `--reporter`
325
- - `--severity` (`low|med|medium|high|critical`; `med` persists as `medium`)
326
- - `--environment`
327
- - `--repro-steps/--repro_steps`
328
- - `--resolution`
329
- - `--expected-result/--expected_result`
330
- - `--actual-result/--actual_result`
331
- - `--affected-version/--affected_version`
332
- - `--fixed-version/--fixed_version`
333
- - `--component`
334
- - `--regression` (`true|false|1|0`)
335
- - `--customer-impact/--customer_impact`
336
- - `--definition-of-ready/--definition_of_ready` (explicit empty allowed)
337
- - `--order/--rank` (integer rank/order)
338
- - `--goal`
339
- - `--objective`
340
- - `--value`
341
- - `--impact`
342
- - `--outcome`
343
- - `--why-now/--why_now`
344
- - required repeatable seed flags (pass each at least once; use `none` for explicit empty intent):
345
- - `--dep`
346
- - `--comment`
347
- - `--note`
348
- - `--learning`
349
- - `--file`
350
- - `--test`
351
- - `--doc`
352
-
353
- Explicit unset behavior:
354
-
355
- - scalar `none` means unset/omit that optional field
356
- - repeatable seed value `none` means explicit empty list intent
357
- - explicit unset intent is recorded in mutation history message metadata
358
-
359
- ### `pm update` explicit-field contract
360
-
361
- `pm update <ID>` accepts explicit mutation flags for canonical front-matter fields:
362
-
363
- - `--title/-t`
364
- - `--description/-d`
365
- - `--status/-s` (supports non-terminal values and `canceled`; use `pm close <ID> <TEXT>` for closure)
366
- - `--priority/-p`
367
- - `--type`
368
- - `--tags`
369
- - `--deadline`
370
- - `--estimate/--estimated-minutes/--estimated_minutes`
371
- - `--acceptance-criteria`, `--acceptance_criteria`, `--ac`
372
- - `--assignee`
373
- - `--parent`
374
- - `--reviewer`
375
- - `--risk` (`low|med|medium|high|critical`; `med` persists as `medium`)
376
- - `--confidence` (`0..100|low|med|medium|high`; `med` persists as `medium`)
377
- - `--sprint`
378
- - `--release`
379
- - `--blocked-by/--blocked_by`
380
- - `--blocked-reason/--blocked_reason`
381
- - `--unblock-note/--unblock_note`
382
- - `--reporter`
383
- - `--severity` (`low|med|medium|high|critical`; `med` persists as `medium`)
384
- - `--environment`
385
- - `--repro-steps/--repro_steps`
386
- - `--resolution`
387
- - `--expected-result/--expected_result`
388
- - `--actual-result/--actual_result`
389
- - `--affected-version/--affected_version`
390
- - `--fixed-version/--fixed_version`
391
- - `--component`
392
- - `--regression` (`true|false|1|0`)
393
- - `--customer-impact/--customer_impact`
394
- - `--definition-of-ready/--definition_of_ready`
395
- - `--order/--rank`
396
- - `--goal`
397
- - `--objective`
398
- - `--value`
399
- - `--impact`
400
- - `--outcome`
401
- - `--why-now/--why_now`
402
- - `--author`
403
- - `--message`
404
- - `--force`
405
-
406
- ### Exit codes
407
-
408
- - `0` success
409
- - `1` generic failure
410
- - `2` invalid usage/arguments
411
- - `3` not found
412
- - `4` conflict (lock/claim)
413
- - `5` dependency failed (e.g. test-all failure)
414
-
415
- ## Output Modes
416
-
417
- Default output is TOON (token-efficient, deterministic).
418
- Use `--json` for machine pipelines expecting JSON.
423
+ ## Sprint/Release Format Policy
419
424
 
420
- Examples:
425
+ `settings.validation.sprint_release_format` controls `--sprint` and `--release` validation behavior during `pm create` and `pm update`:
426
+
427
+ - `warn` (default)
428
+ - accepts non-conforming values and emits deterministic warnings (`validation_warning:sprint_format:<value>` / `validation_warning:release_format:<value>`)
429
+ - `strict_error`
430
+ - rejects non-conforming values with a deterministic usage error
431
+
432
+ Accepted format for conforming values: 1-64 characters matching `[A-Za-z0-9][A-Za-z0-9._/-]*` (no spaces).
433
+
434
+ Configure policy with:
421
435
 
422
436
  ```bash
423
- pm list-open --limit 5
424
- pm list-open --limit 5 --json
425
- pm get pm-a1b2 --quiet; echo $?
437
+ pm config project set sprint-release-format-policy --policy warn
438
+ pm config project set sprint-release-format-policy --policy strict_error
439
+ pm config project get sprint-release-format-policy --json
426
440
  ```
427
441
 
428
- ## Configuration
442
+ ## Parent Reference Validation Policy
443
+
444
+ `settings.validation.parent_reference` controls how `--parent` behaves during `pm create` and `pm update` when the referenced parent item does not exist:
445
+
446
+ - `warn` (default)
447
+ - keeps backward-compatible behavior and emits `validation_warning:parent_reference_missing:<id>`
448
+ - `strict_error`
449
+ - rejects missing parent references with a deterministic usage error
450
+
451
+ Configure policy with:
452
+
453
+ ```bash
454
+ pm config project set parent-reference-policy --policy warn
455
+ pm config project set parent-reference-policy --policy strict_error
456
+ pm config project get parent-reference-policy --json
457
+ ```
429
458
 
430
- Primary config: `.agents/pm/settings.json`
459
+ ## Metadata Validation Profile Policy
431
460
 
432
- Typical keys:
461
+ `settings.validation.metadata_profile` controls default required-field behavior for `pm validate --check-metadata`:
433
462
 
434
- - `id_prefix`
435
- - `author_default`
436
- - `locks.ttl_seconds`
437
- - `output.default_format`
438
- - `workflow.definition_of_done`
439
- - `extensions.enabled / disabled`
440
- - `search.score_threshold`
441
- - `search.hybrid_semantic_weight`
442
- - `search.max_results`
443
- - `search.embedding_model`
444
- - `search.embedding_batch_size`
445
- - `search.scanner_max_batch_retries`
446
- - `search.tuning` (optional object)
447
- - provider + vector-store blocks
463
+ - `core` (default)
464
+ - requires baseline governance fields (`author`, `acceptance_criteria`, `estimated_minutes`, `close_reason` for closed items)
465
+ - `strict`
466
+ - extends core checks with additional governance fields (`reviewer`, `risk`, `confidence`, `sprint`, `release`)
467
+ - `custom`
468
+ - uses `settings.validation.metadata_required_fields` as the required field set (falls back to core + warning when empty)
448
469
 
449
- `search.score_threshold` defaults to `0` and applies mode-specific minimum-score filtering (`keyword` raw lexical score, `semantic` vector score, `hybrid` normalized blended score).
450
- `search.hybrid_semantic_weight` defaults to `0.7` and controls hybrid semantic-vs-lexical blending (`0..1`).
451
- `search.tuning` optionally overrides deterministic lexical weighting (`title_exact_bonus`, `title_weight`, `description_weight`, `tags_weight`, `status_weight`, `body_weight`, `comments_weight`, `notes_weight`, `learnings_weight`, `dependencies_weight`, `linked_content_weight`) for keyword mode and the hybrid lexical component; invalid/negative values fall back to defaults.
452
- `workflow.definition_of_done` defaults to `[]` and stores deterministic team-level close-readiness criteria strings. The baseline config command surface is:
470
+ Configure policy with:
453
471
 
454
472
  ```bash
455
- pm config project set definition-of-done \
456
- --criterion "tests pass" \
457
- --criterion "linked files/tests/docs present"
473
+ pm config project set metadata-validation-profile --policy core
474
+ pm config project set metadata-validation-profile --policy strict
475
+ pm config project set metadata-validation-profile --policy custom
476
+ pm config project get metadata-validation-profile --json
477
+ ```
478
+
479
+ Configure custom required fields with:
458
480
 
459
- pm config project get definition-of-done
460
- pm config global get definition-of-done --json
481
+ ```bash
482
+ pm config project set metadata-required-fields --criterion sprint --criterion release
483
+ pm config project set metadata-required-fields --clear-criteria
484
+ pm config project get metadata-required-fields --json
461
485
  ```
462
486
 
463
- ### Environment variables
487
+ ## Lifecycle Validation Pattern Policy
488
+
489
+ `settings.validation.lifecycle_*_patterns` controls default substring heuristics used by `pm validate --check-lifecycle` and optional stale blocker diagnostics (`--check-stale-blockers`):
464
490
 
465
- - `PM_PATH` - project storage override
466
- - `PM_GLOBAL_PATH` - global extension root override
467
- - `PM_AUTHOR` - default mutation author
491
+ - `settings.validation.lifecycle_stale_blocker_reason_patterns`
492
+ - stale blocker reason substrings matched when stale blocker checks are enabled
493
+ - `settings.validation.lifecycle_closure_like_blocked_reason_patterns`
494
+ - closure-like `blocked_reason` substrings flagged on active items
495
+ - `settings.validation.lifecycle_closure_like_resolution_patterns`
496
+ - closure-like `resolution` substrings flagged on active items
497
+ - `settings.validation.lifecycle_closure_like_actual_result_patterns`
498
+ - closure-like `actual_result` substrings flagged on active items
468
499
 
469
- Precedence:
500
+ Configure lifecycle patterns with:
470
501
 
471
- 1. CLI flags
472
- 2. env vars
473
- 3. settings.json
474
- 4. defaults
502
+ ```bash
503
+ pm config project set lifecycle-stale-blocker-reason-patterns --criterion "no active blocker"
504
+ pm config project set lifecycle-closure-like-blocked-reason-patterns --criterion "work is closed"
505
+ pm config project set lifecycle-closure-like-resolution-patterns --criterion "closed with implementation evidence"
506
+ pm config project set lifecycle-closure-like-actual-result-patterns --criterion "work completed"
507
+ pm config project set lifecycle-closure-like-resolution-patterns --clear-criteria
508
+ pm config project get lifecycle-stale-blocker-reason-patterns --json
509
+ ```
475
510
 
476
- ## Search and Extension System
511
+ ## Test Result Tracking Policy
477
512
 
478
- Keyword search is part of the implemented command surface, `pm search --include-linked` expands keyword scoring across readable linked docs/files/tests content while enforcing scope-root containment (`scope=project` and `scope=global` paths must stay within their allowed roots after both resolve-path and symlink-resolved-realpath checks; out-of-scope or realpath-escape paths are skipped), and `pm reindex` rebuilds deterministic keyword cache artifacts (`index/manifest.json` and `search/embeddings.jsonl`). Provider abstraction baseline is also in place for deterministic OpenAI/Ollama configuration resolution, request-target resolution (including OpenAI-compatible `base_url` normalization for root, `/v1`, and explicit `/embeddings` forms), provider-specific request payload/response normalization (including deterministic OpenAI data-entry index ordering), deterministic request-execution helper behavior, deterministic per-request normalized-input deduplication with output fan-out back to original input cardinality/order, and deterministic embedding cardinality validation (normalized input count must match returned vector count after dedupe expansion). Vector-store abstraction baseline is also in place for deterministic Qdrant/LanceDB configuration resolution, request-target planning, request payload/response normalization, deterministic Qdrant request-execution helper behavior, deterministic LanceDB local query/upsert/delete helper behavior, deterministic local snapshot persistence + reload across process boundaries, and deterministic query-hit ordering normalization (score descending with id ascending tie-break).
513
+ `settings.testing.record_results_to_items` controls whether `pm test --run` / `pm test-all` append bounded `test_runs` summaries to item front matter:
479
514
 
480
- Command-path semantic/hybrid baseline is now implemented: `pm reindex --mode semantic|hybrid` generates provider embeddings for canonical item corpus records and upserts vectors to the active store, while `pm search --mode semantic|hybrid` executes vector-query ranking with deterministic hybrid lexical+semantic blending in hybrid mode. Semantic embedding generation runs in deterministic batches using `settings.search.embedding_batch_size`, and each embedding batch retries failures up to `settings.search.scanner_max_batch_retries` before surfacing deterministic warnings/errors. Keyword/hybrid lexical scoring includes a deterministic exact-title token boost (full-token title matches receive additive lexical bonus weight) plus configurable multi-factor lexical tuning through `settings.search.tuning` (`title_exact_bonus`, `title_weight`, `description_weight`, `tags_weight`, `status_weight`, `body_weight`, `comments_weight`, `notes_weight`, `learnings_weight`, `dependencies_weight`, `linked_content_weight`; invalid/negative values fall back to defaults). Search scoring also honors `settings.search.score_threshold` as a mode-aware minimum score filter (`keyword` raw lexical score, `semantic` vector score, `hybrid` normalized blended score), and hybrid blending weight is configurable with `settings.search.hybrid_semantic_weight` (`0..1`, default `0.7`). Successful item-mutation command paths now invalidate stale keyword cache artifacts (`index/manifest.json` and `search/embeddings.jsonl`) and perform best-effort semantic embedding refresh for affected item IDs when embedding-provider and vector-store configuration are available; missing/deleted affected IDs trigger best-effort vector pruning from the active store. Refresh failures degrade to deterministic warnings. Broader advanced semantic/hybrid relevance tuning remains roadmap work.
515
+ - `disabled` (default)
516
+ - test execution output is returned in command results only
517
+ - `enabled`
518
+ - successful/failed runs append deterministic item-level `test_runs` summary entries (bounded history retention)
481
519
 
482
- Built-in extension command handlers now provide import/export adapters: `pm beads import [--file <path>]` (import-only) ingests Beads JSONL records into PM items with deterministic defaults and `op: "import"` history entries, while `pm todos import|export [--folder <path>]` maps todos markdown files (JSON front-matter + body) to and from PM items using deterministic defaults for missing PM fields, preserves explicit imported IDs verbatim including hierarchical suffixes such as `pm-legacy.1.2`, and preserves canonical optional `ItemFrontMatter` metadata when present, including planning/workflow fields (`definition_of_ready`, `order`, `goal`, `objective`, `value`, `impact`, `outcome`, `why_now`, `reviewer`, `risk`, `confidence`, `sprint`, `release`, `blocked_by`, `blocked_reason`, `unblock_note`) and issue fields (`reporter`, `severity`, `environment`, `repro_steps`, `resolution`, `expected_result`, `actual_result`, `affected_version`, `fixed_version`, `component`, `regression`, `customer_impact`). `confidence`, `risk`, and `severity` aliases normalize deterministically (`med` -> `medium`). The Pi integration contract is provided as a Pi agent extension module at `.pi/extensions/pm-cli/index.ts`, which registers a `pm` tool for action-based invocations and returns `content` + `details` envelopes. Current Pi wrapper action coverage includes the v0.1 command-aligned set (`init`, `config`, `create`, `list`, `list-all`, `list-draft`, `list-open`, `list-in-progress`, `list-blocked`, `list-closed`, `list-canceled`, `get`, `search`, `reindex`, `history`, `activity`, `restore`, `update`, `close`, `delete`, `append`, `comments`, `files`, `docs`, `test`, `test-all`, `stats`, `health`, `gc`, `completion`, `claim`, `release`) plus extension aliases (`beads-import`, `todos-import`, `todos-export`) and workflow presets (`start-task`, `pause-task`, `close-task`). For create/update parity, the wrapper accepts camelCase counterparts for the canonical CLI scalar metadata surface, completion parity field `shell` (`action=completion` -> `pm completion <shell>`), workflow/planning fields (`parent`, `reviewer`, `risk`, `confidence`, `sprint`, `release`, `blockedBy`, `blockedReason`, `unblockNote`, `definitionOfReady`, `order`, `goal`, `objective`, `value`, `impact`, `outcome`, `whyNow`) and issue fields (`reporter`, `severity`, `environment`, `reproSteps`, `resolution`, `expectedResult`, `actualResult`, `affectedVersion`, `fixedVersion`, `component`, `regression`, `customerImpact`), and forwards them deterministically to the corresponding `pm create`/`pm update` flags. Runtime extension loading includes deterministic manifest discovery, settings-aware enable/disable filtering, global-to-project precedence, extension-entry sandbox enforcement (entry paths and resolved symlink targets must remain inside their extension directory), and failure-isolated imports. `pm health` extension checks run the same load/activation probe used at runtime, including enabled built-in extensions, and surface deterministic diagnostics for manifest/entry warnings plus load and activation failures (for example `extension_entry_outside_extension:<layer>:<name>`, `extension_load_failed:<layer>:<name>`, and `extension_activate_failed:<layer>:<name>`).
520
+ Configure policy with:
483
521
 
484
- Hook lifecycle baseline includes `activate(api)` registration with deterministic ordering, registration-time hook handler validation (non-function payloads fail extension activation deterministically), per-hook context snapshot isolation so hook-side mutation cannot leak across callbacks or back into caller state, command-lifecycle `beforeCommand`/`afterCommand` execution with failure containment (including `afterCommand` dispatch on failed commands with `ok=false` and error context), and runtime read/write/index hook dispatch for core item-store reads/writes, create/restore item and history writes, settings read/write operations, history/activity history-directory scans and history-stream reads, health history-directory scans plus history-stream path dispatch, search item/linked reads, reindex flows, stats/health/gc command file-system paths (including `pm gc` onIndex dispatch with mode `gc` and deterministic cache-target totals), lock file read/write/unlink operations, init directory bootstrap ensure-write dispatch, and built-in beads/todos import-export source/item/history file operations.
522
+ ```bash
523
+ pm config project set test-result-tracking --policy enabled
524
+ pm config project set test-result-tracking --policy disabled
525
+ pm config project get test-result-tracking --json
526
+ ```
485
527
 
486
- Extension API baseline now includes deterministic command result override registration for existing core commands, command-handler registration for declared command paths (including built-in `beads import` and `todos import|export` paths plus extension-defined non-core command paths surfaced at runtime), command-handler execution with cloned `args`/`options`/`global` snapshots to prevent mutation leakage back into caller command state, command-override execution with cloned command `args`/`options`/`global` snapshots plus `pm_root` metadata and isolated prior-result snapshots, renderer execution with the same cloned command-context snapshots plus isolated result snapshots, renderer override registration for `toon`/`json` output formatting with safe fallback to built-in rendering on failures, and registration-time validation plus metadata capture for `registerFlags`, `registerItemFields`, `registerMigration`, `registerImporter`, `registerExporter`, `registerSearchProvider`, and `registerVectorStoreAdapter`. `registerImporter`/`registerExporter` registrations now also wire deterministic extension command-handler paths `<name> import` and `<name> export` (canonicalized with trim + lowercase + internal-whitespace collapse), and those handlers execute with the same isolated command-context snapshots as explicit `registerCommand` handlers. Dynamically surfaced extension command paths now include deterministic help sections derived from `registerFlags` metadata while preserving loose option parsing for runtime dispatch, with parser hardening that ignores unsafe prototype keys (`__proto__`, `constructor`, `prototype`) and uses null-prototype option maps before handing parsed options to extension handlers. Extension API and hook registration calls now enforce manifest capability declarations (`commands`, `renderers`, `hooks`, `schema`, `importers`, `search`) and fail activation deterministically when registrations exceed declared capabilities. Unknown capability names are ignored for registration gating and emit deterministic discovery diagnostics `extension_capability_unknown:<layer>:<name>:<capability>`. Activation diagnostics now include deterministic registration summaries for these registries, and health diagnostics include deterministic migration status summaries derived from registered migration definitions (`status=\"failed\"` -> failed, `status=\"applied\"` -> applied, otherwise pending). Core write command paths now enforce deterministic mandatory-migration blocking when registered migration definitions declare `mandatory=true` and status is not `applied` (case-insensitive), with explicit `--force` bypass support on force-capable write commands. Broader runtime wiring for other newly registered definitions remains tracked in `PRD.md`.
528
+ ## Telemetry Tracking Policy and First-Run Consent
487
529
 
488
- ## Pi Agent Extension
530
+ `settings.telemetry.enabled` controls whether command telemetry is exported to the configured ingestion endpoint.
489
531
 
490
- `pm-cli` ships a Pi agent extension source module at `.pi/extensions/pm-cli/index.ts`.
532
+ - default: `enabled`
533
+ - opt-out: `disabled`
534
+ - first-run prompt:
535
+ - interactive TTY only
536
+ - skipped for non-interactive/CI and JSON-oriented automation paths
537
+ - persisted in global settings
491
538
 
492
- Install it via `pm` (recommended):
539
+ Configure policy with:
493
540
 
494
541
  ```bash
495
- # current project scope (default)
496
- pm install pi
542
+ pm config global set telemetry-tracking --policy enabled
543
+ pm config global set telemetry-tracking --policy disabled
544
+ pm config global get telemetry-tracking --json
545
+ ```
497
546
 
498
- # explicit project scope
499
- pm install pi --project
547
+ ### Telemetry payload version and source context
500
548
 
501
- # global Pi scope (~/.pi/agent unless PI_CODING_AGENT_DIR is set)
502
- pm install pi --global
549
+ Command lifecycle telemetry now includes additive payload metadata for segmentation:
550
+
551
+ - `pm_version` - CLI version resolved at runtime.
552
+ - `source_context` - privacy-safe source bucket (`user`, `automation`, `test`, `dogfood`, `audit_smoke`).
553
+ - `source_context_source` - classification provenance (`inferred` or `env_override`).
554
+
555
+ Default inference classifies non-interactive/CI/json runs as `automation`, test runtimes as `test`, and interactive sessions as `user`.
556
+
557
+ For explicit dogfood/audit attribution, override source context with:
558
+
559
+ ```bash
560
+ PM_TELEMETRY_SOURCE_CONTEXT=dogfood pm list-open
561
+ PM_TELEMETRY_SOURCE_CONTEXT=audit_smoke pm context --limit 10
503
562
  ```
504
563
 
505
- Load it in Pi:
564
+ ### Optional local OTEL trace export
565
+
566
+ `pm` can additionally emit one OTLP trace span per command to a local (or custom) collector endpoint:
567
+
568
+ - `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://127.0.0.1:4318/v1/traces`
569
+ - or `OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318` (auto-appends `/v1/traces`)
570
+ - optional service name override: `OTEL_SERVICE_NAME=pm-cli`
571
+ - disable this OTEL side-channel explicitly with `PM_TELEMETRY_OTEL_DISABLED=1`
572
+
573
+ Example:
506
574
 
507
575
  ```bash
508
- pi -e ./.pi/extensions/pm-cli/index.ts
576
+ OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318 OTEL_SERVICE_NAME=pm-cli node dist/cli.js list-open
509
577
  ```
510
578
 
511
- Or place/copy it into a Pi auto-discovery folder such as `.pi/extensions/`.
579
+ ## Config Discovery and Snapshot Export
512
580
 
513
- The extension registers one tool, `pm`, with action-based parameters and returns:
581
+ `pm config` also supports read-only key discovery and one-shot snapshot export for integration workflows:
514
582
 
515
- - `content: [{ type: "text", text: "..." }]`
516
- - `details: { ... }`
583
+ ```bash
584
+ pm config project list --json
585
+ pm config project export --json
586
+ ```
517
587
 
518
- For search parity, wrapper parameters support `includeLinked` and map it to `pm search --include-linked`.
519
- For project tracking access in Pi TUI, run Pi from the project root (so `pm` resolves the repo `.agents/pm`), or pass wrapper `path` to target another PM store.
520
- For command-shape parity, explicit empty-string values are forwarded for empty-allowed flags (for example `--description ""` and `--body ""`) instead of being dropped.
521
- For numeric-flag parity, wrapper parameters accept either JSON numbers or strings for `priority`, `estimate`, `limit`, and `timeout`, and stringify them before CLI invocation.
522
- For claim/release parity, wrapper parameters `author`, `message`, and `force` are forwarded to `pm claim|release --author/--message/--force`.
523
- For packaging resilience (implemented), the wrapper attempts `pm` first and falls back to `node <package-root>/dist/cli.js` when `pm` is unavailable.
588
+ - `list` returns key metadata (`key`, aliases, value kind, applicable set flags, summary) plus current resolved values.
589
+ - `export` returns the resolved config value object in one payload for deterministic machine consumption.
524
590
 
525
- ## Shell Completion
591
+ ## History Diff and Verify
526
592
 
527
- `pm` supports tab-completion for bash, zsh, and fish shells.
593
+ `pm history` now supports additive diagnostics:
528
594
 
529
- ### Bash
595
+ ```bash
596
+ # Include changed-field summaries derived from RFC6902 patches
597
+ pm history pm-a1b2 --diff
598
+
599
+ # Verify before/after hash replay chain and current item hash alignment
600
+ pm history pm-a1b2 --verify --json
601
+ ```
602
+
603
+ `pm restore` also supports history-only recovery when an item file is missing or deleted but its history stream still exists.
604
+
605
+ ## Activity Timeline Filters and Streaming
606
+
607
+ `pm activity` now supports deterministic timeline slicing plus JSON line streaming for downstream automation:
608
+
609
+ - Filters: `--id`, `--op`, `--author`, `--from`, `--to`, `--limit`
610
+ - Time bounds accept ISO/date/relative inputs (`--from -7d --to now`, etc.)
611
+ - `--stream` is JSON-only and emits line-delimited payloads (`rows`, `ndjson`, `jsonl`)
612
+ - boolean-style stream enablement is accepted (`--stream`, `--stream true`, `--stream 1`)
530
613
 
531
614
  ```bash
532
- # Add to ~/.bashrc or ~/.bash_profile
533
- eval "$(pm completion bash)"
615
+ pm activity --id pm-a1b2 --op update --author codex-agent --from -7d --to now --limit 100
616
+ pm activity --json --stream rows --from -1d --limit 200
534
617
  ```
535
618
 
536
- ### Zsh
619
+ ## Deadline and Date Inputs
620
+
621
+ - Date/time inputs used by `--deadline`, `--deadline-before`, `--deadline-after`, calendar `--date/--from/--to`, reminders, and events accept:
622
+ - ISO timestamps
623
+ - Flexible date strings (for example `2026-03-31T13-59`, `20260331`, `20260331T135900Z`)
624
+ - Relative offsets (`+6h`, `+1d`, `+2w`, `+6m`)
625
+ - Accepted values are normalized to canonical ISO timestamps for deterministic storage and filtering.
626
+ - Parse failures now report the precise field context (for example `event.end`, `reminder.at`, `--from`, `deadline-before`) for faster remediation.
627
+ - Compound relative expressions such as `+3d+1h` are rejected; use a single relative token (`+3d`) or an ISO/date string.
628
+
629
+ ## Status Values
630
+
631
+ - Canonical status values are: `draft`, `open`, `in_progress`, `blocked`, `closed`, `canceled`.
632
+ - Status input flags also accept `in-progress` as an alias for `in_progress` (`pm create`, `pm update`, `pm calendar`, and `pm test-all`).
633
+ - Persisted item data and command output remain canonical (`in_progress`) for deterministic storage and filtering.
634
+ - `pm update --close-reason <text>` sets `close_reason` explicitly; `pm update --unset close-reason` clears it.
635
+ - When `pm update --status` reopens an item from `closed` to a non-terminal status, stale `close_reason` is auto-cleared unless `--close-reason` is explicitly provided in that update call.
636
+
637
+ Task lifecycle aliases provide discoverable one-step workflows:
638
+
639
+ - `pm start-task <id>`: claim + move to `in_progress`
640
+ - `pm pause-task <id>`: move to `open` + release claim
641
+ - `pm close-task <id> "<reason>"`: close + release claim metadata
642
+
643
+ These aliases preserve canonical mutation history entries and accept standard mutation controls (`--author`, `--message`, `--force`; `close-task` also accepts `--validate-close`).
644
+
645
+ ## Resilient Entry Input Formats
646
+
647
+ Entry-style flags (`--add`, `--remove`, and repeatable create/update seed flags like `--comment`, `--file`, `--test`, `--doc`, `--reminder`, `--event`, `--type-option`) now accept three deterministic forms:
648
+
649
+ - CSV key/value: `key=value,key2=value2`
650
+ - Markdown-style key/value: `key: value` (single line, bullets, or multiline blocks)
651
+ - Stdin token: pass `-` and pipe payload into the command
652
+
653
+ Examples:
537
654
 
538
655
  ```bash
539
- # Add to ~/.zshrc
540
- eval "$(pm completion zsh)"
656
+ # Files/docs/tests add supports markdown-style key:value
657
+ pm files pm-a1b2 --add "path: src/cli/main.ts,scope: project,note: cli wiring"
658
+ pm docs pm-a1b2 --add $'- path: README.md\n- scope: project\n- note: docs sync'
659
+ pm test pm-a1b2 --add $'command: node scripts/run-tests.mjs test\nscope: project\ntimeout_seconds: 240'
660
+
661
+ # Linked-path hygiene for files/docs (bulk migrate + optional validation/audit)
662
+ pm files pm-a1b2 --add-glob "src/**/*.ts"
663
+ pm docs pm-a1b2 --add-glob "pattern=docs/**/*.md,scope=project,note=docs sweep"
664
+ pm files pm-a1b2 --migrate "from=src/old/,to=src/new/" --validate-paths --audit
665
+ pm docs pm-a1b2 --migrate "from=docs/legacy/,to=docs/current/" --validate-paths --audit
666
+ pm files pm-a1b2 --add "path=src/new/entry.ts,scope=project" --append-stable
667
+
668
+ # Discover file paths mentioned in item text before adding them as links
669
+ pm files discover pm-a1b2
670
+ pm files discover pm-a1b2 --apply --note "discovered from item text"
671
+
672
+ # Comments can be added positionally or with --add
673
+ pm comments pm-a1b2 "captured from shorthand positional text"
674
+ pm comments pm-a1b2 --add "text: captured from markdown formatter"
675
+ pm comments pm-a1b2 --add "handoff note from alternate author" --author "alex-maintainer" --force
676
+ pm comments pm-a1b2 --add "audit note from governance review" --author "audit-maintainer" --allow-audit-comment
677
+
678
+ # Notes and learnings support the same positional/--add shorthand
679
+ pm notes pm-a1b2 "implementation context captured from shorthand positional text"
680
+ pm notes pm-a1b2 --add "text: parser fallback rationale"
681
+ pm notes pm-a1b2 --add "audit note from governance review" --author "audit-maintainer" --allow-audit-comment
682
+ pm learnings pm-a1b2 --add "text: always run linked tests through the sandbox runner"
683
+ pm learnings pm-a1b2 --add "audit learning from governance review" --author "audit-maintainer" --allow-audit-comment
684
+
685
+ # CSV-like key fragments remain plain text unless text is explicit
686
+ pm comments pm-a1b2 --add "text=hello,scope:project" # plain-text fallback
687
+ pm comments pm-a1b2 --add 'text="hello,scope:project"' # explicit structured text field
688
+ pm notes pm-a1b2 --add "text: hello,scope:project" # markdown structured form
689
+
690
+ # Pipe markdown payload via stdin with "-"
691
+ printf '%s\n' 'path: docs/ARCHITECTURE.md' 'scope: project' 'note: piped update' | pm files pm-a1b2 --add -
692
+ printf '%s\n' 'text: evidence from piped stdin' | pm comments pm-a1b2 --add -
693
+ printf '%s\n' 'text: implementation note from piped stdin' | pm notes pm-a1b2 --add -
694
+ printf '%s\n' 'text: learning captured from piped stdin' | pm learnings pm-a1b2 --add -
695
+ printf '%s\n' 'at: +1d' 'text: reminder from piped stdin' | pm update pm-a1b2 --reminder -
696
+ printf '%s\n' 'Backfilled body from stdin token' | pm update pm-a1b2 --body -
697
+ pm update pm-a1b2 --dep "id=pm-b3c4,kind=blocks,author=alex-maintainer,created_at=now"
698
+ pm update pm-a1b2 --dep-remove "pm-b3c4"
699
+ pm update pm-a1b2 --replace-deps --dep "id=pm-c7d8,kind=related,author=alex-maintainer,created_at=now"
700
+ pm update pm-a1b2 --clear-deps
701
+ pm deps pm-a1b2 --format tree
702
+ pm deps pm-a1b2 --format graph --json
703
+
704
+ # Bulk governance snapshots for latest comments across matching items
705
+ pm comments-audit --status in_progress --parent pm-epic01 --tag governance --latest 1 --limit 20 --json
706
+
707
+ # Full-history export rows for NDJSON-friendly downstream processing
708
+ pm comments-audit --status in_progress --sprint sprint-12 --release v0.2 --priority 1 --full-history --limit 20 --json
709
+
710
+ # Summary-only item rows (no comment rows) for scoped inventory checks
711
+ pm comments-audit --status in_progress --latest 0 --limit-items 20 --json
541
712
  ```
542
713
 
543
- ### Fish
714
+ `pm comments-audit --latest` and `--full-history` are intentionally mutually exclusive. `--latest 0` is valid and returns deterministic summary rows with `export.row_count = 0`. `--limit` is an alias for `--limit-items` (both remain supported). All modes now include additive top-level `summary` metrics (`totals`, coverage ratio/percent, and `by_type` breakdown) without changing existing `items`/`filters`/`export` payloads.
715
+
716
+ Use explicit clear flags for repeatable fields (`--clear-files`, `--clear-comments`, `--clear-docs`, etc.) and `--unset <field>` for scalar clears.
717
+
718
+ For `pm create` log-seed flags, `--comment` accepts plain-text shorthand (`--comment "triage note"`) in addition to structured forms. Structured `--comment`/`--note`/`--learning` payloads accept only `author`, `created_at`, and `text` keys. Ambiguous unquoted payloads that introduce extra parsed keys (for example `text=hello,scope:project`) are rejected to prevent silent text truncation. Use quoted text (`text="hello,scope:project"`), markdown-style key/value input, or stdin token `-` for punctuation-heavy text.
719
+
720
+ ## Linked Artifact and Test Policy
721
+
722
+ - Use dedicated linked-artifact commands for file/doc mutations:
723
+ - `pm files <ID> --add/--add-glob/--remove`
724
+ - `pm docs <ID> --add/--add-glob/--remove`
725
+ - Use `pm update <ID> --body <value>` to replace an item's body content (including empty-string backfills); use `pm append <ID> --body <value>` for additive narrative updates.
726
+ - Dependency links on existing items are now mutated through `pm update` (`--dep` to add entries, `--clear-deps` to clear all, `--replace-deps` for one-shot atomic replacement, and `--dep-remove`/`--dep_remove` to remove selectors).
727
+ - Use `pm deps <ID> --format tree|graph` for deterministic read-only dependency visualization.
728
+ - `pm update` supports transactional linked mutations in one lock/history operation via repeatable `--comment`, `--note`, `--learning`, `--file`, `--test`, and `--doc` flags.
729
+ - Dedicated commands (`pm comments|notes|learnings|files|test|docs`) remain available for focused single-surface edits.
730
+ - `pm test <ID> --add` intentionally enforces sandbox-safe, runnable command entries. Every new linked test must include `command=...`; optional `path=...` is metadata-only context.
731
+ - `pm create --test` follows the same policy: `command=...` is required, optional `path=...` can annotate command scope.
732
+ - Linked test entries also support optional per-entry runtime directives/assertions plus context override metadata: `env_set=KEY=VALUE;KEY2=VALUE2`, `env_clear=KEY1;KEY2`, `shared_host_safe=true|false`, `pm_context_mode=schema|tracker|auto`, `assert_stdout_contains=...`, `assert_stdout_regex=...`, `assert_stderr_contains=...`, `assert_stderr_regex=...`, `assert_stdout_min_lines=<int>`, `assert_json_field_equals=path=value`, `assert_json_field_gte=path=<number>`.
733
+ - `pm test <ID> --run` / `pm test-all` execute in temporary sandbox roots but seed project/global `settings.json` and `extensions/` directories from source roots so extension-defined type behavior matches direct workspace commands.
734
+ - `pm test <ID> --run` / `pm test-all` support additive run-level runtime controls: repeatable `--env-set KEY=VALUE`, repeatable `--env-clear NAME`, `--shared-host-safe` (ephemeral/shared-host-friendly defaults such as `PORT=0` when unset), `--pm-context schema|tracker|auto`, `--override-linked-pm-context` (force run-level context over per-test `pm_context_mode`), `--check-context`, `--auto-pm-context`, `--fail-on-context-mismatch`, `--fail-on-skipped`, `--fail-on-empty-test-run`, and `--require-assertions-for-pm`.
735
+ - `pm test-all` supports blast-radius pagination with `--limit` and `--offset` before linked-test execution.
736
+ - `pm test <ID> --run --background` and `pm test-all --background` start managed background runs and return run metadata immediately.
737
+ - `pm test-runs` (no subcommand) defaults to `list` output; `pm test-runs list|status|logs|stop|resume` provides explicit background lifecycle management, log tailing, health snapshots, and stop/resume controls.
738
+ - Background run dedupe prevents parallel duplicate execution when an equivalent active run fingerprint already exists.
739
+ - Background run metadata resolves `requested_by` deterministically through: explicit author -> `PM_AUTHOR` -> settings `author_default` -> `USER`/`LOGNAME`/`USERNAME` -> OS username (`whoami`) -> `unknown`.
740
+ - Linked-test `run_results` include `execution_context` metadata (context mode, PM roots, item counts, mismatch signal, extension seeding state, PM tracker-read classification, `requested_pm_context_mode`, and `auto_pm_context_applied`) so PM-command parity is explicit in machine-readable output.
741
+ - With `--check-context`, run warnings include a `context_preflight:...` summary (`checked_pm_commands`, `tracker_read_commands`, `mismatches`, `auto_remediated`) for deterministic diagnostics before/around linked execution.
742
+ - In default `--pm-context schema` mode, PM tracker-read linked commands (for example `list*`, `get`, `search`, `stats`, `test-all`) fail on dataset mismatch by default; use `--pm-context auto` for automatic tracker-read routing or `--pm-context tracker` for full tracker-mode execution.
743
+ - If run-level `--pm-context tracker` is set but a linked test entry pins `pm_context_mode=schema`, mismatch diagnostics explicitly call out per-test override precedence and recommend either changing/removing per-test metadata or passing `--override-linked-pm-context` to force run-level precedence.
744
+ - `pm test <ID> --run` and `pm test-all` emit heartbeat/progress lines to stderr in interactive terminals during long-running linked commands, and support explicit non-interactive progress output via `--progress`.
745
+ - Linked test timeout handling uses deterministic process termination (including force-kill fallback) and reports explicit timeout/maxBuffer diagnostics in `run_results`.
746
+ - Failed linked test `run_results` now include `failure_category` (for example `infra_collision` vs `assertion_failure`) and `pm test-all` totals include aggregated `failure_categories` counts for triage.
747
+ - `pm test <ID> --run` now returns dependency-failed exit code (`5`) when any linked test run result fails (matching `pm test-all` failure gating behavior).
748
+ - `pm list` / `pm list-*` return front-matter rows by default; `pm list` and `pm list-all` also accept `--status <value>` for status-specific filtering without switching subcommands. Pass `--compact` or `--fields <csv>` for projection control, `--sort <field> --order <asc|desc>` for deterministic ordering, `--include-body` when body projection is needed, `--offset <n>` for pagination, and `--stream` (with `--json`) for newline-delimited item streaming.
749
+
750
+ ## Terminal Compatibility
751
+
752
+ `pm` is intentionally terminal-neutral so it works in native shells, IDE-integrated terminals, and emulated PTY backends:
753
+
754
+ - Output is plain deterministic TOON/JSON/markdown text (no required terminal-specific OSC/ANSI control protocol).
755
+ - Error exits preserve deterministic exit-code mapping while using graceful `process.exitCode` behavior.
756
+ - Help invocations suppress pager hangs in non-interactive contexts by auto-disabling paging when stdout is not a TTY; use global `--no-pager` for explicit suppression in any context.
757
+ - Stdin token entry (`-`) requires piped stdin when invoked from an interactive TTY.
758
+ - `pm beads import --file -` follows the same stdin guard: if stdin is interactive TTY, `pm` returns usage guidance instead of waiting for EOF.
759
+ - Linked test execution uses shell-compatible spawn orchestration instead of buffered one-shot capture, reducing silent long-run behavior in IDE-integrated terminals.
760
+ - During interactive runs, linked tests print periodic stderr heartbeat lines (`[pm test] linked-test ... running`) until completion.
761
+ - Timeout paths attempt graceful termination first, then deterministic force-kill fallback for stubborn subprocess trees.
762
+ - For manual EOF in interactive sessions:
763
+ - Unix/macOS terminals: `Ctrl+D`
764
+ - Windows terminals: `Ctrl+Z` then `Enter`
765
+
766
+ Example piped Beads import (after installing the bundled extension once per scope):
544
767
 
545
768
  ```bash
546
- # Generate and save the completion file
547
- pm completion fish > ~/.config/fish/completions/pm.fish
769
+ pm extension --install --project beads
770
+ cat issues.jsonl | pm beads import --file -
548
771
  ```
549
772
 
550
- ### JSON output
773
+ ## Custom Item Types and Type Options
774
+
775
+ `pm` supports project/global custom item types through `settings.json` and extension registrations. When no custom configuration exists, built-in types keep their default behavior.
776
+ Current built-ins are: `Epic`, `Feature`, `Task`, `Chore`, `Issue`, `Event`, `Reminder`, `Milestone`, and `Meeting`.
777
+
778
+ ### Configure custom types in `settings.json`
779
+
780
+ ```json
781
+ {
782
+ "item_types": {
783
+ "definitions": [
784
+ {
785
+ "name": "Asset",
786
+ "folder": "assets",
787
+ "aliases": ["assets", "3d-asset"],
788
+ "required_create_fields": ["title", "description", "status", "priority", "message"],
789
+ "required_create_repeatables": [],
790
+ "command_option_policies": [
791
+ { "command": "create", "option": "severity", "enabled": false },
792
+ { "command": "create", "option": "reporter", "enabled": false },
793
+ { "command": "create", "option": "goal", "visible": false },
794
+ { "command": "update", "option": "message", "required": true }
795
+ ],
796
+ "options": [
797
+ {
798
+ "key": "category",
799
+ "values": ["Map", "Character", "Prop", "VFX"],
800
+ "required": true,
801
+ "aliases": ["asset_category"],
802
+ "description": "High-level asset classification"
803
+ },
804
+ {
805
+ "key": "pipeline",
806
+ "values": ["Blockout", "Modeling", "Rigging", "Texturing", "Done"]
807
+ }
808
+ ]
809
+ }
810
+ ]
811
+ }
812
+ }
813
+ ```
814
+
815
+ ### Use custom types on create/update
551
816
 
552
817
  ```bash
553
- pm completion bash --json
554
- # => { "shell": "bash", "script": "...", "setup_hint": "..." }
818
+ pm create \
819
+ --title "Forest world map" \
820
+ --description "Primary world navigation mesh and terrain art" \
821
+ --type Asset \
822
+ --status open \
823
+ --priority 1 \
824
+ --message "Track world map asset" \
825
+ --type-option category=Map \
826
+ --type-option pipeline=Modeling
827
+
828
+ pm update pm-a1b2 --type-option category=Character --type-option pipeline=Rigging
555
829
  ```
556
830
 
557
- Completion covers all `pm` subcommands, their flags, and common argument values (item types, statuses, priorities, search modes, shell names).
831
+ `--type-option` accepts `key=value`, `key:value`, and `key=<name>,value=<value>` formats (including markdown-style lines), can read stdin via `-`, and can be cleared with `--clear-type-options`.
832
+
833
+ `command_option_policies` lets each type mark create/update options as:
834
+
835
+ - `required: true|false` (mandatory or optional)
836
+ - `enabled: true|false` (accepted or rejected at runtime)
837
+ - `visible: true|false` (shown or hidden in policy-aware help guidance)
558
838
 
559
- ## FAQ
839
+ ### Improved required `--type` guidance
560
840
 
561
- ### Why JSON front-matter instead of YAML?
841
+ When `--type` is missing, usage output now includes:
562
842
 
563
- Deterministic parsing/serialization and fewer parser ambiguities for agent tooling.
843
+ - why `--type` is required
844
+ - allowed values from the active runtime type registry
845
+ - concrete `pm create` examples (including custom-type usage)
846
+ - deterministic aggregation when multiple required create flags and required `--type-option` keys are missing for the selected type (single response, stable flag ordering)
847
+ - a type-specific "next valid example" command in structured error guidance to accelerate one-shot fixes
564
848
 
565
- ### Why TOON by default?
849
+ For `pm create --help` and `pm update --help`, add `--type <value>` to render type-aware policy details (required/disabled/hidden option lists) and type-option schema details (required marker, allowed values, aliases, description) from active settings/extensions.
566
850
 
567
- TOON reduces token usage and keeps structure predictable for LLM workflows.
851
+ ## Help and Error Guidance
568
852
 
569
- ### Can I use `pm` without semantic search?
853
+ `pm` now treats command guidance as a first-class UX surface:
570
854
 
571
- Yes. Keyword mode is always available.
855
+ - Default help is compact and token-efficient (`Intent` + one high-signal example).
856
+ - Add `--explain` to any `--help` invocation to render deeper rationale, multiple examples, and tips.
857
+ - `pm help` and `pm help <command>` are success paths (exit code `0`) for known command paths; unavailable-command help requests emit explicit `unknown command '<name>'` guidance and return usage exit (`2`).
858
+ - `pm <command> --help --json` and `pm help <command> --json` emit deterministic machine-readable help payloads.
859
+ - Usage/runtime errors use one canonical guidance model:
860
+ - text mode: structured sections (`What happened`, `What is required`, `Why`, `Examples`, optional `Next steps`)
861
+ - `--json` mode: machine-readable envelope (`type`, `code`, `title`, `detail`, `required`, `exit_code`, optional `why/examples/next_steps`)
572
862
 
573
- ### Is a database required?
863
+ Text-mode example:
574
864
 
575
- No for core tracking. Core is file-backed. Vector DB is optional for semantic search.
865
+ ```text
866
+ Error: Missing required option --type <value>
867
+
868
+ What happened:
869
+ Commander rejected the command because --type <value> was not provided.
576
870
 
577
- ### Can I restore previous versions?
871
+ What is required:
872
+ Pass --type <value> with a valid value before running the command.
873
+ ```
874
+
875
+ JSON-mode example (`--json`):
876
+
877
+ ```json
878
+ {
879
+ "type": "urn:pm-cli:error:missing_required_option",
880
+ "code": "missing_required_option",
881
+ "title": "Missing required option --type <value>",
882
+ "detail": "Commander rejected the command because --type <value> was not provided.",
883
+ "required": "Pass --type <value> with a valid value before running the command.",
884
+ "exit_code": 2
885
+ }
886
+ ```
578
887
 
579
- Yes. `pm` supports restoring an item to a prior state by timestamp or history version:
888
+ ## Sparse TOON Default Output
889
+
890
+ For default TOON output, command results are rendered directly from the command payload with recursive compaction:
891
+
892
+ - omit `null` and `undefined`
893
+ - omit empty arrays and empty objects
894
+ - preserve meaningful falsy values (`0`, `false`, non-empty strings)
895
+
896
+ JSON output remains contract-stable and command-contract driven; `pm search` uses compact projection by default unless overridden with `--full` or `--fields`.
897
+
898
+ ## SDK and Full Override Extensions
899
+
900
+ `pm` now ships a stable SDK entrypoint at `@unbrained/pm-cli/sdk` for extension authors.
901
+
902
+ ```ts
903
+ import { defineExtension, type ExtensionApi } from "@unbrained/pm-cli/sdk";
904
+
905
+ export default defineExtension({
906
+ activate(api: ExtensionApi) {
907
+ api.registerCommand({
908
+ name: "list-open",
909
+ run: async (context) => ({ overridden: true, command: context.command }),
910
+ });
911
+ },
912
+ });
913
+ ```
914
+
915
+ Extension runtime behavior is extension-first by default:
916
+
917
+ - Extension command handlers can replace core command execution at dispatch time.
918
+ - Parser overrides (`registerParser`) can rewrite command args/options/global context before dispatch.
919
+ - Preflight overrides (`registerPreflight`) can intercept mutation gate decisions and migration flow.
920
+ - Service overrides (`registerService`) can replace output/error/help rendering and selected internal runtime services.
921
+ - Command-result overrides and renderer overrides still run with deterministic precedence (last registration wins).
922
+ - `beforeCommand` and `afterCommand` hooks receive command args/options/global snapshots and final command result/error state.
923
+ - `registerItemFields(...)` definitions now participate in create/update defaulting and validation.
924
+ - `registerSearchProvider(...)` + `settings.search.provider` and `registerVectorStoreAdapter(...)` + `settings.vector_store.adapter` are now live runtime selectors for `pm search` / `pm reindex`.
925
+ - `registerCommand(...)` definitions can optionally declare action/intent/examples/failure hints/arguments/flags metadata, which is surfaced in dynamic `--help` text, `--help --json` payloads, and `pm contracts`.
926
+
927
+ Use `--no-extensions` to force core-only behavior for a single invocation.
928
+
929
+ ## Extension Lifecycle Manager (`pm extension`)
930
+
931
+ Use `pm extension` to install, adopt, inspect, manage, activate, deactivate, and remove custom extensions in project or global scope.
932
+
933
+ Lifecycle actions (exactly one per call):
934
+
935
+ - `--init` (alias: `--scaffold`)
936
+ - `--install`
937
+ - `--uninstall`
938
+ - `--explore`
939
+ - `--manage`
940
+ - `--doctor`
941
+ - `--adopt`
942
+ - `--adopt-all`
943
+ - `--activate`
944
+ - `--deactivate`
945
+
946
+ Scope selectors:
947
+
948
+ - `--project` (default)
949
+ - `--local` (alias of `--project`)
950
+ - `--global`
951
+
952
+ Install source selectors:
953
+
954
+ - local extension directory path (for example `.agents/pm/extensions/my-ext`)
955
+ - GitHub URL (for example `https://github.com/owner/repo/tree/main/path/to/ext`)
956
+ - GitHub shorthand URL form (for example `github.com/owner/repo/path`)
957
+ - explicit GitHub shorthand flag form `--gh owner/repo/path` (alias: `--github`)
958
+ - optional Git ref override with `--ref <branch|tag|sha>`
959
+
960
+ Requested source equivalence examples:
580
961
 
581
962
  ```bash
582
- pm restore <ID> <TIMESTAMP|VERSION>
963
+ # Scaffold a starter extension project (manifest + entrypoint + README)
964
+ pm extension --init ./my-extension
965
+ pm extension scaffold ./my-extension
966
+
967
+ # Bundled managed aliases shipped with pm-cli (not auto-installed)
968
+ pm extension --install --project beads
969
+ pm extension --install --project todos
970
+
971
+ # Equivalent explicit local bundled paths
972
+ pm extension --install --project .agents/pm/extensions/beads
973
+ pm extension --install --project .agents/pm/extensions/todos
974
+
975
+ # Custom extension roots in repo
976
+ pm extension --install --project https://github.com/unbraind/pm-cli/tree/main/.custom/pm-extensions/my-ext
977
+ pm extension --install --project github.com/unbraind/pm-cli/.custom/pm-extensions/my-ext
978
+ pm extension --install --project --gh unbraind/pm-cli/.custom/pm-extensions/my-ext
979
+
980
+ # Single-extension repo or extension at repository root
981
+ pm extension --install --project https://github.com/unbraind/pm-cli
982
+ pm extension --install --project github.com/unbraind/pm-cli
983
+ pm extension --install --project --gh unbraind/pm-cli
583
984
  ```
584
985
 
585
- Restore replays append-only history to the target point, rewrites the item atomically, and appends a new `restore` history event.
986
+ Canonical public shorthand examples in this repository use `unbraind/pm-cli`. For private repositories, ensure your git credentials can access the source before using `--gh` or `github.com/...` selectors.
586
987
 
587
- ## Troubleshooting
988
+ Activation and health behavior:
588
989
 
589
- ### Item not found
990
+ - `pm extension --init`/`--scaffold` creates an idempotent starter extension scaffold (manifest, entrypoint, README) and reports deterministic next steps.
991
+ - Install auto-activates the extension in selected scope settings.
992
+ - Deactivate/activate toggle `extensions.disabled[]`/`extensions.enabled[]` in settings.
993
+ - `pm extension --explore` lists discovered extensions and compatibility/runtime status fields (`active` compatibility alias, `enabled`, `runtime_active`, `activation_status`).
994
+ - `pm extension --adopt` records an existing unmanaged extension into managed state (local or GitHub provenance metadata) without reinstalling extension files.
995
+ - `pm extension --adopt-all` bulk-adopts all unmanaged extensions in the selected scope without reinstalling files.
996
+ - `pm extension --manage` refreshes GitHub-managed update metadata, persists it to scope-local `.managed-extensions.json`, and includes explicit per-extension `update_check_status`/`update_check_reason` fields (`checked`, `failed`, `skipped_unmanaged`, `skipped_non_github`, `not_checked`) plus triage status totals/remediation hints and update-health coverage diagnostics (`update_health_coverage`, `warning_codes`). `--runtime-probe` opt-in runs doctor-equivalent runtime activation checks for manage output parity. `--fix-managed-state` can adopt unmanaged extensions before update checks.
997
+ - `pm extension --doctor` (or `pm extension doctor`) provides consolidated extension diagnostics with normalized warning codes, canonical load roots, active-vs-loaded consistency diagnostics, update-health coverage signals, remediation hints, optional strict exit gating (`--strict-exit`, alias `--fail-on-warn`), machine-usable blocking indicators (`blocking_failure_count`, `has_blocking_failures`), and optional deep output via `--detail deep`. `--trace` (deep mode) includes actionable registration traces and expected-schema hints for activation failures. `--fix-managed-state` can adopt unmanaged extensions before diagnostics.
998
+ - Doctor load diagnostics include targeted guidance codes for common local setup failures: `extension_load_failed_sdk_dependency_missing` (missing `@unbrained/pm-cli` dependency) and `extension_load_failed_module_mode_mismatch` (ESM entry without `"type": "module"` or `.mjs` mode alignment).
999
+ - Subcommand invocation forms (`pm extension manage ...`, `pm extension doctor ...`) honor the same action flags (`--runtime-probe`, `--detail`, `--trace`, etc.) as top-level action-flag forms.
1000
+ - `pm health` includes managed extension state diagnostics plus a condensed extension triage block for quick load/activation/migration issue triage across project/global roots, including `extension_update_health_partial_coverage` only when unmanaged loaded extensions are action-required for update-check coverage.
1001
+ - Unknown manifest capabilities emit `extension_capability_unknown` diagnostics with inline allowed-capability lists, nearest-match suggestions, and legacy alias guidance (`migration`/`validation` -> `schema`). Health/doctor payloads include machine-readable capability contract metadata (`details.capability_contract`) and parsed guidance entries (`details.capability_guidance`).
1002
+ - Legacy extension command definitions using `handler` remain compatible and map to `run`, with deterministic warning `extension_command_definition_legacy_handler_alias` for migration visibility.
590
1003
 
591
- - Use normalized id and check:
592
- - `pm list-all --limit 100 --json`
1004
+ Use `pm extension --help` for compact guidance or `pm extension --help --explain` for expanded examples/tips.
593
1005
 
594
- ### Command appears missing
1006
+ ## Calendar, Reminders, and Events
595
1007
 
596
- - Check `pm --help` for the implemented command surface in this version.
597
- - Confirm whether the command is listed under "Roadmap (post-v0.1 / partial areas)".
1008
+ `pm` supports persistent reminder metadata, one-off and recurring scheduled events, and a dedicated calendar surface for deadline/reminder/event planning.
598
1009
 
599
- ## Testing and Coverage Policy
1010
+ ### Reminder fields on items
600
1011
 
601
- - All tests must run with a sandbox `PM_PATH` (never the repository's real `.agents/pm`).
602
- - PM-linked test execution should use `node scripts/run-tests.mjs <test|coverage> [-- <vitest args...>]` so both `PM_PATH` and `PM_GLOBAL_PATH` are sandboxed per run; forwarded args target Vitest directly (for example: `node scripts/run-tests.mjs test -- tests/unit/health-command.spec.ts`).
603
- - `pm test <ID>` linked command entries must not invoke `pm test-all` (including global-flag and package-spec launcher forms like `pm --json test-all`, `npx @unbrained/pm-cli@latest --json test-all`, `pnpm dlx @unbrained/pm-cli@latest --json test-all`, and `npm exec -- @unbrained/pm-cli@latest --json test-all`); the CLI rejects recursive orchestration entries at add-time.
604
- - `pm test <ID> --run` defensively skips legacy linked command entries that invoke `pm test-all` (including global-flag and package-spec launcher forms such as `npx`, `pnpm dlx`, and `npm exec` launcher variants) and reports deterministic skipped results.
605
- - `pm test <ID>` linked test-runner command entries must use `node scripts/run-tests.mjs ...` or explicitly set both `PM_PATH` and `PM_GLOBAL_PATH`; the CLI rejects sandbox-unsafe variants at add-time, including unsandboxed package-manager run-script forms like `npm run test` / `pnpm run test` and chained direct test-runner segments that are not explicitly sandboxed.
606
- - `pm test-all` runs each unique linked command/path key once per invocation and marks duplicates as skipped for deterministic orchestration output; duplicate-key timeout conflicts resolve to the maximum `timeout_seconds` for that key.
607
- - Integration tests spawn the built CLI (`node dist/cli.js ...`) with test-specific `PM_PATH`, `PM_GLOBAL_PATH`, and `PM_AUTHOR`.
608
- - Coverage thresholds are enforced at `100%` for lines, branches, functions, and statements.
609
- - `pm` project data in `.agents/pm` is reserved for living planning/logging only.
1012
+ - `pm create` and `pm update` accept repeatable `--reminder` flags.
1013
+ - Reminder value format: `at=<iso|date|relative>,text=<text>`.
1014
+ - Use `--clear-reminders` to clear reminders on create/update.
610
1015
 
611
- ## Community and Governance Files
1016
+ Examples:
612
1017
 
613
- Release-ready repository baseline includes:
1018
+ ```bash
1019
+ pm create \
1020
+ --title "Prepare release notes" \
1021
+ --description "Draft and review release notes for vnext." \
1022
+ --create-mode progressive \
1023
+ --type Task \
1024
+ --status open \
1025
+ --priority 1 \
1026
+ --tags "release,docs" \
1027
+ --body "" \
1028
+ --deadline +2d \
1029
+ --reminder "at=+1d,text=Start first draft" \
1030
+ --reminder "at=+36h,text=Send review draft" \
1031
+ --estimate 45 \
1032
+ --acceptance-criteria "Release notes merged and linked." \
1033
+ --author "maintainer-agent" \
1034
+ --message "Create release notes task with reminders"
1035
+
1036
+ pm update pm-a1b2 --reminder "at=+4h,text=Follow up with reviewer"
1037
+ pm update pm-a1b2 --clear-reminders
1038
+ ```
614
1039
 
615
- - `LICENSE` (MIT)
616
- - `CHANGELOG.md` (Keep a Changelog + SemVer note + `[Unreleased]`)
617
- - `CONTRIBUTING.md` (development and contribution workflow)
618
- - `SECURITY.md` (security reporting policy)
619
- - `CODE_OF_CONDUCT.md` (contributor behavior baseline)
1040
+ ### Event fields on items
1041
+
1042
+ - `pm create` and `pm update` accept repeatable `--event` flags.
1043
+ - Event value format supports:
1044
+ - `start=<iso|date|relative>` (required)
1045
+ - `end=<iso|date|relative>` (optional, must be after `start`)
1046
+ - `title=<text>`, `description=<text>`, `location=<text>`, `timezone=<iana-or-label>`, `all_day=<true|false|1|0|yes|no>`
1047
+ - Recurrence metadata (optional, RFC-lite):
1048
+ - `recur_freq=<daily|weekly|monthly|yearly>`
1049
+ - `recur_interval=<int>=1+`
1050
+ - `recur_count=<int>=1+`
1051
+ - `recur_until=<iso|date|relative>`
1052
+ - `recur_by_weekday=<mon|tue|wed|thu|fri|sat|sun>` (pipe-delimited)
1053
+ - `recur_by_month_day=<1..31>` (pipe-delimited)
1054
+ - `recur_exdates=<iso|date|relative>` (pipe-delimited)
1055
+ - Use `--clear-events` to clear all events in create/update flows.
620
1056
 
621
- ## Release Readiness Checklist
1057
+ Examples:
622
1058
 
623
1059
  ```bash
624
- pnpm install
625
- pnpm build
626
- pnpm typecheck
627
- pnpm test
628
- pnpm test:coverage
629
- pnpm version:check
630
- pnpm security:scan
631
- node scripts/run-tests.mjs coverage
632
- pnpm smoke:npx
1060
+ pm create \
1061
+ --title "Run release planning" \
1062
+ --description "Set recurring planning sync plus a one-off launch checkpoint." \
1063
+ --create-mode progressive \
1064
+ --type Task \
1065
+ --status open \
1066
+ --priority 1 \
1067
+ --tags "release,calendar" \
1068
+ --body "" \
1069
+ --deadline +7d \
1070
+ --event "start=2026-04-03T15:00:00.000Z,title=Launch checkpoint,location=War room" \
1071
+ --event "start=2026-04-01T09:00:00.000Z,title=Weekly planning,recur_freq=weekly,recur_by_weekday=wed,recur_interval=1" \
1072
+ --estimate 30 \
1073
+ --acceptance-criteria "Calendar schedule is captured in item metadata." \
1074
+ --author "maintainer-agent" \
1075
+ --message "Create calendar-rich planning task"
1076
+
1077
+ pm update pm-a1b2 --event "start=+2d,title=Retro,recur_freq=monthly,recur_by_month_day=15"
1078
+ pm update pm-a1b2 --clear-events
633
1079
  ```
634
1080
 
635
- Manual smoke checks:
1081
+ ### Calendar command (`pm calendar` / `pm cal`)
1082
+
1083
+ - Views: `agenda` (default), `day`, `week`, `month`
1084
+ - Default output for calendar is markdown (command-specific override)
1085
+ - Explicit output override: `--format markdown|toon|json` or global `--json`
1086
+ - JSON summary includes deterministic aggregate breakdowns: `by_kind`, `by_type`, `by_status`, and `recurring_events`.
1087
+ - Markdown event lines include richer deterministic metadata for agent parsing (item type, event title, recurrence marker/rule, end-time, timezone, location, and description when present).
1088
+ - Event source controls:
1089
+ - `--include deadlines|reminders|events|all` (comma or pipe-delimited when passing multiple values)
1090
+ - default source set is `all`
1091
+ - Recurrence expansion controls:
1092
+ - `--recurrence-lookahead-days <n>`
1093
+ - `--recurrence-lookback-days <n>`
1094
+ - `--occurrence-limit <n>` (per recurring event; `>= 1`)
1095
+ - Past toggles and range controls:
1096
+ - `--past` includes past events in bounded views
1097
+ - `--full-period` keeps day/week/month windows anchored to full period boundaries (without now-clipping)
1098
+ - `--from` / `--to` supported on `agenda` (accept `today` as a day-start alias)
1099
+ - `--date` anchors day/week/month calculations (accepts `today` as a day-start alias)
1100
+ - Shared filters: `--type`, `--tag`, `--priority`, `--status`, `--assignee`, `--assignee-filter assigned|unassigned`, `--sprint`, `--release`, `--limit`
1101
+
1102
+ Examples:
636
1103
 
637
- - install packed tarball globally and run `pm --help`
638
- - run `bash scripts/install.sh`
639
- - run `pwsh scripts/install.ps1`
1104
+ ```bash
1105
+ pm calendar
1106
+ pm calendar --view day --date today --past
1107
+ pm cal --view week --date +2d --past
1108
+ pm calendar --view week --date 2026-04-06 --full-period --include deadlines,events
1109
+ pm calendar --view agenda --from 2026-04-01T00:00:00.000Z --to 2026-04-08T00:00:00.000Z --assignee alex
1110
+ pm calendar --view agenda --include events --recurrence-lookahead-days 30 --occurrence-limit 50
1111
+ pm calendar --view month --tag release --format json
1112
+ ```
640
1113
 
641
- ### Automated Release
1114
+ ## Context Snapshot (`pm context` / `pm ctx`)
1115
+
1116
+ `pm context` provides a token-efficient project-state snapshot optimized for quickly deciding the next work item.
1117
+
1118
+ - Default output is TOON (sparse and agent-friendly), with explicit `--format markdown|toon|json` and global `--json`.
1119
+ - Focus sections prioritize active work (`in_progress`, then `open`) using deterministic ranking:
1120
+ - status
1121
+ - priority (`0..4`, lower is higher priority)
1122
+ - explicit `order` (when present)
1123
+ - deadline proximity
1124
+ - recency/id tie-breakers
1125
+ - Output is split into:
1126
+ - high-level focus (`Epic`, `Feature`)
1127
+ - low-level focus (`Task`, `Issue`, `Chore`, `Event`, `Reminder`, `Milestone`, `Meeting`, etc.)
1128
+ - Agenda context is included from deadlines, reminders, and scheduled events in an agenda window.
1129
+ - If there are no open or in-progress items, `pm context` automatically includes a blocked-work fallback section.
1130
+ - Shared filters: `--type`, `--tag`, `--priority`, `--assignee`, `--sprint`, `--release`, `--limit`.
1131
+ - Agenda window controls: `--date`, `--from`, `--to`, `--past`.
642
1132
 
643
- Pushing a version tag triggers the automated npm publish workflow:
1133
+ Examples:
644
1134
 
645
1135
  ```bash
646
- git tag v2026.3.9
647
- git push origin v2026.3.9
1136
+ pm context
1137
+ pm ctx --limit 5
1138
+ pm context --assignee alex --priority 1 --limit 10
1139
+ pm context --from +0d --to +7d --format markdown
1140
+ pm context --date 2026-04-01T00:00:00.000Z --past --json
648
1141
  ```
649
1142
 
650
- The `.github/workflows/release.yml` workflow runs full validation, enforces calendar version policy, and publishes `@unbrained/pm-cli` to npm only when all checks pass. It uses the `release` GitHub Environment and requires the `NPM_TOKEN` environment secret.
1143
+ ## Documentation
1144
+
1145
+ - [Architecture](docs/ARCHITECTURE.md)
1146
+ - [SDK Guide](docs/SDK.md)
1147
+ - [Telemetry and GDPR Operations](docs/TELEMETRY.md)
1148
+ - [Remote Telemetry Stack Runbook](docs/operations/REMOTE_TELEMETRY_STACK.md)
1149
+ - [Extensions](docs/EXTENSIONS.md)
1150
+ - [Contributing](CONTRIBUTING.md)
1151
+ - [Security Policy](SECURITY.md)
1152
+ - [Changelog](CHANGELOG.md)
651
1153
 
652
- ## Project Status
1154
+ ## License
653
1155
 
654
- Release-hardening is active.
655
- `PRD.md`, `AGENTS.md`, and this README define the current public and contributor contracts.
1156
+ MIT. See [LICENSE](LICENSE).