@unbrained/pm-cli 2026.3.12 → 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.
- package/.agents/pm/extensions/.managed-extensions.json +42 -0
- package/.agents/pm/extensions/beads/index.js +109 -0
- package/.agents/pm/extensions/beads/manifest.json +7 -0
- package/{dist/cli/commands/beads.js → .agents/pm/extensions/beads/runtime.js} +31 -21
- package/.agents/pm/extensions/beads/runtime.ts +702 -0
- package/.agents/pm/extensions/todos/index.js +126 -0
- package/.agents/pm/extensions/todos/manifest.json +7 -0
- package/{dist/extensions/builtins/todos/import-export.js → .agents/pm/extensions/todos/runtime.js} +39 -29
- package/.agents/pm/extensions/todos/runtime.ts +568 -0
- package/AGENTS.md +196 -92
- package/CHANGELOG.md +404 -0
- package/CODE_OF_CONDUCT.md +42 -0
- package/CONTRIBUTING.md +144 -0
- package/PRD.md +512 -164
- package/README.md +1053 -2
- package/SECURITY.md +51 -0
- package/dist/cli/commands/activity.d.ts +5 -0
- package/dist/cli/commands/activity.js +66 -3
- package/dist/cli/commands/activity.js.map +1 -1
- package/dist/cli/commands/aggregate.d.ts +54 -0
- package/dist/cli/commands/aggregate.js +181 -0
- package/dist/cli/commands/aggregate.js.map +1 -0
- package/dist/cli/commands/append.js +4 -1
- package/dist/cli/commands/append.js.map +1 -1
- package/dist/cli/commands/calendar.d.ts +109 -0
- package/dist/cli/commands/calendar.js +797 -0
- package/dist/cli/commands/calendar.js.map +1 -0
- package/dist/cli/commands/claim.d.ts +5 -1
- package/dist/cli/commands/claim.js +42 -21
- package/dist/cli/commands/claim.js.map +1 -1
- package/dist/cli/commands/close.d.ts +1 -0
- package/dist/cli/commands/close.js +54 -5
- package/dist/cli/commands/close.js.map +1 -1
- package/dist/cli/commands/comments-audit.d.ts +91 -0
- package/dist/cli/commands/comments-audit.js +195 -0
- package/dist/cli/commands/comments-audit.js.map +1 -0
- package/dist/cli/commands/comments.d.ts +1 -0
- package/dist/cli/commands/comments.js +70 -21
- package/dist/cli/commands/comments.js.map +1 -1
- package/dist/cli/commands/completion.d.ts +10 -4
- package/dist/cli/commands/completion.js +1184 -137
- package/dist/cli/commands/completion.js.map +1 -1
- package/dist/cli/commands/config.d.ts +35 -3
- package/dist/cli/commands/config.js +968 -13
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/context.d.ts +86 -0
- package/dist/cli/commands/context.js +299 -0
- package/dist/cli/commands/context.js.map +1 -0
- package/dist/cli/commands/contracts.d.ts +78 -0
- package/dist/cli/commands/contracts.js +920 -0
- package/dist/cli/commands/contracts.js.map +1 -0
- package/dist/cli/commands/create.d.ts +48 -14
- package/dist/cli/commands/create.js +1331 -160
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/dedupe-audit.d.ts +81 -0
- package/dist/cli/commands/dedupe-audit.js +330 -0
- package/dist/cli/commands/dedupe-audit.js.map +1 -0
- package/dist/cli/commands/deps.d.ts +52 -0
- package/dist/cli/commands/deps.js +204 -0
- package/dist/cli/commands/deps.js.map +1 -0
- package/dist/cli/commands/docs.d.ts +19 -0
- package/dist/cli/commands/docs.js +212 -13
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/extension.d.ts +122 -0
- package/dist/cli/commands/extension.js +1850 -0
- package/dist/cli/commands/extension.js.map +1 -0
- package/dist/cli/commands/files.d.ts +52 -1
- package/dist/cli/commands/files.js +455 -13
- package/dist/cli/commands/files.js.map +1 -1
- package/dist/cli/commands/gc.d.ts +11 -1
- package/dist/cli/commands/gc.js +89 -11
- package/dist/cli/commands/gc.js.map +1 -1
- package/dist/cli/commands/get.d.ts +13 -0
- package/dist/cli/commands/get.js +35 -3
- package/dist/cli/commands/get.js.map +1 -1
- package/dist/cli/commands/health.d.ts +10 -2
- package/dist/cli/commands/health.js +774 -23
- package/dist/cli/commands/health.js.map +1 -1
- package/dist/cli/commands/history.d.ts +20 -0
- package/dist/cli/commands/history.js +152 -6
- package/dist/cli/commands/history.js.map +1 -1
- package/dist/cli/commands/index.d.ts +16 -3
- package/dist/cli/commands/index.js +16 -3
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.d.ts +7 -2
- package/dist/cli/commands/init.js +137 -5
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/learnings.d.ts +17 -0
- package/dist/cli/commands/learnings.js +129 -0
- package/dist/cli/commands/learnings.js.map +1 -0
- package/dist/cli/commands/list.d.ts +29 -1
- package/dist/cli/commands/list.js +289 -53
- package/dist/cli/commands/list.js.map +1 -1
- package/dist/cli/commands/normalize.d.ts +51 -0
- package/dist/cli/commands/normalize.js +298 -0
- package/dist/cli/commands/normalize.js.map +1 -0
- package/dist/cli/commands/notes.d.ts +17 -0
- package/dist/cli/commands/notes.js +129 -0
- package/dist/cli/commands/notes.js.map +1 -0
- package/dist/cli/commands/reindex.d.ts +1 -0
- package/dist/cli/commands/reindex.js +208 -32
- package/dist/cli/commands/reindex.js.map +1 -1
- package/dist/cli/commands/restore.js +164 -30
- package/dist/cli/commands/restore.js.map +1 -1
- package/dist/cli/commands/search.d.ts +14 -1
- package/dist/cli/commands/search.js +475 -81
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/stats.js +26 -10
- package/dist/cli/commands/stats.js.map +1 -1
- package/dist/cli/commands/templates.d.ts +26 -0
- package/dist/cli/commands/templates.js +179 -0
- package/dist/cli/commands/templates.js.map +1 -0
- package/dist/cli/commands/test-all.d.ts +19 -1
- package/dist/cli/commands/test-all.js +161 -13
- package/dist/cli/commands/test-all.js.map +1 -1
- package/dist/cli/commands/test-runs.d.ts +63 -0
- package/dist/cli/commands/test-runs.js +179 -0
- package/dist/cli/commands/test-runs.js.map +1 -0
- package/dist/cli/commands/test.d.ts +75 -1
- package/dist/cli/commands/test.js +1360 -41
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/commands/update-many.d.ts +57 -0
- package/dist/cli/commands/update-many.js +631 -0
- package/dist/cli/commands/update-many.js.map +1 -0
- package/dist/cli/commands/update.d.ts +30 -0
- package/dist/cli/commands/update.js +1393 -84
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/commands/validate.d.ts +30 -0
- package/dist/cli/commands/validate.js +1151 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/error-guidance.d.ts +33 -0
- package/dist/cli/error-guidance.js +337 -0
- package/dist/cli/error-guidance.js.map +1 -0
- package/dist/cli/extension-command-options.d.ts +1 -0
- package/dist/cli/extension-command-options.js +92 -0
- package/dist/cli/extension-command-options.js.map +1 -1
- package/dist/cli/help-content.d.ts +20 -0
- package/dist/cli/help-content.js +543 -0
- package/dist/cli/help-content.js.map +1 -0
- package/dist/cli/main.js +3625 -445
- package/dist/cli/main.js.map +1 -1
- package/dist/core/extensions/index.d.ts +13 -1
- package/dist/core/extensions/index.js +108 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/item-fields.d.ts +2 -0
- package/dist/core/extensions/item-fields.js +79 -0
- package/dist/core/extensions/item-fields.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +322 -9
- package/dist/core/extensions/loader.js +911 -20
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runtime-registrations.d.ts +5 -0
- package/dist/core/extensions/runtime-registrations.js +51 -0
- package/dist/core/extensions/runtime-registrations.js.map +1 -0
- package/dist/core/history/history-stream-policy.d.ts +20 -0
- package/dist/core/history/history-stream-policy.js +53 -0
- package/dist/core/history/history-stream-policy.js.map +1 -0
- package/dist/core/history/history.js +90 -1
- package/dist/core/history/history.js.map +1 -1
- package/dist/core/item/id.js +4 -1
- package/dist/core/item/id.js.map +1 -1
- package/dist/core/item/index.d.ts +1 -0
- package/dist/core/item/index.js +1 -0
- package/dist/core/item/index.js.map +1 -1
- package/dist/core/item/item-format.d.ts +11 -5
- package/dist/core/item/item-format.js +507 -24
- package/dist/core/item/item-format.js.map +1 -1
- package/dist/core/item/parent-reference-policy.d.ts +6 -0
- package/dist/core/item/parent-reference-policy.js +32 -0
- package/dist/core/item/parent-reference-policy.js.map +1 -0
- package/dist/core/item/parse.d.ts +5 -0
- package/dist/core/item/parse.js +216 -19
- package/dist/core/item/parse.js.map +1 -1
- package/dist/core/item/sprint-release-format.d.ts +6 -0
- package/dist/core/item/sprint-release-format.js +33 -0
- package/dist/core/item/sprint-release-format.js.map +1 -0
- package/dist/core/item/status.d.ts +3 -0
- package/dist/core/item/status.js +24 -0
- package/dist/core/item/status.js.map +1 -0
- package/dist/core/item/type-registry.d.ts +37 -0
- package/dist/core/item/type-registry.js +706 -0
- package/dist/core/item/type-registry.js.map +1 -0
- package/dist/core/lock/lock.d.ts +1 -1
- package/dist/core/lock/lock.js +101 -12
- package/dist/core/lock/lock.js.map +1 -1
- package/dist/core/output/command-aware.d.ts +1 -0
- package/dist/core/output/command-aware.js +394 -0
- package/dist/core/output/command-aware.js.map +1 -0
- package/dist/core/output/output.d.ts +3 -0
- package/dist/core/output/output.js +124 -6
- package/dist/core/output/output.js.map +1 -1
- package/dist/core/schema/runtime-field-filters.d.ts +3 -0
- package/dist/core/schema/runtime-field-filters.js +39 -0
- package/dist/core/schema/runtime-field-filters.js.map +1 -0
- package/dist/core/schema/runtime-field-values.d.ts +8 -0
- package/dist/core/schema/runtime-field-values.js +154 -0
- package/dist/core/schema/runtime-field-values.js.map +1 -0
- package/dist/core/schema/runtime-schema.d.ts +68 -0
- package/dist/core/schema/runtime-schema.js +554 -0
- package/dist/core/schema/runtime-schema.js.map +1 -0
- package/dist/core/search/cache.d.ts +13 -1
- package/dist/core/search/cache.js +123 -14
- package/dist/core/search/cache.js.map +1 -1
- package/dist/core/search/semantic-defaults.d.ts +6 -0
- package/dist/core/search/semantic-defaults.js +120 -0
- package/dist/core/search/semantic-defaults.js.map +1 -0
- package/dist/core/search/vector-stores.js +3 -1
- package/dist/core/search/vector-stores.js.map +1 -1
- package/dist/core/shared/command-types.d.ts +2 -0
- package/dist/core/shared/conflict-markers.d.ts +7 -0
- package/dist/core/shared/conflict-markers.js +27 -0
- package/dist/core/shared/conflict-markers.js.map +1 -0
- package/dist/core/shared/constants.d.ts +15 -4
- package/dist/core/shared/constants.js +141 -1
- package/dist/core/shared/constants.js.map +1 -1
- package/dist/core/shared/errors.d.ts +10 -1
- package/dist/core/shared/errors.js +3 -1
- package/dist/core/shared/errors.js.map +1 -1
- package/dist/core/shared/text-normalization.d.ts +4 -0
- package/dist/core/shared/text-normalization.js +33 -0
- package/dist/core/shared/text-normalization.js.map +1 -0
- package/dist/core/shared/time.d.ts +1 -2
- package/dist/core/shared/time.js +98 -11
- package/dist/core/shared/time.js.map +1 -1
- package/dist/core/store/index.d.ts +1 -0
- package/dist/core/store/index.js +1 -0
- package/dist/core/store/index.js.map +1 -1
- package/dist/core/store/item-format-migration.d.ts +9 -0
- package/dist/core/store/item-format-migration.js +87 -0
- package/dist/core/store/item-format-migration.js.map +1 -0
- package/dist/core/store/item-store.d.ts +13 -4
- package/dist/core/store/item-store.js +238 -51
- package/dist/core/store/item-store.js.map +1 -1
- package/dist/core/store/paths.d.ts +21 -3
- package/dist/core/store/paths.js +59 -4
- package/dist/core/store/paths.js.map +1 -1
- package/dist/core/store/settings.d.ts +14 -1
- package/dist/core/store/settings.js +463 -7
- package/dist/core/store/settings.js.map +1 -1
- package/dist/core/telemetry/consent.d.ts +2 -0
- package/dist/core/telemetry/consent.js +79 -0
- package/dist/core/telemetry/consent.js.map +1 -0
- package/dist/core/telemetry/runtime.d.ts +38 -0
- package/dist/core/telemetry/runtime.js +733 -0
- package/dist/core/telemetry/runtime.js.map +1 -0
- package/dist/core/test/background-runs.d.ts +117 -0
- package/dist/core/test/background-runs.js +760 -0
- package/dist/core/test/background-runs.js.map +1 -0
- package/dist/core/test/item-test-run-tracking.d.ts +9 -0
- package/dist/core/test/item-test-run-tracking.js +50 -0
- package/dist/core/test/item-test-run-tracking.js.map +1 -0
- package/dist/sdk/cli-contracts.d.ts +92 -0
- package/dist/sdk/cli-contracts.js +2357 -0
- package/dist/sdk/cli-contracts.js.map +1 -0
- package/dist/sdk/index.d.ts +34 -0
- package/dist/sdk/index.js +23 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/types.d.ts +197 -3
- package/dist/types.js +48 -1
- package/dist/types.js.map +1 -1
- package/docs/ARCHITECTURE.md +368 -39
- package/docs/EXTENSIONS.md +454 -49
- package/docs/RELEASING.md +70 -19
- package/docs/SDK.md +123 -0
- package/docs/examples/starter-extension/README.md +48 -0
- package/docs/examples/starter-extension/index.js +191 -0
- package/docs/examples/starter-extension/manifest.json +17 -0
- package/docs/examples/starter-extension/package.json +10 -0
- package/package.json +41 -14
- package/.pi/extensions/pm-cli/index.ts +0 -778
- package/dist/cli/commands/beads.d.ts +0 -16
- package/dist/cli/commands/beads.js.map +0 -1
- package/dist/cli/commands/install.d.ts +0 -18
- package/dist/cli/commands/install.js +0 -87
- package/dist/cli/commands/install.js.map +0 -1
- package/dist/core/extensions/builtins.d.ts +0 -3
- package/dist/core/extensions/builtins.js +0 -47
- package/dist/core/extensions/builtins.js.map +0 -1
- package/dist/extensions/builtins/beads/index.d.ts +0 -8
- package/dist/extensions/builtins/beads/index.js +0 -33
- package/dist/extensions/builtins/beads/index.js.map +0 -1
- package/dist/extensions/builtins/todos/import-export.d.ts +0 -26
- package/dist/extensions/builtins/todos/import-export.js.map +0 -1
- package/dist/extensions/builtins/todos/index.d.ts +0 -8
- package/dist/extensions/builtins/todos/index.js +0 -38
- package/dist/extensions/builtins/todos/index.js.map +0 -1
package/PRD.md
CHANGED
|
@@ -20,16 +20,17 @@ Existing trackers either rely on hosted backends, store state in non-diff-friend
|
|
|
20
20
|
|
|
21
21
|
- Build a cross-platform TypeScript CLI named `pm`.
|
|
22
22
|
- Store all core tracker data in project-local files under `.agents/pm` by default.
|
|
23
|
-
- Model work as first-class items: `Epic`, `Feature`, `Task`, `Chore`, `Issue`.
|
|
23
|
+
- Model work as first-class items: `Epic`, `Feature`, `Task`, `Chore`, `Issue`, `Event`, `Reminder`, `Milestone`, `Meeting`.
|
|
24
24
|
- Support full item lifecycle operations, deterministic listing/filtering, and rich metadata.
|
|
25
|
+
- Support reminder-aware scheduling workflows with deterministic calendar views for agents and humans.
|
|
25
26
|
- Provide append-only item history with patch-level restore.
|
|
26
27
|
- Provide safe mutation under concurrent access (claim/release + lock + atomic writes).
|
|
27
28
|
- Default stdout to TOON; support `--json` parity for every command.
|
|
28
29
|
- Provide extension architecture for commands, schema, rendering, import/export, search adapters, and hooks.
|
|
29
|
-
- Ship
|
|
30
|
-
- Beads import
|
|
31
|
-
- todos.ts import/export
|
|
32
|
-
- Pi agent extension wrapper module
|
|
30
|
+
- Ship bundled managed extension sources:
|
|
31
|
+
- Beads import (`beads` alias, installed via `pm extension --install`)
|
|
32
|
+
- todos.ts import/export (`todos` alias, installed via `pm extension --install`)
|
|
33
|
+
- Pi agent extension wrapper source module
|
|
33
34
|
- Provide optional semantic search with provider + vector-store adapters.
|
|
34
35
|
|
|
35
36
|
## 3) Explicit Non-Goals
|
|
@@ -76,7 +77,7 @@ From TOON guidance:
|
|
|
76
77
|
|
|
77
78
|
- Show structure directly, keep deterministic layout, and preserve strict machine parseability.
|
|
78
79
|
- Keep output schema stable and field ordering deterministic.
|
|
79
|
-
- JSON fallback should
|
|
80
|
+
- JSON fallback should preserve the full command payload; TOON may be a sparse projection optimized for token efficiency.
|
|
80
81
|
|
|
81
82
|
## 5) Core Concepts
|
|
82
83
|
|
|
@@ -87,6 +88,10 @@ From TOON guidance:
|
|
|
87
88
|
- `Task`
|
|
88
89
|
- `Chore`
|
|
89
90
|
- `Issue`
|
|
91
|
+
- `Event`
|
|
92
|
+
- `Reminder`
|
|
93
|
+
- `Milestone`
|
|
94
|
+
- `Meeting`
|
|
90
95
|
|
|
91
96
|
### 5.2 Status lifecycle
|
|
92
97
|
|
|
@@ -99,6 +104,10 @@ Allowed values:
|
|
|
99
104
|
- `closed`
|
|
100
105
|
- `canceled`
|
|
101
106
|
|
|
107
|
+
Input compatibility:
|
|
108
|
+
|
|
109
|
+
- Accept `in-progress` as an input alias and normalize to canonical `in_progress` for persisted item data and command output.
|
|
110
|
+
|
|
102
111
|
Lifecycle rules:
|
|
103
112
|
|
|
104
113
|
- Any non-terminal status may transition to `canceled` via `pm update <ID> --status canceled`.
|
|
@@ -106,6 +115,9 @@ Lifecycle rules:
|
|
|
106
115
|
- `pm update <ID> --status closed` is invalid usage and returns exit code `2`.
|
|
107
116
|
- `closed` and `canceled` are terminal unless explicitly restored or reopened.
|
|
108
117
|
- `close` command must write `close_reason`.
|
|
118
|
+
- `pm close <ID> <TEXT> --validate-close [warn|strict]` validates closure resolution metadata (`resolution`, `expected_result`, `actual_result`) in warning-first mode unless strict is explicitly requested.
|
|
119
|
+
- `pm update <ID> --close-reason <TEXT>` explicitly sets `close_reason`; `pm update <ID> --unset close-reason` clears it.
|
|
120
|
+
- When `pm update` reopens an item from `closed` to a non-terminal status, stale `close_reason` is auto-cleared unless `--close-reason` is explicitly supplied on that same mutation.
|
|
109
121
|
- `claim` on terminal status fails unless explicitly overridden by `--force`.
|
|
110
122
|
|
|
111
123
|
### 5.3 Ownership model
|
|
@@ -113,7 +125,9 @@ Lifecycle rules:
|
|
|
113
125
|
- Ownership marker is `assignee`.
|
|
114
126
|
- `pm claim <id>` sets ownership to current mutation author identity.
|
|
115
127
|
- `pm release <id>` clears ownership.
|
|
116
|
-
-
|
|
128
|
+
- `pm claim <id>` may take over non-terminal items assigned to another assignee without `--force`.
|
|
129
|
+
- Mutations other than `claim` against items assigned to another assignee return conflict unless `--force` (`comments`/`notes`/`learnings` can use additive `--allow-audit-comment` for append-only audit entries, and `release` can use `--allow-audit-release` for non-owner handoffs that only clear assignee metadata).
|
|
130
|
+
- Ownership-conflict guidance should call out approved `--force` scenarios (for example PM audits, coordinated lead-maintainer metadata correction, or explicit ownership handoff cleanup).
|
|
117
131
|
|
|
118
132
|
### 5.4 Dependencies model
|
|
119
133
|
|
|
@@ -138,6 +152,7 @@ These are append-friendly audit fields:
|
|
|
138
152
|
- `comments`: user-visible conversational updates.
|
|
139
153
|
- `notes`: implementation observations.
|
|
140
154
|
- `learnings`: post-task durable findings.
|
|
155
|
+
- Existing items are extended through `pm comments`, `pm notes`, and `pm learnings` add flows; create-time seed flags only bootstrap initial values.
|
|
141
156
|
|
|
142
157
|
All append operations produce history entries.
|
|
143
158
|
|
|
@@ -215,15 +230,16 @@ Constraints:
|
|
|
215
230
|
|
|
216
231
|
## 7) Item File Format
|
|
217
232
|
|
|
218
|
-
Each item is one
|
|
233
|
+
Each item is one document at `<type-folder>/<id>.toon` (default) or `<type-folder>/<id>.md` (JSON+Markdown alternative).
|
|
219
234
|
|
|
220
235
|
Format:
|
|
221
236
|
|
|
222
|
-
1.
|
|
223
|
-
2.
|
|
224
|
-
|
|
237
|
+
1. TOON root-object metadata keys (default) or JSON object metadata block (markdown format).
|
|
238
|
+
2. Optional `body` field / markdown body.
|
|
239
|
+
|
|
240
|
+
### 7.1 Canonical item-metadata schema
|
|
225
241
|
|
|
226
|
-
|
|
242
|
+
`front_matter` remains the internal field name in TypeScript (`ItemDocument.front_matter`), but TOON documents store the same metadata as top-level keys.
|
|
227
243
|
|
|
228
244
|
Required fields:
|
|
229
245
|
|
|
@@ -233,14 +249,15 @@ Required fields:
|
|
|
233
249
|
- `tags: string[]`
|
|
234
250
|
- `status: "draft" | "open" | "in_progress" | "blocked" | "closed" | "canceled"`
|
|
235
251
|
- `priority: 0 | 1 | 2 | 3 | 4`
|
|
236
|
-
- `type: "Epic" | "Feature" | "Task" | "Chore" | "Issue"`
|
|
252
|
+
- `type: "Epic" | "Feature" | "Task" | "Chore" | "Issue" | "Event" | "Reminder" | "Milestone" | "Meeting"`
|
|
237
253
|
- `created_at: ISO string`
|
|
238
254
|
- `updated_at: ISO string`
|
|
239
255
|
|
|
240
256
|
Optional fields:
|
|
241
257
|
|
|
242
258
|
- `assignee?: string`
|
|
243
|
-
- `deadline?: ISO string` (relative input resolved to ISO at write time)
|
|
259
|
+
- `deadline?: ISO string` (ISO/date-string/relative input resolved to ISO at write time)
|
|
260
|
+
- `reminders?: Reminder[]` where `Reminder = { at: ISO string; text: string }`
|
|
244
261
|
- `dependencies?: Dependency[]`
|
|
245
262
|
- `comments?: Comment[]`
|
|
246
263
|
- `author?: string`
|
|
@@ -257,6 +274,7 @@ Optional fields:
|
|
|
257
274
|
- `learnings?: LogNote[]`
|
|
258
275
|
- `files?: LinkedFile[]`
|
|
259
276
|
- `tests?: LinkedTest[]`
|
|
277
|
+
- `test_runs?: ItemTestRunSummary[]`
|
|
260
278
|
- `docs?: LinkedDoc[]`
|
|
261
279
|
- `estimated_minutes?: number`
|
|
262
280
|
- `parent?: string` (item ID reference; shorthand for a `kind=parent` dependency)
|
|
@@ -289,7 +307,9 @@ Types:
|
|
|
289
307
|
- `LogNote = { created_at: string; author: string; text: string }`
|
|
290
308
|
- `LinkedFile = { path: string; scope: "project" | "global"; note?: string }`
|
|
291
309
|
- `LinkedTest = { command?: string; path?: string; scope: "project" | "global"; timeout_seconds?: number; note?: string }`
|
|
310
|
+
- `ItemTestRunSummary = { run_id: string; kind: "test" | "test-all"; status: "passed" | "failed" | "stopped" | "canceled"; started_at: string; finished_at: string; recorded_at: string; attempt?: number; resumed_from?: string; passed: number; failed: number; skipped: number; items?: number; linked_tests?: number; fail_on_skipped_triggered?: boolean }`
|
|
292
311
|
- `LinkedDoc = { path: string; scope: "project" | "global"; note?: string }`
|
|
312
|
+
- `Reminder = { at: string; text: string }`
|
|
293
313
|
- `IssueSeverity = "low" | "medium" | "high" | "critical"`
|
|
294
314
|
|
|
295
315
|
### 7.2 Canonical key order
|
|
@@ -306,65 +326,70 @@ Keys MUST serialize in this order:
|
|
|
306
326
|
8. `created_at`
|
|
307
327
|
9. `updated_at`
|
|
308
328
|
10. `deadline`
|
|
309
|
-
11. `
|
|
310
|
-
12. `
|
|
311
|
-
13. `
|
|
312
|
-
14. `
|
|
313
|
-
15. `
|
|
314
|
-
16. `
|
|
315
|
-
17. `
|
|
316
|
-
18. `
|
|
317
|
-
19. `
|
|
318
|
-
20. `
|
|
319
|
-
21. `
|
|
320
|
-
22. `
|
|
321
|
-
23. `
|
|
322
|
-
24. `
|
|
323
|
-
25. `
|
|
324
|
-
26. `
|
|
325
|
-
27. `
|
|
326
|
-
28. `
|
|
327
|
-
29. `
|
|
328
|
-
30. `
|
|
329
|
-
31. `
|
|
330
|
-
32. `
|
|
331
|
-
33. `
|
|
332
|
-
34. `
|
|
333
|
-
35. `
|
|
334
|
-
36. `
|
|
335
|
-
37. `
|
|
336
|
-
38. `
|
|
337
|
-
39. `
|
|
338
|
-
40. `
|
|
339
|
-
41. `
|
|
340
|
-
42. `
|
|
341
|
-
43. `
|
|
342
|
-
44. `
|
|
343
|
-
45. `
|
|
344
|
-
46. `
|
|
345
|
-
47. `
|
|
346
|
-
48. `
|
|
347
|
-
49. `
|
|
348
|
-
50. `
|
|
349
|
-
51. `
|
|
329
|
+
11. `reminders`
|
|
330
|
+
12. `assignee`
|
|
331
|
+
13. `author`
|
|
332
|
+
14. `estimated_minutes`
|
|
333
|
+
15. `acceptance_criteria`
|
|
334
|
+
16. `definition_of_ready`
|
|
335
|
+
17. `order`
|
|
336
|
+
18. `goal`
|
|
337
|
+
19. `objective`
|
|
338
|
+
20. `value`
|
|
339
|
+
21. `impact`
|
|
340
|
+
22. `outcome`
|
|
341
|
+
23. `why_now`
|
|
342
|
+
24. `parent`
|
|
343
|
+
25. `reviewer`
|
|
344
|
+
26. `risk`
|
|
345
|
+
27. `confidence`
|
|
346
|
+
28. `sprint`
|
|
347
|
+
29. `release`
|
|
348
|
+
30. `blocked_by`
|
|
349
|
+
31. `blocked_reason`
|
|
350
|
+
32. `unblock_note`
|
|
351
|
+
33. `reporter`
|
|
352
|
+
34. `severity`
|
|
353
|
+
35. `environment`
|
|
354
|
+
36. `repro_steps`
|
|
355
|
+
37. `resolution`
|
|
356
|
+
38. `expected_result`
|
|
357
|
+
39. `actual_result`
|
|
358
|
+
40. `affected_version`
|
|
359
|
+
41. `fixed_version`
|
|
360
|
+
42. `component`
|
|
361
|
+
43. `regression`
|
|
362
|
+
44. `customer_impact`
|
|
363
|
+
45. `dependencies`
|
|
364
|
+
46. `comments`
|
|
365
|
+
47. `notes`
|
|
366
|
+
48. `learnings`
|
|
367
|
+
49. `files`
|
|
368
|
+
50. `tests`
|
|
369
|
+
51. `test_runs`
|
|
370
|
+
52. `docs`
|
|
371
|
+
53. `close_reason`
|
|
350
372
|
|
|
351
373
|
Unset optional fields are omitted.
|
|
352
374
|
|
|
353
375
|
### 7.3 Determinism rules
|
|
354
376
|
|
|
355
377
|
- `updated_at` MUST change for every mutation.
|
|
356
|
-
- Relative deadlines (`+6h`, `+1d`, `+2w`) resolve on write and persist as absolute ISO.
|
|
378
|
+
- Relative deadlines (`+6h`, `+1d`, `+2w`, `+6m`) and accepted date-string forms resolve on write and persist as absolute ISO.
|
|
357
379
|
- `tags` sorted lexicographically, deduplicated.
|
|
358
380
|
- `risk` CLI input alias `med` normalizes to canonical stored value `medium`.
|
|
359
381
|
- `confidence` CLI input accepts integers `0..100` or `low|med|medium|high`; `med` persists as `medium`.
|
|
360
382
|
- `severity` CLI input alias `med` normalizes to canonical stored value `medium`.
|
|
361
383
|
- `dependencies`, `comments`, `notes`, `learnings` sorted by `created_at` ascending; stable tie-break by text/id.
|
|
362
|
-
- `
|
|
384
|
+
- `reminders` sorted by `at` ascending, then `text` ascending.
|
|
385
|
+
- `files` preserve provided order in canonical storage; `pm files` default mutation mode writes deterministic sorted order unless `--append-stable` is explicitly selected.
|
|
363
386
|
- `tests` sorted by `scope` asc, then `path` asc, then `command` asc, then `timeout_seconds` asc, then `note` asc.
|
|
387
|
+
- `test_runs` sorted by `recorded_at` asc, then `run_id` asc, then `kind` asc; retention is bounded to latest N entries per item.
|
|
364
388
|
- `docs` sorted by `scope` asc, then `path` asc, then `note` asc.
|
|
365
389
|
- Paths normalized to forward-slash logical form for storage while preserving OS-correct access at runtime.
|
|
366
|
-
- For optional create/update fields, explicit
|
|
367
|
-
- scalar
|
|
390
|
+
- For optional create/update fields, explicit clear intent is supported via dedicated flags:
|
|
391
|
+
- scalar fields use repeatable `--unset <field>` (for example `--unset deadline`, `--unset assignee`)
|
|
392
|
+
- repeatable collections use `--clear-*` flags (for example `--clear-deps`, `--clear-comments`)
|
|
368
393
|
- these intents MUST be represented in `changed_fields` and history `message`.
|
|
369
394
|
|
|
370
395
|
### 7.4 Example item file
|
|
@@ -474,7 +499,7 @@ Canonical patch document shape:
|
|
|
474
499
|
|
|
475
500
|
`pm restore <ID> <TIMESTAMP|VERSION>`
|
|
476
501
|
|
|
477
|
-
1. Resolve item and load full history.
|
|
502
|
+
1. Resolve item or matching history stream for ID and load full history.
|
|
478
503
|
2. Replay patches from initial create through target version/timestamp.
|
|
479
504
|
3. Rebuild exact canonical document (`front_matter` + `body`).
|
|
480
505
|
4. Write item atomically.
|
|
@@ -485,6 +510,57 @@ Guarantees:
|
|
|
485
510
|
- History is immutable (restore appends, never rewrites old entries).
|
|
486
511
|
- Restored item bytes match canonical serialization of target state exactly.
|
|
487
512
|
|
|
513
|
+
### 9.4 Missing history stream policy
|
|
514
|
+
|
|
515
|
+
`settings.history.missing_stream` controls missing-stream behavior for history-touching command paths:
|
|
516
|
+
|
|
517
|
+
- `auto_create` (default): create missing streams for existing item IDs, then continue command execution.
|
|
518
|
+
- `strict_error`: fail fast when a required stream is missing.
|
|
519
|
+
|
|
520
|
+
Scope: this policy applies to read/diagnostic paths (`history`, `activity`, `stats`, `health`) and existing-item mutation/restore flows.
|
|
521
|
+
|
|
522
|
+
### 9.5 Sprint/release format policy
|
|
523
|
+
|
|
524
|
+
`settings.validation.sprint_release_format` controls `--sprint` and `--release` behavior for `create`/`update`:
|
|
525
|
+
|
|
526
|
+
- `warn` (default): accept non-conforming values and emit deterministic warnings.
|
|
527
|
+
- `strict_error`: reject non-conforming values with deterministic usage errors.
|
|
528
|
+
|
|
529
|
+
Conforming value pattern: `^[A-Za-z0-9][A-Za-z0-9._/-]*$` (max 64 characters, no spaces).
|
|
530
|
+
|
|
531
|
+
### 9.6 Metadata validation profile policy
|
|
532
|
+
|
|
533
|
+
`settings.validation.metadata_profile` controls default required-field behavior for `pm validate --check-metadata`:
|
|
534
|
+
|
|
535
|
+
- `core` (default): baseline required fields (`author`, `acceptance_criteria`, `estimated_minutes`, and `close_reason` for closed items).
|
|
536
|
+
- `strict`: extends core with additional governance fields (`reviewer`, `risk`, `confidence`, `sprint`, `release`).
|
|
537
|
+
- `custom`: uses `settings.validation.metadata_required_fields` as the required field set.
|
|
538
|
+
|
|
539
|
+
`settings.validation.metadata_required_fields` accepts deterministic required-field selectors:
|
|
540
|
+
|
|
541
|
+
- `author`
|
|
542
|
+
- `acceptance_criteria`
|
|
543
|
+
- `estimated_minutes`
|
|
544
|
+
- `close_reason`
|
|
545
|
+
- `reviewer`
|
|
546
|
+
- `risk`
|
|
547
|
+
- `confidence`
|
|
548
|
+
- `sprint`
|
|
549
|
+
- `release`
|
|
550
|
+
|
|
551
|
+
If `metadata_profile=custom` and `metadata_required_fields` is empty, runtime falls back to core required fields and emits warning `validate_metadata_custom_profile_missing_required_fields:0`.
|
|
552
|
+
|
|
553
|
+
`pm validate --metadata-profile <core|strict|custom>` can override configured profile per invocation.
|
|
554
|
+
|
|
555
|
+
### 9.7 Test-result tracking policy
|
|
556
|
+
|
|
557
|
+
`settings.testing.record_results_to_items` controls whether linked-test executions append bounded `test_runs` summaries to item front matter:
|
|
558
|
+
|
|
559
|
+
- `false` (default): command output only; no item mutation for run summaries.
|
|
560
|
+
- `true`: `pm test --run` and `pm test-all` append deterministic summary entries (`run_id`, `kind`, `status`, counts, timestamps) with bounded retention.
|
|
561
|
+
|
|
562
|
+
Background executions (`--background`) reuse the same run pipeline and therefore follow the same policy gate.
|
|
563
|
+
|
|
488
564
|
## 10) Concurrency, Claiming, Locking, Safe Writes
|
|
489
565
|
|
|
490
566
|
### 10.1 Assignee identity
|
|
@@ -541,9 +617,30 @@ If any step fails, return non-zero exit code and preserve prior item bytes.
|
|
|
541
617
|
- `--quiet` suppress stdout
|
|
542
618
|
- `--path <dir>` override project root path for invocation
|
|
543
619
|
- `--no-extensions` disable extension loading
|
|
620
|
+
- `--explain` render extended rationale/examples in help output
|
|
544
621
|
- `--profile` print deterministic timing diagnostics (stderr)
|
|
545
622
|
- `--version` print CLI version
|
|
546
623
|
|
|
624
|
+
Default output note:
|
|
625
|
+
|
|
626
|
+
- Core default remains TOON.
|
|
627
|
+
- Default TOON output renders command payloads directly and applies sparse compaction (omit `null`/`undefined`/empty arrays/empty objects).
|
|
628
|
+
- `pm calendar` is a deliberate exception and defaults to markdown unless explicitly overridden by `--format` or `--json`.
|
|
629
|
+
- Runtime output is terminal-neutral plain text (TOON/JSON/markdown) with no required terminal-specific OSC/ANSI control protocol.
|
|
630
|
+
- Error handling should preserve exit-code mapping while preferring graceful process termination semantics (`process.exitCode`) over forced synchronous exits when feasible.
|
|
631
|
+
- Linked test execution should prefer spawn-based shell-compatible orchestration over buffered one-shot capture, so long runs remain observable in emulated terminals.
|
|
632
|
+
- Interactive linked test runs should emit deterministic stderr heartbeat progress events while commands are still running.
|
|
633
|
+
- Long-running command paths that support explicit progress controls (`pm test`, `pm test-all`, `pm reindex`) should expose additive `--progress` behavior for non-interactive runs without changing default output contracts.
|
|
634
|
+
|
|
635
|
+
Help and error UX note:
|
|
636
|
+
|
|
637
|
+
- Command help should default to compact token-efficient guidance (`Intent` + one high-signal example) and support an explicit deep-help surface via `--explain`.
|
|
638
|
+
- `pm help` and `pm help <command>` should remain deterministic success flows for known command paths; unavailable-command help requests should emit explicit `unknown command '<name>'` guidance with usage exit semantics.
|
|
639
|
+
- `--help --json` should emit machine-readable help payloads instead of text help.
|
|
640
|
+
- Usage and runtime errors should be rendered from one canonical guidance model:
|
|
641
|
+
- text mode: structured sections for what happened, what is required, why, examples, and optional next steps
|
|
642
|
+
- `--json` mode: machine-readable envelope (`type`, `code`, `title`, `detail`, `required`, `exit_code`, optional `why/examples/next_steps`)
|
|
643
|
+
|
|
547
644
|
### 11.2 Exit codes
|
|
548
645
|
|
|
549
646
|
- `0` success
|
|
@@ -551,12 +648,12 @@ If any step fails, return non-zero exit code and preserve prior item bytes.
|
|
|
551
648
|
- `2` usage / invalid args
|
|
552
649
|
- `3` not found
|
|
553
650
|
- `4` conflict (claim/lock/ownership)
|
|
554
|
-
- `5` dependency failed (for orchestration
|
|
651
|
+
- `5` dependency failed (for orchestration failures, `pm test-all`, and `pm test --run` when linked test run results fail)
|
|
555
652
|
|
|
556
653
|
### 11.3 Core commands (required for v0.1 release-ready scope)
|
|
557
654
|
|
|
558
655
|
- `pm init [<PREFIX>]`
|
|
559
|
-
- `pm install
|
|
656
|
+
- `pm extension [target] --install|--uninstall|--explore|--manage|--doctor|--adopt|--activate|--deactivate [--project|--local|--global] [--gh|--github <owner/repo[/path]>] [--ref <ref>]`
|
|
560
657
|
- `pm list`
|
|
561
658
|
- `pm list-all`
|
|
562
659
|
- `pm list-draft`
|
|
@@ -565,33 +662,63 @@ If any step fails, return non-zero exit code and preserve prior item bytes.
|
|
|
565
662
|
- `pm list-blocked`
|
|
566
663
|
- `pm list-closed`
|
|
567
664
|
- `pm list-canceled`
|
|
665
|
+
- `pm aggregate`
|
|
666
|
+
- `pm dedupe-audit`
|
|
568
667
|
- `pm get <ID>`
|
|
569
668
|
- `pm search <keywords>`
|
|
570
669
|
- `pm reindex`
|
|
670
|
+
- `pm calendar` (alias: `pm cal`)
|
|
671
|
+
- `pm context` (alias: `pm ctx`)
|
|
571
672
|
- `pm create`
|
|
673
|
+
- `pm templates save <NAME>`
|
|
674
|
+
- `pm templates list`
|
|
675
|
+
- `pm templates show <NAME>`
|
|
572
676
|
- `pm update <ID>`
|
|
677
|
+
- `pm update-many`
|
|
573
678
|
- `pm append <ID>`
|
|
574
679
|
- `pm claim <ID>`
|
|
575
680
|
- `pm release <ID>`
|
|
681
|
+
- `pm start-task <ID>`
|
|
682
|
+
- `pm pause-task <ID>`
|
|
683
|
+
- `pm close-task <ID> <TEXT>`
|
|
576
684
|
- `pm delete <ID>`
|
|
577
|
-
- `pm comments <ID
|
|
685
|
+
- `pm comments <ID> [TEXT]`
|
|
686
|
+
- `pm comments-audit`
|
|
687
|
+
- `pm notes <ID> [TEXT]`
|
|
688
|
+
- `pm learnings <ID> [TEXT]`
|
|
578
689
|
- `pm files <ID>`
|
|
579
690
|
- `pm docs <ID>`
|
|
691
|
+
- `pm deps <ID>`
|
|
580
692
|
- `pm test <ID>`
|
|
581
693
|
- `pm test-all`
|
|
694
|
+
- `pm test-runs <list|status|logs|stop|resume>`
|
|
582
695
|
- `pm stats`
|
|
583
696
|
- `pm health`
|
|
697
|
+
- `pm validate`
|
|
584
698
|
- `pm gc`
|
|
585
699
|
- `pm history <ID>`
|
|
586
700
|
- `pm activity`
|
|
587
701
|
- `pm restore <ID> <TIMESTAMP|VERSION>`
|
|
588
702
|
- `pm config <project|global> set definition-of-done --criterion <text>`
|
|
589
703
|
- `pm config <project|global> get definition-of-done`
|
|
704
|
+
- `pm config <project|global> set item-format --format toon|json_markdown`
|
|
705
|
+
- `pm config <project|global> get item-format`
|
|
706
|
+
- `pm config <project|global> set history-missing-stream-policy --policy auto_create|strict_error`
|
|
707
|
+
- `pm config <project|global> get history-missing-stream-policy`
|
|
708
|
+
- `pm config <project|global> set sprint-release-format-policy --policy warn|strict_error`
|
|
709
|
+
- `pm config <project|global> get sprint-release-format-policy`
|
|
710
|
+
- `pm config <project|global> set parent-reference-policy --policy warn|strict_error`
|
|
711
|
+
- `pm config <project|global> get parent-reference-policy`
|
|
712
|
+
- `pm config <project|global> set test-result-tracking --policy enabled|disabled`
|
|
713
|
+
- `pm config <project|global> get test-result-tracking`
|
|
714
|
+
- `pm config <project|global> list`
|
|
715
|
+
- `pm config <project|global> export`
|
|
590
716
|
- `pm close <ID> <TEXT>`
|
|
591
717
|
- `pm beads import [--file <path>]`
|
|
592
718
|
- `pm todos import [--folder <path>]`
|
|
593
719
|
- `pm todos export [--folder <path>]`
|
|
594
720
|
- `pm completion <bash|zsh|fish>`
|
|
721
|
+
- `pm completion-tags` (internal helper command used by generated completion scripts)
|
|
595
722
|
|
|
596
723
|
Roadmap commands (post-v0.1, tracked but not release blockers):
|
|
597
724
|
|
|
@@ -603,61 +730,84 @@ Mutating `create` (all schema fields MUST be passable explicitly):
|
|
|
603
730
|
|
|
604
731
|
- `--title`, `-t` (required)
|
|
605
732
|
- `--description`, `-d` (required; empty string allowed when explicitly passed)
|
|
606
|
-
- `--type` (required: `
|
|
607
|
-
- `--
|
|
608
|
-
- `--
|
|
609
|
-
- `--
|
|
610
|
-
- `--
|
|
611
|
-
- `--
|
|
733
|
+
- `--type` (required; allowed values are resolved from the runtime item-type registry: built-ins + `settings.item_types.definitions` + extension registrations)
|
|
734
|
+
- `--create-mode`, `--create_mode` (optional; `strict` default, or `progressive` for staged creation that relaxes type-level required create fields/repeatables)
|
|
735
|
+
- `--status`, `-s` (required in strict mode; defaults to `open` in progressive mode when omitted)
|
|
736
|
+
- `--priority`, `-p` (required in strict mode; defaults to `2` in progressive mode when omitted)
|
|
737
|
+
- `--tags` (required in strict mode; defaults to empty list in progressive mode when omitted)
|
|
738
|
+
- `--body`, `-b` (required in strict mode; defaults to empty body in progressive mode when omitted)
|
|
739
|
+
- `--deadline` (explicit; accepts ISO/date strings or relative `+6h/+1d/+2w/+6m`)
|
|
612
740
|
- `--estimate`, `--estimated-minutes`, `--estimated_minutes` (explicit; accepts `0`)
|
|
613
741
|
- `--acceptance-criteria`, `--acceptance_criteria`, `--ac` (explicit; empty allowed)
|
|
614
742
|
- `--author` (explicit; fallback `PM_AUTHOR`/settings allowed)
|
|
615
743
|
- `--message` (explicit history message; empty allowed)
|
|
616
|
-
- `--
|
|
617
|
-
- `--
|
|
618
|
-
- `--
|
|
619
|
-
- `--
|
|
620
|
-
- `--
|
|
621
|
-
- `--
|
|
622
|
-
- `--
|
|
623
|
-
- `--
|
|
624
|
-
- `--blocked-
|
|
625
|
-
- `--
|
|
626
|
-
- `--
|
|
627
|
-
- `--
|
|
628
|
-
- `--
|
|
629
|
-
- `--
|
|
630
|
-
- `--
|
|
631
|
-
- `--
|
|
632
|
-
- `--
|
|
633
|
-
- `--
|
|
634
|
-
- `--
|
|
635
|
-
- `--
|
|
636
|
-
- `--
|
|
637
|
-
- `--
|
|
638
|
-
- `--
|
|
639
|
-
- `--
|
|
640
|
-
- `--
|
|
641
|
-
- `--
|
|
642
|
-
- `--
|
|
643
|
-
- `--
|
|
644
|
-
- `--
|
|
645
|
-
- `--
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
- `--
|
|
651
|
-
- `--
|
|
652
|
-
- `--
|
|
653
|
-
- `--
|
|
654
|
-
- `--
|
|
655
|
-
- `--
|
|
744
|
+
- `--template` (optional; reusable defaults loaded from `pm templates save <NAME>`)
|
|
745
|
+
- `--assignee` (explicit; clear with `--unset assignee`)
|
|
746
|
+
- `--parent` (optional; item ID reference; clear with `--unset parent`; missing-parent behavior controlled by `settings.validation.parent_reference`)
|
|
747
|
+
- `--reviewer` (optional; clear with `--unset reviewer`)
|
|
748
|
+
- `--risk` (optional; `low|med|medium|high|critical`; clear with `--unset risk`; `med` persists as `medium`)
|
|
749
|
+
- `--confidence` (optional; `0..100|low|med|medium|high`; clear with `--unset confidence`; `med` persists as `medium`)
|
|
750
|
+
- `--sprint` (optional; clear with `--unset sprint`; format policy controlled by `settings.validation.sprint_release_format`)
|
|
751
|
+
- `--release` (optional; clear with `--unset release`; format policy controlled by `settings.validation.sprint_release_format`)
|
|
752
|
+
- `--blocked-by`, `--blocked_by` (optional; item ID or free-text; clear with `--unset blocked-by`)
|
|
753
|
+
- `--blocked-reason`, `--blocked_reason` (optional; clear with `--unset blocked-reason`)
|
|
754
|
+
- `--unblock-note`, `--unblock_note` (optional; unblock rationale note; clear with `--unset unblock-note`)
|
|
755
|
+
- `--reporter` (optional; issue reporter; clear with `--unset reporter`)
|
|
756
|
+
- `--severity` (optional; `low|med|medium|high|critical`; clear with `--unset severity`; `med` persists as `medium`)
|
|
757
|
+
- `--environment` (optional; issue environment context; clear with `--unset environment`)
|
|
758
|
+
- `--repro-steps`, `--repro_steps` (optional; issue reproduction steps; clear with `--unset repro-steps`)
|
|
759
|
+
- `--resolution` (optional; issue resolution summary; clear with `--unset resolution`)
|
|
760
|
+
- `--expected-result`, `--expected_result` (optional; issue expected behavior; clear with `--unset expected-result`)
|
|
761
|
+
- `--actual-result`, `--actual_result` (optional; issue observed behavior; clear with `--unset actual-result`)
|
|
762
|
+
- `--affected-version`, `--affected_version` (optional; impacted version identifier; clear with `--unset affected-version`)
|
|
763
|
+
- `--fixed-version`, `--fixed_version` (optional; fixed version identifier; clear with `--unset fixed-version`)
|
|
764
|
+
- `--component` (optional; owning component; clear with `--unset component`)
|
|
765
|
+
- `--regression` (optional; boolean `true|false|1|0`; clear with `--unset regression`)
|
|
766
|
+
- `--customer-impact`, `--customer_impact` (optional; customer impact summary; clear with `--unset customer-impact`)
|
|
767
|
+
- `--definition-of-ready`, `--definition_of_ready` (optional; explicit empty allowed; clear with `--unset definition-of-ready`)
|
|
768
|
+
- `--order`, `--rank` (optional; integer rank/order; clear with `--unset order`)
|
|
769
|
+
- `--goal` (optional; clear with `--unset goal`)
|
|
770
|
+
- `--objective` (optional; clear with `--unset objective`)
|
|
771
|
+
- `--value` (optional; clear with `--unset value`)
|
|
772
|
+
- `--impact` (optional; clear with `--unset impact`)
|
|
773
|
+
- `--outcome` (optional; clear with `--unset outcome`)
|
|
774
|
+
- `--why-now`, `--why_now` (optional; clear with `--unset why-now`)
|
|
775
|
+
|
|
776
|
+
Mutating `create` flags (repeatable; strict mode may require each at least once depending on type policy, while progressive mode allows staged omission; clear with explicit `--clear-*` flags):
|
|
777
|
+
|
|
778
|
+
- `--dep` value format: `id=<id>,kind=<blocks|parent|child|parent_child|child_of|related|related_to|discovered_from|blocked_by|incident_from|epic|supersedes|task>,author=<a>,created_at=<iso|now>,source_kind=<value?>` (also accepts markdown `key: value` lines and stdin token `-`)
|
|
779
|
+
- `--comment` value format: `author=<a>,created_at=<iso|now>,text=<t>` (also accepts markdown `key: value` lines and stdin token `-`)
|
|
780
|
+
- `--note` value format: `author=<a>,created_at=<iso|now>,text=<t>` (also accepts markdown `key: value` lines and stdin token `-`)
|
|
781
|
+
- `--learning` value format: `author=<a>,created_at=<iso|now>,text=<t>` (also accepts markdown `key: value` lines and stdin token `-`)
|
|
782
|
+
- Log-seed repeatables (`--comment`/`--note`/`--learning`) accept only `author`, `created_at`, and `text` keys. Parsed extra keys are rejected with usage guidance to avoid silent truncation when unquoted comma segments resemble key/value pairs; quoted text (`text="hello,scope:project"`), markdown key/value input, and stdin token `-` remain supported.
|
|
783
|
+
- `--file` value format: `path=<p>,scope=<project|global>,note=<n?>` (also accepts markdown `key: value` lines and stdin token `-`)
|
|
784
|
+
- `--test` value format: `command=<c>,path=<p?>,scope=<project|global>,timeout_seconds=<n?>,env_set=<KEY=VALUE;...?>,env_clear=<KEY;...?>,shared_host_safe=<bool?>,note=<n?>` (also accepts markdown `key: value` lines and stdin token `-`; `command` is required and `path` is optional metadata)
|
|
785
|
+
- `--doc` value format: `path=<p>,scope=<project|global>,note=<n?>` (also accepts markdown `key: value` lines and stdin token `-`)
|
|
786
|
+
- `--reminder` value format: `at=<iso|date|relative>,text=<text>` (also accepts markdown `key: value` lines and stdin token `-`; use `--clear-reminders` to clear)
|
|
787
|
+
- `--type-option` / `--type_option` value format: `key=value`, `key:value`, or `key=<name>,value=<value>` (also accepts markdown `key: value` lines and stdin token `-`; use `--clear-type-options` to clear)
|
|
788
|
+
|
|
789
|
+
Per-type option policy overrides (`settings.item_types.definitions[]` and extension `registerItemTypes(...)`):
|
|
790
|
+
|
|
791
|
+
- `command_option_policies[].command`: `create` or `update`
|
|
792
|
+
- `command_option_policies[].option`: canonical option key (for example `message`, `severity`, `typeOption`)
|
|
793
|
+
- `required: true|false`: mark option mandatory/optional for the targeted command and type
|
|
794
|
+
- `enabled: true|false`: reject/allow the option at runtime for the targeted command and type
|
|
795
|
+
- `visible: true|false`: show/hide the option in policy-aware help guidance
|
|
796
|
+
|
|
797
|
+
Help and error guidance:
|
|
798
|
+
|
|
799
|
+
- `pm create --help` / `pm update --help` accept `--type <value>` to render policy-aware required/disabled/hidden option summaries plus type-option schema details (required marker, allowed values, aliases, description).
|
|
800
|
+
- Missing `--type` usage errors include rationale, active allowed values, and custom-type examples.
|
|
801
|
+
- Type-governed create validation aggregates all missing required create options and required `--type-option` keys into one deterministic usage error payload (stable flag ordering) instead of iterative one-at-a-time failures.
|
|
802
|
+
- Aggregated create/type-option validation guidance includes a deterministic type-specific "next valid example" command for one-shot remediation.
|
|
803
|
+
- Commander usage errors are normalized into a single structured guidance payload (duplicate default commander stderr messaging is not emitted).
|
|
804
|
+
- Runtime `PmCliError` paths should surface structured guidance while preserving canonical exit-code mapping, with machine-readable JSON error envelopes when `--json` is active.
|
|
656
805
|
|
|
657
806
|
Mutating `update` (v0.1 baseline):
|
|
658
807
|
|
|
659
808
|
- `--title`, `-t`
|
|
660
809
|
- `--description`, `-d`
|
|
810
|
+
- `--body`, `-b` (explicit empty string allowed; use `pm append --body` for additive narrative updates)
|
|
661
811
|
- `--status`, `-s`
|
|
662
812
|
- `--priority`, `-p`
|
|
663
813
|
- `--type`
|
|
@@ -666,12 +816,12 @@ Mutating `update` (v0.1 baseline):
|
|
|
666
816
|
- `--estimate`, `--estimated-minutes`, `--estimated_minutes`
|
|
667
817
|
- `--acceptance-criteria`, `--acceptance_criteria`, `--ac`
|
|
668
818
|
- `--assignee`
|
|
669
|
-
- `--parent`
|
|
819
|
+
- `--parent` (missing-parent behavior controlled by `settings.validation.parent_reference`)
|
|
670
820
|
- `--reviewer`
|
|
671
821
|
- `--risk` (`low|med|medium|high|critical`; `med` persists as `medium`)
|
|
672
822
|
- `--confidence` (`0..100|low|med|medium|high`; `med` persists as `medium`)
|
|
673
|
-
- `--sprint`
|
|
674
|
-
- `--release`
|
|
823
|
+
- `--sprint` (format policy controlled by `settings.validation.sprint_release_format`)
|
|
824
|
+
- `--release` (format policy controlled by `settings.validation.sprint_release_format`)
|
|
675
825
|
- `--blocked-by`, `--blocked_by`
|
|
676
826
|
- `--blocked-reason`, `--blocked_reason`
|
|
677
827
|
- `--unblock-note`, `--unblock_note`
|
|
@@ -697,22 +847,66 @@ Mutating `update` (v0.1 baseline):
|
|
|
697
847
|
- `--why-now`, `--why_now`
|
|
698
848
|
- `--author`
|
|
699
849
|
- `--message`
|
|
850
|
+
- `--allow-audit-update`, `--allow_audit_update` (ownership-safe non-owner metadata update mode; intentionally disallows lifecycle/ownership/linkage field mutations in this mode)
|
|
851
|
+
- `--allow-audit-dep-update`, `--allow_audit_dep_update` (ownership-safe non-owner append-only dependency update mode; requires at least one `--dep` and is mutually exclusive with `--allow-audit-update`)
|
|
852
|
+
- `--dep` (repeatable add format `id=<id>,kind=<...>,author=<a?>,created_at=<iso|now>,source_kind=<value?>`; use `--clear-deps` to clear all dependencies)
|
|
853
|
+
- `--dep-remove`, `--dep_remove` (repeatable selector remove by `id` or `id=<id>,kind=<kind?>,source_kind=<value?>`)
|
|
854
|
+
- `--comment` (repeatable log seed; supports plain-text shorthand for comment text, or structured `author=<a>,created_at=<iso|now>,text=<t>`; use `--clear-comments` to clear comments)
|
|
855
|
+
- `--note` (repeatable log seed format `author=<a>,created_at=<iso|now>,text=<t>`; use `--clear-notes` to clear notes)
|
|
856
|
+
- `--learning` (repeatable log seed format `author=<a>,created_at=<iso|now>,text=<t>`; use `--clear-learnings` to clear learnings)
|
|
857
|
+
- `--file` (repeatable linked-file format `path=<p>,scope=<project|global>,note=<n?>`; use `--clear-files` to clear files)
|
|
858
|
+
- `--test` (repeatable linked-test format `command=<c>,path=<p?>,scope=<project|global>,timeout_seconds=<n?>,...`; use `--clear-tests` to clear tests)
|
|
859
|
+
- `--doc` (repeatable linked-doc format `path=<p>,scope=<project|global>,note=<n?>`; use `--clear-docs` to clear docs)
|
|
860
|
+
- `--reminder` (repeatable `at=<iso|date|relative>,text=<text>`; use `--clear-reminders` to clear)
|
|
861
|
+
- `--event` (repeatable event metadata format; use `--clear-events` to clear)
|
|
862
|
+
- `--type-option`, `--type_option` (repeatable type option metadata; use `--clear-type-options` to clear)
|
|
700
863
|
|
|
701
864
|
`pm update` status semantics:
|
|
702
865
|
|
|
703
866
|
- `--status` supports all non-terminal values plus `canceled`.
|
|
704
867
|
- `--status closed` is not supported; callers must use `pm close <ID> <TEXT>` so `close_reason` is always captured.
|
|
868
|
+
- `--close-reason`, `--close_reason` support explicit close-reason set; clear with `--unset close-reason`.
|
|
869
|
+
- Reopen transition safety: moving from `closed` to a non-terminal status via `--status` auto-clears stale `close_reason` unless `--close-reason` is explicitly provided on that update call.
|
|
870
|
+
|
|
871
|
+
`pm update-many` (bulk mutation with native checkpoint lifecycle):
|
|
872
|
+
|
|
873
|
+
- Targeting filters: `--filter-status`, `--filter-type`, `--filter-tag`, `--filter-priority`, `--filter-parent`, `--filter-deadline-before`, `--filter-deadline-after`, `--filter-assignee`, `--filter-assignee-filter`, `--filter-sprint`, `--filter-release`
|
|
874
|
+
- Paging scope controls: `--limit`, `--offset`
|
|
875
|
+
- Apply payload: `pm update` mutation parity, including scalar/unset metadata flags plus linked-array repeatables (`--dep`, `--comment`, `--note`, `--learning`, `--file`, `--test`, `--doc`, `--reminder`, `--event`), explicit `--clear-*` controls, and atomic replacement flags (`--replace-deps`, `--replace-tests`)
|
|
876
|
+
- Workflow controls:
|
|
877
|
+
- `--dry-run` (preview planned per-item changes without mutation)
|
|
878
|
+
- `--rollback <checkpoint-id>` (restore a prior checkpoint snapshot)
|
|
879
|
+
- `--no-checkpoint` (disable apply-mode checkpoint capture)
|
|
880
|
+
- Safety rule: `--rollback` is exclusive with mutation payload flags.
|
|
705
881
|
|
|
706
882
|
List/search filters:
|
|
707
883
|
|
|
708
884
|
- `--type`
|
|
709
885
|
- `--tag`
|
|
710
886
|
- `--priority`
|
|
887
|
+
- `--parent` (`list*` commands; exact match on parent item ID for hierarchical scoping)
|
|
888
|
+
- `--limit`
|
|
889
|
+
- `--offset` (`list*` commands; apply offset before limit for deterministic pagination)
|
|
890
|
+
- `--stream` (`list*` commands; JSON-only newline-delimited item streaming)
|
|
711
891
|
- `--deadline-before`
|
|
712
892
|
- `--deadline-after`
|
|
713
|
-
- `--assignee` (exact match on `assignee` field
|
|
893
|
+
- `--assignee` (exact match on `assignee` field)
|
|
894
|
+
- `--assignee-filter assigned|unassigned` (assignee presence filter)
|
|
714
895
|
- `--sprint` (exact match on `sprint` field)
|
|
715
896
|
- `--release` (exact match on `release` field)
|
|
897
|
+
- `--include-body` (list* only; when enabled, each returned item includes `body`; default list rows remain front-matter-only)
|
|
898
|
+
- `--compact` / `--fields <csv>` (`list*` projection controls; mutually exclusive)
|
|
899
|
+
- `--sort <priority|deadline|updated_at|created_at|title|parent>` + `--order <asc|desc>` (`list*` deterministic sort controls; `--order` requires `--sort`)
|
|
900
|
+
- `--compact` / `--full` / `--fields <csv>` (`search` only; mutually exclusive projection controls, default compact)
|
|
901
|
+
|
|
902
|
+
Command-specific query and contract flags:
|
|
903
|
+
|
|
904
|
+
- `pm comments-audit`: `--latest <n>` (`0` allowed for summary-only rows), `--full-history` (mutually exclusive with `--latest`)
|
|
905
|
+
- `pm calendar`: `--full-period` (day/week/month full anchored window; invalid for agenda)
|
|
906
|
+
- `pm activity`: `--id`, `--op`, `--author`, `--from`, `--to`, `--stream [rows|ndjson|jsonl]` (`--stream` requires `--json`)
|
|
907
|
+
- `pm contracts`: `--flags-only`, `--availability-only` (mutually exclusive), command-scoped default behavior when `--command` is provided
|
|
908
|
+
- `pm contracts`: command flag/alias payloads include both canonical flag rows and commander alias metadata (`command_flags` + `commander_aliases`) for machine consumers
|
|
909
|
+
- `pm completion`: `--eager-tags` (legacy eager embedding; default generated scripts use lazy runtime tag lookup via `pm completion-tags`)
|
|
716
910
|
|
|
717
911
|
Mutation safety:
|
|
718
912
|
|
|
@@ -724,43 +918,88 @@ Mutation safety:
|
|
|
724
918
|
|
|
725
919
|
All commands return deterministic top-level objects (TOON by default, JSON with `--json`).
|
|
726
920
|
|
|
921
|
+
Canonical command/action schema metadata is centralized in `src/sdk/cli-contracts.ts` and reused across:
|
|
922
|
+
|
|
923
|
+
- commander normalization in `src/cli/main.ts`
|
|
924
|
+
- shell completion generation in `src/cli/commands/completion.ts`
|
|
925
|
+
- Pi wrapper `inputSchema` + action mapping in `.pi/extensions/pm-cli/index.ts`
|
|
926
|
+
|
|
927
|
+
Contract compatibility policy keeps command names/flags/aliases stable while allowing stricter machine contracts:
|
|
928
|
+
|
|
929
|
+
- Existing CLI command paths and aliases remain valid.
|
|
930
|
+
- Pi tool input validation uses strict action-scoped schema branches (schema v4) with per-action required fields and `additionalProperties: false`.
|
|
931
|
+
- `pm contracts` provides deterministic runtime contract introspection (`--action`, `--command`, `--schema-only`, `--runtime-only`, `--active-only`) for agent callers, including action availability metadata (`action_availability`) with invocability/provider diagnostics and additive extension command/action schema inclusion (`extension_commands`).
|
|
932
|
+
- Intentional compatibility exception: `pm contracts --command <name>` now narrows command/action/availability output to that selected command by default to reduce machine payload noise (omit `--command` for full corpus output).
|
|
933
|
+
- `pm contracts --flags-only` and `pm contracts --availability-only` provide mutually exclusive lightweight projections for machine consumers.
|
|
934
|
+
- Shell completion generation is sourced from the same normalized contract registry so parser/runtime/contracts/completion flag parity remains deterministic (including alias candidates).
|
|
935
|
+
- Command output remains deterministic; `--json` exposes command-contract machine payloads and JSON error envelopes.
|
|
936
|
+
|
|
727
937
|
| Command | Key inputs | Output object |
|
|
728
938
|
| --- | --- | --- |
|
|
729
939
|
| `pm init [PREFIX]` | optional prefix, `--path` | `{ ok, path, settings, created_dirs, warnings }` |
|
|
730
|
-
| `pm
|
|
731
|
-
| `pm list` | optional filter flags; excludes terminal statuses (`closed`, `canceled`) by default | `{ items, count, filters, now }` |
|
|
732
|
-
| `pm list-all` | optional filter flags; includes all statuses including terminal | `{ items, count, filters, now }` |
|
|
733
|
-
| `pm list-draft` | optional type/tag/priority/deadline/assignee/sprint/release filters | `{ items, count, filters, now }` |
|
|
734
|
-
| `pm list-open` | optional type/tag/priority/deadline/assignee/sprint/release filters | `{ items, count, filters, now }` |
|
|
940
|
+
| `pm extension [target] --install\|--uninstall\|--explore\|--manage\|--doctor\|--adopt\|--adopt-all\|--activate\|--deactivate` | exactly one lifecycle action, optional `target` (required for install/uninstall/activate/deactivate/adopt; disallowed for `adopt-all`; `doctor` supports `pm extension doctor` target syntax), scope flags (`--project` default, `--local` alias, `--global`), install/adopt source selectors (`target`, `--gh`, `--github`, optional `--ref`), bundled aliases (`beads`, `todos`), doctor detail mode (`--detail summary\|deep`), doctor trace mode (`--trace` with deep detail), manage runtime parity probe (`--runtime-probe`), optional managed-state remediation (`--fix-managed-state`), doctor strict warning exits (`--strict-exit`, alias `--fail-on-warn`); top-level action and subcommand forms share the same flag forwarding (`pm extension --doctor ...` == `pm extension doctor ...`) | `{ ok, action, scope, roots, warnings, details }` where `details` is action-specific: `explore/manage` include per-extension state/status fields (`active` compatibility alias, `enabled`, `runtime_active`, `activation_status`) plus `update_check_status`/`update_check_reason`; `manage` includes optional `runtime_probe` and `managed_state_fix` metadata; `manage`/`doctor` include triage rollups (`warning_codes`, `update_health_coverage`, `update_health_partial`, `update_check_status_totals`, remediation) with top-level warning parity; doctor summary includes blocking-failure indicators (`blocking_failure_count`, `has_blocking_failures`), trace status (`trace_enabled`), and capability metadata (`capability_contract_version`/`capability_guidance`/`capability_contract`); `adopt` reports adoption result/provenance (`adopted`, `already_managed?`, `source`) without reinstalling extension files; `adopt-all` reports bulk adoption totals and per-extension adoption rows |
|
|
941
|
+
| `pm list` | optional filter flags (including `--parent`, `--include-body`, `--compact`, `--fields`, `--sort`, `--order`, `--offset`, and JSON-only `--stream`); excludes terminal statuses (`closed`, `canceled`) by default | `{ items, count, filters, projection, sorting, now }` (or streamed newline-delimited rows when `--json --stream`) |
|
|
942
|
+
| `pm list-all` | optional filter flags (including `--parent`, `--include-body`, `--compact`, `--fields`, `--sort`, `--order`, `--offset`, and JSON-only `--stream`); includes all statuses including terminal | `{ items, count, filters, projection, sorting, now }` (or streamed newline-delimited rows when `--json --stream`) |
|
|
943
|
+
| `pm list-draft` | optional type/tag/priority/parent/deadline/assignee/sprint/release/include-body/compact/fields/sort/order/offset filters plus JSON-only stream mode | `{ items, count, filters, projection, sorting, now }` (or streamed newline-delimited rows when `--json --stream`) |
|
|
944
|
+
| `pm list-open` | optional type/tag/priority/parent/deadline/assignee/sprint/release/include-body/compact/fields/sort/order/offset filters plus JSON-only stream mode | `{ items, count, filters, projection, sorting, now }` (or streamed newline-delimited rows when `--json --stream`) |
|
|
735
945
|
| `pm list-in-progress` | same as above | `{ items, count, filters, now }` |
|
|
736
946
|
| `pm list-blocked` | same as above | `{ items, count, filters, now }` |
|
|
737
947
|
| `pm list-closed` | same as above | `{ items, count, filters, now }` |
|
|
738
948
|
| `pm list-canceled` | same as above | `{ items, count, filters, now }` |
|
|
739
|
-
| `pm
|
|
740
|
-
| `pm
|
|
741
|
-
| `pm
|
|
742
|
-
| `pm
|
|
949
|
+
| `pm aggregate` | grouped-count governance query (`--group-by parent,type` default; supported dimensions: `parent,type,priority,status,assignee,tags,sprint,release`; `--count` accepted for explicit parity) with list-like filters and optional `--include-unparented` | `{ groups, count, totals, filters, now, warnings? }` |
|
|
950
|
+
| `pm dedupe-audit` | duplicate-audit query with `--mode title_exact|title_fuzzy|parent_scope`, optional `--threshold`, optional `--limit`, and list-like filters | `{ clusters, count, mode, filters, now, warnings? }` |
|
|
951
|
+
| `pm get <ID>` | normalized id | `{ item, body, linked: { files, tests, docs }, claim_state }` where `claim_state` includes current assignee plus latest claim/release history context |
|
|
952
|
+
| `pm search <keywords...>` | keyword query tokens + optional mode/include-linked/compact/full/fields/limit filters | `{ query, mode, items, count, filters, projection, now }` |
|
|
953
|
+
| `pm reindex` | optional `--mode` (`keyword|semantic|hybrid` baseline) and additive `--progress` stderr visibility | `{ ok, mode, total_items, artifacts, warnings, generated_at }` |
|
|
954
|
+
| `pm calendar` / `pm cal` | `--view agenda|day|week|month`, `--date`, `--from`/`--to` (agenda), `--past`, `--full-period` (day/week/month only), list-like filters (`type`, `tag`, `priority`, `status`, `assignee`, `sprint`, `release`, `limit`), source controls (`--include`), and recurrence bounds (`--recurrence-lookahead-days`, `--recurrence-lookback-days`, `--occurrence-limit`) | `{ view, output_default, now, anchor, range, filters, summary, events, days }` where `range` includes period metadata (`period_start`, `period_end`, `full_period`), `summary` includes deterministic aggregate breakdown fields (`by_kind`, `by_type`, `by_status`, `recurring_events`), and markdown output includes rich event detail tokens by default |
|
|
955
|
+
| `pm context` / `pm ctx` | `--date`, `--from`/`--to`, `--past`, list-like filters (`type`, `tag`, `priority`, `assignee`, `sprint`, `release`, `limit`), `--format` | `{ output_default, now, window, filters, summary, high_level, low_level, blocked_fallback, agenda }` (defaults to TOON unless `--format` or `--json` override) |
|
|
956
|
+
| `pm beads import [--file <path\|->] [--preserve-source-ids]` | optional Beads JSONL source path (`.beads/issues.jsonl` auto-discovered first, then `issues.jsonl`; implicit `sync_base.jsonl` fallback is refused as unsafe; `--file -` requires piped stdin and fails fast on interactive TTY stdin) | `{ ok, source, imported, skipped, ids, warnings }` |
|
|
743
957
|
| `pm todos import --folder <path?>` | optional todos markdown source folder (defaults to `.pi/todos`); preserves canonical optional `ItemFrontMatter` metadata when present and applies deterministic defaults for missing PM fields | `{ ok, folder, imported, skipped, ids, warnings }` |
|
|
744
958
|
| `pm todos export --folder <path?>` | optional todos markdown destination folder (defaults to `.pi/todos`) | `{ ok, folder, exported, ids, warnings }` |
|
|
745
|
-
| `pm create ...` | required title +
|
|
746
|
-
| `pm
|
|
959
|
+
| `pm create ...` | required `--title` + `--description` + `--type`; strict mode is default (`--create-mode strict`) and enforces type-governed required options; progressive mode (`--create-mode progressive`) supports staged omission of type-level required create fields/repeatables; optional `--template` reusable defaults | `{ item, changed_fields, warnings }` |
|
|
960
|
+
| `pm templates save <NAME> ...` | template name + create-compatible option payload (subset of create flags, including repeatable entries) | `{ name, path, template, saved_at }` |
|
|
961
|
+
| `pm templates list` | optional output controls (`--json`/TOON) | `{ templates, count }` |
|
|
962
|
+
| `pm templates show <NAME>` | template name | `{ name, template }` |
|
|
963
|
+
| `pm update <ID> ...` | id + patch-like flags (`--status closed` is rejected; use `pm close <ID> <TEXT>`; `--close-reason`/`--close_reason` explicitly set `close_reason`; `--unset close-reason` clears it; reopening from `closed` to a non-terminal status auto-clears stale `close_reason` unless explicit `--close-reason` is provided; body replacement is supported via `--body`/`-b`; dependencies are mutable via `--dep` / `--dep-remove` / `--clear-deps` / `--replace-deps` (atomic replacement mode); repeatable transactional linked/log flags `--comment`/`--note`/`--learning`/`--file`/`--test`/`--doc` are supported on update with explicit `--clear-*` semantics; `--allow-audit-update` enables ownership-safe non-owner metadata updates only; `--allow-audit-dep-update` enables append-only non-owner dependency additions via `--dep`) | `{ item, changed_fields, warnings, audit_update? }` |
|
|
964
|
+
| `pm update-many` | bulk update orchestration with selection filters (`--filter-*` family), update payload parity with scalar + linked-array update flags (`--dep/--comment/--note/--learning/--file/--test/--doc/--reminder/--event`, `--clear-*`, `--replace-deps`, `--replace-tests`), and workflow controls (`--dry-run`, `--rollback <checkpoint-id>`, `--no-checkpoint`) | apply: `{ mode, matched_count, dry_run, ids, updated_count, skipped_count, failed_count, checkpoint?, rows }`; dry-run: `{ mode, matched_count, dry_run, ids, filters, planned_update_options, item_plans }` where `item_plans[].changes` includes linked-array mutation intent summaries; rollback: `{ mode, matched_count, dry_run, ids, rollback_checkpoint_id, restored_count, failed_count, rows }` |
|
|
747
965
|
| `pm delete <ID>` | id + optional `--author`/`--message`/`--force` | `{ item, changed_fields, warnings }` |
|
|
748
|
-
| `pm close <ID> <TEXT>` | id + close reason text + optional `--author/--message/--force` | `{ item, changed_fields, warnings }` |
|
|
749
|
-
| `pm append <ID> --body` | id + appended markdown | `{ item, appended, changed_fields }` |
|
|
750
|
-
| `pm claim <ID>` | id, optional `--author`/`--message`/`--force` | `{ item, claimed_by, previous_assignee, forced }` |
|
|
751
|
-
| `pm release <ID>` | id, optional `--author`/`--message`/`--force` | `{ item, released_by, previous_assignee, forced }` |
|
|
752
|
-
| `pm
|
|
753
|
-
| `pm
|
|
754
|
-
| `pm
|
|
755
|
-
| `pm
|
|
966
|
+
| `pm close <ID> <TEXT>` | id + close reason text + optional `--author/--message/--force/--validate-close [warn|strict]` | `{ item, changed_fields, warnings }` |
|
|
967
|
+
| `pm append <ID> --body` | id + appended markdown (`--body -` reads piped stdin) | `{ item, appended, changed_fields }` |
|
|
968
|
+
| `pm claim <ID>` | id, optional `--author`/`--message`/`--force` (`--force` required for terminal/lock override paths; non-terminal assignee takeover does not require force) | `{ item, claimed_by, previous_assignee, forced }` |
|
|
969
|
+
| `pm release <ID>` | id, optional `--author`/`--message`/`--allow-audit-release`/`--force` | `{ item, released_by, previous_assignee, audit_release, forced }` |
|
|
970
|
+
| `pm start-task <ID>` | lifecycle alias command (`claim` + `update --status in_progress`) with optional `--author`, `--message`, `--force` | `{ id, action: "start_task", claim, update }` |
|
|
971
|
+
| `pm pause-task <ID>` | lifecycle alias command (`update --status open` + `release`) with optional `--author`, `--message`, `--force` | `{ id, action: "pause_task", update, release }` |
|
|
972
|
+
| `pm close-task <ID> <TEXT>` | lifecycle alias command (`close` + `release`) with optional `--author`, `--message`, `--validate-close`, `--force` | `{ id, action: "close_task", close, release }` |
|
|
973
|
+
| `pm comments <ID> [TEXT] --add/--limit` | id + optional positional comment text shorthand + comment text/limit (`--add` accepts plain text, `text=<value>`, markdown `text: <value>`, or stdin token `-`; positional `TEXT` is shorthand for `--add <TEXT>`; ambiguous CSV-like key fragments such as `text=hello,scope:project` remain plain text unless `text` is explicit); optional mutation metadata flags `--author`/`--message`/`--force`; additive ownership-safe audit path `--allow-audit-comment` for non-owner append-only comments | `{ id, comments, count }` |
|
|
974
|
+
| `pm comments-audit` | optional governance filters (`--status`, `--type`, `--assignee`, `--assignee-filter`, `--parent`, `--tag`, `--sprint`, `--release`, `--priority`, `--limit-items`) plus latest/full-history export mode controls (`--latest`, `--full-history`; mutually exclusive, `--latest 0` allowed for summary-only rows) | `{ items, count, summary, filters, export, now, warnings? }` where `summary` includes additive totals/coverage/by-type metrics, `filters.full_history` and `export.mode` indicate latest vs full-history behavior, and `export.row_count` is deterministic (`0` in summary-only latest mode); in full-history mode, `rows[]` includes flat per-comment export entries for NDJSON-friendly downstream processing |
|
|
975
|
+
| `pm notes <ID> [TEXT] --add/--limit` | id + optional positional note text shorthand + note text/limit (`--add` accepts plain text, `text=<value>`, markdown `text: <value>`, or stdin token `-`; positional `TEXT` is shorthand for `--add <TEXT>`; ambiguous CSV-like key fragments such as `text=hello,scope:project` remain plain text unless `text` is explicit); optional mutation metadata flags `--author`/`--message`/`--force`; additive ownership-safe audit path `--allow-audit-comment` for non-owner append-only notes | `{ id, notes, count }` |
|
|
976
|
+
| `pm learnings <ID> [TEXT] --add/--limit` | id + optional positional learning text shorthand + learning text/limit (`--add` accepts plain text, `text=<value>`, markdown `text: <value>`, or stdin token `-`; positional `TEXT` is shorthand for `--add <TEXT>`; ambiguous CSV-like key fragments such as `text=hello,scope:project` remain plain text unless `text` is explicit); optional mutation metadata flags `--author`/`--message`/`--force`; additive ownership-safe audit path `--allow-audit-comment` for non-owner append-only learnings | `{ id, learnings, count }` |
|
|
977
|
+
| `pm files <ID> --add/--add-glob/--remove/--migrate/--append-stable/--validate-paths/--audit/--list`; `pm files discover <ID> [--apply]` | id + file refs (`--add/--remove` accept CSV key/value, markdown `key: value`, or stdin token `-`); optional glob expansion via repeatable `--add-glob` (plain glob or `pattern=<glob>,scope=<scope>,note=<text>`); optional additive linked-path hygiene (`--migrate from=<old>,to=<new>`, path existence validation, cross-item audit, non-mutating list); optional `--append-stable` avoids full-array resorting and appends new links while preserving current order; `discover` scans item text for existing project/global file paths, skips already linked files, and writes missing links only with `--apply` | standard files: `{ id, files, changed, count, migrations_applied, validation, audit }`; discover: `{ id, files, changed, apply, count, candidate_count, addable_count, added_count, skipped_existing_count, candidates, added, skipped_existing }` |
|
|
978
|
+
| `pm test <ID> --add/--remove/--run` | id + test refs/options (`--add/--remove` accept CSV key/value, markdown `key: value`, or stdin token `-`; new linked test entries must include `command=...` and may include `path=...` as optional metadata; optional linked-test runtime directives support `env_set`, `env_clear`, `shared_host_safe`, optional per-test context override `pm_context_mode=schema\|tracker\|auto`, and assertion metadata fields `assert_stdout_contains` / `assert_stdout_regex` / `assert_stderr_contains` / `assert_stderr_regex` / `assert_stdout_min_lines` / `assert_json_field_equals` / `assert_json_field_gte`; run-time supports additive `--background`, `--env-set`, `--env-clear`, `--shared-host-safe`, `--pm-context schema\|tracker\|auto`, `--check-context`, `--auto-pm-context`, `--fail-on-context-mismatch`, `--fail-on-skipped`, `--fail-on-empty-test-run`, and `--require-assertions-for-pm`; path-only add/create entries are rejected; reject recursive `test-all` linked commands at add-time, including global-flag and package-spec launcher forms such as `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`; defensively skip legacy recursive entries at run-time; reject sandbox-unsafe test-runner commands including unsandboxed direct package-manager run-script forms such as `npm run test`/`pnpm run test` and chained direct runner segments evaluated independently; linked command execution seeds sandbox project/global settings and extensions from source roots for extension/type parity, routes context per test (per-test override > run-level, `auto` routes PM tracker-read commands to tracker mode), fails PM tracker-read command mismatches by default in schema mode, emits `execution_context` metadata (including tracker-read classification plus `requested_pm_context_mode` and `auto_pm_context_applied`) in each run result, supports preflight mismatch summary warnings (`context_preflight`) when requested, supports high-confidence empty-selection detection when requested, and runs linked commands via shell-compatible spawn orchestration with deterministic timeout/maxBuffer diagnostics and structured `failure_category` classification) | foreground: `{ id, tests, run_results, failure_categories, fail_on_skipped_triggered?, warnings?, changed, count }`; background start: `{ started, duplicate_of?, run }` |
|
|
979
|
+
| `pm test-all --status --timeout` | optional status filter plus additive run controls `--background`, `--progress`, `--env-set`/`--env-clear`/`--shared-host-safe`/`--pm-context`/`--check-context`/`--auto-pm-context`/`--fail-on-context-mismatch`/`--fail-on-skipped`/`--fail-on-empty-test-run`/`--require-assertions-for-pm` (schema-mode runs fail PM tracker-read command mismatches by default); duplicate linked command/path entries are deduped per invocation (keyed by scope+normalized command or scope+path plus runtime directives + context metadata + assertion metadata) and reported as skipped; when duplicate keys carry different `timeout_seconds`, execution uses deterministic maximum timeout for that key | foreground: `{ totals, failed, passed, skipped, fail_on_skipped_triggered?, warnings?, results }`; background start: `{ started, duplicate_of?, run }` (`totals.failure_categories` included) |
|
|
980
|
+
| `pm test-runs [list|status|logs|stop|resume]` | list/status/log/stop/resume lifecycle control for managed background test runs; bare `pm test-runs` defaults to list output (`logs` supports `--stream stdout|stderr|both` and `--tail`; `stop` supports `--force`); run attribution resolves `requested_by` via explicit author -> `PM_AUTHOR` -> settings author default -> env user identifiers -> OS username -> `unknown` | list: `{ runs, count, filters }`; status: `{ run, health }`; logs: `{ run, stream, tail, stdout, stderr }`; stop: `{ run, signal_sent }`; resume: `{ resumed_from, run }` |
|
|
756
981
|
| `pm stats` | none | `{ totals, by_type, by_status, generated_at }` |
|
|
757
|
-
| `pm health` | none | `{ ok, checks, warnings, generated_at }` |
|
|
758
|
-
| `pm
|
|
759
|
-
| `pm
|
|
760
|
-
| `pm
|
|
761
|
-
| `pm
|
|
982
|
+
| `pm health` | none (runs settings/directories/extensions/storage plus integrity, history-drift, and vectorization diagnostics); supports `--strict-directories` to treat optional built-in item-type directories as required warning/failure conditions, strict warning exits (`--strict-exit`, alias `--fail-on-warn`), and vector refresh controls (`--check-only`, `--no-refresh`, `--refresh-vectors`) | `{ ok, checks, warnings, generated_at }` with extension diagnostics including condensed `details.triage`, capability guidance metadata, and directory check details (`required`, `optional`, `missing_required`, `missing_optional`) |
|
|
983
|
+
| `pm validate` | optional scoped checks (`--check-metadata`, `--check-resolution`, `--check-lifecycle`, `--check-stale-blockers`, `--check-files`, `--check-command-references`, `--check-history-drift`; default all checks); metadata checks accept `--metadata-profile core|strict|custom`; lifecycle checks surface active closure-like metadata and active items whose parents are terminal, with optional stale blocker heuristics when `--check-stale-blockers` is enabled and settings-backed lifecycle pattern lists (`settings.validation.lifecycle_*_patterns`) controlling substring matching; file checks accept `--scan-mode default|tracked-all|tracked-all-strict` plus `--include-pm-internals` opt-in and report filtered + raw candidate metrics (`candidate_total`, `candidate_scanned`, `candidate_total_raw`, `candidate_scanned_raw`) plus structured exclusion summaries (`excluded_by_reason`); resolution checks include default remediation command templates for missing resolution fields; strict warning exits via `--strict-exit` (alias `--fail-on-warn`) | `{ ok, checks, warnings, generated_at }` where metadata details include profile/source/fallback visibility fields, lifecycle details include deterministic per-category row summaries plus effective lifecycle pattern arrays and per-field pattern-source metadata (`default|settings`), and tracked-all-strict visibility includes explicit file-check detail flags (`strict_mode_forces_pm_internals`, `strict_mode_forces_pm_internals_notice`) plus warning token `validate_files_tracked_all_strict_forces_pm_internals` when strict mode force-enables PM internals |
|
|
984
|
+
| `pm config <project\|global> <get\|set\|list\|export> [key]` | scope + action; `get/set` require key, `list/export` reject key; policy/format/criterion flags apply where relevant (criterion-list keys include `definition-of-done`, `metadata-required-fields`, and lifecycle pattern keys `lifecycle-*-patterns`) | `get/set`: existing key-specific result shape; `list`: `{ scope, keys, count, settings_path, changed, warnings? }`; `export`: `{ scope, values, settings_path, changed, warnings? }` |
|
|
985
|
+
| `pm gc` | optional `--dry-run` (preview no-side-effect cleanup) and repeatable/comma-delimited `--scope index\|embeddings\|runtime` | `{ ok, dry_run, scope, removed, retained, warnings, guidance, generated_at }` |
|
|
986
|
+
| `pm contracts [--action <value>] [--command <value>] [--schema-only] [--runtime-only|--active-only] [--flags-only|--availability-only]` | optional action/command filters, schema-only mode, runtime invocability filtering, and lightweight projection modes; when `--command` is provided, command/action/availability output is narrowed to that selected command by default; when `--action` is provided without `--command`, `--flags-only` command flag output is action-scoped to matching command surfaces | `{ schema_version, schema_id, selected, actions?, action_availability?, commands?, schema?, extension_commands?, command_flags?, commander_aliases?, command_path?, cli_exposed? }` |
|
|
987
|
+
| `pm docs <ID> --add/--add-glob/--remove/--migrate/--validate-paths/--audit` | id + doc refs (`--add/--remove` accept CSV key/value, markdown `key: value`, or stdin token `-`); optional glob expansion via repeatable `--add-glob` (plain glob or `pattern=<glob>,scope=<scope>,note=<text>`); optional additive linked-path hygiene (`--migrate from=<old>,to=<new>`, path existence validation, cross-item audit) | `{ id, docs, changed, count, migrations_applied, validation, audit }` |
|
|
988
|
+
| `pm deps <ID> --format tree|graph` | id + optional output selector (`tree` default, `graph` for node/edge projection), traversal controls (`--max-depth`), repeat-collapse mode (`--collapse none|repeated`), and count-only summary mode (`--summary`) | `{ id, format, node_count, edge_count, missing_count, tree? graph? }` |
|
|
989
|
+
| `pm history <ID> --limit/--diff/--verify` | id + optional limit + additive diagnostics (`--diff` changed-field patch summaries, `--verify` hash-chain/current-hash verification) | `{ id, history, count, limit, diff, verify }` |
|
|
990
|
+
| `pm activity --limit` | optional limit plus filters (`--id`, `--op`, `--author`, `--from`, `--to`) and JSON-only stream mode (`--stream [rows|ndjson|jsonl]`) | standard: `{ activity, count, limit, filters }`; stream: line-delimited JSON entries with deterministic `meta` and `entry` records |
|
|
762
991
|
| `pm restore <ID> <TIMESTAMP\|VERSION>` | id + restore target + optional `--author/--message/--force` | `{ item, restored_from, changed_fields, warnings }` |
|
|
763
|
-
| `pm completion <shell>` | `bash`, `zsh`, or `fish`; non-JSON output is the raw script suitable for eval or pipe; JSON output is `{ shell, script, setup_hint }` | `{ shell, script, setup_hint }` |
|
|
992
|
+
| `pm completion <shell>` | `bash`, `zsh`, or `fish`; supports `--eager-tags` to embed static tag completions; default script mode uses lazy runtime tag lookup via `pm completion-tags`; non-JSON output is the raw script suitable for eval or pipe; JSON output is `{ shell, script, setup_hint }` | `{ shell, script, setup_hint }` |
|
|
993
|
+
| `pm completion-tags` | internal helper command returning current tag values for completion script lazy lookup | `{ tags, count }` |
|
|
994
|
+
|
|
995
|
+
List command row projection:
|
|
996
|
+
|
|
997
|
+
- Default `list*` rows contain `ItemFrontMatter` fields only.
|
|
998
|
+
- `--compact` projects deterministic compact fields (`id`, `title`, `status`, `type`, `priority`, `parent`, `updated_at`).
|
|
999
|
+
- `--fields <csv>` projects caller-selected list fields.
|
|
1000
|
+
- With `--include-body`, each row additionally includes `body` and `filters.include_body` is `true` (`null` when omitted in JSON; omitted in sparse TOON).
|
|
1001
|
+
- Without `--include-body`, omission of `body` is intentional for lightweight list payloads; use `pm get <ID>` when full body content is required.
|
|
1002
|
+
- `--sort` + `--order` emits deterministic `sorting` metadata describing the active sort field and direction.
|
|
764
1003
|
|
|
765
1004
|
Roadmap output contracts remain defined in this PRD for extension areas and advanced search tuning that are still out of v0.1 release scope.
|
|
766
1005
|
|
|
@@ -772,12 +1011,14 @@ Examples:
|
|
|
772
1011
|
|
|
773
1012
|
- `list*`:
|
|
774
1013
|
- `{ items, count, filters, now }`
|
|
1014
|
+
- default rows: `ItemFrontMatter`
|
|
1015
|
+
- with `--include-body`: `ItemFrontMatter + body`
|
|
775
1016
|
- `search`:
|
|
776
1017
|
- `{ query, mode, items, count, filters, now }`
|
|
777
1018
|
- `get`:
|
|
778
1019
|
- `{ item, body, linked: { files, tests, docs } }`
|
|
779
1020
|
- `create/update/delete`:
|
|
780
|
-
- `{ item, changed_fields, warnings }`
|
|
1021
|
+
- `{ item, changed_fields, warnings }` (`update` may also include `audit_update` when `--allow-audit-update` is active)
|
|
781
1022
|
- `append`:
|
|
782
1023
|
- `{ item, appended, changed_fields }`
|
|
783
1024
|
- `test-all`:
|
|
@@ -789,29 +1030,35 @@ Determinism requirements:
|
|
|
789
1030
|
- Stable key order in every object.
|
|
790
1031
|
- Stable array order for `items` (default sort: non-terminal before terminal, then priority asc, then updated_at desc, then id asc).
|
|
791
1032
|
- `pm list` excludes terminal statuses (`closed`, `canceled`) by default; `pm list-all` includes all statuses.
|
|
792
|
-
-
|
|
1033
|
+
- JSON output preserves command-contract fields (including explicit `null` placeholders where applicable by command contract); `pm search` compact projection is default unless `--full` or `--fields` is provided.
|
|
1034
|
+
- TOON output is a sparse projection that omits `null`/`undefined`/empty arrays/empty objects while preserving non-empty values.
|
|
793
1035
|
- `--quiet` prints nothing to stdout but still uses exit codes.
|
|
1036
|
+
- Stdin token paths requiring piped input fail fast on interactive TTY stdin with actionable guidance instead of waiting indefinitely for EOF.
|
|
1037
|
+
- Manual interactive EOF guidance remains explicit and cross-platform: `Ctrl+D` (Unix/macOS) and `Ctrl+Z` then `Enter` (Windows).
|
|
1038
|
+
- Output writes handle broken pipes (`EPIPE`) as expected shell behavior: stdout `EPIPE` preserves success exits for early-closing consumers and stderr `EPIPE` remains non-zero, with unhandled stack traces suppressed.
|
|
794
1039
|
|
|
795
1040
|
## 13) Search Architecture
|
|
796
1041
|
|
|
797
1042
|
### 13.0 Command contract (implemented baseline)
|
|
798
1043
|
|
|
799
|
-
`pm search <keywords
|
|
1044
|
+
`pm search <keywords...>` is implemented across keyword, semantic, and hybrid modes with deterministic ordering. The command accepts quoted or unquoted multi-word queries, searches core item corpus fields, supports vector-query execution when configured (or when local Ollama auto-defaults are resolved), and returns stable JSON/TOON payloads with compact projection default.
|
|
800
1045
|
|
|
801
1046
|
Initial flags:
|
|
802
1047
|
|
|
803
1048
|
- `--mode <keyword|semantic|hybrid>` (all modes implemented baseline; advanced semantic/hybrid tuning planned)
|
|
804
1049
|
- `--include-linked` (keyword mode and hybrid lexical component: include readable linked docs/files/tests content in corpus scoring)
|
|
805
1050
|
- `--limit <n>`
|
|
1051
|
+
- projection controls: `--compact` (default), `--full`, `--fields <csv>` (mutually exclusive)
|
|
806
1052
|
- `--limit 0` is valid and returns a deterministic empty result set (after mode/config validation) without executing embedding/vector query requests
|
|
807
1053
|
- shared list-like filters where applicable (`--type`, `--tag`, `--priority`, `--deadline-before`, `--deadline-after`)
|
|
808
|
-
- shared `--type` and `--priority` filters follow canonical validation (`--type`
|
|
1054
|
+
- shared `--type` and `--priority` filters follow canonical validation (`--type` resolved by runtime item-type registry aliases, `--priority` integer `0..4`)
|
|
809
1055
|
|
|
810
1056
|
### 13.1 Modes
|
|
811
1057
|
|
|
812
1058
|
- `keyword` (always available)
|
|
813
1059
|
- `semantic` (when embedding provider + vector store configured)
|
|
814
|
-
- `hybrid` (default if semantic available)
|
|
1060
|
+
- `hybrid` (default if semantic capability is available through explicit settings or local Ollama auto-default resolution)
|
|
1061
|
+
- for implicit default mode, if auto-defaulted semantic execution fails at runtime, search degrades to keyword mode for compatibility
|
|
815
1062
|
|
|
816
1063
|
### 13.2 Keyword corpus fields
|
|
817
1064
|
|
|
@@ -844,6 +1091,7 @@ Keyword/hybrid lexical scoring baseline also applies a deterministic exact-title
|
|
|
844
1091
|
- `index/manifest.json` (indexed item metadata summary)
|
|
845
1092
|
- `search/embeddings.jsonl` (line-delimited keyword corpus records)
|
|
846
1093
|
- `pm reindex --mode semantic|hybrid` baseline generates deterministic provider embeddings for canonical item corpus records and upserts vector records to the active vector store.
|
|
1094
|
+
- `pm reindex --mode semantic|hybrid` also rewrites `search/vectorization-status.json` with deterministic `id -> updated_at` records for the indexed corpus so health-time vector freshness checks stay in sync.
|
|
847
1095
|
- Semantic embedding generation in `pm reindex --mode semantic|hybrid` and mutation-triggered refresh paths executes in deterministic batches sized by `search.embedding_batch_size`, and each batch retries failed embedding requests up to `search.scanner_max_batch_retries` before surfacing deterministic warnings/errors.
|
|
848
1096
|
- Successful item-mutation command paths invalidate stale keyword cache artifacts (`index/manifest.json` and `search/embeddings.jsonl`) as best-effort non-fatal cleanup before the next explicit `reindex`.
|
|
849
1097
|
- Successful item-mutation command paths also perform best-effort semantic embedding refresh for affected item IDs when embedding-provider and vector-store configuration are available; when an affected ID no longer exists (for example after delete), refresh attempts prune the stale vector entry from the active store. Refresh failures degrade to deterministic warnings.
|
|
@@ -880,6 +1128,8 @@ Implemented baseline:
|
|
|
880
1128
|
|
|
881
1129
|
- Deterministic provider-configuration resolution exists in core search runtime plumbing.
|
|
882
1130
|
- OpenAI/Ollama provider blocks are normalized from settings and surfaced through a provider abstraction layer for command-time validation, request-target resolution (including OpenAI-compatible `base_url` normalization for root, `/v1`, and explicit `/embeddings` forms), 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).
|
|
1131
|
+
- When semantic settings are otherwise unset and local Ollama is installed, runtime auto-resolves built-in semantic defaults (`providers.ollama`, local `vector_store.lancedb.path`, and `search.embedding_model`) for `search`/`reindex`; auto model selection prefers `PM_OLLAMA_MODEL`, then `ollama list` embedding-like model names, then deterministic fallback `qwen3-embedding:0.6b`.
|
|
1132
|
+
- Auto-default behavior is compatibility-guarded: explicit semantic settings always take precedence, and auto-defaults can be disabled via `PM_DISABLE_OLLAMA_AUTO_DEFAULTS=1`.
|
|
883
1133
|
- `pm search --mode semantic|hybrid` and `pm reindex --mode semantic|hybrid` use this abstraction for deterministic semantic/hybrid execution (embedding generation/request handling) after configuration validation.
|
|
884
1134
|
|
|
885
1135
|
Vector stores:
|
|
@@ -894,6 +1144,26 @@ Implemented baseline:
|
|
|
894
1144
|
- Request-target planning, request payload/response normalization, deterministic Qdrant request-execution helper behavior, deterministic LanceDB local query/upsert execution helper behavior, and deterministic query-hit ordering normalization (score desc, id asc tie-break) are available through this abstraction layer.
|
|
895
1145
|
- `pm search --mode semantic|hybrid` and `pm reindex --mode semantic|hybrid` use this abstraction for deterministic vector query/upsert execution after configuration validation.
|
|
896
1146
|
|
|
1147
|
+
### 13.5 Health integrity, drift, and vectorization diagnostics
|
|
1148
|
+
|
|
1149
|
+
- `pm health` includes deterministic `directories` diagnostics:
|
|
1150
|
+
- separates core required directories from optional built-in type directories (`events`, `reminders`, `milestones`, `meetings`)
|
|
1151
|
+
- reports `missing_required` and `missing_optional` details independently
|
|
1152
|
+
- `--strict-directories` treats missing optional directories as warning/failure contributors
|
|
1153
|
+
- `--strict-exit` (alias `--fail-on-warn`) returns non-zero exit (`1`) when health warnings are present (`ok=false`)
|
|
1154
|
+
- `pm health` includes deterministic `integrity` diagnostics:
|
|
1155
|
+
- scans item/history files for merge-conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`)
|
|
1156
|
+
- emits deterministic warning codes for conflict markers, invalid item parses, and invalid JSONL history lines
|
|
1157
|
+
- `pm health` includes deterministic `history_drift` diagnostics:
|
|
1158
|
+
- checks current item corpus against history stream availability/parsability
|
|
1159
|
+
- compares current canonical item hash to latest history `after_hash`
|
|
1160
|
+
- emits deterministic warning codes for missing streams, unreadable streams, and hash mismatches
|
|
1161
|
+
- `pm health` includes deterministic `vectorization` diagnostics:
|
|
1162
|
+
- compares current item `updated_at` values to `search/vectorization-status.json`
|
|
1163
|
+
- computes stale/missing vectorization entries deterministically (sorted by item ID)
|
|
1164
|
+
- triggers targeted semantic refresh for stale IDs when semantic runtime is available (no forced full reindex)
|
|
1165
|
+
- preserves compatibility under auto-resolved Ollama defaults by keeping auto-default refresh failures non-fatal in health status while still exposing refresh details in check output
|
|
1166
|
+
|
|
897
1167
|
## 14) Extension Architecture
|
|
898
1168
|
|
|
899
1169
|
### 14.1 Locations
|
|
@@ -901,6 +1171,23 @@ Implemented baseline:
|
|
|
901
1171
|
- Global: `~/.pm-cli/extensions` (or `PM_GLOBAL_PATH/extensions`)
|
|
902
1172
|
- Project: `.agents/pm/extensions` (or `PM_PATH/extensions`)
|
|
903
1173
|
|
|
1174
|
+
Lifecycle manager command:
|
|
1175
|
+
|
|
1176
|
+
- `pm extension` is the canonical extension lifecycle command surface for install/uninstall/explore/manage/doctor/adopt/adopt-all/activate/deactivate.
|
|
1177
|
+
- Scope selection: `--project` (default), `--local` (alias of project), `--global`.
|
|
1178
|
+
- Install sources: local directory, GitHub HTTPS URL, `github.com/<owner>/<repo>[/path]`, or `--gh/--github <owner>/<repo>[/path]` with optional `--ref`.
|
|
1179
|
+
- GitHub subpath resolution probes deterministic default extension roots (`.agents/pm/extensions`, `.custom/pm-extensions`, `.custom/pm-extension`) when shorthand inputs do not include full paths.
|
|
1180
|
+
- Scope-local managed state is persisted in `<extension-root>/.managed-extensions.json` and includes source metadata plus update-check status.
|
|
1181
|
+
- `pm extension --manage` performs GitHub remote update checks for managed GitHub entries, persists latest check metadata, and returns deterministic per-extension `update_check_status`/`update_check_reason` fields plus `details.triage` status totals/remediation hints.
|
|
1182
|
+
- `pm extension --manage --runtime-probe` is opt-in and adds doctor-like runtime activation probing (`runtime_active`/`activation_status`) while preserving default manage behavior when omitted.
|
|
1183
|
+
- `pm extension --manage --fix-managed-state` can adopt unmanaged extensions before update checks to reduce managed-state remediation friction.
|
|
1184
|
+
- `pm extension --adopt <name>` records existing unmanaged installs into managed state metadata (local or GitHub provenance via `--gh/--github` and optional `--ref`) without reinstalling files.
|
|
1185
|
+
- `pm extension --adopt-all` bulk-records all unmanaged installs in selected scope into managed state metadata without reinstalling files.
|
|
1186
|
+
- `pm extension --doctor` (or `pm extension doctor`) returns consolidated diagnostics with summary/deep modes (`--detail summary|deep`), normalized warning codes, canonical load roots, active-vs-loaded project consistency diagnostics, explicit state fields (`active` compatibility alias plus `enabled`/`runtime_active`/`activation_status`), strict warning exits (`--strict-exit`, alias `--fail-on-warn`), update-health coverage signals (`update_health_coverage`, `update_health_partial`), blocking-failure indicators (`blocking_failure_count`, `has_blocking_failures`), capability guidance/contract metadata, and remediation hints.
|
|
1187
|
+
- `pm extension --doctor --detail deep --trace` adds actionable registration traces (method, command, registration index, expected schema, sanitized received payload, hint) for activation failures.
|
|
1188
|
+
- `pm extension --doctor --fix-managed-state` can adopt unmanaged extensions before diagnostics are evaluated.
|
|
1189
|
+
- `pm health` extension diagnostics include managed-state summaries/warnings for both project and global scope plus condensed `details.triage` counts/remediation for load, activation, and migration issues, including parity warning code `extension_update_health_partial_coverage` when action-required unmanaged extensions reduce update-check coverage and capability guidance/contract metadata for unknown manifest capabilities.
|
|
1190
|
+
|
|
904
1191
|
### 14.2 Load order and precedence
|
|
905
1192
|
|
|
906
1193
|
1. Core built-ins
|
|
@@ -923,6 +1210,9 @@ Precedence:
|
|
|
923
1210
|
"priority": 100,
|
|
924
1211
|
"capabilities": [
|
|
925
1212
|
"commands",
|
|
1213
|
+
"parser",
|
|
1214
|
+
"preflight",
|
|
1215
|
+
"services",
|
|
926
1216
|
"schema",
|
|
927
1217
|
"renderers",
|
|
928
1218
|
"importers",
|
|
@@ -934,31 +1224,41 @@ Precedence:
|
|
|
934
1224
|
|
|
935
1225
|
Capability declarations are enforced during extension activation. API registrations and
|
|
936
1226
|
hook registrations must match declared capabilities (`commands`, `renderers`, `hooks`,
|
|
937
|
-
`schema`, `importers`, `search`) or activation fails with deterministic
|
|
1227
|
+
`schema`, `importers`, `search`, `parser`, `preflight`, `services`) or activation fails with deterministic
|
|
938
1228
|
`extension_activate_failed:<layer>:<name>` diagnostics.
|
|
939
1229
|
Unknown capability names are ignored for registration gating and produce deterministic
|
|
940
|
-
discovery diagnostics `extension_capability_unknown:<layer>:<name>:<capability
|
|
1230
|
+
discovery diagnostics `extension_capability_unknown:<layer>:<name>:<capability>:allowed=<csv>:suggested=<capability|none>` with legacy alias suggestions when applicable (for example `migration`/`validation` -> `schema`).
|
|
1231
|
+
Health/doctor payloads additionally publish machine-readable contract metadata (`capability_contract.version`, `capability_contract.capabilities`, `capability_contract.legacy_aliases`) for automation parity.
|
|
941
1232
|
|
|
942
1233
|
### 14.4 Extension API contracts (v1 draft)
|
|
943
1234
|
|
|
944
|
-
|
|
1235
|
+
Current implementation (single-wave override model):
|
|
945
1236
|
|
|
946
1237
|
- `activate(api)` hook registration surface is available.
|
|
947
1238
|
- `api.hooks.beforeCommand/afterCommand/onWrite/onRead/onIndex` dispatch is deterministic with failure containment and per-hook context snapshot isolation.
|
|
948
1239
|
- Hook registration APIs (`api.hooks.beforeCommand/afterCommand/onWrite/onRead/onIndex`) require function handlers; invalid payloads throw during extension activation and surface deterministic `extension_activate_failed:<layer>:<name>` warnings.
|
|
949
|
-
- `api.registerCommand(
|
|
950
|
-
- `api.registerCommand(
|
|
1240
|
+
- `api.registerCommand(...)` validation failures now carry actionable trace metadata that doctor deep trace mode can expose (method, registration index, command, expected schema, received payload, hint) to speed activation triage.
|
|
1241
|
+
- `api.registerCommand(name, override)` supports deterministic synchronous overrides for existing command results before output rendering; override execution receives cloned command `args`/`options`/`global` snapshots, `pm_root`, and a cloned prior result payload so extensions can apply contextual overrides without mutating caller fallback state.
|
|
1242
|
+
- `api.registerCommand({ name, run })` supports deterministic extension command handlers for declared command paths, including dynamically surfaced non-core extension command paths (for example `beads import` and `acme sync`) and extension-first replacement of core command handlers at dispatch time.
|
|
1243
|
+
- `api.registerParser(command, override)` supports command-scoped parser override contracts (sync/async) that can rewrite `args`, `options`, and `global` context before handler dispatch.
|
|
1244
|
+
- `api.registerPreflight(override)` supports command preflight interception (sync/async) to control item-format gate enforcement, preflight migration sync, extension migration execution, and mandatory-migration gate enforcement.
|
|
1245
|
+
- `api.registerService(service, override)` supports deterministic service-level override hooks (`output_format`, `error_format`, `help_format`, `lock_acquire`, `lock_release`, `history_append`, `item_store_write`, `item_store_delete`) with last-wins precedence per service key.
|
|
951
1246
|
- Extension command-handler execution receives cloned `args`/`options`/`global` snapshots so handler-side mutation cannot leak into caller runtime command state.
|
|
952
1247
|
- Registered extension command names are canonicalized with trim + lowercase + internal-whitespace collapse before storage and dispatch matching, ensuring equivalent command paths resolve deterministically.
|
|
953
1248
|
- Required extension-command dispatch semantics are deterministic: no matched handler returns command-not-found for extension-only paths, while a matched handler throw returns generic failure with warning code `extension_command_handler_failed:<layer>:<name>:<command>`.
|
|
954
1249
|
- `api.registerRenderer(format, renderer)` supports deterministic `toon`/`json` output overrides; renderer execution receives isolated command context snapshots (`command`, `args`, `options`, `global`, `pm_root`) plus an isolated result snapshot so failed renderer-side mutation cannot alter core fallback output.
|
|
955
|
-
- Extension API registration baseline now includes deterministic registration-time validation and metadata capture for `api.registerFlags`, `api.registerItemFields`, `api.registerMigration`, `api.registerImporter`, `api.registerExporter`, `api.registerSearchProvider`, and `api.registerVectorStoreAdapter`.
|
|
1250
|
+
- Extension API registration baseline now includes deterministic registration-time validation and metadata capture for `api.registerFlags`, `api.registerItemFields`, `api.registerItemTypes`, `api.registerMigration`, `api.registerImporter`, `api.registerExporter`, `api.registerSearchProvider`, and `api.registerVectorStoreAdapter`.
|
|
956
1251
|
- `api.registerImporter(name, importer)` and `api.registerExporter(name, exporter)` now provide runtime command wiring in addition to metadata capture: each registration deterministically exposes extension command-handler paths `<name> import` and `<name> export` (canonicalized with trim + lowercase + internal-whitespace collapse) and executes through the same isolated command-handler context snapshots used by `api.registerCommand({ name, run })`.
|
|
957
1252
|
- Dynamically surfaced extension command paths now render deterministic help metadata derived from registered `api.registerFlags(...)` definitions while preserving loose option parsing behavior for runtime command dispatch.
|
|
958
|
-
- Extension API and hook registration calls enforce manifest capability declarations (`commands`, `renderers`, `hooks`, `schema`, `importers`, `search`) and fail activation deterministically when an extension registers outside its declared capabilities.
|
|
959
|
-
- Extension activation diagnostics include deterministic registration counts and metadata summaries for the above registries (flags, item fields, migrations, importers, exporters, search providers, and vector store adapters), `pm health` exposes deterministic migration status summaries from registered migration definitions (`status="failed"` -> failed, `status="applied"` -> applied, any other/missing status -> pending), and core write command paths enforce deterministic mandatory-migration gating (`mandatory=true` + status not `"applied"` -> unresolved blocker, with `--force` bypass on force-capable write commands).
|
|
1253
|
+
- Extension API and hook registration calls enforce manifest capability declarations (`commands`, `renderers`, `hooks`, `schema`, `importers`, `search`, `parser`, `preflight`, `services`) and fail activation deterministically when an extension registers outside its declared capabilities.
|
|
1254
|
+
- Extension activation diagnostics include deterministic registration counts and metadata summaries for the above registries (flags, item fields, item types, migrations, importers, exporters, search providers, and vector store adapters), `pm health` exposes deterministic migration status summaries from registered migration definitions (`status="failed"` -> failed, `status="applied"` -> applied, any other/missing status -> pending), and core write command paths enforce deterministic mandatory-migration gating (`mandatory=true` + status not `"applied"` -> unresolved blocker, with `--force` bypass on force-capable write commands). Mandatory extension migrations are executed in pre-action lifecycle before write-gate enforcement.
|
|
1255
|
+
- Registration runtime wiring is live for:
|
|
1256
|
+
- item-field defaults + validation on create/update (`registerItemFields`)
|
|
1257
|
+
- search provider selection via `settings.search.provider` (`registerSearchProvider`)
|
|
1258
|
+
- vector adapter query/upsert selection via `settings.vector_store.adapter` (`registerVectorStoreAdapter`)
|
|
1259
|
+
- migration runtime execution and mandatory gate evaluation (`registerMigration`)
|
|
960
1260
|
|
|
961
|
-
Full v1 draft surface
|
|
1261
|
+
Full v1 draft surface:
|
|
962
1262
|
|
|
963
1263
|
```ts
|
|
964
1264
|
export interface PmExtension {
|
|
@@ -968,8 +1268,12 @@ export interface PmExtension {
|
|
|
968
1268
|
|
|
969
1269
|
export interface ExtensionApi {
|
|
970
1270
|
registerCommand(def: CommandDefinition): void;
|
|
1271
|
+
registerParser(command: string, override: ParserOverride): void;
|
|
1272
|
+
registerPreflight(override: PreflightOverride): void;
|
|
1273
|
+
registerService(service: ExtensionServiceName, override: ServiceOverride): void;
|
|
971
1274
|
registerFlags(targetCommand: string, flags: FlagDefinition[]): void;
|
|
972
1275
|
registerItemFields(fields: SchemaFieldDefinition[]): void;
|
|
1276
|
+
registerItemTypes(types: ItemTypeDefinition[]): void;
|
|
973
1277
|
registerMigration(def: SchemaMigrationDefinition): void;
|
|
974
1278
|
registerRenderer(format: "toon" | "json", renderer: Renderer): void;
|
|
975
1279
|
registerImporter(name: string, importer: Importer): void;
|
|
@@ -990,7 +1294,7 @@ export interface ExtensionApi {
|
|
|
990
1294
|
|
|
991
1295
|
- Extension load failure must not corrupt core data.
|
|
992
1296
|
- Failed extension is marked unhealthy and reported via `pm health`.
|
|
993
|
-
- `pm health` extension checks must run safe runtime load and activation probes (including
|
|
1297
|
+
- `pm health` extension checks must run safe runtime load and activation probes (including installed managed extensions) and emit deterministic warning codes for import/activation failures (for example `extension_load_failed:<layer>:<name>` and `extension_activate_failed:<layer>:<name>`).
|
|
994
1298
|
- Extension manifest `entry` paths must resolve within the extension directory after canonical path resolution (including symlink targets); traversal/escape paths are rejected with deterministic diagnostics (for example `extension_entry_outside_extension:<layer>:<name>`).
|
|
995
1299
|
- Core commands remain functional unless extension is explicitly required by invoked command.
|
|
996
1300
|
|
|
@@ -1007,7 +1311,7 @@ export interface ExtensionApi {
|
|
|
1007
1311
|
- Mandatory migration resolution is deterministic: `status` equal to `"applied"` (case-insensitive) is treated as resolved; any other/missing status is unresolved.
|
|
1008
1312
|
- Force-capable write commands may bypass the guard with explicit `--force`; write commands without `--force` remain blocked until blockers resolve.
|
|
1009
1313
|
|
|
1010
|
-
## 15)
|
|
1314
|
+
## 15) Bundled Managed Extensions Required in v1
|
|
1011
1315
|
|
|
1012
1316
|
### A) Beads import
|
|
1013
1317
|
|
|
@@ -1017,7 +1321,8 @@ Command:
|
|
|
1017
1321
|
|
|
1018
1322
|
Current baseline status (release-hardening):
|
|
1019
1323
|
|
|
1020
|
-
- Command is
|
|
1324
|
+
- Command is packaged in bundled managed extension source (`.agents/pm/extensions/beads`) using `activate(api)` and `api.registerCommand({ name, run })` for `beads import`.
|
|
1325
|
+
- Command path is available only after extension install/activation in selected scope (`pm extension --install beads` or explicit path install).
|
|
1021
1326
|
|
|
1022
1327
|
Behavior:
|
|
1023
1328
|
|
|
@@ -1038,7 +1343,8 @@ Commands:
|
|
|
1038
1343
|
|
|
1039
1344
|
Current baseline status (release-hardening):
|
|
1040
1345
|
|
|
1041
|
-
- Commands are
|
|
1346
|
+
- Commands are packaged in bundled managed extension source (`.agents/pm/extensions/todos`) using `activate(api)` and `api.registerCommand({ name, run })` for `todos import` and `todos export`.
|
|
1347
|
+
- Command paths are available only after extension install/activation in selected scope (`pm extension --install todos` or explicit path install).
|
|
1042
1348
|
|
|
1043
1349
|
Behavior:
|
|
1044
1350
|
|
|
@@ -1061,7 +1367,8 @@ Current baseline status (release-hardening):
|
|
|
1061
1367
|
|
|
1062
1368
|
- Implemented as a Pi agent extension source module at `.pi/extensions/pm-cli/index.ts` (outside the `pm` CLI command surface).
|
|
1063
1369
|
- Registers one Pi tool named `pm` via Pi's extension API (`registerTool`) and maps `action` + command-shaped fields to `pm` CLI invocations.
|
|
1064
|
-
-
|
|
1370
|
+
- Tool action enums and parameter JSON Schema are sourced from the shared command contract registry (`src/sdk/cli-contracts.ts`) to avoid drift with core CLI/completion surfaces.
|
|
1371
|
+
- Action dispatch currently covers the full v0.1 command-aligned set (`init`, `config`, `create`, `list`, `list-all`, `list-draft`, `list-open`, `list-in-progress`, `list-blocked`, `list-closed`, `list-canceled`, `calendar`, `context`, `get`, `search`, `reindex`, `history`, `activity`, `restore`, `update`, `close`, `delete`, `append`, `comments`, `notes`, `learnings`, `files`, `docs`, `deps`, `test`, `test-all`, `stats`, `health`, `validate`, `gc`, `completion`, `templates-save`, `templates-list`, `templates-show`, `claim`, `release`) plus extension lifecycle actions (`extension-install`, `extension-uninstall`, `extension-explore`, `extension-manage`, `extension-doctor`, `extension-adopt`, `extension-adopt-all`, `extension-activate`, `extension-deactivate`), extension action aliases (`beads-import`, `todos-import`, `todos-export`), and workflow presets (`start-task`, `pause-task`, `close-task`).
|
|
1065
1372
|
- Invocation fallback order is deterministic for distribution resilience: attempt `pm` first, then fallback to packaged `node <package-root>/dist/cli.js` when `pm` is unavailable.
|
|
1066
1373
|
|
|
1067
1374
|
- Expose one tool `pm`.
|
|
@@ -1070,8 +1377,11 @@ Current baseline status (release-hardening):
|
|
|
1070
1377
|
- common fields (`id`, `title`, `status`, `tags`, `body`, etc.)
|
|
1071
1378
|
- completion parity field `shell` (`action=completion` -> `pm completion <shell>`)
|
|
1072
1379
|
- search-specific parity fields including `mode` and `includeLinked` (`--include-linked`)
|
|
1380
|
+
- list/runtime parity fields including `offset` and `progress` where command surfaces support those flags
|
|
1381
|
+
- close/validate parity fields including `validateClose`, `checkMetadata`, `checkResolution`, `checkLifecycle`, `checkStaleBlockers`, `checkFiles`, `scanMode`, `includePmInternals`, `strictExit`, `failOnWarn`, `checkHistoryDrift`, and `checkCommandReferences`
|
|
1382
|
+
- contracts parity fields including `schemaOnly`, `runtimeOnly`, and `activeOnly`
|
|
1073
1383
|
- claim/release metadata parity fields including `author`, `message`, and `force` (`--author`, `--message`, `--force`)
|
|
1074
|
-
- create/update scalar parity fields using camelCase wrapper parameters that forward to the canonical CLI flags for planning/workflow metadata (`parent`, `reviewer`, `risk`, `confidence`, `sprint`, `release`, `blockedBy`, `blockedReason`, `unblockNote`, `definitionOfReady`, `order`, `goal`, `objective`, `value`, `impact`, `outcome`, `whyNow`) and issue metadata (`reporter`, `severity`, `environment`, `reproSteps`, `resolution`, `expectedResult`, `actualResult`, `affectedVersion`, `fixedVersion`, `component`, `regression`, `customerImpact`)
|
|
1384
|
+
- create/update scalar parity fields using camelCase wrapper parameters that forward to the canonical CLI flags for planning/workflow metadata (`parent`, `reviewer`, `risk`, `confidence`, `sprint`, `release`, `blockedBy`, `blockedReason`, `unblockNote`, `definitionOfReady`, `order`, `goal`, `objective`, `value`, `impact`, `outcome`, `whyNow`, `closeReason`) and issue metadata (`reporter`, `severity`, `environment`, `reproSteps`, `resolution`, `expectedResult`, `actualResult`, `affectedVersion`, `fixedVersion`, `component`, `regression`, `customerImpact`)
|
|
1075
1385
|
- explicit empty-string passthrough for empty-allowed CLI flags (for example `--description ""` and `--body ""`)
|
|
1076
1386
|
- numeric scalar parity for numeric CLI flags: wrapper accepts either JSON numbers or strings for `priority`, `estimate`, `limit`, and `timeout`, then stringifies values for deterministic CLI argument emission
|
|
1077
1387
|
- Return object:
|
|
@@ -1080,6 +1390,13 @@ Current baseline status (release-hardening):
|
|
|
1080
1390
|
|
|
1081
1391
|
Wrapper behavior must remain aligned with CLI semantics and exit conditions.
|
|
1082
1392
|
|
|
1393
|
+
Schema-capability registrations are also validated deterministically at activation-time:
|
|
1394
|
+
|
|
1395
|
+
- `registerFlags`: each entry must provide at least one of `long`/`short`; optional metadata fields must match expected scalar types.
|
|
1396
|
+
- `registerItemFields`: each entry requires non-empty `name` and `type`.
|
|
1397
|
+
- `registerItemTypes`: each type requires non-empty `name`; nested `options[]` and `command_option_policies[]` entries enforce required key fields and boolean toggles.
|
|
1398
|
+
- `registerMigration`: typed migration metadata (`id`, `description`, `status`, `mandatory`, `run`) is validated when provided.
|
|
1399
|
+
|
|
1083
1400
|
## 16) Security and Data Integrity
|
|
1084
1401
|
|
|
1085
1402
|
- All writes are lock-protected + atomic.
|
|
@@ -1089,10 +1406,18 @@ Wrapper behavior must remain aligned with CLI semantics and exit conditions.
|
|
|
1089
1406
|
- Extension manifest `entry` paths must not escape their owning extension directory.
|
|
1090
1407
|
- Dynamic extension command loose-option parsing must ignore unsafe prototype keys (`__proto__`, `constructor`, `prototype`) and use null-prototype option maps before passing option snapshots to extension command handlers.
|
|
1091
1408
|
- Never execute linked test commands without explicit `--run`.
|
|
1409
|
+
- Reject new linked test entries that omit `command` metadata (`pm test --add` and `pm create --test`); `path` is optional metadata and cannot be the only runnable signal.
|
|
1092
1410
|
- Reject linked test command entries that invoke `pm test-all` (including global-flag and package-spec launcher variants such as `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 loops.
|
|
1093
1411
|
- `pm test <ID> --run` defensively skips legacy linked command entries that invoke `pm test-all` (including global-flag and package-spec launcher variants such as `npx`, `pnpm dlx`, and `npm exec` launcher forms) and records deterministic skipped results.
|
|
1094
1412
|
- Reject linked test-runner command entries (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 and rejected when not explicitly sandboxed.
|
|
1413
|
+
- Linked command execution in `pm test --run` and `pm test-all` must keep temporary sandbox isolation while seeding both project/global `settings.json` and `extensions/` directories from source roots so extension-defined type behavior matches direct workspace commands.
|
|
1414
|
+
- Linked PM-command test runs support additive context mode `--pm-context schema|tracker|auto` plus per-test metadata override `pm_context_mode=schema|tracker|auto`; tracker mode seeds tracker corpus into sandbox, auto mode routes PM tracker-read commands to tracker context, per-test overrides take precedence over run-level mode, and every run result emits deterministic `execution_context` metadata (resolved roots, item counts, mismatch signal, PM tracker-read classification).
|
|
1415
|
+
- In default `--pm-context schema` mode, PM tracker-read linked commands fail on context mismatch by default; `--fail-on-context-mismatch` remains available to enforce mismatch failures for non-tracker-read PM command shapes.
|
|
1416
|
+
- `pm test --run` and `pm test-all` support additive strict governance guards: `--fail-on-context-mismatch`, `--fail-on-skipped`, `--fail-on-empty-test-run`, and `--require-assertions-for-pm`.
|
|
1417
|
+
- Linked test assertion metadata (`assert_stdout_contains`, `assert_stdout_regex`, `assert_stderr_contains`, `assert_stderr_regex`, `assert_stdout_min_lines`, `assert_json_field_equals`, `assert_json_field_gte`) is optional and must be evaluated as deterministic assertion failures even when process exit code is `0`.
|
|
1095
1418
|
- `pm test-all` executes each unique linked command/path key at most once per run; duplicate entries are reported as skipped to keep totals deterministic while avoiding redundant execution. Duplicate-key timeout conflicts resolve deterministically to the maximum `timeout_seconds` value for that key.
|
|
1419
|
+
- Linked test execution should emit stderr heartbeat lines in interactive terminals so long-running commands remain observable instead of appearing hung.
|
|
1420
|
+
- Linked test timeout handling should attempt graceful termination first and then apply deterministic force-kill fallback for stubborn child process trees.
|
|
1096
1421
|
- Optional providers use explicit settings; secrets come from env or settings with documented precedence.
|
|
1097
1422
|
- Restore must verify replay hashes and fail loudly on mismatch.
|
|
1098
1423
|
|
|
@@ -1105,7 +1430,10 @@ Wrapper behavior must remain aligned with CLI semantics and exit conditions.
|
|
|
1105
1430
|
- `author_default`
|
|
1106
1431
|
- `locks.ttl_seconds`
|
|
1107
1432
|
- `output.default_format`
|
|
1433
|
+
- `history.missing_stream`
|
|
1434
|
+
- `validation.sprint_release_format`
|
|
1108
1435
|
- `workflow.definition_of_done[]`
|
|
1436
|
+
- `item_types.definitions[]` (custom type aliases/folders, required create fields/repeatables, `options[]`, and optional `command_option_policies[]`)
|
|
1109
1437
|
- `extensions.enabled[]`
|
|
1110
1438
|
- `extensions.disabled[]`
|
|
1111
1439
|
- `search.score_threshold`
|
|
@@ -1137,9 +1465,18 @@ Default `settings.json` object written by `pm init`:
|
|
|
1137
1465
|
"output": {
|
|
1138
1466
|
"default_format": "toon"
|
|
1139
1467
|
},
|
|
1468
|
+
"history": {
|
|
1469
|
+
"missing_stream": "auto_create"
|
|
1470
|
+
},
|
|
1471
|
+
"validation": {
|
|
1472
|
+
"sprint_release_format": "warn"
|
|
1473
|
+
},
|
|
1140
1474
|
"workflow": {
|
|
1141
1475
|
"definition_of_done": []
|
|
1142
1476
|
},
|
|
1477
|
+
"item_types": {
|
|
1478
|
+
"definitions": []
|
|
1479
|
+
},
|
|
1143
1480
|
"extensions": {
|
|
1144
1481
|
"enabled": [],
|
|
1145
1482
|
"disabled": []
|
|
@@ -1182,6 +1519,16 @@ Definition-of-Done config baseline:
|
|
|
1182
1519
|
- `pm config <project|global> get definition-of-done` returns the currently effective list for the selected scope with deterministic TOON/JSON output.
|
|
1183
1520
|
- Empty criteria are rejected; duplicate criteria are deduplicated with lexicographic ordering.
|
|
1184
1521
|
|
|
1522
|
+
History missing-stream policy config baseline:
|
|
1523
|
+
|
|
1524
|
+
- `pm config <project|global> set history-missing-stream-policy --policy auto_create|strict_error` updates `settings.history.missing_stream`.
|
|
1525
|
+
- `pm config <project|global> get history-missing-stream-policy` returns the active policy.
|
|
1526
|
+
|
|
1527
|
+
Sprint/release format policy config baseline:
|
|
1528
|
+
|
|
1529
|
+
- `pm config <project|global> set sprint-release-format-policy --policy warn|strict_error` updates `settings.validation.sprint_release_format`.
|
|
1530
|
+
- `pm config <project|global> get sprint-release-format-policy` returns the active policy.
|
|
1531
|
+
|
|
1185
1532
|
Notes:
|
|
1186
1533
|
|
|
1187
1534
|
- Key order in file output MUST remain exactly as shown above.
|
|
@@ -1206,8 +1553,9 @@ Sandbox safety requirements (hard):
|
|
|
1206
1553
|
- Tests MUST NOT read/write the repository's real `.agents/pm`.
|
|
1207
1554
|
- Every test suite uses temporary sandbox storage via `PM_PATH`.
|
|
1208
1555
|
- PM-driven test execution MUST use a sandbox wrapper command (`node scripts/run-tests.mjs test|coverage`) that creates a temporary directory, sets both `PM_PATH` and `PM_GLOBAL_PATH`, runs the requested test command, and cleans up the sandbox afterward.
|
|
1209
|
-
- `pm test <ID> --add` MUST enforce this by rejecting sandbox-unsafe test-runner command entries at add-time unless they use `node scripts/run-tests.mjs ...` or explicitly set both `PM_PATH` and `PM_GLOBAL_PATH`; this includes unsandboxed direct package-manager run-script variants (for example `npm run test` and `pnpm run test`) and chained direct test-runner segments that are not explicitly sandboxed.
|
|
1556
|
+
- `pm test <ID> --add` MUST enforce this by requiring `command` metadata (with optional `path` metadata) and rejecting sandbox-unsafe test-runner command entries at add-time unless they use `node scripts/run-tests.mjs ...` or explicitly set both `PM_PATH` and `PM_GLOBAL_PATH`; this includes unsandboxed direct package-manager run-script variants (for example `npm run test` and `pnpm run test`) and chained direct test-runner segments that are not explicitly sandboxed.
|
|
1210
1557
|
- `pm test <ID> --run` MUST defensively skip legacy linked command entries that invoke `pm test-all` (including global-flag and package-spec launcher variants such as `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`) and surface deterministic skipped diagnostics.
|
|
1558
|
+
- `pm test <ID> --run` and `pm test-all` MUST preserve sandbox isolation while seeding project/global `settings.json` and `extensions/` into sandbox roots so extension-defined schemas and type filters remain parity-consistent with direct workspace runs.
|
|
1211
1559
|
- Integration tests spawn built CLI subprocesses (`node dist/cli.js ...`) with explicit
|
|
1212
1560
|
`PM_PATH`, `PM_GLOBAL_PATH`, and `PM_AUTHOR`.
|
|
1213
1561
|
- Temporary sandbox directories must be cleaned up after each test/suite.
|
|
@@ -1216,7 +1564,7 @@ Required unit coverage areas:
|
|
|
1216
1564
|
|
|
1217
1565
|
- Parser/serializer round-trip and key ordering determinism.
|
|
1218
1566
|
- ID normalization/generation behavior.
|
|
1219
|
-
- Deadline and
|
|
1567
|
+
- Deadline parsing and explicit clear/unset validation behavior.
|
|
1220
1568
|
- History patch + hash generation.
|
|
1221
1569
|
- Lock conflict/stale-lock behavior.
|
|
1222
1570
|
|
|
@@ -1347,11 +1695,11 @@ Definition of Done:
|
|
|
1347
1695
|
Checklist:
|
|
1348
1696
|
|
|
1349
1697
|
- [x] extension manifest loader + sandboxed execution boundary (deterministic manifest discovery, precedence, failure-isolated runtime loading, realpath/symlink-resolved entry containment enforcement, command-handler context snapshot isolation for `args`/`options`/`global`, per-hook context snapshot isolation, and dynamic extension command loose-option parsing hardening (null-prototype option maps + prototype-pollution key rejection) are implemented; broader command sandbox API surface is post-v0.1 roadmap)
|
|
1350
|
-
- [x] hook lifecycle (extension `activate(api)` baseline with deterministic hook registration is implemented; registration now validates hook handlers as functions at activation time, per-hook context snapshot isolation prevents mutation leakage across hook callbacks and caller state, and `beforeCommand`/`afterCommand` command-lifecycle execution plus baseline read/write/index call-site wiring 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
|
|
1698
|
+
- [x] hook lifecycle (extension `activate(api)` baseline with deterministic hook registration is implemented; registration now validates hook handlers as functions at activation time, per-hook context snapshot isolation prevents mutation leakage across hook callbacks and caller state, and `beforeCommand`/`afterCommand` command-lifecycle execution plus baseline read/write/index call-site wiring 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 bundled managed beads/todos import-export source/item/history file operations are implemented)
|
|
1351
1699
|
- [x] renderer and command extension points (deterministic core-command override + renderer override registration/dispatch is implemented with failure containment, extension command handlers for declared command paths including dynamically surfaced non-core paths are implemented, dynamic command help now surfaces `registerFlags` metadata deterministically, deep snapshot isolation for override/renderer result contexts is implemented, and override/renderer execution now includes cloned command `args`/`options`/`global` snapshots plus `pm_root` metadata for contextual deterministic extension output behavior)
|
|
1352
|
-
- [x]
|
|
1353
|
-
- [x]
|
|
1354
|
-
- [x]
|
|
1700
|
+
- [x] bundled managed beads import extension (bundled source packaging in `.agents/pm/extensions/beads`, install-only command surfacing through `pm extension`, Beads JSONL field mapping, deterministic defaults, `op: "import"` history entries, and parity polish implemented)
|
|
1701
|
+
- [x] bundled managed todos import/export extension (bundled source packaging in `.agents/pm/extensions/todos`, install-only command surfacing through `pm extension`, todos markdown round-trip, canonical optional metadata preservation including planning/workflow and issue fields, hierarchical ID preservation, and `med` alias normalization implemented)
|
|
1702
|
+
- [x] Pi tool wrapper extension source module (Pi agent extension module at `.pi/extensions/pm-cli/index.ts` with full v0.1 action dispatch parity, including `completion` + `shell` mapping, camelCase parameter surface for all canonical scalar metadata, explicit empty-string passthrough, numeric-flag stringification, claim/release parity, packaged CLI fallback, and distribution packaging polish implemented)
|
|
1355
1703
|
|
|
1356
1704
|
Definition of Done:
|
|
1357
1705
|
|