Agent Guide
This guide is optimized for coding agents that need to understand and mutate repository work with minimal context.
Agent Quick Context
Run this before heavy work. The first call is the canonical cold start. Then run the request-specific duplicate and ownership checks before item mutation:
pm context --limit 10 --for orient
pm search "<request keywords>" --limit 10
pm list --status open --limit 20
pm list --status in_progress --limit 20
Run the optional guidance setup commands only when needed:
pm init --agent-guidance status
pm package install guide-shell --project
pm guide workflows
The completed-task replay gate selects that one-call protocol from equivalent fixed-corpus candidates: 1,055 estimated tokens versus 2,293 for the historical four-read sequence and 4,798 for contracts --summary plus next. The reviewed numbers and per-step receipts live in the published token baseline.
If a relevant item exists, reuse it. If not, create a parent lineage, then create and claim the child implementation item.
When AGENTS/CLAUDE guidance is missing, use pm init --agent-guidance add to inject compact workflow guardrails, or pm init --agent-guidance skip to persist an explicit decline.
Tracked documentation work: pm-u9d0.
Canonical Loop
- Orient
pm context --limit 10 --for orient
pm search "<keywords>" --limit 10
pm list --status open --limit 20
pm list --status in_progress --limit 20
- Create only when necessary
pm create --create-mode progressive \
--title "..." \
--description "..." \
--type Epic \
--status open \
--priority high \
--comment "created_at=now,text=Duplicate check evidence: ..."
Priority accepts either numeric 0..4 or named aliases critical, high, medium, low, and minimal.
Repeated singular/plural list flags accumulate, so --tag a --tag b is equivalent to --tags a,b (same for --status and --fields on read commands). You no longer have to pre-join values into one comma list, and list/search accept --tags as a never-block alias for the canonical read filter --tag.
--tags REPLACES the whole tag list. To edit tags without restating the full set, prefer --add-tags <value> (adds without replacing) and --remove-tags <value> (prunes) on create/update/update-many (both repeatable; CSV or JSON-array). --remove-tags is update/update-many only. Also note --expected/--actual are short aliases for --expected-result/--actual-result on these commands, matching pm close.
--acceptance-criteria/--ac likewise explicitly REPLACES the whole criteria value and cannot be combined with --add-ac or --remove-ac. Prefer --add-ac <text> (appends one criterion; deduped on exact text) and --remove-ac <text> (removes one criterion by exact text) on update/update-many so concurrent branch edits with disjoint additions merge instead of clobbering. Every removal must match or the complete mutation fails atomically with structured unmatched-selector recovery. Acceptance criteria use semicolons as storage boundaries, so one criterion cannot itself contain a semicolon.
Local dependency targets supplied to create, update, or update-many must already exist. Mark cross-workspace targets with source_kind=external; reserve --allow-unresolved-deps for deliberate staged imports and retain its structured warning as evidence.
pm update <item-id> --add-tags urgent,backend # keep existing tags, add two
pm update <item-id> --remove-tags stale # drop one, keep the rest
Create hierarchy from broad to narrow: Epic -> Feature -> Task or Issue. Use --parent <id> for child items.
- Claim
pm claim <item-id>
pm update <item-id> --status in_progress --message "Start implementation"
- Clarify
pm update <item-id> --description "..." --ac "..." --estimate 90
pm append <item-id> --body "Implementation notes..."
- Link execution context
pm files <item-id> --add path=src/app.ts,note="entrypoint"
pm files <item-id> --add src/app.ts --note "entrypoint"
pm docs <item-id> --add path=docs/COMMANDS.md,note="public docs"
pm test <item-id> --add command="node scripts/run-tests.mjs test -- tests/unit/app.spec.ts",timeout_seconds=240
- Record progress
pm comments <item-id> "Implemented the retry path."
pm notes <item-id> --add "Design rationale or tradeoff."
pm learnings <item-id> --add "Durable lesson for future work."
- Validate and close
pm test <item-id> --run --progress
node scripts/run-tests.mjs coverage
pm comments <item-id> "Evidence: linked test and coverage passed."
pm close <item-id> "Acceptance criteria met; verification passed." --resolution "Delivered behavior" --expected "Required outcome" --actual "Verified outcome" --validate-close warn
pm release <item-id>
If a warning close omitted evidence, use its recovery.suggested_retry_args
to append an evidence update while preserving the original close event. See
Close Evidence Recovery.
For real subprocess tests, set cwd, PM_PATH, and PM_GLOBAL_PATH to the
fixture's temporary workspace and trackers. This also isolates bootstrap and
implicit discovery reads. Disable external probes with
PM_AGENT_PROBES=0 when testing deterministic process output.
When testing conflicting ambient context, preserve that deliberate input in the
fixture. CLI and MCP dispatch scope SDK identity signals to the resolved tracker;
tests compare complete history bytes while the unrelated tracker's claims change.
Token-Minimal Retrieval
| Need | Command |
|---|---|
| The single next action + why | pm next (concrete ready leaves first; completed-container closeout rows surface only when no leaf work is ready; --ready-only for the tightest output) |
| Next ready work in one epic | pm next --parent <id> |
| Canonical cold-start orientation | pm context --limit 10 --for orient (1,055 estimated tokens on the fixed 101-item replay corpus) |
| Next work and agenda | pm context --limit 10 |
| Comprehensive whole-tracker snapshot | pm context --depth full (every section, no per-section row cap) |
| Status of one epic/subtree | pm context --parent <id> --depth deep |
| Relevant items | pm search "<keywords>" --limit 10 (keyword hits are score-ranked; keyword mode defaults to 50 results, result.total reports the full pre-limit count) |
| Require every query token | pm search "<keywords>" --match-mode and (hard-filter; exact = contiguous phrase; default or adds an all-terms ranking bonus) |
| Just the match count | pm search "<keywords>" --count (no hit rows; count/total carry the matched total) |
| Per-query score threshold | pm search "<keywords>" --min-score 5 (overrides settings search.score_threshold for this query) |
| Every matched row (no cap) | pm list --all --no-truncate --brief (result.total reports the full count when a --limit/--offset truncates) |
| Item bodies in bulk (one call) | pm list --status open --json --include-body (avoids one pm get per item) |
| Open work only | pm search "<keywords>" --status open (drops closed-history noise; did-you-mean on typos) |
| Scope search like list | pm search "<keywords>" --type Task --assignee <name> --parent <id> (full pm list filter parity) |
| Items changed since last window | pm list --all --updated-after <prev-run-ISO> --brief (relative -2h/-7d also work) |
| Open items changed today | pm list --status open --today --brief (local-midnight shorthand; mutually exclusive with --updated-after) |
| Items changed recently | pm list --all --recent --brief (last seven days; mutually exclusive with --updated-after) |
| Single item | pm get <id> |
| Full machine payload | pm get <id> --full --json |
| Command flags | pm <command> --help --json |
| Command intent map | pm contracts --summary --json (one command plus terse intent per row; use before command-scoped contracts) |
| Low-noise machine contracts | pm contracts --command <command> --flags-only --json |
| Semantic index refresh | pm reindex --mode semantic --progress (stale-first by default; add --full to force full rebuild; requires the search-advanced package) |
| Timeline | pm activity --id <id> --limit 20 |
| Audited history redaction | pm history-redact <id> --literal "<secret>" --replacement "[redacted]" --dry-run |
| Audited history re-anchor | pm history-repair <id> --dry-run (clears drift flagged by pm health/pm validate) |
| Register custom item type | pm schema add-type <Name> --description "<text>" --default-status open (then pm create <Name> "...") |
| Remove custom item type | pm schema remove-type <Name> (warns if items still use it; built-ins refused) |
| Register custom status | pm schema add-status <id> --role <active|terminal|...> --alias <name> --order <n> |
| Remove custom status | pm schema remove-status <id> (warns if items use it; built-in statuses refused) |
| Agent plan create | pm plan create --title "<scope>" --harness claude-code --scope "<short>" --claim |
| Agent plan create with steps | pm plan create --title "<scope>" --step "<step 1>" --step "<step 2>" --step "<step 3>" (repeated --step seeds ordered steps) |
| Agent plan step update | pm plan update-step <plan-id> plan-step-001 --step-status in_progress --step-evidence "<short>" |
| Agent plan read | pm plan show <plan-id> --depth brief (or --fields id,title,steps_summary) |
| Materialize plan steps | pm plan materialize <plan-id> --steps plan-step-002 --materialize-type Task |
| Dependencies | pm deps <id> --format tree |
| Graph queries | pm graph successors <id> --limit 20 (also ancestors, paths, impact, analyze, audit, communities, redundancy, dominators, plan) |
| Bulk update by id allowlist | pm update-many --ids pm-a,pm-b --priority 1 --dry-run (preview, then drop --dry-run) |
| Audited bulk close (sprint closeout) | pm close-many --filter-sprint <s> --reason "<text>" --dry-run (full pm close semantics per item; --rollback <id> to undo) |
| Local docs routing | pm install guide-shell --project, then pm guide <topic> |
| Compact mutation echo | pm --no-changed-fields create "..." (drops the redundant changed_fields array, keeps changed_field_count) |
| Minimal mutation echo | pm --id-only create "..." (prints only id and status for single-item mutations) |
| Duplicate close | pm close <duplicate> --duplicate-of <canonical> (or -d <canonical>) |
| Long body from a file | pm create <Type> "<title>" --body-file ./spec.md (also on pm update; mutually exclusive with --body) |
| Close with short flags | pm close <id> -r "<reason>" / -m "<history msg>" / -d <canonical> |
| Close via resolution only | pm close <id> --resolution "<summary>" (used as the close reason when one is required) |
Default TOON output is preferred for model-readable loops. Use --json only when strict parsing is needed.
list/search compact mode is intentionally token-light: it returns compact items plus only active filters (and runtime schema filters when present), omitting default projection/sorting/now trailer metadata.
Over MCP the mutation tools (pm_create/pm_update/pm_append/pm_close, and pm_run for update-many) are already compact by default: they return changed_field_count instead of the full changed_fields array. Pass fullChangedFields=true only when you need the explicit field-level delta, or idOnly=true for single-item id/status output.
pm create --parent <id> fails fast when the parent cannot be found. Use --allow-missing-parent only for deliberate imports or staged backlog reconstruction.
Guide Routing for Agents
Use the canonical guide topic map when local in-CLI documentation routing is useful.
Ownership Rules
- Claim before heavy edits.
pm claim <id>can take over non-terminal work from another owner.- Use
--forceonly for explicit override paths. - Release when pausing, handing off, or after close.
Reviewed Delivery Closeout
Before closing repository defects, set escape_class and structured
gate_evidence through pm update as described in
Defect Evidence.
Run pnpm quality:defect-evidence after the terminal transitions: a static
gate run before closure cannot validate evidence required only for closed items.
Treat PM evidence, item closure, and the generated changelog as part of the
reviewed change. Add all evidence known before merge to the active branch,
close and release the item there, regenerate CHANGELOG.md, and include those
artifacts in the same pull request.
If evidence depends on the merge commit SHA or a post-merge hosted result, use
a normal main-based follow-up pull request for the repository mutation. Never
push tracker-only or changelog-only closeout directly to main: that direct
commit becomes the release candidate but has no reviewed analyzer provenance,
so Release analyzer readiness (main) must refuse it. Record external
post-merge observations on GitHub without changing repository state when no
tracked closeout update is required. See Releasing
for the release contract.
Review and Analyzer Proof
Use the review helper to wait for terminal checks, then inspect its paginated inventory of comments, reviews, inline threads, edits, reactions, and resolution state. Inspect failed-check details in the receipt even when the helper itself exits successfully.
node scripts/reviews/pr-review-loop.mjs watch --pr <number> --repo unbraind/pm-cli --interval 60
node scripts/release/hosted-analysis-gate.mjs --repo unbraind/pm-cli --sha <full-40-character-head-sha> --json
Both receipts must pass for the exact current head before merge. A successful CodeFactor check can still contain a notice: the stricter analyzer gate requires zero outstanding annotations and verifies DeepScan plus branch protection. Do not substitute a green check conclusion for that proof. This escape and its correction are recorded in pm-08mt4k.
Use the helper's acknowledge-inline operation for actionable inline findings
and acknowledge for top-level comments or review summaries. Rate valid feedback
positively and explain false or stale findings on their actual review surface.
After each push, request the reviewers again and wait for terminal results;
provider quota or skipped reviews are limitations, not approvals. Before merge,
run inventory once more to catch new or edited feedback, and require all
findings to have an explicit disposition. Compare each artifact's revision
and pass it as --revision when acknowledging feedback, so edited bodies get
fresh decisions and retrying a handled revision adds no duplicate reply.
See Review Loop for the revision and reply contracts.
Documentation Rules for Agents
- Keep README short.
- Put details in focused docs under
docs/. - Keep reusable workflow prompts in
.agents/skills/*and route viapm guide skillsafterguide-shellis installed. - Use relative links such as
[Command Reference](https://github.com/unbraind/pm-cli/blob/056b37fb2916ba3386744208fe9206daee591288/docs/COMMANDS.md). - Add tracker references near the top of new docs when a task created the change.
- Link docs back to the active item with
pm docs. - Do not link public docs to ignored local operations artifacts or private evidence logs.
Scheduling and Handoff
Read SDK execution contracts before building an
agent work allocator. Use next and claim --next for executable work; inspect
decision_needed, gate_needed, and containers when no recommendation is
available. Only opt into those buckets when the current task calls for them.
Use pause-task to stop work; release alone preserves in-progress status.
Context summary totals describe the matching population, while returned_focus
describes the bounded selection.
Safe Defaults
Use these defaults unless the task requires otherwise:
- Automatic supported-harness attribution for mutations; use
--authoronly when an explicit override is required. node scripts/run-tests.mjs testandnode scripts/run-tests.mjs coveragefor tests.pm validate --check-resolution --check-history-driftbefore closing broad work.pm history-redact <id> --dry-runbefore rewriting sensitive history payloads, then rerun without--dry-runonce scope is confirmed.pm history-repair <id> --dry-runwhenpm healthorpm validate --check-history-driftreport drifted streams; it re-anchors the hash chain and reconciles with the on-disk item without touching item content. Rerun without--dry-runto apply.pm merge reconcile --dry-run --jsonafter a branch merge that touched tracker data. Review every discarded-value receipt before applying; a lossy reconciliation requires the explicit--forceacceptance flag.history-repairalone does not settle merge receipts.pm schema listandpm schema show <Type>before creating custom-domain work; they show built-in, persisted custom, and extension-provided item types without reading schema files by hand.pm schema add-type <Name>whenpm create/pm updatereject a project-specific type as invalid; it registers the type in.agents/pm/schema/types.jsonsopm create <Name> "..."works. Built-in types are reserved; the upsert is idempotent.pm schema remove-type <Name>removes a custom type (warns, non-blocking, if items still use it).pm schema add-status <id> --role <role>/pm schema remove-status <id>manage custom lifecycle statuses in.agents/pm/schema/statuses.json; roles come from the runtime status-role vocabulary, the upsert is idempotent, and built-in default statuses cannot be removed.pm schema listnow reports statuses (builtin vs custom) alongside types.pm init --type-preset agile|ops|researchfor new projects that should start with domain item types instead of generic tasks only.pm initmaintains a fenced.gitignoreblock for.agents/pm/runtime/,.agents/pm/search/, and.agents/pm/locks/. If those caches were committed before initialization, remove them from the index once withgit rm -r --cached .agents/pm/runtime .agents/pm/search .agents/pm/locks.- After switching embedding provider/model, run
pm reindex --mode semantic --fullorpm reindex --mode hybrid --fullto rebuild vectors completely;pm reindex --mode keywordignores--fulland now warns when ledger identity drift is detected. pm normalize --dry-run --jsonbefore lifecycle metadata cleanups (requires thegovernance-auditpackage).pm health --check-onlywhen inspecting repository health without refresh side effects.- Mistyped command names get a
Did you mean: <command>?hint, including typos of the executable shortcut aliases —pm shwo <id>suggestsget(the canonical ofshow/view), andpm comemntsuggestscomments.
Multi-Branch and Worktree Workflows
Concurrent agents work on ordinary Git branches/worktrees; tracker artifacts need the semantic merge contract from Merge Safety. The short loop:
- After a fresh clone or new worktree, run
pm merge installonce so the field-aware merge drivers back the committed.gitattributesfence. - After every merge that touches
.agents/pm, runpm merge reconcile --dry-run --json, review the receipt classification, then applypm merge reconcile. Add--forceonly after explicitly accepting or re-applying every discarded scalar value. Finish withpm validate --check-storage-integrity --check-history-drift, thenpm history <id> --verify --strict-exitfor each affected stream (_workspacefor workspace state). - Repositories fanning out many branches between merges should raise id entropy:
pm config project set ids_token_length 6. - Use
--add-ac/--remove-ac(not--ac) so concurrent acceptance-criteria edits merge instead of clobbering.
Self-Repair Remediation
When gating on pm health / pm validate, read the executable fix command from the output instead of hardcoding a warning-code-to-command mapping:
pm health --jsonper-checkdetails.remediation_mapmaps each warning-code prefix to apmfix command (for example{ "history_drift_missing_stream": "pm history-repair <id>" }). It is present in default/--fulloutput and omitted in--brief/--summary. With more than one drifted stream the history_drift commands point atpm history-repair --all(one audited bulk pass) instead of the per-item template.pm healthincludes a read-onlylockscheck (stale/unreadable/unparseable lock counts using the same classificationpm gc --scope locksacts on);locks_stale_count:<n>remediates viapm gc --scope locks,locks_unreadable:<n>viapm gc --scope locks --dry-run.pm validate --fix-hints(read-only) addsdetails.fix_hints[]to each failing check — a uniform list of executablepmcommands for that check's findings.pm validate --auto-fixapplies the safe, deterministic subset of those fixes itself (resolution/close_reason backfills derived from the item's own fields) and reports every action infixes.planned_fixes[]/applied_fixes[](item id + field + equivalentpmcommand). Preview with--dry-run. Two scopes are gated (opt-in): structural lifecycle fixes (reparent an active child off a terminal parent, or clear the parent link) behind--fix-scope lifecycle, and per-typeestimated_minutesbackfills behind--fix-scope estimates(config-driven defaults viavalidation.estimate_defaults_by_type). Gated fixes appear inplanned_fixes[]/gated_fixes[]until granted.--fix-scopeis an exact allowlist (default:metadata,resolution), so--fix-scope estimatesapplies only estimate fixes. Acceptance criteria are deliberately hint-only (no deterministic source to derive from). Auto-fix never closes or deletes items.pm validate --check-filesreportsdetails.missing_linked_path_rows— owner attribution for every stale linked path (<path>:<classification> owner=<id> status=… field=files|docsone-liners by default;--verbose-file-listsfor the full{ path, classification, items: [...] }objects) so an agent can fix the right item without a reverse lookup.pm validate --prune-missingremoves stale linked-file/doc LINKS whose paths classify asdeleted(no same-basename candidate left in the workspace scan);movedpaths keep their relink candidate indetails.missing_linked_path_classificationsinstead of being pruned. Honors--dry-run; never touches real files.
Both draw from the same remediation registry, so an agent can substitute the concrete <id> and run the command to auto-repair findings. Extension health checks expose their remediation under details.triage.remediation instead. See Command Reference.