Thanks for helping improve pm-cli. This project is designed for deterministic, agent-friendly workflows and uses pm itself as the source of truth for planning and implementation tracking.
- Node.js 22.18+
- pnpm 10+
pnpm install
pnpm build
node dist/cli.js --helpFor maintainer sessions that mutate real tracker data in this repository:
# from repository root
export PM_AUTHOR="maintainer-agent"
# refresh global pm from this repository and verify availability
npm install -g .
pm --version
# prefer global pm after refresh; fallback to the built CLI if needed
export PM_CMD="pm"
# export PM_CMD="node dist/cli.js"
$PM_CMD --version
node -v
pnpm -v
pnpm buildFor real repository tracking, do not override PM_PATH.
For tests, always use sandboxed storage via node scripts/run-tests.mjs ... (sets both PM_PATH and PM_GLOBAL_PATH).
- Track work in
pmitems (claim, link files/tests/docs, and log comments/evidence). - Treat
pmdata and runtime behavior as the source of truth; update user-facing docs as needed without using them as test contracts. - Prefer small, reviewable changesets with deterministic behavior.
Run standard checks:
pnpm build
pnpm typecheck
pnpm test
pnpm test:coverageFor pm-linked safe execution (required when running tests through pm test / pm test-all), use:
node scripts/run-tests.mjs test
node scripts/run-tests.mjs coverageThe runner creates a temporary sandbox and sets PM_PATH and PM_GLOBAL_PATH so tests never touch repository planning data.
When validating linked-test automation behavior, include guard-flag coverage for --fail-on-skipped, --fail-on-empty-test-run, and --require-assertions-for-pm.
When changing validation behavior, include targeted checks for:
pm validate --check-metadata --metadata-profile core|strict|custompm validate --check-files --scan-mode tracked-allpm validate --check-files --scan-mode tracked-all-strict
Every change must only improve the codebase — CI blocks any pull request that introduces a new quality issue. Run the lint suite before pushing:
pnpm lint # eslint (complexity + maintainability) + jscpd duplication + static-quality gateComplex Method no-regression gate. ESLint enforces a cyclomatic-complexity
ceiling (complexity max 17 — a function at CC ≥ 18 fails), calibrated to
CodeFactor's "Complex Method" detector. The full set of pre-existing violations is
grandfathered in eslint-suppressions.json (ESLint native bulk suppressions), so:
- A new complex method (or making an existing one worse) fails
pnpm lintin CI — you must simplify it. - Fixing a complex method makes its suppression unused, which also fails lint
until you prune the baseline. Run
pnpm lint:eslint:pruneand commit the smallereslint-suppressions.json— the baseline only ever shrinks.
Do not regenerate the whole baseline (pnpm lint:complexity:baseline) to silence a
new violation; that defeats the gate. Driving the baseline to empty is the path to a
CodeFactor A+ (tracked under epic pm-92if).
Greptile review. pnpm review:greptile:gate runs the Greptile CLI reviewer over
the current branch and fails on findings. It is wired into pnpm release:gates
(skip with --skip-greptile) and skips gracefully when the Greptile CLI is
unavailable or unauthenticated, so token-less CI never blocks on it; the Greptile
GitHub App still reviews every PR independently.
When changing stdin, output, exit handling, or linked test execution, run targeted terminal-compatibility regressions before full-suite validation:
node scripts/run-tests.mjs test -- \
tests/unit/parse-utils.spec.ts \
tests/unit/beads-command.spec.ts \
tests/unit/test-command.spec.ts \
tests/integration/cli.integration.spec.ts \
tests/integration/release-readiness-runtime.spec.tsBehavior expectations to preserve:
- Interactive TTY stdin is rejected for piped-only
-inputs with actionable guidance. - Exit-code mappings stay stable (
0..5) while CLI failures remain deterministic. - Linked test orchestration remains non-interactive and reports timeout/maxBuffer failures clearly.
Start with the documentation index. Focused pages:
- Onboarding - first-two-hours maintainer and contributor setup.
- Quickstart - first repository setup and item lifecycle.
- Agent Guide - canonical
pmworkflow for coding agents. - Command Reference - command families and examples.
- Configuration - settings, output, storage, search, and validation.
- Testing - sandbox-safe local and linked-test workflows.
- Architecture - source tree, storage, mutation contract, history, search, and extension host internals.
- Extensions and SDK - extension lifecycle and public SDK.
- Releasing - maintainer release procedure.
pm-cli extensions live in .agents/pm/extensions/ (project) or ~/.pm-cli/extensions/ (global). See docs/EXTENSIONS.md for the full guide. Each extension needs:
- A manifest file
manifest.jsondeclaringname,version,entry,priority, andcapabilities. - An entry module exporting
activate(api).
The api object provides:
api.registerCommand({ name, run })— add or override command handlers (handlerremains backward-compatible but emits migration warning; preferrun).api.registerRenderer(format, renderer)— overridetoon/jsonoutput.api.registerImporter(name, importer)— adds<name> importcommand path.api.registerExporter(name, exporter)— adds<name> exportcommand path.api.registerFlags(targetCommand, flags)— declare flags for extension commands.api.registerItemFields(fields)— declare custom schema fields.api.registerMigration(def)— declare schema migrations.api.registerSearchProvider(provider)— add custom search providers.api.registerVectorStoreAdapter(adapter)— add custom vector store adapters.api.hooks.beforeCommand/afterCommand/onWrite/onRead/onIndex— lifecycle hooks.
Use the published SDK import path for extension type contracts:
import { defineExtension, type ExtensionApi } from "@unbrained/pm-cli/sdk";Dispatch behavior is extension-first for registered command handlers: matching extension command paths can replace core command execution at runtime. Keep compatibility in mind and provide explicit rollback instructions (--no-extensions) in docs/tests when introducing new override behavior.
Only register capabilities that are listed in your manifest's capabilities array. Registration outside declared capabilities fails extension activation deterministically.
Run pm health to inspect extension load/activation status, capability guidance/contract metadata, and migration summaries.
Use pm extension --doctor --detail deep --trace when triaging activation failures, and pm extension --manage --runtime-probe when you need opt-in runtime parity in manage output.
When unmanaged extension state is expected to be managed, use pm extension --doctor --fix-managed-state or pm extension --manage --fix-managed-state before re-running diagnostics.
- Include focused scope and rationale.
- Confirm all checks pass (
pnpm build && pnpm typecheck && pnpm test:coverage). - CI runs the full build/test matrix —
ubuntu-latest(Node 22, 24) andmacos-latest(Node 24) — on every pull request and onmainpushes (doc/markdown-only pushes tomainare skipped viapaths-ignore; pull requests always run regardless of the changed paths). Nightly keeps broader regression coverage (Windows and Node 25). - Update relevant user-facing docs when behavior changes, but keep enforcement in
pmdata and runtime tests. - Keep private operations artifacts out of tracked public docs and package output.
- Add/maintain tests for any new behavior (100% coverage required).
- Reference relevant
pmitem IDs in PR description.