Documentation
On this page
  1. Command migration
  2. Compact transport receipts
  3. SDK and MCP

Lifecycle Commands and Ownership

Tracked by pm-ik19 and pm-eq4x and pm-r1f9f1.

Bulk mutations and ownership compositions share SDK implementations with their compatibility spellings. Runtime help and contracts describe the active surface:

pm update many --help
pm close many --help
pm close delete --help
pm contracts --command 'close many' --flags-only --json

Command migration

Canonical invocation Compatibility invocation
pm update many --ids <ids> --priority 1 pm update-many --ids <ids> --priority 1
pm close many --ids <ids> --reason "Verified" pm close-many --ids <ids> --reason "Verified"
pm close delete <id> --dry-run pm delete <id> --dry-run
pm claim <id> --start pm start-task <id>
pm release <id> --pause pm pause-task <id>
pm close <id> "Verified" --release-assignment pm close-task <id> "Verified"

The old spellings remain accepted as hidden aliases. Bulk aliases are permanent; the three task aliases are deprecated. Human output for deprecated aliases can include migration hints according to ux.deprecation_hints; JSON and quiet invocations suppress those hints. Bulk commands retain their existing filters, stdin selection, dry runs, rollback behavior, and evidence flags. Put bulk flags after many. Deletion recovery remains pm history restore <id> <version>.

Plain claim, release, update, and close keep their original semantics. claim <id> --start rejects --if-available before mutation. It claims ownership, then moves the item to the configured in-progress status. claim --next --start selects the next caller-available item with the same filters, --if-available behavior, and race-loss walk as claim --next. Ranking happens before any lock, so a candidate can change before it is claimed. Each attempt re-reads the candidate under its item lock and then claims it and moves it to the configured in-progress status in one locked mutation and one claim history event. No other agent can therefore observe the claimed item before it starts. Configured type workflows are enforced, a terminal candidate is refused (terminal_state_conflict), and the receipt carries start: { from_status, to_status }. A claim without an id or --next is refused with missing_required_argument, and claim <id> --next with ambiguous_option_combination; their next steps never tell the caller to pass a flag that is already present. claim <id> --start --next (or --if-available) is refused by the explicit-start composition with invalid_argument_value, whose recovery names the flags to remove. release --pause moves work to the configured open status, then releases ownership. close --release-assignment records the close and its inline evidence, then releases ownership.

Each constituent operation enforces its own policy and writes its own history. Compositions do not provide rollback across operations: for example, if the status transition fails after a successful claim, the claim remains. Inspect the item before retrying after an error. A second-step failure retains the original error code and adds recovery guidance naming the completed operation. Its SDK error cause retains the underlying failure.

Compact transport receipts

CLI and MCP compositions default to an id, final status, action, and changed_field_count, plus compact receipts for each constituent step. The root count is the number of distinct fields touched across the steps, not their sum. Step receipts retain ownership, close reason, warnings, and recovery evidence. Item descriptions, bodies, and annotation histories are not echoed by default.

Use CLI --full-changed-fields or MCP fullChangedFields: true for complete constituent results; --id-only or idOnly: true returns only the final identity and status. CLI --no-changed-fields preserves item snapshots while replacing field arrays with counts. Plain release supports the same output controls. Typed PmClient methods and the direct SDK primitives retain full results.

SDK and MCP

import { PmClient } from "@unbrained/pm-cli/sdk";

const pm = new PmClient({ pmRoot: "/project/.agents/pm" });
const started = await pm.claim("pm-example", { start: true });
const nextStarted = await pm.claimNext({ start: true }); // ranked selection, then one locked claim-and-start write
const paused = await pm.release("pm-example", { pause: true });
const closed = await pm.close("pm-example", "Acceptance verified", {
  releaseAssignment: true,
  resolution: "Implemented the requested behavior",
  expectedResult: "Acceptance checks pass",
  actualResult: "Acceptance checks passed",
  validateClose: "warn",
});

Literal true options return typed StartTaskResult, PauseTaskResult, or CloseTaskResult receipts. Their discriminators remain start_task, pause_task, and close_task, with the constituent results available under claim, update, close, or release. Public runStartTask, runPauseTask, and runCloseTask primitives expose the same SDK-owned compositions.

MCP actions remain claim, release, and close, using start, pause, and releaseAssignment. MCP claim with next: true and start: true uses the same ranked selection and single locked claim-and-start write as claim --next --start. Action-specific discovery types claim's start as boolean; scheduling actions retain string timestamps. For the broad provider tool schema, pass the claim boolean through options: { start: true } because its shared flat start property retains the scheduling string contract. Bulk action names remain update_many, close_many, and delete for transport compatibility.

See SDK Lifecycle Policy for transaction and policy ownership and CLI Scripting Contract for output projection.

From docs/LIFECYCLE_COMMANDS.md in pm 2026.11.13. View on GitHub