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

  1. 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
  1. 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.

  1. Claim
pm claim <item-id>
pm update <item-id> --status in_progress --message "Start implementation"
  1. Clarify
pm update <item-id> --description "..." --ac "..." --estimate 90
pm append <item-id> --body "Implementation notes..."
  1. 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
  1. 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."
  1. 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 --force only 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 via pm guide skills after guide-shell is 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 --author only when an explicit override is required.
  • node scripts/run-tests.mjs test and node scripts/run-tests.mjs coverage for tests.
  • pm validate --check-resolution --check-history-drift before closing broad work.
  • pm history-redact <id> --dry-run before rewriting sensitive history payloads, then rerun without --dry-run once scope is confirmed.
  • pm history-repair <id> --dry-run when pm health or pm validate --check-history-drift report drifted streams; it re-anchors the hash chain and reconciles with the on-disk item without touching item content. Rerun without --dry-run to apply.
  • pm merge reconcile --dry-run --json after a branch merge that touched tracker data. Review every discarded-value receipt before applying; a lossy reconciliation requires the explicit --force acceptance flag. history-repair alone does not settle merge receipts.
  • pm schema list and pm 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> when pm create/pm update reject a project-specific type as invalid; it registers the type in .agents/pm/schema/types.json so pm 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 list now reports statuses (builtin vs custom) alongside types.
  • pm init --type-preset agile|ops|research for new projects that should start with domain item types instead of generic tasks only.
  • pm init maintains a fenced .gitignore block for .agents/pm/runtime/, .agents/pm/search/, and .agents/pm/locks/. If those caches were committed before initialization, remove them from the index once with git rm -r --cached .agents/pm/runtime .agents/pm/search .agents/pm/locks.
  • After switching embedding provider/model, run pm reindex --mode semantic --full or pm reindex --mode hybrid --full to rebuild vectors completely; pm reindex --mode keyword ignores --full and now warns when ledger identity drift is detected.
  • pm normalize --dry-run --json before lifecycle metadata cleanups (requires the governance-audit package).
  • pm health --check-only when 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> suggests get (the canonical of show/view), and pm comemnt suggests comments.

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 install once so the field-aware merge drivers back the committed .gitattributes fence.
  • After every merge that touches .agents/pm, run pm merge reconcile --dry-run --json, review the receipt classification, then apply pm merge reconcile. Add --force only after explicitly accepting or re-applying every discarded scalar value. Finish with pm validate --check-storage-integrity --check-history-drift, then pm history <id> --verify --strict-exit for each affected stream (_workspace for 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 --json per-check details.remediation_map maps each warning-code prefix to a pm fix command (for example { "history_drift_missing_stream": "pm history-repair <id>" }). It is present in default/--full output and omitted in --brief/--summary. With more than one drifted stream the history_drift commands point at pm history-repair --all (one audited bulk pass) instead of the per-item template.
  • pm health includes a read-only locks check (stale/unreadable/unparseable lock counts using the same classification pm gc --scope locks acts on); locks_stale_count:<n> remediates via pm gc --scope locks, locks_unreadable:<n> via pm gc --scope locks --dry-run.
  • pm validate --fix-hints (read-only) adds details.fix_hints[] to each failing check — a uniform list of executable pm commands for that check's findings.
  • pm validate --auto-fix applies the safe, deterministic subset of those fixes itself (resolution/close_reason backfills derived from the item's own fields) and reports every action in fixes.planned_fixes[] / applied_fixes[] (item id + field + equivalent pm command). 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-type estimated_minutes backfills behind --fix-scope estimates (config-driven defaults via validation.estimate_defaults_by_type). Gated fixes appear in planned_fixes[]/gated_fixes[] until granted. --fix-scope is an exact allowlist (default: metadata, resolution), so --fix-scope estimates applies 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-files reports details.missing_linked_path_rows — owner attribution for every stale linked path (<path>:<classification> owner=<id> status=… field=files|docs one-liners by default; --verbose-file-lists for the full { path, classification, items: [...] } objects) so an agent can fix the right item without a reverse lookup.
  • pm validate --prune-missing removes stale linked-file/doc LINKS whose paths classify as deleted (no same-basename candidate left in the workspace scan); moved paths keep their relink candidate in details.missing_linked_path_classifications instead 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.


Agent Guide remote
Report an issue