# Changelog — What's New in Each pm Release Source: https://pm-plugin.dev/changelog Every pm release, its date, and what changed. Mirrors CHANGELOG.md in the pm plugin's repo. All notable changes to the `pm` plugin, mirroring [CHANGELOG.md](https://github.com/cfdude/pm/blob/main/CHANGELOG.md) in the plugin's repo. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this project adheres to [Semantic Versioning](https://semver.org/). *** ### Fixed * **`/pm:upgrade`'s own instructions now defend against a real misread: an agent treating the command invocation itself as passive local-command output and skipping it entirely.** When `/reload-plugins` and `/pm:upgrade` land in the same turn — the exact sequence this command's own preamble recommends — the harness wraps that turn's local command output in a caveat meant for `/reload-plugins`'s passive stdout, and an agent can over-apply that caveat to `/pm:upgrade` itself. Self-inflicted by this command's own documented workflow — fixed by having the command's own text state plainly: if you're seeing these instructions, the command was invoked, execute it. ### Added * **`update-epic --add-story ""` and `update-epic <id> --story <n> --done`.** Closes a recurring hand-edit-of-`state.json` risk for inline `stories[]` — `--add-story` appends `{ title, done: false }` (creating the array on its first inline story); `--story <n>` is 1-indexed and currently requires `--done` (the only supported mutation today) — both reject out-of-range/empty input and write nothing on failure. * **`render --diff-summary`** — prints `epic-relevant: yes` or `epic-relevant: no` after rendering. The "Last rendered" timestamp and the "Recent detours" table both change PROJECT.md on nearly every render even when nothing about the epics themselves changed, forcing manual `git diff` eyeballing before every "is this safe to discard" call. `--diff-summary` normalizes both known-trivial sources away and reports whether anything else differs, making the check mechanical. ### Fixed * **The `conductor: engine <version> @ <path>` banner no longer prints on every single invocation in a self-hosting/dev context.** Suppressed by default whenever `CLAUDE_PROJECT_DIR` is set — set `PM_VERBOSE_ENGINE_BANNER=1` to force it back on. `PM_QUIET_ENGINE_BANNER=1` still works unchanged outside that context. * **`.githooks/pre-commit` is now quiet on success** — a one-line `pre-commit: N/N passing` summary; full output (and a non-zero exit) only surfaces when a test actually fails. * **`verify-worktrees` now also flags a hierarchy-child worktree whose branch is already merged, not just ones whose epic status is `archived`.** Each flagged worktree's `reasons` array lists which trigger(s) fired. ### Changed * **`scripts/conductor.mjs` split into `scripts/lib/*.mjs` modules — no behavior change.** The engine (2,537 lines, 85 functions) is now a 121-line entry point plus 20 focused `scripts/lib/*.mjs` modules, one per pre-existing section. Motivated by AI-agent token-efficiency, not human-readability tech debt. Purely internal — verified by all 250 pre-existing black-box tests passing unchanged throughout. </Update> <Update label="0.22.0" description="2026-07-20"> ### Added * **On-demand AI-agent doc reference: `llms.txt`/`llms-full.txt`.** Mintlify auto-publishes both at `pm-plugin.dev` — `llms.txt` is a lightweight (\~7KB) index of every doc page, `llms-full.txt` is the entire site as one markdown document (\~200KB, tens of thousands of tokens). Referenced from the one-time orientation points that already exist (`/pm:init`'s step 0, the `conductor` skill's new "Further reference" section) rather than the persistent CLAUDE.md rules block, with an explicit size/token warning at every reference point. Also added a docs-site pointer to README.md's intro. </Update> <Update label="0.21.1" description="2026-07-20"> ### Added * **Security scanning via `.github/workflows/security.yml`.** Calls the two reusable `workflow_call` workflows published in `cfdude/.github` — Semgrep SAST and a Trivy filesystem scan — on push/PR to `main` and a weekly schedule, publishing SARIF results to the repo's Security tab. Both are non-blocking by design. Pinned to a commit SHA (not `@main`) to avoid a supply-chain gap where a moving branch ref could silently change what runs in CI. * **`SECURITY.md`** — vulnerability reporting instructions and a short architecture note. </Update> <Update label="0.21.0" description="2026-07-20"> ### Added * **CLAUDE.md rules block gains an unconditional "Feedback" section** encouraging the agent to proactively use `/pm:feedback [bug|feature] "<summary>"` (or ask the user "want me to file this as feedback?") whenever it hits a bug, a missing CLI verb, or repeated friction — instead of silently working around it. Motivated by a real gap: `/pm:feedback` shipped in 0.14.0 and was never used once, while the friction of hand-editing `.conductor/state.json` to flip a story's `done` flag (no CLI verb exists for it) recurred silently across several sessions before being reported. </Update> <Update label="0.20.1" description="2026-07-20"> ### Added * **`/pm:upgrade` now recommends adopting relevant new capabilities.** After printing the changelog delta, the command's instructions tell the agent to review each `Added` headline, judge whether it's an opt-in capability (a new flag/subcommand/behavior, not a bug fix or automatic change) relevant to the repo's current `.conductor/state.json`, and recommend it — one line, one reason, the command to run — without enabling anything itself. Instruction-only change (`commands/upgrade.md`, `README.md`); no engine code or schema touched. </Update> <Update label="0.20.0" description="2026-07-20"> ### Added * **Completion-time tracker resync instruction.** When an inward-pull-capable tracker is configured (a `github-issues` primary, or any secondary tracker), the CLAUDE.md rules block now adds a "Sync after completing tracker-linked work" section: after closing/transitioning a tracker-linked issue as part of completing an epic, re-sync with your tracker(s) (`/pm:sync`) right away, since you're already doing tracker I/O for that epic. Phrased tracker-count- agnostic ("your tracker(s)") so it reads correctly whether a repo has one tracker or several (primary + secondary). * **Session-start sync nudge.** The SessionStart brief now includes a one-line, non-blocking nudge — "N tracker(s) configured (...) — consider `/pm:sync` this session to pull in any new issues" — whenever any tracker (primary or secondary) is configured. This is a reminder only; the engine never calls a tracker itself, and the agent decides whether syncing is worth it. Deliberately does not track a last-synced-at timestamp — the nudge is enough without it. </Update> <Update label="0.19.0" description="2026-07-19"> ### Added * **Support a primary tracker plus zero or more secondary trackers.** `state.tracker` is unchanged and is now, implicitly, the **primary** tracker — full existing bidirectional behavior (outward issue creation on new epics, `statusIntent`-driven status transitions), including the `github-issues`-as-primary inward-only special case, byte-for-byte unchanged. New optional `state.secondaryTrackers[]` lets a repo also watch additional trackers — e.g. Jira as the real dev tracker plus a GitHub repo for inbound issues from outside contributors or another internal repo publishing cross-project notifications — via `set-tracker --role secondary --system <sys> --repo <repo>` (or `--project <key>`), removable with `--remove`. Secondary trackers get inward pull (open issues become untriaged epics) plus a new capability that didn't exist even for the old inward-only `github-issues` case: **completion status writeback** — when an epic sourced from a secondary tracker reaches `archived`, the agent closes the linked issue there too. Secondary trackers never receive outward-created issues; that stays exclusive to the primary tracker. Dedup for both inward pull and writeback now matches on `externalUrl` (globally unique) rather than bare `externalId` (only unique within one tracker/repo) — fixing a latent cross-tracker collision risk (e.g. issue `#42` existing in two different secondary-tracker repos) surfaced during this change's own Gate 1 review, before any code shipped. </Update> <Update label="0.18.0" description="2026-07-17"> ### Added * **Mechanical pre-commit hook: the full test suite must pass immediately before every commit, enforced, not just documented.** A genuinely failing test was committed once already (0.16.0) because a prose reminder alone wasn't enough — "run the tests one more time before committing" is exactly the kind of rule that gets skipped under momentum. `.githooks/pre-commit` runs `node --test scripts/conductor.test.mjs` and blocks the commit on any failure. One-time setup per clone: `git config core.hooksPath .githooks` (documented in `CONTRIBUTING.md`). Found and fixed a real bug on first live use: git sets `GIT_DIR`/`GIT_INDEX_FILE`/etc. for hook processes, which leaked into the test suite's own child `git` processes (tmp-repo fixtures), causing them to operate against the outer repo's locked index instead of their own tmp dirs — the hook now unsets those variables before running tests. </Update> <Update label="0.17.0" description="2026-07-17"> ### Added * **Added a mechanical test that catches README.md "Commands" drift from the real dispatch table**, mirroring the existing SKILL.md drift test. Running it against the current docs caught 8 real gaps (`commit-nudge`, `log-detour`, `honcho-memory`, `set-review-mode`, `verify-state`, `write-rules`, `snapshot`, `changesets`) — several of them genuinely undocumented user-facing subcommands (`honcho-memory`, `verify-state`, `changesets`), fixed in the same pass. `agents/hierarchy-child-executor.md`'s standing instructions and the conductor skill's epic-hierarchy preflight section now explicitly require a README.md update (not just SKILL.md) whenever a child epic adds/changes a user-facing command, flag, or behavior — the same class of gap that let `record-gate-review` ship in 0.16.0 with zero README mention. </Update> <Update label="0.16.0" description="2026-07-16"> ### Added * **OpenSpec's two mandatory gates are now mechanically enforced at archive time, not just narrated.** Nothing previously checked that an `openspec`-lane epic actually passed Gate 1 (spec review, before code) and Gate 2 (implementation review, before docs) before it was archived — an epic could go straight from `apply` to `archive` on narration alone. A new `record-gate-review <epicId> --gate 1|2 --verdict pass|fail [--reviewer "<note>"]` subcommand writes a fresh-context reviewer's verdict durably onto the epic (`gateReview.gate1`/`gate2`, mirroring `record-reconcile`'s shape), and `update-epic --status archived` now REJECTS the transition for any `openspec`-lane epic that doesn't already have a recorded `gateReview.gate2.verdict === "pass"`. Scoped strictly to the `openspec` lane — `superpowers`/`claude-code`/`decision`/`external` epics are completely unaffected, since they have no two-gate process. * **Added a mechanical test that catches SKILL.md "Commands" drift from the real dispatch table.** `conductor.test.mjs` now extracts every subcommand key from `conductor.mjs`'s dispatch table and asserts each one is mentioned somewhere in `skills/conductor/SKILL.md`, failing CI the next time a new subcommand ships without a doc mention (the same bug class fixed once by hand in 0.12.0, now enforced instead of relying on someone remembering). Running it against the current docs caught two real gaps — `snapshot` (the PreCompact-hook-only re-render) and `write-rules` (the `/pm:init`/`/pm:upgrade`-only CLAUDE.md rules-block refresher) were both real, invoked subcommands with no mention anywhere in SKILL.md — fixed by adding a line for each to the Commands section. ### Changed * **The `github-issues` tracker no longer tells the agent to auto-create a GitHub issue for every unmirrored local epic.** `rulesBlock()` now suppresses the outward "External tracker sync" section entirely when `tracker.system === "github-issues"`, leaving only the existing inward "GitHub issue sync" section (open issues → untriaged epics) in effect. Filing a public GitHub issue for any local claude-code epic just because a `github-issues` tracker is configured is a materially bigger, more consequential default than mirroring toward an internal Jira/Linear instance, so `github-issues` is now documented and implemented as INWARD-ONLY by design. Jira, Linear, and any other tracker `--system` keep the full bidirectional outward-mirror behavior unchanged. ### Fixed * **`commit-nudge`'s auto-detour heuristic no longer false-positives on routine conductor bookkeeping.** A commit touching only pm's own state-output files (`.conductor/state.json`, `PROJECT.md`, `.conductor/render-stamp.json`) is never auto-logged as a stray minimal detour, even if it matches the `fix:`/`chore:` + `<=3 files` shape — this fired 3 separate times in one session (registering epics, archiving epics, granting autonomy), always on commits that were routine administration, never a real detour. `CLAUDE.md` is deliberately excluded from this allowlist: it's user-authored content, not purely engine-generated output, so a commit touching it could still be a genuine detour. * **`render-stamp.json` no longer produces a spurious diff on every `render()` call when nothing meaningful changed.** Root cause: `writeRenderStamp()` unconditionally rewrote `.conductor/render-stamp.json` on every `render()` invocation, bumping its `renderedAt` timestamp even when `state.json` (and therefore the rendered `PROJECT.md` content) hadn't changed at all — producing a byte-only diff that had to be manually discarded roughly a dozen times across a single dogfooding session. `verify-state` (the mechanism this stamp exists for) only ever compares the recorded `stateMtimeMs` against `state.json`'s current mtime; it never reads `renderedAt` back for correctness. `writeRenderStamp()` now skips the rewrite entirely when the existing stamp's `stateMtimeMs` already matches `state.json`'s current mtime, so the sidecar file is only ever touched when something that actually matters changed. `.conductor/brief.txt` was confirmed already gitignored in this repo (a prior fix); no further action was needed there. </Update> <Update label="0.15.0" description="2026-07-15"> ### Added * **Changesets-style fragment files replace direct `CHANGELOG.md` edits for hierarchy children.** Every parallel hierarchy-child batch was hitting a 100% collision rate on `CHANGELOG.md`'s shared `## [Unreleased]` header — every dispatched child edited the same section, guaranteeing a merge conflict on every multi-child batch. Children now write their changelog entry to `.changesets/<epic-id>.md` instead (same bullet format `CHANGELOG.md` already uses: a bold one-line summary, then wrapped prose). The orchestrator remains the sole writer of `CHANGELOG.md` — consistent with it already being the sole writer of `.conductor/state.json` — and consolidates all pending fragments into the real `[Unreleased]`/new-version section once, at release time, then deletes the consumed fragment files. A new zero-dependency `changesets` engine subcommand (`node conductor.mjs changesets`) lists `.changesets/*.md` fragments as `{ changesets: [{ id, path, body }] }`, sorted by epic id, to make that consolidation step mechanical rather than a manual `cat` + guesswork. (First real-world test, this very release: zero CHANGELOG.md conflicts across 3 parallel children, versus a 100% collision rate before.) * **Mandatory post-resolution verification for the epic-hierarchy merge-conflict ladder.** After ANY conflict resolution (self-resolved by the orchestrator, via `agents/merge-conflict-resolver`, or via an escalated model/`advisor()` opinion), before the merge is committed: grep every touched file for leftover `<<<<<<<`/`=======`/`>>>>>>>` markers, and run `node -c` on every touched `.mjs`/`.js` file. Either failure means the file is still unresolved. Closes a gap found during this repo's own 0.14.0 dogfood run, where a resolution removed only the closing conflict markers and left the opening `<<<<<<< HEAD` marker in place — caught only by a manual re-grep, not by any required step. * **Session-continuity check for live external-infra epics.** The `hierarchy-child-executor` agent now has a required checklist item: before finalizing its report, if the epic's work made a live change to external infrastructure the orchestrator itself depends on for the rest of the session (branch protection rules, credential/token rotation, webhook/API changes, etc.), it must explicitly answer "does this change affect how the orchestrator itself needs to operate for the rest of this session?" in CONCERNS — even an explicit "no" is required output, not silence. Fixes a real incident: `branch-protection-and-pr-workflow` applied live branch- protection settings to `main`, and the orchestrator's very next `git push origin main` was rejected — discovered only empirically, not flagged by that epic's own report. * **README.md fully revamped.** Replaces the agent-facing, all-over-the-place structure with a Comet-inspired layout: a real banner image, honest badges (CI/version/license only — no DeepWiki/CodeCov/trending until the tooling behind them actually exists), a "Why Use PM?" section built from real, verifiable repo history (not a fabricated benchmark), a genuine "From Industry-Frontier Practice" write-up of the design patterns PM's architecture actually mirrors, a Supported Platforms table with an honest Status column (Claude Code: Supported; Codex/Gemini CLI/Grok Build/`AGENTS.md` format: Planned, tracked under `multi-platform-agent-support`), collapsible `<details>` command reference instead of one long flat table, and a Star History chart. Resolves `df-readme-stale-since-gate-guard` (README hadn't been touched since `f77d774`, missing everything shipped since). * **Branch protection + PR workflow on `cfdude/pm`.** `main` now requires pull requests (no direct pushes), the `test` job from `.github/workflows/ci.yml` as a required status check, 0 required approving reviews (solo maintainer), and squash-merge-only at the repo level. Day-to-day work moves to a new `dev` branch (created from `main`'s tip); PRs merge `dev` → `main`. See `CONTRIBUTING.md` for the full workflow. This is a live GitHub repo settings change, not a code change — no `state.json` schema impact. </Update> <Update label="0.14.0" description="2026-07-15"> ### Added * **`github-issues` tracker: inward pull (open issues → new untriaged epics).** `set-tracker --system github-issues --repo <owner/name>` records a repo alongside the tracker's `system`. The rules block now gains a "GitHub issue sync" section (in addition to the existing outward "External tracker sync" mirror) telling the interactive agent — as part of `/pm:sync` — to `gh issue list --repo <repo> --state open`, skip issues already mapped to an epic via `externalId`, and register the rest with `add-epic --status untriaged --external-id <n> --external-url <url> --lane claude-code --priority P2` (a `P0`/`P1`/`P2`/`P3` label on the issue overrides the P2 default). The engine itself never calls `gh` — same instruction-layer law as every other tracker. `add-epic` now also rejects a duplicate `--external-id` outright (exits non-zero, writes nothing), so re-running sync can never create a duplicate epic for the same issue even off a stale local view. See `commands/tracker.md`, `commands/sync.md`, and the conductor skill's "Hierarchy & external trackers" section. * **`.github/workflows/ci.yml`.** A GitHub Actions CI workflow on push to `main` and on every pull request targeting `main`, running Node 18.x: a `node -c` syntax check on `scripts/conductor.mjs` and `scripts/conductor.test.mjs`, then the full test suite via `node --test scripts/conductor.test.mjs`. This repo is zero-dependency, so "lint" here means the syntax check rather than a third-party linter. The job is named `test` (`jobs.test`) — a follow-up epic wires this job into required branch-protection status checks. * **`/pm:feedback [bug|feature] "<summary>"`.** File a bug report or feature request against `pm` itself directly as a GitHub issue on `cfdude/pm`, from any session using the plugin — replacing the previous workflow of manually copy-pasting details between sessions. Pure command-doc addition: the interactive agent gathers the report, searches open issues on `cfdude/pm` for a near-duplicate title (commenting on a match instead of filing a new issue), and otherwise runs `gh issue create --repo cfdude/pm` with a `bug`/`enhancement` label, reporting back the issue URL. No engine code involved — `scripts/conductor.mjs` never calls GitHub itself; all `gh` calls are agent-invoked Bash, per the instruction-layer law. See `commands/feedback.md`. </Update> <Update label="0.13.0" description="2026-07-15"> ### Added * **`record-reconcile <epicId> --detour <detourId> --verdict valid|invalidated [--amendments "<a>;<b>"]`.** The reconciler agent's verdict at the POP-protocol reconcile gate previously only ever lived in the conversation transcript. This subcommand writes a structured `{verdict, amendments, reconciledAt}` object onto the paused epic's link to the detour that triggered reconciliation (creating a `may-invalidate` link if none exists yet), and clears `reconcileNeeded` — so the judgment is durable in `.conductor/state.json` and visible in `PROJECT.md`, not just something Claude said once. `agents/reconciler.md`'s report format, `commands/resume.md`, and the conductor skill's POP protocol / rules block now describe this writeback step. * **Per-repo lane-routing overrides.** New optional `laneRouting.overrides` config block in `.conductor/state.json` — keyword/glob rules (`{match, lane}`) checked BEFORE the generic lane heuristic when an agent decides which lane should build an epic. Set via the new `set-lane-routing --add "<match>:<lane>" [--add ...] | --remove "<match>" | --clear` subcommand; looked up via the new `suggest-lane "<free text>"` subcommand, which prints `{lane, matched}` JSON (`lane: null` means no override matched — fall back to the generic heuristic). Replaces the need for a CLAUDE.md prose carve-out when the generic heuristic is wrong for a repo (e.g. "anything touching billing always goes through openspec"). See `commands/lane-routing.md` and the `conductor` skill's "Lane routing overrides" section. Pure local state write — the engine still never assigns a lane itself; `add-epic` always takes an explicit `--lane`. * **Per-epic review-mode override (escalation-only).** `update-epic <id> --review-mode off|standard|thorough` sets an epic-level override that can only ESCALATE above the repo-global `set-review-mode` dial — never de-escalate below it (an attempt to set a lower mode than the current global dial is rejected outright, state unchanged). `currentReviewMode` now accepts an optional `epicId` and returns the effective mode for that epic: the higher-ranked of the global dial and the epic's override. `rules --epic <id>` surfaces the effective per-epic mode in the emitted "Current mode" line. Lets one security-sensitive epic force `thorough` review without flipping an otherwise-`standard` repo's global dial. * **Auto-detected minimal detours from commit diff shape.** `commit-nudge` (the `PostToolUse(Bash)` hook that already fires after every `git commit`) now recognizes an UNLOGGED minimal detour by its shape — a small commit (`<=3 files` changed) with a `fix:`/`chore:` conventional-commit subject, made while no detour is active, and not scoped to the currently active epic (a `fix(<active-epic-id>): ...` subject is read as that epic's own work, not a stray detour) — and appends an `AUTO-DETOUR` entry to `.conductor/detours.log` automatically, without waiting for `/pm:detour --minimal` to be run by hand. Three separate dogfooding sessions converged on "the agent forgets to log the minimal detour" as the #1 pain point; this closes that gap at the mechanism level (hook-driven, not agent-remembered) rather than relying on the agent to recall the rule. See `looksLikeUnloggedMinimalDetour()` / `headChangedFileCount()` in `conductor.mjs`. * **`honcho-memory <push|pop> <epicId> "<reason>"` subcommand.** Formats the exact ready-to-copy one-line Honcho memory string for a detour-stack PUSH/POP (per CLAUDE.md rule 4), prints it to stdout, and appends a timestamped copy to the new `.conductor/honcho-memories.log`. Previously the interactive agent had to compose that string itself from context on every PUSH/POP, with no engine support and no durable record of what was actually sent — easy to forget or word inconsistently. The engine still never calls Honcho itself (pure string formatting + local logging, staying inside the instruction-layer law); `commands/detour.md`, `commands/resume.md`, and the `conductor` skill's PUSH/POP protocols now call it and paste its output into the actual Honcho MCP call. * **Dependency-aware ordering for the top-level queue, not just hierarchy siblings.** The brief's NEXT UP list (and thus `/pm:next`'s recommendation) now applies the same `depends-on` topological ordering `plan-hierarchy` already used for one parent's children to ALL top-level queued/untriaged epics: a higher-priority epic with an unresolved `depends-on` link to another still-queued epic is no longer listed (or picked) ahead of the dependency it's waiting on, even across otherwise-unrelated epics with no shared parent. When ordering overrides plain priority this way, the brief prints a one-line note naming the blocker, e.g. `⚠ epic \`high-blocked\` ready but waiting on \`low-dep\``. Unlike `plan-hierarchy\`, a dependency cycle among queued epics does not error here — it's a display/selection helper, not an execution plan, so it falls back to the original priority order for the stuck remainder. * **SessionStart upgrade nudge now inlines top Added-bullet headlines.** The `pm X.Y.Z → A.B.C available` nudge previously named only the old/new versions, forcing a separate `/pm:changelog` round trip to judge whether upgrading was worth mid-epic churn. It now inlines up to 3 "Added" bullet headlines (first line only, not the full multi-line body) drawn from every CHANGELOG.md section strictly between the stamped and newest version, so a session can judge upgrade value inline. * **Category-based `--preauthorize` shorthand for epic-level autonomy.** `set-autonomy <id> --preauthorize "category:<filesystem|network|schema|external-api>:<reason>"` grants routine actions by category instead of requiring every one enumerated individually. Stored as a distinct `{ category, reason?, grantedAt }` grant shape alongside existing exact-action `{ action, reason?, grantedAt }` grants in the same `preAuthorized[]` array — exact-action matching is unchanged. Unknown categories are rejected with a non-zero exit and no state write. The matching heuristic each category expands to at decision-rule time (approximate by design) is documented in the `conductor` skill's "Epic-level autonomy — the preflight scan" section. ### Changed * **Epic-level-autonomy decision rule now says "`--notify` incrementally as it happens," not "record for the end-of-epic report."** The `--notify` mechanism already writes durably to `state.json`'s `notifications[]` array; the prior wording implied WARN-class (c) and consequential (e) decisions were only gathered in-memory for a report assembled at the end of the epic, which loses them if the session is compacted or interrupted mid-epic. Fixed in both `CLAUDE.md`'s rules block and the identical generated block in `scripts/conductor.mjs`'s `renderRulesBlock`-equivalent. The end-of-epic report step now reads back `notifications[]` rather than being the primary record. No code change — `--notify`/`notifications[]` already worked this way; this is a wording fix so the documented process matches the existing mechanism. * **Gate guard is now on by default whenever an epic owes a reconcile.** `gateGuardCheck()` now blocks `Edit`/`Write`/`NotebookEdit` unconditionally when the active epic's `reconcileNeeded` is `true`, regardless of the repo's `gateGuard` setting in `state.json` — `set-gate-guard off` no longer bypasses this specific case. Applies retroactively to any epic that already has `reconcileNeeded: true`, not just future detour POPs. Reverses the original opt-in design after real-usage feedback (`docs/feedback/2026-07-14-pm-plugin-improvement-feedback.md`) showed the guard had never actually been turned on across several sessions where it would have caught a real skip. The repo-level `gateGuard` flag and `set-gate-guard on|off` command still exist, reserved for any future generalization of the hook to other checks. See `commands/gate-guard.md` and the `conductor` skill's POP protocol. ### Fixed * **`missing()` now excludes `status === "archived"` epics.** An already-archived openspec epic (proposed, built, and archived — its `openspec/changes/<id>` directory legitimately moved to `openspec/specs/` by the archive process) could still render the unresolvable "⚠ no change on disk" warning forever if its on-disk archive-dir name didn't match `isArchived()`'s dated-prefix convention. Same class of bug already fixed for `planHierarchy()` (`df-plan-hierarchy-includes-archived-children`, 0.12.1), applied here to the missing-change-warning code path. </Update> <Update label="0.12.2" description="2026-07-15"> ### Added * **`startedAt`/`completedAt` timestamps on epics, and a staleness indicator.** `set-active` now stamps `startedAt` (ISO string) the first time an epic goes active (re-activation after a demotion does not reset it); `update-epic --status archived` stamps `completedAt`. Both fields are purely additive — existing epics simply lack them until touched, so no migration is needed. `PROJECT.md`'s epic table, its "Now" section, and the brief's `NOW`/`NEXT UP` lines all surface `⚠ stale, Nd active` for any epic with `startedAt` set, no `completedAt`, and more than 14 days elapsed — supporting velocity tracking and the weekly Ship-Real-Software check. * **`verify-state` subcommand.** `render()` now writes `.conductor/render-stamp.json` (`renderedAt` + the state.json mtime it rendered from) every time it runs. `verify-state` compares state.json's current filesystem mtime against that stamp and fails loudly (non-zero exit, clear stderr) if state.json was modified after the last recorded render — mechanical evidence of an undetected hand-edit, which CLAUDE.md explicitly forbids (state.json/PROJECT.md must only change through the engine's subcommands). Also fails loudly if no stamp exists yet (state.json has never been rendered). * **Engine version+source banner on every invocation.** `conductor.mjs` now prints `conductor: engine <version> @ <path>` to stderr on every run (silenceable via `PM_QUIET_ENGINE_BANNER=1`). Discovered live while dogfooding: `$ENGINE` resolution had silently picked up the installed plugin cache's `0.12.0` copy while this repo — the plugin's own source — was already at `0.12.1`, with no signal anything was stale. ### Fixed * **ENGINE-resolution snippets (skill doc + every command doc) now prefer a repo-local `$CLAUDE_PROJECT_DIR/scripts/conductor.mjs` before `$CLAUDE_PLUGIN_ROOT` and the installed-cache fallback.** When the repo being worked on IS the pm plugin source (self-hosting), that copy is always the one under active development and should win over a stale cached install. </Update> <Update label="0.12.1" description="2026-07-15"> ### Fixed * **`plan-hierarchy` no longer includes already-archived children in a hierarchy plan.** Children were filtered by `parent` only, with no status check — a done child (e.g. one already merged and archived from a prior dispatch batch) still showed up in the plan, indistinguishable from real pending work. Discovered via the first live dogfood resumption against `pm-plugin-improvements-2026-07-14`. Excluding `status === "archived"` from the children filter also correctly makes a `depends-on` reference to an archived sibling fall outside the hierarchy's dependency graph — the same existing behavior as a link to any epic outside the hierarchy, since a done dependency imposes no wait. </Update> <Update label="0.12.0" description="2026-07-15"> ### Added * **`verify-worktrees` — orphaned hierarchy-dispatch worktree detection.** Cross-references `git worktree list` against epic status: any worktree on a `hierarchy-child/<epic-id>` branch whose epic is already archived (successfully merged and closed out) is flagged. Bakes worktree hygiene into the plugin itself — checkable on any fresh install — rather than depending on a user's personal CLAUDE.md discipline. Pure read, flags without deleting. * **Worktree-isolated epic-hierarchy dispatch, replacing the original "just dispatch in parallel" instructions.** Discovered via the first live dogfood attempt against a real hierarchy (every child touched `scripts/conductor.mjs`): concurrent children mutating shared files was a real, unaddressed race. Each child now works in its own git worktree; children never write `.conductor/state.json` themselves (the orchestrator is the sole writer, applied once per batch); worktree branches merge back sequentially. An ordinary merge conflict is never a hard stop — it's resolved via a tiered ladder (normal merge → dispatch the new `agents/merge-conflict-resolver` → escalate to a stronger model/`advisor()` → commit best-effort + log a follow-up epic under the same parent) — a direct, consistent application of epic-level autonomy's existing decision rule, since a git-tracked conflict is always recoverable via history (criterion (c), never the unconditional-stop criterion (b)). * **`agents/merge-conflict-resolver.md`** — a new packaged agent (mirrors `reconciler.md`'s shape) dispatched to resolve a worktree-merge conflict, reporting `resolved`/`uncertain`/ `failed` so the orchestrator knows whether to escalate further. ### Fixed * Doc drift in the conductor skill's Commands line: `remove-epic`, `plan-hierarchy`, and `verify-worktrees` were all missing despite `remove-epic`/`plan-hierarchy` already having shipped in prior releases. </Update> <Update label="0.11.0" description="2026-07-15"> ### Added * **`remove-epic <id> [--cascade]` — hard-delete an epic**, replacing the raw `git checkout` workaround that was the only prior recovery from a mis-registered epic. Blocked by default if the epic has children: prints a concise `(id, title, lane/priority/status)` table of the parent plus every child and exits non-zero, so removing a parent with descendants is always a deliberate, informed choice; `--cascade` removes the epic and all descendants together in one atomic write. Any other epic's `links[]` entries referencing a removed id are stripped automatically, with a warning naming the affected epics. Recoverable only via git history — deliberately no in-app undo, since this verb exists specifically to replace that workaround, not add a softer one next to it. </Update> <Update label="0.10.0" description="2026-07-14"> ### Added * **`plan-hierarchy --parent <id>` — batched execution plan for a parent epic's children.** Computes batches from data pm already tracks (no new persistent state): `priority` and `depends-on` links between siblings drive a topological sort — children with no dependency on each other land in the same batch (dispatchable in parallel), children in a dependency chain land in separate, ordered batches. Each child is annotated with whether it already has `autonomy.level: "autonomous"` (from epic-level autonomy), so a hierarchy dispatch never fires a child that hasn't been preflighted. Each child also carries `dependsOn`, its sibling dependency ids within the hierarchy, so a blocked-child handler can check whether a later batch depends on it (directly or transitively) rather than guessing from batch order alone. A dependency cycle among children is rejected outright, naming the cycle path, rather than producing a bogus order. * **`agents/hierarchy-child-executor.md` — a packaged subagent** dispatched once per child epic in a batch: front-loaded with the epic's full context and its autonomy grant, works the epic to completion using its lane's normal workflow, follows epic-level autonomy's decision rule for genuine stops, and returns a fixed report (`STATUS`/`DONE`/`DECISIONS`/`CONCERNS`). * The `conductor` skill documents the full end-to-end process: preflight every child up front (reusing epic-level autonomy's scan, consolidated into one batch of questions) → `plan-hierarchy` → dispatch batch by batch (parallel within a batch, sequential across batches) → one consolidated end-of-hierarchy report flagging anything controversial. * Deferred to a later release: the fuller execution-strategy-selection framework (plain subagents vs. the Workflow tool vs. other execution modes) — this release covers only subagent-per-child dispatch. </Update> <Update label="0.9.3" description="2026-07-14"> ### Fixed * **`add-epic --link` accepted a malformed value silently instead of erroring.** It split the string on `:` and stored whatever came out with no validation — a typo like `type:related:epic:...` parsed successfully as `{type:"type", epic:"related"}` since nothing checked that `"related"` was a real epic id. `parseLinkFlags()` now requires at least two segments and that `<epic>` references a known, existing epic id, rejecting otherwise with a clear error (shared by `add-epic` and `update-epic`). * **`update-epic` had no `--link` flag**, so a malformed link (from before this validation existed, or from a hand-edit) had no CLI path to fix — forcing a direct `state.json` edit, which is what caused a reported em-dash JSON-escaping corruption across unrelated epics. `update-epic <id> --link "<type>:<epic>[:<reason>]"` now REPLACES the epic's links wholesale (unlike the other flags, which patch a single field) — the intended fix path. </Update> <Update label="0.9.2" description="2026-07-14"> ### Added * **`set-gate-guard <on|off>` — optional, opt-in `PreToolUse` guard hook.** Blocks `Edit`/`Write`/`NotebookEdit` while the active epic still owes a reconcile after a detour POP (`reconcileNeeded`). Off by default and dormant until `/pm:init`. This is the one place pm's law tolerates mechanical blocking over pure instruction — it protects the single highest-stakes skip (writing source before the reconcile gate runs) as a deliberate, reversible opt-in, never a silent default. ### Fixed * **POP protocol never actually told you to SET `reconcileNeeded`.** The conductor skill documented clearing it after reconciliation, but never setting it true on the paused epic before its detour-stack frame is popped — without that, the flag (and the new gate guard) would never actually trigger. Documented as a hand-edited step, mirroring how the frame itself is already hand-edited. * **Doc drift in the conductor skill:** the Commands line and `state.json` reference were missing `set-autonomy`, `set-review-mode`, `autonomy`, `reviewMode`, and `gateGuard` — none had been added when those features shipped in 0.8.0/0.9.0. </Update> <Update label="0.9.1" description="2026-07-14"> ### Fixed * **Regression from 0.8.4: `reconcileNeeded` was cleared on an active epic with no live detour frame, defeating the post-pop reconcile gate.** POP protocol removes the detour- stack frame BEFORE reconciliation runs, so deriving the flag purely from live-frame presence wiped it out at exactly the moment it needed to stay true (just-resumed, reconcile not yet done). `reconcileArchived()` now only recomputes what's safely derivable from current state: an archived epic always clears it (reconcile is moot); a still-paused epic with a live `reconcileOnResume` frame gets it forced true; anything else stale heals to false only if it's NOT the current active epic, since that's exactly the legitimate post-pop-pre-reconcile window. </Update> <Update label="0.9.0" description="2026-07-14"> ### Added * **`set-review-mode <off|standard|thorough>` — a bounded, repo-level review-count dial.** Incorporates Comet's `review_mode` concept: a single setting (not per-epic) replacing an ad-hoc "how many reviews, when" judgment call with an explicit, dedup'd table. `off` = self- review only; `standard` (default when unset) = one fresh-context reviewer per gate; `thorough` = two independent reviewers per gate with disagreement adjudicated by you. Writes `state.reviewMode` and refreshes the CLAUDE.md rules block's new unconditional "## Review mode" section, which always shows the currently active mode. Pure instruction-layer — no external calls. </Update> <Update label="0.8.4" description="2026-07-14"> ### Fixed * **Recompute-don't-remember: `.active` validity and `reconcileNeeded` are re-derived from disk, not trusted as stored flags.** `reconcileArchived()` previously only cleared `.active` when it pointed at an *archived* epic — a pointer referencing an epic id missing entirely from `state.epics` was never healed. `reconcileNeeded` was pure remembered state (set/cleared only by hand-editing per the PUSH/POP protocol), with no recovery if a session lost context mid-detour. Both are now recomputed from ground truth (the epics array, the detour stack's `reconcileOnResume` frames) every time `render()` runs — including at the end of `/pm:resume` — healing stale flags in either direction. `brief()` stays deliberately read-only, displaying the same recomputed truth in-memory without persisting. </Update> <Update label="0.8.3" description="2026-07-14"> ### Fixed * **`state.json` writes are now atomic (tmp+rename).** `saveState()` previously wrote directly via `writeFileSync`; a crash or kill mid-write could leave a truncated, unparseable `state.json` with no recovery path. Now writes to a `.tmp-<pid>-<ts>` file in the same directory and `rename(2)`s over the real path — atomic on the same filesystem, so a crash leaves a truncated tmp file instead of corrupting the system of record. </Update> <Update label="0.8.2" description="2026-07-14"> ### Fixed * **`KNOWN_STATUSES` omitted `later`/`blocked` despite both being documented** in the README's Epic statuses table and `commands/init.md` — `add-epic`/`update-epic --status later` (or `blocked`) was rejected outright. Both statuses now validate and persist correctly; NEXT UP already excluded them (only `queued`/`untriaged` are included) with no other code change needed, and they correctly still count in the lanes rollup (only `planned` is excluded from both NEXT UP and the rollup, per the documented distinction). </Update> <Update label="0.8.1" description="2026-07-14"> ### Fixed * **`update-epic` silently no-op'd on an unrecognized flag.** A typo'd or unwired flag would parse, run `saveState`/`render`, and print `conductor: updated '<id>'` even though nothing changed — the only way to catch it was cross-checking `git diff`. `update-epic` now validates its flags against a known set and exits non-zero with an "unknown flag" error instead of a false success. * **`update-epic` had no `--title` flag.** `add-epic` supports `--title` at creation, but correcting a title after an investigation changes what an epic is actually about (a common, legitimate mid-epic event) had no CLI path and required hand-editing `state.json`, which the tool explicitly discourages. `update-epic <id> --title "..."` now works. </Update> <Update label="0.8.0" description="2026-07-13"> ### Added * **`set-autonomy <id>` — per-epic autonomy contract.** An epic can be granted broad execution trust (`autonomy.level: "autonomous"`, default `"off"` — unchanged behavior) so it runs through phase transitions without stopping for permission each time. Autonomy is granted only after a preflight risk-scan (documented in the `conductor` skill) records the user's pre-authorized actions and supplied context via `--preauthorize`/`--context` (repeatable, additive). A five-criteria execution-time decision rule (injected into the CLAUDE.md rules block) still hard-stops for anything with no backup/restore path or no context to act on — autonomy never overrides a genuine safety gate, only removes false ones. `PROJECT.md` and the session brief mark an autonomous epic with 🤖. Tracker-linked epics (Jira etc.) get an addendum covering lane-aware source reading, non-authoritative comment-mirroring of approvals, and mid-run drift as its own stop condition. * Development-time scope only — this does not cover actions with irreversible EXTERNAL side effects (sending email/Slack, deploying to production, third-party API calls, pushing to a shared branch); those remain out of scope regardless of autonomy level. </Update> <Update label="0.7.0" description="2026-07-08"> ### Added * **`set-active <id>` / `clear-active` — a CLI verb for the top-level active epic** (closes [#1](https://github.com/cfdude/cfdude-plugins/issues/1)). Previously `.active` — the pointer the briefing's "NOW" line reads — had *no* CLI setter, so `/pm:next`'s "make it active" forced hand-editing `state.json`, against the "CLI is the safe interface" model. `set-active <id>` (positional id) sets the pointer; `clear-active` drops it. ### Fixed * **`.active` and `status: "active"` can no longer silently disagree.** They were independent fields — `update-epic --status active` flipped the status but left `.active` null, so the brief reported "no active epic" despite an active epic. Now a single-active invariant is enforced through every CLI path: `set-active`, `update-epic --status active`, and `add-epic --status active` all set `.active` **and** the epic's status together and demote any previously-active epic to `queued`; moving the active epic off `active` (or `clear-active`) clears the pointer. `set-active` rejects an unknown or archived id. ### Changed * **Skills/commands resolve the engine version-independently.** The `conductor` skill and `/pm:next` now prefer `$CLAUDE_PLUGIN_ROOT` and fall back to the newest installed `conductor.mjs` (`ls -t …/pm/*/… | head -1`) instead of embedding a versioned cache path like `…/pm/0.6.1/…`, which broke on upgrade. `set-active`/`clear-active` are documented in `/pm:next`, `/pm:epic`, the skill, and the README. ### Upgrade Minor release — no schema change, no data migration. Update the plugin → `/reload-plugins` → `/pm:upgrade`. </Update> <Update label="0.6.1" description="2026-06-26"> ### Fixed * **Archived OpenSpec epics stayed stuck as the active epic.** `isArchived()` only matched an archive dir named exactly `<id>`, but OpenSpec archives a change as `openspec/changes/archive/<YYYY-MM-DD>-<id>`. So the engine never detected the archive: the epic kept its `active` status, `state.active` kept pointing at it, `/pm:status` showed a finished epic as **NOW**, `/pm:next` wouldn't advance, and the epic could even be mis-flagged "⚠ no change on disk." Fixed three ways: * `isArchived()` now matches both the exact id and OpenSpec's date-prefixed dir. * **Display honesty:** `render`/`brief` no longer present an archived epic as the active one — they show "(no active epic — `X` was archived)", so `/pm:status` and `/pm:next` are correct immediately, with no state mutation. * **Self-heal:** a new `reconcileArchived()` clears an `active` pointer aimed at an archived epic and stamps `status: archived`. It runs in `sync`, `commit-nudge` (so the state heals on the same commit that archives the change), `init`, and `upgrade` — no more hand-editing `state.json` after an archive. ### Upgrade Patch release — no schema change, no data migration. Update the plugin → `/reload-plugins` → `/pm:upgrade`. </Update> <Update label="0.6.0" description="2026-06-25"> ### Added * **Knowledge surfacing — the plugin now teaches the agent at the two moments that matter.** Previously an upgrade exposed new commands but never explained *what* it brought, and a first-time install gave the agent no orientation beyond command descriptions. Closed both: * **`/pm:upgrade` prints a changelog delta.** After applying migrations, the engine reads its own `CHANGELOG.md` and prints every entry in `(stamped, running]` — so the agent and user see exactly what the version added, not just that it happened. * **New `changelog` subcommand + `/pm:changelog [--since <x.y.z>]`.** On-demand changelog delta; defaults its floor to the version stamped in this repo's `state.json`. Zero-dependency markdown parsing (sections split on `## [x.y.z]` headers); graceful when no CHANGELOG ships. * **`/pm:init` orients the agent first.** Init now instructs the agent to load the `conductor` skill (the agent-facing how-to) — and points at the shipped `README.md` for deeper reference — so even a cold install of a much-later version knows how to drive the plugin. Deep orientation stays a one-time/on-demand load; the persistent CLAUDE.md rules block remains the recurring anchor (no full-orientation injection every session). ### Upgrade Minor release — no schema change, no data migration. Update the plugin → `/reload-plugins` → `/pm:upgrade`; the upgrade will now print what this version (and any you skipped) brought. </Update> <Update label="0.5.1" description="2026-06-25"> ### Fixed * **Multi-version upgrade ordering (hardening).** `upgrade()` already replayed every migration newer than the stamped version, so a repo several versions behind (e.g. `0.2.0 → 0.5.x`) was upgraded correctly. This release makes that guarantee robust: migrations are now applied **sorted by release** (independent of array authoring order), the `MIGRATIONS` array is documented as **append-only / never-reorder**, and a regression test asserts a two-versions-behind repo replays *both* the 0.3.0 (lane) and 0.5.0 (link-normalize) migrations in order. * **Tracker detection no longer over-triggers on Git hosting.** The `/pm:tracker`, `/pm:init`, and `/pm:upgrade` detection guidance previously let the agent infer a tracker from the fact that a repo is hosted on GitHub. Hosting on any Git service (GitHub, GitLab, Bitbucket, …) is **not** a signal — they all have issues/PRs, but a remote is not evidence that work is managed there. Detection now requires a *real* signal (an in-use tracker MCP, issue-key conventions, or an explicit statement), frames tracker mirroring as an **optional choice**, and reassures that declining loses nothing — the conductor always tracks everything locally in `.conductor/state.json` + `PROJECT.md`; a tracker only *adds* an external mirror. Choosing a Git host as the tracker (issues + PRs) remains fully valid. ### Upgrade Patch release — no schema change, no data migration. Update the plugin → `/reload-plugins` → `/pm:upgrade` to stamp `0.5.1` and refresh the rules/command docs. </Update> <Update label="0.5.0" description="2026-06-25"> ### Added * **First-class epic hierarchy.** Epics gain an optional `parent` field (single-parent tree, arbitrary depth). `add-epic --parent <id>` validates the reference (must exist, no self-parent, no cycle) via a shared `parentError()` ancestor-walk helper. `PROJECT.md` renders children indented beneath their parent (`└─`, deepened per level), groups families ordered by parent priority, and shows an `X/Y children archived` rollup in the parent's Progress cell. The briefing's NEXT UP annotates a child with its parent id. **Grouping is render-only** — the `resolveEpics` priority sort is untouched, so a P0 child of a P2 parent keeps its NEXT UP slot. * **External-tracker awareness (instruction layer only).** An optional `tracker` block in `state.json` (`system`, `instance`, `projectKey`, `mechanism`, and a semantic `statusIntent` map) makes the conductor *aware* a project mirrors epics to Jira/GitHub/Linear. **The engine never calls the tracker** — it only shapes the instructions it already emits: * the CLAUDE.md rules block gains an "External tracker sync" section assigning the interactive agent ownership (create issue + record key; transition on status change toward the semantic `statusIntent`; parent epic → tracker epic); * the briefing gains a `TRACKER SYNC` block listing only honestly-computable drift — active-work epics (`queued`/`active`/`paused`, excluding `missing()` ghosts) with no `externalId`. No transition-drift is fabricated (the engine cannot see tracker state). * New `set-tracker` subcommand (repeatable `--intent <status>:<target>`; `parseFlags` now accumulates `intent` like `link`) writes the block and refreshes the rules. * New per-epic `externalId`/`externalUrl` fields (on `add-epic` and `update-epic`). * New **`update-epic <id>`** write-back subcommand (positional id) mutates `externalId`/`externalUrl`/`parent`/`status`/`priority` on an existing epic under the same validation as creation — closing the sync loop after the agent creates an issue. * New `/pm:tracker` command doc; `/pm:init` and `/pm:upgrade` gain an agent-driven detection step (detect signals → confirm with the user → `set-tracker`; upgrade only when unset). * **Atomic bulk creation.** New `add-many --from <path|->` reads a JSON `{ parent?, epics[] }` batch. If `parent` is present it is created first and children default their `parent` to it. Every entry is validated up front (id format, uniqueness vs existing AND within the batch, lane, status, parent refs + intra-batch cycles); on any failure nothing is written and it exits non-zero. A valid batch persists in a single write — removing the race that forced chaining individual `add-epic` calls. JSON only (the engine stays zero-dependency). ### Fixed * **Stale-link rendering.** `render()` and the briefing now emit a link only when both its `type` and `epic` are strings (shared `validLink()` helper), so malformed or older-schema link entries no longer render as `undefined undefined`. ### Migration * **0.5.0 migration (repair-first).** `MIGRATIONS` gains a `0.5.0` entry that normalizes stored `links`: valid `{type, epic}` objects pass through, the documented colon-string encoding `type:epic[:reason]` is repaired into an object, and unrecoverable entries are dropped. Additive and idempotent. Defensive rendering (above) is the shape-agnostic durable fix. ### Compatibility All additions are optional and backward-compatible: a `state.json` written by v0.4.1 loads unchanged, and a 0.5.0-written state remains loadable by the older engine (it ignores the new optional fields). ### Upgrade **Existing repos:** update the plugin → `/reload-plugins` (or restart) → `/pm:upgrade` per repo. The upgrade runs the additive, idempotent 0.5.0 migration, refreshes the rules, and stamps `pmVersion: 0.5.0`. To make a repo tracker-aware, run `/pm:tracker` (or answer the detection prompt during `/pm:upgrade`). </Update> <Update label="0.4.1" description="2026-06-22"> ### Added * **`/pm:upgrade` staleness guard.** `/pm:upgrade` now checks whether the running engine version matches the newest installed version before proceeding. If they differ (i.e. the plugin was updated but Claude Code has not been reloaded), it refuses with a clear message — "this is pm `<old>` but `<new>` is installed; run `/reload-plugins` or restart Claude Code first" — instead of silently re-stamping an old version. From 0.4.1 forward every upgrade is self-guarding. * **SessionStart nudge fires from newest installed version.** The upgrade nudge in the SessionStart briefing now keys on the newest installed version (from the plugin's `plugin.json`) rather than the running engine version. This means the nudge fires even before you reload Claude Code, and it names the full sequence: (1) reload/restart; (2) `/pm:upgrade` per repo. * **Documented update sequence.** `upgrade.md` and README both document the required three-step sequence: update the plugin → `/reload-plugins` or restart → `/pm:upgrade` per project. The upgrade command note now explains why the reload step is mandatory (Claude Code loads the engine at session start). ### Limitation The staleness guard ships inside 0.4.1, so the first upgrade *into* 0.4.1 still runs the old 0.4.0 engine until you `/reload-plugins`. From 0.4.1 forward every upgrade is self-guarding. ### Upgrade **Existing repos:** run `/pm:upgrade` after updating — refreshes rules, stamps 0.4.1 into `state.json`. Idempotent; safe to run multiple times. No data migration required. Remember to `/reload-plugins` first (see above). </Update> <Update label="0.4.0" description="2026-06-18"> ### Added * **`status: planned` — roadmap as ordered backlog.** A new epic status for items that are known, sequenced, but not yet ready to start. `planned: N` appears as a brief summary line in the briefing; planned epics are excluded from NEXT UP and the lanes rollup, but are shown in the PROJECT.md epics table so the full backlog is visible. * **`sync` auto-transitions proposed planned epics → untriaged (openspec lane).** When `sync`/`init` discovers a new OpenSpec change on disk and an epic with the same id already exists with `status: planned`, it transitions that epic to `untriaged` automatically so it enters the normal triage flow without manual state editing. * **PROJECT.md stamp-on-content-change only.** `render` now compares the new output to the current file before writing; if the content is identical, the file is not touched. Prevents mtime churn and spurious git diffs when nothing meaningful changed. * **`add-epic` validates `--status` against known statuses.** Passing an unknown status to `/pm:epic add` is now an error rather than silently stored. A valueless-flag guard also catches `--status` with no argument (e.g. `--status --lane`) and reports a clear error instead of treating the next flag as the status value. * **Portable `ls -t` glob in command docs.** The `find`-based file listing in `sync` command documentation is replaced with a portable `ls -t` glob, removing a macOS/GNU `find` incompatibility. * **`--status` documented in `/pm:epic`.** The `add` sub-command now shows all valid status values (including `planned`) in its help text and the commands table. * **Roadmap on-ramp guidance.** README and SKILL document how to import an existing roadmap into the conductor without parsing: in an interactive session, read the roadmap doc and register each item via `/pm:epic add … --status planned`, choosing the appropriate execution lane. The conductor does not parse roadmap files automatically. ### Changed * Rules block wording updated: documents `planned` status (roadmap on-ramp), auto-transition of planned epics on `sync`, and stamp-on-content-change behaviour. ### Upgrade **Existing repos:** run `/pm:upgrade` after updating — refreshes rules, stamps 0.4.0 into `state.json`. Idempotent; safe to run multiple times. No data migration required. </Update> <Update label="0.3.0" description="2026-06-18"> ### Added * **Lane-agnostic epics.** Epics are no longer restricted to OpenSpec proposals. Every epic now carries a `lane` tag — `openspec | superpowers | claude-code | decision | external` — so the conductor tracks the full backlog regardless of how work is executed. * **Epic schema fields.** * `lane` (string, optional, backward-compatible): execution lane. Defaults to `"openspec"` on read so existing `state.json` files are unaffected. * `planPath` (string, optional): repo-relative path to a Superpowers/markdown plan file. Used as a progress source when `stories[]` is absent. * `stories` (array, optional): inline `{ title, done }` story list. Highest-priority progress source. * **Progress precedence resolver.** `epicProgress(epic)` replaces `storyProgress(id)` and resolves progress in order: `stories[]` → `planPath` checkboxes → `openspec/changes/<id>/tasks.md` → `—`. A dangling `planPath` renders `⚠ planPath missing` rather than silent `0/0`. * **Non-OpenSpec epics in the briefing.** Non-OpenSpec epics now appear in NEXT UP and the Epics table. Only OpenSpec epics missing their on-disk change are flagged `⚠ no change on disk`; other lanes are shown as-is. * **Bounded briefing.** NEXT UP is capped at **top-5** by priority-then-lane, with a per-lane count summary (`lanes: openspec 4 · superpowers 12 · claude-code 9`) and a `(+N more — see PROJECT.md)` overflow line, so the briefing stays compact regardless of backlog size. * **`/pm:epic add`.** Registers a new epic directly (no `state.json` edit required): ```text theme={null} /pm:epic add --id X --title "…" --lane superpowers --priority P1 ``` Validates id format (`^[a-z0-9][a-z0-9._-]*$`), lane, and uniqueness. Optional flags: `--plan PATH`, `--status STATUS`, `--link "type:id:reason"`. * **`sync` imports Superpowers plans.** `docs/superpowers/plans/*.md` are scanned on `sync`/`init` and registered as lane-`superpowers` epics (id = filename without `.md`, `planPath` set, title from first `#` heading). Additive and id-collision-safe (colliding ids are skipped with a warning). The plans directory may be absent — the scan returns `[]` gracefully. * **Version-aware upgrade subsystem.** * `init` and `upgrade` stamp `pmVersion` (the running release) into `state.json`. * `brief()` compares the stamped version to the running release; if older, prepends a one-line upgrade nudge (re-shown every SessionStart and PreCompact until resolved). * **`/pm:upgrade`** runs registered migrations (those whose `release` is newer than the stamped version), then unconditionally refreshes the CLAUDE.md rules block, re-renders `PROJECT.md`, and re-stamps `pmVersion`. Idempotent — a second run is a no-op. * **0.3.0 migration:** stamps an explicit `lane: "openspec"` on any epic lacking one, making `state.json` self-describing. * **Lane-agnostic detour rules.** A substantial detour becomes its own **epic in the appropriate lane** (not necessarily an OpenSpec proposal). The `rulesBlock()` wording and PUSH/POP templates are updated accordingly. ### Changed * Epics table header changed from `Epic (OpenSpec change)` to `Epic`; a **Lane** column is added. Epics are sorted by priority rank then lane rank in both `PROJECT.md` and the brief. * NOW line includes the lane tag. * `rulesBlock()`: "epics = proposals" replaced with "epics are lane-agnostic; OpenSpec is one lane (openspec | superpowers | claude-code | decision | external)." ### Upgrade **Existing repos:** after updating the plugin, run `/pm:upgrade` once. It will: 1. Refresh the CLAUDE.md rules block with lane-agnostic wording. 2. Stamp explicit `lane: "openspec"` on all pre-0.3.0 epics. 3. Record `pmVersion: "0.3.0"` in `state.json` so the upgrade nudge stops appearing. The command is **idempotent** — running it more than once is safe and produces no changes on the second run. No data is lost; the migration is purely additive. </Update> <Update label="0.2.0" description="2026-06-01"> Initial public release. Tracks OpenSpec proposals as epics, maintains an explicit detour stack, and enforces a reconcile gate so nothing is lost when development pivots or context is compacted. </Update> # /pm:changelog — Review What Changed Between Versions Source: https://pm-plugin.dev/commands/changelog Show pm's own CHANGELOG entries newer than a given version — what an upgrade brought, on demand or for a specific version range. `/pm:changelog` surfaces the `pm` plugin's own `CHANGELOG.md` entries that are newer than a given version, so you (and your agent) know exactly what a version brought — not just that an upgrade happened. By default the floor is the version stamped in this repo's `.conductor/state.json` (`pmVersion`). ## Usage ```bash theme={null} /pm:changelog # entries newer than this repo's stamped pmVersion /pm:changelog --since 0.3.0 # everything released after 0.3.0 ``` | Flag | Description | | ----------------- | -------------------------------------------------------------------------------------------- | | `--since <x.y.z>` | Optional. Sets the floor version explicitly instead of using the repo's stamped `pmVersion`. | ## Relationship to /pm:upgrade `/pm:upgrade` already prints this same delta automatically for every version it crosses — you don't need to run `/pm:changelog` right after an upgrade to see what changed. Use `/pm:changelog` directly when you want to review the delta again later, or inspect a different version range on demand (e.g. checking what a much newer release added before deciding whether to upgrade at all). <Tip> `/pm:upgrade`'s instructions now go a step further: after showing the delta, the agent reviews each `Added` headline and recommends adopting any opt-in capability relevant to your project — see the Upgrade page's "Recommending adoption of new capabilities" section. </Tip> # /pm:changesets — List Pending CHANGELOG Fragments Source: https://pm-plugin.dev/commands/changesets List .changesets/*.md fragment files a hierarchy child has written, so a release can consolidate them into CHANGELOG.md without a shared-header merge conflict. `/pm:changesets` lists every `.changesets/<epic-id>.md` fragment a hierarchy child has written, so whoever cuts the release can consolidate them into `CHANGELOG.md` without a shared-header merge conflict. ## Why this exists A parallel multi-agent hierarchy batch (see the [Multi-Agent guide](/guides/multi-agent-hierarchy)) used to hit a 100% collision rate when every dispatched child edited `CHANGELOG.md`'s shared `## [Unreleased]` section directly. Children now write their own changelog entry to `.changesets/<epic-id>.md` instead — same bullet format `CHANGELOG.md` already uses (a bold one-line summary, then wrapped prose) — and never touch `CHANGELOG.md` themselves. ## Usage ```bash theme={null} /pm:changesets ``` Prints `{ changesets: [{ id, path, body }] }`, sorted by epic id. Returns `{ changesets: [] }` if `.changesets/` doesn't exist or is empty — it never errors on a missing directory. ## Consolidating at release time `/pm:changesets` is a pure read — it never writes, deletes, or concatenates on its own. To release: <Steps> <Step title="Run /pm:changesets to see every pending fragment"> Each fragment's `body` is already in the same format `CHANGELOG.md` expects. </Step> <Step title="Fold each body into CHANGELOG.md"> Add each fragment's content to `CHANGELOG.md`'s `[Unreleased]` section, or a new version section for a version release. Whoever cuts the release is the sole writer of `CHANGELOG.md` — there's nothing to merge-conflict here even though the fragments came from parallel hierarchy-child dispatches. </Step> <Step title="Delete the consumed fragment files"> Once a fragment's content is in `CHANGELOG.md`, delete it from `.changesets/`. </Step> </Steps> <Note> `.changesets/` is a normal tracked directory, not gitignored — fragments are consumed and deleted at release time, so there's nothing sensitive or generated to hide from version control in the meantime. </Note> # /pm:detour — Park Current Work for an Interruption Source: https://pm-plugin.dev/commands/detour Classify a mid-build interruption as minimal or substantial: fix-and-log it fast, or push the current epic onto the detour stack to preserve context. `/pm:detour` handles mid-build interruptions without losing the thread. Pass it a description of what came up — PM classifies it, either logs a quick fix or pushes the current epic onto the detour stack, and sets up the new work in its own lane. The classification step is mandatory: do not start fixing before you know which path you're on. ## Usage ```bash theme={null} /pm:detour "<what came up>" /pm:detour --minimal "<what you fixed>" # fast path: skip classification ``` ## Minimal detour (fast path) A minimal detour is small, self-contained, has no design ambiguity, fits before the next compaction, and doesn't reshape the current proposal. If it passes all those tests, fix it immediately — no stack entry, no new epic. The flow is: fix the issue → test → commit → record the detour so it leaves a trail: ```bash theme={null} conductor.mjs log-detour "<what you fixed>" ``` This appends a timestamped line plus the current commit SHA to `.conductor/detours.log`. Then resume the paused work as normal. If you invoke `/pm:detour --minimal "<what>"`, PM takes exactly this path and stops — no classification prompt, no push. ## Substantial detour (full flow) A detour is substantial when it needs its own design, changes shared behavior, or is multi-step. It becomes its own epic in the appropriate lane and is worked through that lane's full workflow. When a detour is substantial, follow these steps before building anything: 1. Make the current epic's `tasks.md` reflect reality and commit so nothing is left uncommitted. 2. Set the current epic's `status` to `paused` in `.conductor/state.json`. 3. Push a stack frame with `pausedEpic`, `pausedAt`, `reason`, `spawnedDetour`, and `reconcileOnResume: true` (default true whenever the detour will touch code the paused epic depends on). 4. Create the detour as a new epic with `role: detour` at P0 by default, in the appropriate lane. 5. Record cross-links: the detour gets a `resolves-blocker-for` link pointing to the parent; the parent gets a `may-invalidate` link pointing to the detour. 6. Set the detour epic as active, then create its OpenSpec proposal and build through the normal propose → review → apply → review → commit → archive loop. **Example:** You're mid-build on `api-gateway` (openspec, P1) when you discover webhook HMAC verification is broken in production. That's substantial — it needs its own spec, and its fix will change the shared request-validation path the `api-gateway` work depends on. PM pauses `api-gateway`, pushes a stack frame, and creates `webhook-hmac-fix` (P0, role: detour), then opens a fresh proposal for it. ## Honcho memory After a substantial detour push, preserve the context pivot for Honcho so it survives across repos and compactions: ```bash theme={null} conductor.mjs honcho-memory push <parent-epic-id> "<reason>" ``` This prints a formatted `paused <parent> for <reason>` memory line and appends a timestamped copy to `.conductor/honcho-memories.log`. Paste the printed line into your Honcho MCP memory tool. The engine only formats and logs the string — it never calls Honcho itself. ## After the detour When the detour epic is archived and its work is committed, run `/pm:resume` to pop the stack frame and run the mandatory reconcile gate. Do not skip the gate — it is the structured re-entry that checks whether the detour's changes affect the paused plan. <Tip> When in doubt, treat it as substantial. A needless stack entry is cheaper than re-deriving a lost context after compaction. </Tip> # /pm:epic — Add, Update, Remove, and Manage Epics Source: https://pm-plugin.dev/commands/epic Add, update, remove, and manage epics in PM. Covers add, update-epic, remove-epic, add-many, set-active, clear-active, and set-autonomy subcommands. `/pm:epic` is PM's primary interface for registering and modifying epics. Use it to add new work items in any lane, update their status and links, manage parent–child hierarchy, and grant execution autonomy for unattended agents. Every write operation is validated up front — unknown ids, malformed links, and cycle-forming parent assignments are all rejected with a clear error rather than silently stored. ## Adding an epic Register a new epic with the `add` subcommand. Only `--id`, `--title`, `--lane`, and `--priority` are required; all other flags are optional. ```bash theme={null} conductor.mjs add-epic \ --id <id> --title "<title>" --lane <lane> --priority <P0-P3> \ [--status <status>] [--parent <parent-id>] \ [--external-id <KEY>] [--external-url <url>] \ [--plan <path>] [--link "<type>:<epic>[:<reason>]"] ``` **Flag reference:** * **`--id`** — Unique identifier in kebab-case (e.g. `auth-service-refresh`). Must be unique across all epics in the project. * **`--title`** — Human-readable name for the epic (quoted string). * **`--lane`** — One of `openspec | superpowers | claude-code | decision | external`. Routes the epic to the correct workflow. * **`--priority`** — One of `P0` (critical), `P1` (high), `P2` (medium), `P3` (low), or `P?` (untriaged). Determines ordering in the NEXT UP queue. * **`--status`** — Defaults to `queued`. Use `planned` for roadmap items you intend to do but haven't proposed or scaffolded yet — `planned` epics appear in `PROJECT.md` but are excluded from NEXT UP. * **`--parent`** — Nests this epic under an existing parent. The parent must already exist, an epic may not be its own parent, and the link may not form a cycle. * **`--external-id`** — Links the epic to an issue key in a configured external tracker (e.g. `JOB-506`). See `/pm:tracker`. * **`--external-url`** — Full URL to the corresponding issue in the external tracker. * **`--plan`** — Repo-relative path to a markdown plan file. Used as the progress source for `superpowers`-lane epics. * **`--link`** — Validated, not just parsed: the referenced epic id must already exist and the value must split into at least `type` and `epic`. A malformed value (typo'd id, wrong segment order) is rejected with a clear error rather than stored silently. The flag is repeatable. ## Bulk create with add-many To register a parent epic and its children in one atomic operation — for example, a sprint and its child tickets — author a JSON batch file and pass it with `--from`: ```json theme={null} { "parent": { "id": "sprint-q1", "title": "Q1 Sprint", "lane": "external", "priority": "P0", "status": "queued" }, "epics": [ { "id": "task-001", "title": "Auth service", "lane": "openspec", "priority": "P0" }, { "id": "task-002", "title": "API gateway", "lane": "openspec", "priority": "P1" } ] } ``` ```bash theme={null} conductor.mjs add-many --from /path/to/batch.json ``` When a `parent` key is present, it is created first and each entry in `epics[]` defaults its `parent` field to it. The operation is **atomic**: every entry is validated up front — id format, uniqueness against existing epics and within the batch itself, lane, status, and parent refs/cycles. On any failure, nothing is written and the command exits non-zero naming the offender. A valid batch is persisted in a single write, so there is no partial-state race. Pass `--from -` to read the batch from stdin. The `parent` key is optional; a bare `{ "epics": [...] }` batch also works. ## Updating an epic Change any field on an existing epic with `update-epic`. The id is positional. ```bash theme={null} conductor.mjs update-epic <id> \ [--title <title>] [--status <status>] [--priority <P?>] \ [--parent <id>] [--external-id <KEY>] [--external-url <url>] \ [--link "<type>:<epic>[:<reason>]"] [--review-mode off|standard|thorough] ``` All validations from `add-epic` apply: no self-parent, no cycles, known status values, and referenced epic ids must exist. On an unknown id or any invalid flag value, the command exits non-zero and writes nothing. **`--link` replaces the epic's links wholesale** — unlike the other flags, which patch a single field, passing `--link` discards all existing links and stores only the ones you provide in this call. This is the intended path for fixing a malformed link without touching `state.json` directly. Pass every link you want the epic to have; omitting `--link` entirely leaves existing links untouched. **`--review-mode`** can escalate a single epic above the repo's bounded review dial (`off → standard → thorough`), but never de-escalate below it. ## Removing an epic Hard-delete an epic with `remove-epic`. The only prior recovery path was a raw `git checkout` on `state.json`; this command replaces that workaround. ```bash theme={null} conductor.mjs remove-epic <id> [--cascade] ``` * **Blocked by default** if the epic has any descendants. The command prints a `(id, title, lane, priority, status)` table of the parent and every descendant at any depth, then exits non-zero. Reassign or remove the descendants first, or use `--cascade`. * **`--cascade`** removes the epic and all its descendants together in one atomic write. The preview table from the blocked attempt and the `--cascade` blast radius always agree — confirming from that table is confirming the real deletion set. * **Dangling links are cleaned up automatically.** Any other epic's `links[]` entries that reference the removed id are stripped, and the command reports which epics were affected. * If the removed epic was the active epic, the `.active` pointer is cleared automatically. <Warning> `remove-epic` is a hard delete — recoverable only via `git history`. Before using `--cascade`, review the blast-radius table that the blocked attempt prints and confirm explicitly. The engine has no interactive prompt; that confirmation step is your responsibility. </Warning> ## Setting the active epic The top-level `.active` pointer (what the briefing's "NOW" line reads) has dedicated verbs. Never hand-edit `state.json` for this. ```bash theme={null} conductor.mjs set-active <id> # sets .active and status: active; demotes previous conductor.mjs clear-active # clears the active pointer ``` `set-active` sets `.active = <id>` and the epic's `status: "active"` together, demoting any previously-active epic to `queued` — so the pointer and status can never disagree. It rejects an unknown or archived id. `update-epic <id> --status active` keeps them in sync too, and moving the active epic off `active` clears the pointer automatically. ## Granting autonomy Before an epic can run unattended through phase transitions and destructive actions, it needs a preflight scan and your recorded answers. Use `set-autonomy` to capture the results. ```bash theme={null} conductor.mjs set-autonomy <id> \ --level autonomous \ --preauthorize "drop-scratch-table:safe to drop" \ --preauthorize "category:filesystem:routine file writes" \ --context "staging DB only, no prod access" ``` **Flag reference:** * **`--level autonomous`** — Enables unattended execution. The default is `off` (today's behavior, unchanged). Pass this only after all preflight questions are answered and recorded. * **`--preauthorize`** — Pre-approves a specific action (e.g. `"drop-scratch-table:reason"`) or an entire category (`"category:<name>:<reason>"`). Valid category names are `filesystem`, `network`, `schema`, and `external-api`. Any category name outside this list is rejected, so a typo fails loudly. The flag is repeatable. * **`--context`** — Records a piece of background supplied during the preflight scan. Repeatable. * **`--notify`** — Records a WARN-class decision durably alongside the autonomy grant. Repeatable. All of `--preauthorize`, `--context`, and `--notify` are **additive** — re-running `set-autonomy` on the same epic appends to the existing entries and never clobbers them. Only `--level` replaces. <Note> `update-epic --status archived` on an `openspec`-lane epic requires a passing Gate 2 verdict already recorded via `record-gate-review`. If the verdict is missing or `fail`, the transition is rejected with a clear error naming what's missing. Non-openspec epics are unaffected by this check. </Note> # /pm:feedback — File a Bug Report or Feature Request Source: https://pm-plugin.dev/commands/feedback File a bug or feature request to the PM repo from Claude Code. Checks for near-duplicate issues first and comments on matches instead of filing duplicates. `/pm:feedback` lets you file a bug report or feature request for PM itself without leaving your Claude Code session. Instead of copy-pasting context between windows, you describe the issue once and your agent posts it straight to the `cfdude/pm` GitHub repo. It searches for near-duplicate issues first — if a match exists, it comments on the existing issue rather than creating a duplicate. ## Usage ```bash theme={null} /pm:feedback bug "<summary>" /pm:feedback feature "<summary>" ``` | Subcommand | Description | | ----------- | -------------------------------------------------------- | | `bug` | File a bug report against `cfdude/pm`. | | `feature` | File a feature request against `cfdude/pm`. | | `<summary>` | A concise, specific description of the issue or request. | For a bug report, include what you expected, what actually happened, the command or subcommand involved, and any error output. For a feature request, describe the concrete use case and, if you know it, which lane, command, or skill section it would touch. ## Deduplication Before filing anything new, PM searches open issues on `cfdude/pm` for near-duplicates: ```bash theme={null} gh issue list --repo cfdude/pm --state open --search "<key terms from the title>" ``` If a clearly matching issue is found, your agent **comments on the existing issue** with your new details rather than creating a duplicate: ```bash theme={null} gh issue comment <number> --repo cfdude/pm \ --body "<new details or repro context from this session>" ``` Your agent reports the existing issue's URL back to you and stops — no new issue is created. ## How it works When no duplicate exists, your agent creates a new issue: ```bash theme={null} gh issue create --repo cfdude/pm \ --title "<title>" \ --body "<description + relevant context>" \ --label "bug" # or "enhancement" for feature requests ``` This is a pure agent-driven workflow. **The PM engine (`conductor.mjs`) is never involved and never calls GitHub.** All `gh` calls are made by your Claude Code agent via Bash — the same instruction-layer law that governs tracker sync, feedback filing, and every other external action in PM. `/pm:feedback` only targets `cfdude/pm`. It is not a general-purpose issue filer and should not be pointed at other repos. ## Proactive adoption The CLAUDE.md rules block includes an unconditional "Feedback" section instructing your agent to use `/pm:feedback` proactively — not just when you ask for it. If it hits a bug, a missing CLI verb, an unexpected limitation, or repeated friction working with PM, it should file it (or ask you "want me to file this as feedback?") rather than silently working around it. This exists because the command shipped once and went unused: a real, recurring friction point (hand-editing `.conductor/state.json` to flip a story's `done` flag, since no CLI verb existed for it) recurred across several separate sessions before anyone reported it. <Tip> Include as much context as you can in the summary — what you expected, what happened, and your current PM version. You can find the version in the SessionStart briefing or in `state.json` under `pmVersion`. </Tip> # /pm:gate-guard — Block Writes While a Reconcile Is Owed Source: https://pm-plugin.dev/commands/gate-guard A PreToolUse hook that blocks writes while the active epic owes a reconcile. Always on for that case — running set-gate-guard off will not bypass it. The gate guard is PM's safety mechanism for the highest-stakes skip: writing source code before a reconcile gate has run. It is a `PreToolUse` hook that intercepts every `Edit`, `Write`, and `NotebookEdit` call and blocks them while the active epic has `reconcileNeeded: true`. This is the one place PM tolerates mechanical blocking over pure instruction — protecting you from overwriting work before a detour is properly reconciled. ## How it works Every `Edit`, `Write`, and `NotebookEdit` call is intercepted by the hook. Before allowing the tool call to proceed, PM checks whether the currently active epic has `reconcileNeeded: true` — meaning the epic popped out of a detour and still owes a reconcile gate. * If `reconcileNeeded` is `true`: the tool call is **blocked** with a message directing you to run the reconciler agent via `/pm:resume`. * If `reconcileNeeded` is `false` or absent: the tool call proceeds normally. Epics with no pending reconcile are completely unaffected. ## Always on for reconcile-owed epics This check is **always active** for any epic carrying `reconcileNeeded: true` — including epics that already had the flag set before this behavior was introduced. It previously required an explicit `set-gate-guard on`; real-usage feedback showed that opt-in was never actually turned on across several sessions where it would have caught a real skip, so the default was flipped. **There is no bypass for this case.** Running `set-gate-guard off` does **not** silence the reconcile-owed block. The only path through it is completing the reconcile gate: run `/pm:resume`, let the reconciler agent complete the reconcile gate, and the block clears automatically. Once cleared, file writes proceed as normal. ## The `set-gate-guard` command The command still exists and toggles the repo-level `gateGuard` flag in `state.json`: ```bash theme={null} conductor.mjs set-gate-guard on conductor.mjs set-gate-guard off ``` This flag is reserved for any future generalization of the hook to additional checks beyond the reconcile-owed case. It has **no effect** on the reconcile-owed block described above. ## Checking gate guard status Run `/pm:gate-guard` at any time to inspect the current state of the hook — whether `gateGuard` is on or off in `state.json`, and whether any epic currently carries `reconcileNeeded: true`. This is the fastest way to understand why a write was blocked without digging into `state.json` directly. <Warning> If you see "blocked by gate guard" on an `Edit` or `Write` call, the only resolution is to run `/pm:resume` and complete the reconcile gate. There is no workaround — `set-gate-guard off` will not help here. </Warning> <Note> The gate guard hook is dormant until `/pm:init` has been run in a project. It activates only in projects that have been initialized and have a `.conductor/state.json` present. </Note> # /pm:hierarchy — Plan and Dispatch a Multi-Agent Hierarchy Source: https://pm-plugin.dev/commands/hierarchy Plan and dispatch a parent epic's children as batched, worktree-isolated agents. Each child runs unattended in its own branch and merges back sequentially. `/pm:hierarchy` is PM's multi-agent dispatch harness. Give it a parent epic and it computes an execution plan from child priorities and `depends-on` links, then dispatches each child as an isolated agent in its own git worktree, converging them back through sequential merge. Everything is recomputed from current state each time — there is no "hierarchy in progress" flag to get out of sync. ## Planning the execution Before dispatching, preview the computed batches with `plan-hierarchy`: ```bash theme={null} conductor.mjs plan-hierarchy --parent <parent-id> ``` This prints: ```json theme={null} { "parent": "sprint-q1", "batches": [ { "batch": 1, "epics": [ { "id": "task-001", "priority": "P0", "autonomous": true, "dependsOn": [] }, { "id": "task-002", "priority": "P0", "autonomous": true, "dependsOn": [] } ] }, { "batch": 2, "epics": [ { "id": "task-003", "priority": "P1", "autonomous": true, "dependsOn": ["task-001"] } ] } ] } ``` Batches run in order. Epics within a batch have no mutual dependencies and may dispatch in parallel. The `dependsOn` field lists each epic's sibling ids it depends on within this hierarchy — use it to check transitively whether a later batch depends on a blocked child. A dependency cycle among children exits non-zero, naming the cycle. <Note> `plan-hierarchy` is a pure read — it recomputes from current `parent`, `priority`, `links`, and `autonomy` blocks every time. There is no "hierarchy in progress" flag to get out of sync; re-running it at any point reflects current reality. </Note> ## Preflight requirements Before dispatch, every child epic in the plan must show `autonomous: true`. Any child that doesn't was not cleared in the preflight step. Use `set-autonomy` to grant trust: ```bash theme={null} conductor.mjs set-autonomy <id> --level autonomous ``` Run the full preflight scan for each child first — read its complete source, identify destructive or irreversible actions, and record your answers before setting `--level autonomous`. PM blocks dispatch for any non-autonomous child; do not skip the preflight. ## Dispatching Each child runs as an isolated subagent in its own `git worktree` on its own branch (`hierarchy-child/<epic-id>`). Epics within the same batch that have no dependencies on each other may be dispatched in parallel using the Task tool. **The orchestrator is the sole writer of `.conductor/state.json` throughout.** Children never write state directly — they return a fixed report, and you apply all state transitions in one pass after the batch (marking each merged child `archived`). This is what makes parallel dispatch safe for the state file: there is only ever one writer, so there is nothing to merge-conflict on `state.json`. ## Merge convergence and conflict resolution After each child completes, merge its worktree branch back sequentially — one at a time, even though the work ran in parallel. On a merge conflict, work through the resolution ladder in order: 1. Attempt the merge normally (fast path). 2. On conflict, dispatch a subagent to read both sides plus the merge base and resolve it. 3. If the subagent reports `STATUS: uncertain`, escalate — retry with a more capable model before finalizing. 4. If still genuinely unresolvable, commit the best-effort resolution and log a follow-up epic under the same parent, then continue. Mechanical conflicts — such as a shared CHANGELOG header or usage string — resolve automatically at the merge step and are never a real logic collision. After any conflict resolution, before committing the merge, verify that every touched file has no leftover conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) and that every touched `.mjs`/`.js` file passes `node -c <file>`. Neither check is optional and neither substitutes for the other. <Warning> A dependency cycle exits non-zero and names the cycle. Fix the offending `links` on the child epics before retrying. Do not retry blindly — a cycle is a real data problem, not a transient failure. </Warning> ## Changelog fragments Children write their changelog entries to `.changesets/<epic-id>.md`, never to `CHANGELOG.md`'s shared `## [Unreleased]` section directly. Writing to that shared header is a guaranteed merge conflict across every parallel batch. Because each child touches only its own fragment file, fragments never conflict with each other. Use `/pm:changesets` to list pending fragments and consolidate them into `CHANGELOG.md` once, at release time. ## Cleanup After each batch, verify no orphaned worktrees remain: ```bash theme={null} conductor.mjs verify-worktrees ``` This cross-references `git worktree list` against epic status and flags any `hierarchy-child/*` worktree whose epic is already archived but was not cleaned up. Once a child's branch has merged, remove its worktree and delete its branch immediately — never leave them dangling. # /pm:init — Initialize PM in Your Project Directory Source: https://pm-plugin.dev/commands/init Scaffold .conductor/state.json, register existing OpenSpec epics, write the CLAUDE.md rules block, and render PROJECT.md. Safe to re-run. `/pm:init` bootstraps PM in your project. Run it once in any directory — it creates the `.conductor/` state directory, scans for existing OpenSpec proposals to register as epics, writes the managed rules block into `CLAUDE.md`, and renders the initial `PROJECT.md`. Until you run this command, all of PM's hooks stay dormant in your project, so this is always your first step. Before scaffolding, your agent should also load the `conductor` skill — the agent-facing how-to (mental model, lanes, statuses, the detour → PUSH/POP → reconcile workflow). For deeper reference beyond that skill and `README.md`, [`llms.txt`](https://pm-plugin.dev/llms.txt) is a lightweight (\~7KB) index of every doc page on this site; [`llms-full.txt`](https://pm-plugin.dev/llms-full.txt) is the entire site as one document (\~200KB, tens of thousands of tokens) — fetch it only if you genuinely need the complete reference, not as a default. ## What it creates <CardGroup> <Card title=".conductor/state.json" icon="database"> The single source of truth for every epic, the detour stack, tracker config, and the `pmVersion` stamp. All engine operations read and write this file. </Card> <Card title="CLAUDE.md rules block" icon="book-open"> A managed section injected into your project's `CLAUDE.md` that carries the PM discipline — lanes, statuses, detour workflow, and decision rules — into every Claude Code session automatically. </Card> <Card title="PROJECT.md" icon="file-lines"> A generated project briefing view rendered from `state.json`. Re-rendered on every `/pm:status`, `/pm:sync`, and `/pm:upgrade` call. </Card> </CardGroup> ## What happens during init <Steps> <Step title="Engine scaffolds state"> The conductor engine creates `.conductor/state.json` with an empty epic index, an empty detour stack, and a `pmVersion` stamp matching your installed version. </Step> <Step title="Scans for existing work"> PM scans for OpenSpec change directories (`openspec/changes/<id>/`). Any found are registered as `untriaged` epics in the `openspec` lane so no prior work is lost. </Step> <Step title="Writes the CLAUDE.md rules block"> The managed rules block is inserted into `CLAUDE.md` (or the file is created if it doesn't exist). The block is delimited so future `/pm:upgrade` calls can refresh it without touching your surrounding content. </Step> <Step title="Renders PROJECT.md"> The engine renders the initial project briefing from state, giving you a human-readable snapshot of every registered epic and the current detour stack (empty at this point). </Step> <Step title="Offers tracker mirroring (conditional)"> If PM detects real signals of active issue-tracker usage — a connected tracker MCP, issue-key conventions in your history, or an explicit note in your codebase — it offers to connect an external mirror. Being hosted on GitHub, GitLab, or Bitbucket is **not** a signal. Saying no loses nothing; PM tracks everything locally regardless. </Step> <Step title="Shows /pm:status output"> Init finishes by printing the full conductor briefing so you can see your registered epics and immediately begin triage. </Step> </Steps> ## After init Once init completes, PM prompts you to triage your epics. Triage means: * Designating exactly one epic as **active** (the thing being built right now) * Assigning each epic a **priority** of `P0`, `P1`, `P2`, or `P3` * Setting each epic's **status** to `active`, `queued`, or `later` Until you triage them, any epics discovered during the scan sit in the `untriaged` lane. PM won't recommend untriaged epics via `/pm:next` — triage is the gate that admits work into the priority queue. ## Idempotency If `.conductor/state.json` already exists, init is a complete no-op — you can re-run it safely. If you genuinely need to reset your project's PM state, delete `.conductor/state.json` and run `/pm:init` again, though this is rarely the right move. For version migrations after installing a new PM release, use `/pm:upgrade` instead — it preserves your epic history and runs the correct migration scripts. ## Example output after init ```text theme={null} ╔══════════════════════════════════════════╗ ║ PROJECT BRIEFING ║ ╚══════════════════════════════════════════╝ NOW ○ (none active — triage needed) DETOUR STACK (empty) NEXT UP [P?] auth-overhaul untriaged openspec [P?] dashboard-redesign untriaged openspec LANE COUNTS openspec 2 epics (2 untriaged) TRACKER SYNC (no tracker configured) ``` <Note> PM's hooks stay dormant in your project until `/pm:init` runs. This is intentional, matching the same design as `openspec init`. Running init is what arms the hooks for all future sessions. </Note> # /pm:lane-routing — Customize Lane Assignment Rules Source: https://pm-plugin.dev/commands/lane-routing Define keyword or glob rules that override PM's lane heuristic — so 'billing always goes through openspec' becomes a durable rule, not a one-time note. By default, PM uses a generic heuristic to assign a lane when you add an epic — routing by estimated effort, scope, and change type. `/pm:lane-routing` lets you define per-repo rules on top of that heuristic: keyword or glob patterns that are checked first, before the generic logic runs. When a pattern matches, the lane it specifies wins. Most repos never need this, but it becomes invaluable when your project has standing conventions the generic heuristic can't know about. ## Managing routing rules Use `set-lane-routing` with `--add`, `--remove`, or `--clear` to manage the overrides list: ```bash theme={null} # Add a single routing rule conductor.mjs set-lane-routing --add "billing:openspec" # Add a glob rule conductor.mjs set-lane-routing --add "hotfix-*:claude-code" # Add multiple rules at once conductor.mjs set-lane-routing --add "billing:openspec" --add "infra:decision" # Remove a specific rule by its match string conductor.mjs set-lane-routing --remove "billing" # Clear all rules conductor.mjs set-lane-routing --clear ``` Each rule uses the format `"<match>:<lane>"`: * `<match>` is either a plain, case-insensitive substring (`hotfix` matches "urgent hotfix for prod") or a `*`-glob (`billing-*` matches "billing-refund-flow"). * `<lane>` must be one of `openspec`, `superpowers`, `claude-code`, `decision`, or `external`. * Adding a rule with the same `<match>` as an existing rule **replaces** the earlier rule. * `--clear` and `--remove` are applied before `--add` when combined in a single invocation. * Rules are checked **in the order they were added**; the first match wins. Re-running `set-lane-routing` merges — only what you pass changes. ## Looking up a lane suggestion Before assigning a lane to a new epic, your agent should call `suggest-lane` with the epic title. If a rule matches, it returns the lane and the matched pattern; if nothing matches, it returns `null` and the generic heuristic applies as normal. ```bash theme={null} conductor.mjs suggest-lane "hotfix: fix broken login button" # {"lane":"claude-code","matched":"hotfix"} conductor.mjs suggest-lane "add a brand-new subsystem" # {"lane":null,"matched":null} ``` ## Use cases Routing rules shine wherever your project has conventions that are obvious to your team but opaque to a heuristic: * **`"billing:openspec"`** — anything touching billing always goes through spec-driven review, regardless of estimated size. A two-hour billing change still needs the spec gate. * **`"hotfix-*:claude-code"`** — hotfixes skip spec and go straight to the `claude-code` lane. Speed matters more than formality here. * **`"infra*:decision"`** — infrastructure changes are recorded as architectural decisions, not built through a code-delivery lane. <Tip> Lane routing rules are stored in `state.json` under `laneRouting[]` and are re-applied by the `CLAUDE.md` rules block every session. You do not need to re-set them after a context compaction — the rules are durable from the moment you add them. </Tip> # /pm:next — Get a Concrete Next-Work Recommendation Source: https://pm-plugin.dev/commands/next PM reads the current state and recommends exactly one thing to work on next, following the detour-stack-first, then priority-order decision rule. `/pm:next` reads the current conductor state and tells you precisely what to work on. It follows a strict, deterministic decision rule so you never have to guess, names any blockers explicitly when it can't advance, and surfaces genuine ties to you rather than making an arbitrary call. The output is always a single, concrete recommendation — the epic, and the specific story or phase within it to tackle. ## Decision rule PM applies the following order every time you call `/pm:next`: <Steps> <Step title="Detour stack check (highest priority)"> If the detour stack is non-empty, the next action is always to finish or resume the **top frame**. If the detour epic is already archived, PM triggers the reconcile gate via `/pm:resume`. PM never starts new work while a detour is unresolved — the stack must be empty first. </Step> <Step title="Priority queue (when stack is clear)"> With an empty detour stack, PM selects the highest-priority `queued` epic in P0 → P3 order. If the currently active epic still has open stories, that's the default next action rather than switching epics. Any epic whose `depends-on` epic hasn't been archived yet is skipped, and the blocker is named explicitly in the output. </Step> <Step title="Tie-breaking and ambiguity"> If two or more epics share the same priority with no clear differentiator, PM surfaces the tie to you and asks you to choose rather than picking arbitrarily. Ambiguity is always made visible, never silently resolved. </Step> </Steps> ## What it does after choosing Once PM identifies the next epic, it makes that epic active by updating `state.json` atomically: the top-level `.active` pointer is set, the chosen epic's `status` is set to `active`, and any previously-active epic is demoted back to `queued`. This keeps the briefing's **NOW** line accurate without requiring you to manually update state. PM then states the specific next story or phase to build — not just the epic name, but the concrete unit of work within it. ```text theme={null} Next: auth-overhaul — Story 4: Implement refresh-token rotation endpoint. ``` <Tip> If you're at the start of a session and the detour stack is non-empty, `/pm:next` will tell you to resume the top frame before starting anything new. This is intentional — PM enforces the detour-stack-first rule unconditionally. Clear the detour (via `/pm:resume`) before asking for the next queued epic. </Tip> # /pm:resume — Resume a Paused Epic After a Detour Source: https://pm-plugin.dev/commands/resume Pop the detour stack, restore the paused epic to active, and run the reconcile gate — a fresh-context re-validation before any new code is written. `/pm:resume` pops the top frame from the detour stack, restores the paused epic to active status, and runs the mandatory reconcile gate if the frame has `reconcileOnResume: true`. This is the structured re-entry to work that was parked — the step otherwise lost after a context compaction. Do not skip it or hand-clear `reconcileNeeded` directly. ## Prerequisites Before running `/pm:resume`, confirm that the detour epic is **archived** and its work is committed and deployed. If the detour isn't finished yet, it is not time to resume — finish the detour first and archive it, then come back here. ## What happens <Steps> <Step title="Verify the detour is complete"> Confirm the detour epic is archived and all changes are committed. If anything is still in progress, stop and finish the detour first. </Step> <Step title="Pop the stack frame"> Remove the top frame from `detourStack` in `.conductor/state.json`. </Step> <Step title="Restore the paused epic"> Set the paused epic's `status` back to `active` and update the `.active` pointer to it. </Step> <Step title="Delegate to the reconciler (if required)"> If the popped frame had `reconcileOnResume: true`, do not write any code yet. Delegate a clean-context review to the **reconciler** agent via the Task tool, passing it the paused epic id and the detour epic id. </Step> <Step title="Receive the verdict"> The reconciler re-reads the paused proposal, diffs what the detour actually changed, and reports back `VERDICT: valid|invalidated` plus `AMENDMENTS:` — one story to add, remove, or amend per line. </Step> <Step title="Write the verdict back durably"> Record the result with: ```bash theme={null} conductor.mjs record-reconcile <paused-id> \ --detour <detour-id> \ --verdict <valid|invalidated> \ --amendments "<amendment-a>;<amendment-b>" ``` This attaches `{ verdict, amendments, reconciledAt }` to the paused epic's link to the detour and clears `reconcileNeeded` in one step. Do not hand-clear `reconcileNeeded` — use this command. </Step> <Step title="Re-render and continue"> Run `conductor.mjs render`, then state the exact next story to build on the resumed epic. </Step> </Steps> ## Reconcile verdicts | Verdict | Meaning | What to do | | ------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------- | | `valid` | The detour's changes don't affect the paused plan — it is still sound. | Resume building immediately. | | `invalidated` | The detour's changes affect the paused plan. | Amend the OpenSpec proposal and `tasks.md` before continuing. | Either way, always write the verdict back with `record-reconcile`. Narration alone in the transcript does not clear `reconcileNeeded`. ## Honcho memory After the reconcile gate completes, preserve the resume context for Honcho: ```bash theme={null} conductor.mjs honcho-memory pop <parent-epic-id> "<detour-id>; reconcile = valid" ``` This prints a formatted `resumed <parent>, reconciled vs <detour-id>; reconcile = valid` line and appends a timestamped copy to `.conductor/honcho-memories.log`. Paste the printed line into your Honcho MCP memory tool. The engine only formats and logs the string — it never calls Honcho itself. <Warning> The gate guard mechanically blocks `Edit`, `Write`, and `NotebookEdit` on the active epic while `reconcileNeeded` is true. This is unconditional — it applies regardless of the repo's `gateGuard` setting and cannot be bypassed with `set-gate-guard off`. Run the full reconcile gate and call `record-reconcile` to clear it. </Warning> # /pm:review-mode — Configure the Repo Review Intensity Source: https://pm-plugin.dev/commands/review-mode Set the repo review dial: off (self-review only), standard (one reviewer per gate), or thorough (two independent reviewers, adjudicated on disagreement). `/pm:review-mode` sets the review intensity for the entire repository. The dial controls how many fresh-context reviewers run at each gate — a single repo-wide setting that individual epics can escalate above but never de-escalate below. It is a pure instruction-layer setting: PM never runs a review itself, it only shapes what the `CLAUDE.md` rules block tells your agent to do. ## The three levels | Mode | Reviewer budget | When to use | | ---------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | `off` | None — self-review only | Tiny, low-risk, single-file tweaks where a second reviewer adds no value. | | `standard` | One fresh-context reviewer per gate | The default. Covers Gate 1, Gate 2, and reconcile reviews for most repos. | | `thorough` | Two independent fresh-context reviewers per gate; adjudicate any disagreement | Schema or migration changes, security-sensitive work, or anything explicitly flagged high-stakes. | If `set-review-mode` has never been run, the mode is `standard` — matching the default Gate 1/Gate 2 behavior already documented in the conductor skill. ## Setting repo review mode Pass the desired mode with the `--mode` flag: ```bash theme={null} conductor.mjs set-review-mode --mode off conductor.mjs set-review-mode --mode standard conductor.mjs set-review-mode --mode thorough ``` Re-running the command replaces the prior mode outright — there is only one active mode at a time. The `CLAUDE.md` rules block is refreshed automatically so the "Current mode" line stays accurate. ## Per-epic escalation Individual epics can be escalated above the repo-wide dial without changing the setting for the whole repo: ```bash theme={null} conductor.mjs update-epic <id> --review-mode thorough ``` The escalation rules are strict: * An epic can **always escalate** above the repo dial. A P0 epic in a `standard` repo can run as `thorough`. * An epic can **never de-escalate** below the repo dial. Attempting to set `--review-mode off` on an epic in a `standard` repo is rejected with a non-zero exit and leaves state unchanged. * The **effective mode** for a given epic is `max(global dial, epic override)`. If you later raise the global dial above an epic's override, the global dial wins — an override never pins a lower effective mode than the current global setting. To query the effective mode for a specific epic, read `state.epics[].reviewMode` alongside `state.reviewMode`. <Note> The review mode setting is stored in `state.json` under `reviewMode`. It persists across sessions and is re-applied by every fresh `CLAUDE.md` rules refresh — you do not need to re-run `set-review-mode` after a context compaction. </Note> <Tip> For high-stakes production changes, escalate the specific epic to `thorough` even if the repo is set to `standard`. One command before starting the epic is all it takes — the rest of the repo's epics continue at `standard`. </Tip> # /pm:status — Display the Current Project Briefing Source: https://pm-plugin.dev/commands/status Re-render PROJECT.md from state.json and display the full briefing: active epic, detour stack, next-up queue, lane counts, and tracker sync status. `/pm:status` runs the conductor engine's `render` command, then reads `PROJECT.md` and summarizes the project's position: what's actively being built, what's paused and why, what's queued next, and how many epics exist per lane. It's the fastest way to re-orient yourself at the start of a session or after any state-changing operation. ## What the briefing shows <CardGroup> <Card title="NOW" icon="circle-play"> The active epic with its lane icon, priority badge, and live story progress derived from checkbox counts in the epic's `tasks.md` file. If no epic is active, this section prompts you to triage. </Card> <Card title="DETOUR STACK" icon="layer-group"> All paused epics in LIFO order, each annotated with the reason it was pushed onto the stack. Any frame with a pending reconcile-on-resume gate is flagged with ⚠ to remind you to reconcile before resuming. </Card> <Card title="NEXT UP" icon="list-ol"> The top-priority `queued` epics in P0 → P3 order. Blocked epics appear in this list but name their blocker explicitly — the dependency is surfaced rather than silently hidden. </Card> <Card title="LANE COUNTS" icon="chart-bar"> A snapshot of how many epics exist across each lane (`openspec`, `superpowers`, `claude-code`, `decision`, `external`) broken down by status, so you can see the overall shape of the backlog at a glance. </Card> <Card title="TRACKER SYNC" icon="arrows-rotate"> When an external tracker is configured, this section lists any currently active epics that are missing an `externalId`. These are candidates for `/pm:sync` or manual tracker linkage. </Card> </CardGroup> ## When to run it Run `/pm:status` at the **start of every session** to confirm where you left off, after `/pm:resume` to verify the detour stack contracted correctly, after `/pm:sync` to see newly registered epics, and any time you want to re-orient mid-session. The `SessionStart` hook fires it automatically when Claude Code opens your project — running it manually just forces a fresh render at any point you choose. Story progress counts come from each epic's `openspec/changes/<id>/tasks.md` checkboxes in real time. If the counts look stale, the `tasks.md` file is the source of truth — `/pm:status` will recount on the next render. ## Sample PROJECT.md output ```text theme={null} ╔══════════════════════════════════════════════════════════╗ ║ PROJECT BRIEFING ║ ╚══════════════════════════════════════════════════════════╝ NOW ◆ [P1] auth-overhaul openspec 3 / 7 stories complete "Implement OAuth 2.0 refresh-token rotation" DETOUR STACK ▲ [P2] hotfix-rate-limit claude-code ⚠ reconcile pending reason: "Urgent rate-limit regression in prod" NEXT UP 1. [P0] payments-v2 queued superpowers 2. [P1] dashboard-search queued openspec 3. [P2] export-api queued openspec blocked-by: payments-v2 LANE COUNTS openspec 4 epics (1 active, 2 queued, 1 later) superpowers 1 epic (1 queued) claude-code 1 epic (1 detour) TRACKER SYNC ◆ auth-overhaul — no externalId (consider /pm:sync) ``` # /pm:sync — Register New Proposals and External Issues Source: https://pm-plugin.dev/commands/sync Scan for new OpenSpec proposals, Superpowers plans, or GitHub Issues not yet tracked as epics and register them. Deduplicates automatically. `/pm:sync` scans your project for work that should be tracked as epics but isn't yet. It picks up new OpenSpec proposals and Superpowers plans found on disk, and — when a `github-issues` tracker is configured — pulls open GitHub Issues in as untriaged epics. After sync completes, PM prompts you to triage any newly registered epics: assign priorities, set statuses, and add any dependency links. ## What it registers <CardGroup> <Card title="OpenSpec proposals" icon="file-circle-plus"> Any `openspec/changes/<id>/` directory not yet tracked becomes an `openspec`-lane epic registered with `status: untriaged` and `priority: P?`. </Card> <Card title="Superpowers plans" icon="bolt"> Any Superpowers plan file not yet tracked becomes a `superpowers`-lane epic registered with `status: untriaged` and `priority: P?`. </Card> <Card title="GitHub Issues" icon="github"> When a `github-issues` tracker is configured, open issues without a matching `externalId` become `claude-code`-lane epics. Default priority is `P2`; a `P0`, `P1`, `P2`, or `P3` label on the issue overrides the default. </Card> </CardGroup> ## Deduplication Sync never creates duplicate epics. For OpenSpec and Superpowers sources, deduplication is by the epic's id — if an epic with that id already exists in `state.json`, the candidate is skipped silently. For GitHub Issues, deduplication is by `externalId` (the issue number): if any existing epic already carries that `externalId`, the issue is not re-registered. Re-running `/pm:sync` as many times as you like is always safe. ## When to run it Run `/pm:sync` after **pulling changes from another branch** that may have introduced new OpenSpec proposals, after **generating new proposals** in the current session, at the **start of a session** when you know new work was filed in your issue tracker since you last worked, or any time you suspect the epic index is out of date relative to disk. <Note> For `github-issues` sync, the engine itself only scans local files and never calls an external system directly. When `github-issues` is configured (via `/pm:tracker`), the sync process fetches open issues, deduplicates them against existing `externalId` values in `state.json`, and registers each new issue as an untriaged `claude-code`-lane epic at `P2`. Any `P0`–`P3` label present on the issue overrides the `P2` default. Configure your GitHub tracker via `/pm:tracker` before expecting issue sync to work. </Note> # /pm:tracker — Connect an External Tracker to Your Repo Source: https://pm-plugin.dev/commands/tracker Mirror epics to Jira, Linear, GitHub Issues, or any tracker. PM shapes the sync instructions; your agent executes them using your existing tooling. `/pm:tracker` makes PM aware of an external issue tracker. Once configured, PM shapes the sync instructions in your `CLAUDE.md` rules block — telling your Claude Code agent which epics need issues created and when to transition them. The engine itself never calls the tracker; your agent does, using whatever tooling you have (an MCP server, the GitHub CLI, a REST client). ## Detection PM detects tracker signals before asking — but it is careful not to over-infer. **Hosting a repo on GitHub, GitLab, or Bitbucket is NOT a signal.** The mere presence of a remote does not mean your team manages work in that platform's issue tracker. PM treats the following as real signals that a tracker is in active use: * A connected issue-tracker MCP that is in use — `mcp__jira__*`, `mcp__linear__*`, a GitHub Issues/Projects tool, or similar. * Real issue-key conventions in commit or branch history — for example, `PROJ-123` or `#42`. * An explicit statement in `CLAUDE.md` or `README` that "we track work in \<X>". When a signal is found, PM offers the connection as a choice — it never assumes. Saying no changes nothing about local tracking; the conductor still records every epic, status, priority, and story in `.conductor/state.json` and `PROJECT.md`. ## Configuring a tracker Use the `set-tracker` subcommand to record or update tracker settings for the repo: ```bash theme={null} conductor.mjs set-tracker \ --system jira \ --instance your-company \ --project PROJ \ --mechanism mcp \ --intent active:in-progress \ --intent paused:todo \ --intent archived:done ``` | Flag | Description | | ------------- | -------------------------------------------------------------------------------------------------- | | `--system` | Any string identifying the tracker — `jira`, `linear`, `github-issues`, `gitlab`, etc. | | `--instance` | Your tracker's hostname or workspace slug (e.g., `your-company` for `your-company.atlassian.net`). | | `--project` | The project key your epics belong to, such as `PROJ` or `JOB`. | | `--mechanism` | How your agent calls the tracker — `mcp`, `cli`, `api`, or any other label. | | `--intent` | Repeatable. Maps a PM lifecycle status to a semantic tracker target (see below). | Re-running `set-tracker` merges — only the flags you pass change. The `CLAUDE.md` rules block is refreshed automatically. ## `statusIntent` mapping `--intent` maps PM's lifecycle statuses to **semantic goals**, not literal workflow-transition names. Your agent resolves the actual transition using its own tooling at sync time. For example, `active:in-progress` means "when an epic is active, move its linked issue toward an in-progress state" — PM does not care whether your Jira board calls that transition "Start Progress" or "Begin". A fully configured tracker block in `state.json` looks like this: ```json theme={null} { "tracker": { "system": "jira", "instance": "your-company", "project": "PROJ", "mechanism": "mcp", "statusIntent": { "active": "in-progress", "paused": "todo", "archived": "done" } } } ``` ## Bidirectional mirroring (Jira, Linear, etc.) For any `--system` other than `github-issues`, the `CLAUDE.md` rules block instructs your agent to: 1. **Create an issue** for any epic that lacks an `externalId`, then record the returned key: ```bash theme={null} conductor.mjs update-epic <id> --external-id PROJ-123 --external-url https://... ``` 2. **Transition the issue** toward the `statusIntent` target each time the epic's status changes — resolving the real workflow transition with your own tooling. 3. **Link child epics** to a parent tracker epic when a hierarchy is involved. ## GitHub Issues (inward-only) `--system github-issues` is a special, inward-facing shape. Instead of mirroring local epics out to GitHub Issues, it pulls open GitHub Issues **in** as new untriaged epics during `/pm:sync` — the same pattern PM uses to auto-register OpenSpec changes found on disk. ```bash theme={null} conductor.mjs set-tracker --system github-issues --repo owner/name ``` During `/pm:sync`, your agent: 1. Lists open issues with `gh issue list --repo <repo> --state open --json number,title,url,labels`. 2. Checks whether an epic already has that issue number as its `externalId` — if so, skips it. 3. Registers each new issue as an epic: ```bash theme={null} conductor.mjs add-epic --status untriaged \ --external-id <issue-number> \ --external-url <issue-url> \ --lane claude-code \ --title "<issue-title>" \ --priority P2 ``` If the issue carries a `P0`/`P1`/`P2`/`P3` label, use that label's priority instead of the `P2` default. 4. `add-epic` itself rejects a duplicate `--external-id` (exits non-zero, writes nothing) as a second line of defense against a stale local view producing a duplicate. `github-issues` does **not** auto-create GitHub Issues for local epics. That direction is intentionally omitted to avoid silently creating public issues on your behalf. ## Primary + secondary trackers A repo has exactly one **primary** tracker — everything above — plus, optionally, one or more **secondary** trackers. Secondary trackers cover a different case: your real dev tracker is Jira, but you also want to watch a GitHub repo for inbound issues, for example from outside contributors, or from another internal repo publishing cross-project notifications (a service filing a GitHub issue in a downstream repo to flag a breaking change). A secondary tracker gets exactly two behaviors: 1. **Inward pull** — open issues become untriaged epics, the same shape as the `github-issues` inward sync above, but deduped by `externalUrl` (globally unique) rather than bare `externalId` (only unique within one tracker/repo — two secondary trackers can each have an issue numbered `#42` without colliding). 2. **Completion status writeback** — when an epic sourced from a secondary tracker reaches `archived`, your agent closes the linked issue there too. This is new: even the inward-only `github-issues` case above never did this before. A secondary tracker **never** gets outward-created issues. That direction stays exclusive to the primary tracker. ```bash theme={null} # Add a secondary tracker conductor.mjs set-tracker --role secondary --system github-issues --repo acme/market-intelligence # A repo can have more than one conductor.mjs set-tracker --role secondary --system github-issues --repo acme/risk-engine # Remove one that's gone stale conductor.mjs set-tracker --role secondary --system github-issues --repo acme/decommissioned-repo --remove ``` Identify a secondary entry the same way you'd identify the primary tracker — `--system` plus `--repo` or `--project`. Re-running `set-tracker --role secondary` with a matching `system` + `repo`/`project` merges into the existing entry instead of adding a duplicate. `--remove` against a key with no match exits non-zero and changes nothing. Once configured, the `CLAUDE.md` rules block gains one "Secondary tracker sync" section per entry, in addition to — never instead of — the primary tracker's own section. ## Resyncing after completion Whenever an inward-pull-capable tracker is configured — a `github-issues` primary, or any secondary tracker — the rules block also gains a "Sync after completing tracker-linked work" section: after your agent closes or transitions a tracker-linked issue as part of completing an epic, it re-syncs with your tracker(s) (`/pm:sync`) right away, since it's already doing tracker I/O for that epic. The instruction is phrased tracker-count-agnostic — "re-sync with your tracker(s)" — so it reads correctly whether a repo has one tracker configured or several. The session briefing mirrors this with a one-line, non-blocking nudge whenever any tracker is configured ("N tracker(s) configured — consider `/pm:sync` this session"). This is only ever a reminder; PM never runs a sync itself, and there's no `lastSyncedAt` tracking behind it — just a prompt for your agent to decide whether it's worth the round trip. ## TRACKER SYNC briefing line In the session briefing, the `TRACKER SYNC` line lists only epics with an active status that still lack an `externalId`. PM never fabricates transition state — it cannot see the tracker's current workflow position and will not guess at it. <Info> Tracker awareness is additive. The conductor always tracks everything locally. A tracker only adds an external mirror — saying no to a tracker prompt changes nothing about local tracking, issue counts, or epic statuses. </Info> # /pm:upgrade — Migrate State and Refresh PM Rules Source: https://pm-plugin.dev/commands/upgrade Refresh the CLAUDE.md managed rules block, run any pending state migrations, re-render PROJECT.md, and stamp the new pmVersion. Safe to run more than once. `/pm:upgrade` brings your project up to date after installing a new version of PM. It refreshes the managed rules block in `CLAUDE.md`, runs any pending migrations on `.conductor/state.json`, re-renders `PROJECT.md`, and stamps the new `pmVersion` — all without touching your epic history or any non-PM content. Use it whenever the `SessionStart` briefing shows an upgrade nudge like `pm 0.4.0 → 0.4.1 available`. ## When to run it The `SessionStart` briefing tells you when an upgrade is needed. The sequence is always: 1. Install the new PM version via the Claude Code plugin marketplace. 2. Run `/reload-plugins` (or restart Claude Code) to load the new plugin code into the running session. 3. Run `/pm:upgrade` to migrate your project's state and refresh the rules block. If you skip step 2, Claude Code is still executing the old plugin code and the upgrade will not apply the correct migrations. The briefing message `"this is pm 0.4.0 but 0.4.1 is installed"` is the reload reminder — it means the reload has not happened yet. ## What it does <Steps> <Step title="Refreshes the CLAUDE.md rules block"> The managed PM section in `CLAUDE.md` is replaced with the version shipped by the new plugin. Any content outside the managed delimiters — your own notes, other tool rules, project context — is left completely untouched. </Step> <Step title="Runs pending state migrations"> The engine applies any schema migrations needed to bring `state.json` up to the new version's format. Migrations are idempotent: if your state is already at the target schema, the migration step is skipped with no changes written. </Step> <Step title="Re-renders PROJECT.md"> `PROJECT.md` is regenerated from the now-migrated `state.json`, picking up any new fields or formatting changes introduced in the new version. </Step> <Step title="Stamps pmVersion"> The `pmVersion` field in `state.json` is updated to the newly installed version, so future `SessionStart` checks know the upgrade has been applied and stop showing the nudge. </Step> </Steps> ## Idempotency Running `/pm:upgrade` more than once is always safe. If your project is already at the latest version, every step is a no-op — nothing is written, nothing is changed, and the command exits cleanly. <Warning> Always run `/reload-plugins` **before** `/pm:upgrade` when you've just installed a new version. If you skip the reload, Claude Code is still running the old plugin code, and the upgrade command will apply the old engine's logic rather than the new one. Reload first, then upgrade. </Warning> ## Recommending adoption of new capabilities After printing the changelog delta, PM doesn't just leave you to read it — the agent reviews each `Added` headline in the "What's new in pm" output and judges whether it describes an **opt-in capability** (a new flag, a new `set-*` subcommand, a new tracker/autonomy/review-mode behavior) rather than a bug fix or a change that applies automatically with no action needed. For anything opt-in that looks relevant to your project's current `.conductor/state.json` — say, you already have a primary tracker configured but haven't added a secondary one, or you're touching schema-sensitive files without `thorough` review mode turned on — the agent recommends it in one line: what it is, why it fits, and the exact command to enable it. It never enables anything on its own; adoption is always your call. If nothing in the delta is opt-in or relevant to your project, the agent says so rather than silently skipping the review. ## /pm:changelog — Review what changed between versions `/pm:changelog` surfaces the PM plugin's own changelog entries that are newer than a given version, so you know exactly what a release brought rather than just that an upgrade happened. By default, the floor is the version stamped in your project's `.conductor/state.json` (`pmVersion`) — so running it after an upgrade shows you everything that version introduced. `/pm:upgrade` automatically prints this changelog delta for the versions it crosses, so you see what changed as part of every upgrade. Use `/pm:changelog` directly to review the delta again or to inspect a different version range on demand. ```text theme={null} /pm:changelog # entries newer than this repo's stamped pmVersion /pm:changelog --since 0.3.0 # everything released after 0.3.0 ``` # The Detour Stack: Resumable Interruptions Source: https://pm-plugin.dev/concepts/detour-stack The PM detour stack is an explicit PUSH/POP mechanism that parks current work when an interruption hits, preserving full context for a clean resume later. When something breaks mid-build, most tools lose the thread. PM's detour stack treats every interruption as a structured stack frame: the current epic is paused and pushed onto the stack, the interrupt becomes its own epic in the right lane, and resume is a deliberate POP with a mandatory reconcile gate. Nothing is left to memory — the reason, the cross-links, and the obligation to reconcile are all written durably into `.conductor/state.json` before a single line of detour code is written. ## Minimal vs. substantial detours The first step of `/pm:detour` is always classification. Do not start fixing before deciding which kind the interruption is. <CardGroup> <Card title="Minimal detour" icon="wrench"> Small, self-contained, no design ambiguity. Fits before the next context compaction and doesn't reshape the current proposal. **Path:** Fix → test → commit → `log-detour "<what you fixed>"` → resume. No stack entry. No proposal. The log call appends a timestamped line + commit SHA to `.conductor/detours.log`. </Card> <Card title="Substantial detour" icon="layer-group"> Needs its own design, changes shared behavior, or is multi-step. **Path:** Becomes its own epic in the appropriate lane. Run PUSH. When unsure, treat as substantial — a needless stack entry is cheap; a lost thread is the whole problem PM is solving. </Card> </CardGroup> ## What a stack frame contains A detour stack frame records everything needed to restore context after the detour is resolved: ```json theme={null} { "pausedEpic": "my-feature-epic", "pausedAt": "2026-07-15T14:32:00.000Z", "reason": "Auth middleware rejects all requests — must fix before feature can be tested", "spawnedDetour": "fix-auth-middleware", "reconcileOnResume": true } ``` | Field | Description | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `pausedEpic` | The epic id that was active when the interruption hit. | | `pausedAt` | ISO timestamp of when the PUSH occurred. | | `reason` | A concrete human-readable explanation of why work was parked. | | `spawnedDetour` | The id of the new epic created to resolve the interruption. | | `reconcileOnResume` | When `true`, the reconcile gate fires automatically on POP. Default `true` whenever the detour touches code or behavior the paused epic depends on. | The stack is LIFO — the most recent push is always what `/pm:resume` pops. Multiple nested detours are supported; each POP restores exactly one level. ## PUSH: entering a substantial detour When `/pm:detour` classifies an interruption as substantial, the following steps run in order: <Steps> <Step title="Commit all uncommitted work"> Make the current epic's progress source (e.g. `tasks.md`) reflect reality, then commit so nothing is left staged or dirty. The paused epic's state must be clean before it's parked. </Step> <Step title="Pause the current epic"> Set the current epic's `status` to `paused` in `.conductor/state.json`. </Step> <Step title="Push a frame onto detourStack"> Write the stack frame with `pausedEpic`, `pausedAt`, `reason`, `spawnedDetour`, and `reconcileOnResume: true` (default) onto `.conductor/state.json`'s `detourStack[]`. </Step> <Step title="Create the detour epic"> Register the detour as a new epic with `role: "detour"`, the appropriate lane, and usually priority `P0`. Add the cross-links: detour `resolves-blocker-for` parent; parent `may-invalidate` detour. </Step> <Step title="Set the detour as active"> Call `set-active <detour-id>`. Build the detour through its lane's normal workflow and archive it when complete. </Step> <Step title="Write a Honcho memory"> Get the ready-to-copy memory line and log it durably: ```bash theme={null} node "$ENGINE" honcho-memory push <parent-epic-id> "<reason>" ``` This prints `paused <parent> for <reason>` and appends a timestamped copy to `.conductor/honcho-memories.log`. Paste the printed line into your Honcho MCP memory tool call — the engine only formats and logs the string, it never calls Honcho itself. </Step> </Steps> ## POP: leaving a detour When the detour epic is archived and `/pm:resume` runs: <Steps> <Step title="Verify the detour is archived"> Confirm the detour epic's status is `archived` and its work is committed or deployed. If not, it's not time to resume — finish the detour first. </Step> <Step title="Pop the top frame"> Remove the top frame from `detourStack[]` in `.conductor/state.json`. If `reconcileOnResume` was `true`, set `reconcileNeeded: true` on the paused epic before popping — this is the only place that obligation survives once the frame is gone. </Step> <Step title="Restore the paused epic to active"> Set the paused epic's `status` back to `active` and call `set-active <paused-id>`. </Step> <Step title="Run the reconcile gate"> If `reconcileOnResume` was `true`, the reconcile gate fires now. A fresh-context review re-reads the paused proposal and diffs what the detour actually shipped. Do not write code until the gate clears. See [The Reconcile Gate](/concepts/reconcile-gate) for the full flow. </Step> </Steps> <Warning> Never start writing code after popping a detour until the reconcile gate has run. The `PreToolUse` gate-guard hook mechanically blocks `Edit`, `Write`, and `NotebookEdit` while `reconcileNeeded: true` is set on the active epic. This is unconditional and cannot be bypassed with `set-gate-guard off`. The only path past it is running the reconcile gate and recording the verdict via `record-reconcile`. </Warning> ## Honcho integration Both `/pm:detour` (PUSH) and `/pm:resume` (POP) emit a ready-to-copy Honcho memory line via the `honcho-memory` subcommand: ```bash theme={null} # On PUSH node "$ENGINE" honcho-memory push <parent-epic-id> "<reason>" # → prints: paused <parent> for <reason> # On POP node "$ENGINE" honcho-memory pop <parent-epic-id> "<detour-id>; reconcile = valid | amended: …" # → prints: resumed <parent>, reconciled vs <detour-id>; reconcile = valid | amended: … ``` Both calls also append a timestamped copy of the emitted string to `.conductor/honcho-memories.log`. This local log exists precisely because the line needs to be pasted into an actual Honcho MCP tool call — if you forget to paste it, the log is your fallback. The engine only formats and logs; it never calls Honcho itself. This keeps PM squarely on the instruction layer and never the integration layer. Honcho is valuable here because it lets the detour relationship survive outside this repo — across context compactions, across machines, and across sessions weeks later. The detour stack in `.conductor/state.json` is the live working set for one project; Honcho is where the relationship goes when it needs to outlive the project's own context window. # Epics and Lanes: How PM Organizes Work Source: https://pm-plugin.dev/concepts/epics-and-lanes Epics are PM's unit of work. Every epic is tagged with a lane that determines its workflow: openspec, superpowers, claude-code, decision, or external. In PM, an epic is any discrete chunk of work — a feature, a bug fix, a spike, a decision. Every epic lives in exactly one lane, which tells PM (and you) what workflow it follows and where its stories live. The lane also determines what mechanical gates apply: which review steps are required, how stories are tracked, and whether the reconcile gate needs to run before resuming. ## The five lanes <CardGroup> <Card title="openspec" icon="file-lines"> Spec-driven work following the proposal → design → tasks → Gate 1 → apply → Gate 2 → archive workflow. Stories live in `openspec/changes/<id>/tasks.md` checkboxes. Two gate reviews are mechanically required before archiving. </Card> <Card title="superpowers" icon="bolt"> Execution-focused work driven by a Superpowers plan (brainstorming, TDD, subagent-driven development). Stories live in the plan file referenced by the epic's `planPath` field — PM tracks when and in what order; Superpowers drives how well. </Card> <Card title="claude-code" icon="code"> Freeform Claude Code work with no external spec tool required. Stories live inline in `.conductor/state.json` under the epic's `stories[]` array. Each story has a `title` and a `done` boolean. </Card> <Card title="decision" icon="scale-balanced"> Architectural or process decisions. No stories, no task list — just a durable record that the decision was made, what was decided, and when. The epic is the artifact. </Card> <Card title="external" icon="arrow-up-right-from-square"> Work tracked in an external system (Jira ticket, GitHub issue, Linear card). PM records the `externalId` and `externalUrl`; the external system owns the stories. PM mirrors status transitions via its tracker integration. </Card> </CardGroup> <Info> Stories (checkboxes, phases, plan steps) always live in the best available external source — PM never copies them into `state.json` except for `claude-code`-lane epics using inline `stories[]`. Keeping the source of truth in OpenSpec or Superpowers is intentional: it prevents duplication and keeps PM's state file lean. </Info> ## Epic lifecycle Every epic moves through a defined set of statuses. The normal progression is linear, but epics can be paused and unpaused by the detour stack. | Status | Meaning | | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `untriaged` | Just registered — no priority or lane decision made yet. Appears in the backlog but not in NEXT UP. | | `planned` | On the roadmap but not yet ready to queue. Excluded from NEXT UP and per-lane counts. Transitions to `untriaged` automatically when an OpenSpec change is created and `/pm:sync` runs. | | `queued` | Prioritized and ready to work. Eligible for `/pm:next` selection. | | `active` | Currently being worked. Only one epic is active at a time (set via `set-active`). | | `paused` | Pushed onto the detour stack. Will be restored to `active` when `/pm:resume` pops it. | | `later` | Deferred — not yet planned or queued. Lower-commitment than `planned`; use for items you want to track without committing to a roadmap slot. | | `blocked` | Cannot proceed because an external condition or dependency is unresolved. Distinct from `paused` — no detour stack frame is involved. | | `archived` | Done. For `openspec`-lane epics, Gate 2 must be recorded before this transition is allowed. | ## Priority PM uses four priority levels plus an unset sentinel: | Priority | Meaning | | -------- | ----------------------------------------------------------------------------------------------- | | `P0` | Critical or blocking. Detours are almost always P0. `/pm:next` will always surface these first. | | `P1` | High priority — important work that should happen soon. | | `P2` | Normal priority — the default for most backlog items. | | `P3` | Low priority — nice to have, not blocking anything. | | `P?` | Not yet triaged. Set automatically on `untriaged` epics before they've been prioritized. | ## Epic links Epics can be related to each other via typed links. Links are directional and recorded on both ends. | Link type | Meaning | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `depends-on` | This epic relies on the linked epic's output. `/pm:next` skips any epic whose `depends-on` target is still unresolved and names the blocking epic explicitly. | | `resolves-blocker-for` | This epic (typically a detour) exists to unblock the linked epic. Set on the detour. | | `may-invalidate` | The linked epic's design **may have been invalidated** by this epic's changes. Set on the parent when a detour is pushed. This is the reconcile relationship — it connects a detour to the epic it might have made stale. | | `relates-to` | A general association between two epics — no ordering or dependency semantics. | The `may-invalidate` link is the most important in the system. When the detour is archived and `/pm:resume` runs, the reconcile gate re-validates the paused proposal against what the detour actually shipped. The verdict is written back durably onto this link as `{verdict, amendments, reconciledAt}`. ## Hierarchy Epics can be nested under a single parent, forming a tree. Use `--parent <id>` on `/pm:epic add` (or `add-many --from <json>` for bulk creation) to nest an epic. When a parent epic has children: * `PROJECT.md` indents children under their parent and shows a rolled-up **`X/Y children archived`** count in the briefing. * NEXT UP preserves global priority order — grouping is render-only. * A parent epic with all children `autonomous` can be dispatched as an **unattended multi-agent batch** via `plan-hierarchy --parent <id>`, where each child runs in its own git worktree and converges back sequentially. Hierarchy validation is enforced by the engine: a parent must exist, self-loops are rejected, and cycles are rejected. `remove-epic` is blocked by default if an epic still has children — pass `--cascade` to remove the parent and all descendants together. # The Reconcile Gate: Safe Resumption After Detours Source: https://pm-plugin.dev/concepts/reconcile-gate The reconcile gate runs a fresh-context re-validation of your paused epic against what the detour actually shipped, before any new code is written. The reconcile gate is the safety mechanism that fires every time you pop a detour. A fresh-context review re-reads the paused epic's proposal and diffs what the detour actually changed, then delivers a verdict — `valid` or `invalidated` — before a single new line of code gets written. This is PM's answer to a real problem: the thing that got interrupted doesn't get to just "remember" what was planned. It gets re-validated, the same discipline as saving and restoring context around a hardware interrupt. ## Why it exists A detour might ship changes that invalidate the design or task list of the paused epic. A bug fix might refactor the very interface your feature was building against. A shared-behavior change might make three of your queued tasks redundant — or contradictory. Resuming blindly means building on a stale plan. If the detour was substantial enough to push onto the stack (rather than handled as a minimal detour), it was substantial enough to potentially change what the paused epic needs to do. The gate catches this mechanically rather than relying on an agent to remember to check, or on a human to notice the drift before it compounds into a harder conflict later. ## How it works <Steps> <Step title="Resume triggers the gate"> `/pm:resume` pops the top detour stack frame and checks whether `reconcileOnResume` was `true`. If yes, `reconcileNeeded: true` is set on the paused epic and the gate fires before any code can be written. </Step> <Step title="A fresh-context review is dispatched"> A clean-context review is delegated via the Task tool with the paused epic id and the detour epic id. It runs with no prior conversation history — this is intentional, preventing any in-session assumptions from contaminating the review. </Step> <Step title="The review reads and diffs"> The review reads the paused epic's proposal (and `tasks.md` for `openspec`-lane epics), then diffs what the detour actually shipped. It returns a structured response: * `VERDICT: valid` or `VERDICT: invalidated` * `AMENDMENTS:` — one amendment per line (stories to add, remove, or change). Empty if valid. </Step> <Step title="The verdict is written back durably"> The verdict is recorded via: ```bash theme={null} node "$ENGINE" record-reconcile <paused-id> \ --detour <detour-id> \ --verdict <valid|invalidated> \ --amendments "<amendment-a>;<amendment-b>;..." ``` This attaches `{verdict, amendments, reconciledAt}` to the paused epic's `may-invalidate` link to the detour in `.conductor/state.json` (creating the link if it doesn't already exist), and clears `reconcileNeeded` in one step. The judgment survives past this conversation instead of only ever living in the transcript. </Step> </Steps> ## Verdicts and outcomes <CardGroup> <Card title="valid" icon="circle-check"> The detour's changes don't affect the paused epic's design or task list. The review says so explicitly. State is updated and you can resume building. No amendments needed. </Card> <Card title="invalidated" icon="triangle-exclamation"> The detour shipped changes that conflict with or supersede part of the paused proposal. You must update the OpenSpec proposal and `tasks.md` (or the `stories[]` for a `claude-code`-lane epic) to reflect the amendments before writing new code. </Card> </CardGroup> Either way, the `record-reconcile` call is required — even for a `valid` verdict. It's what actually clears `reconcileNeeded` and lifts the gate-guard block. Do not hand-clear `reconcileNeeded` directly in `state.json`. ## The gate guard The gate guard is a `PreToolUse` hook that mechanically blocks `Edit`, `Write`, and `NotebookEdit` while the active epic has `reconcileNeeded: true`. It is: * **On by default** — no configuration required. * **Unconditional** — it fires regardless of the repo's `gateGuard` setting. `set-gate-guard off` no longer bypasses this specific check; that flag is reserved for any future generalization of the hook mechanism. * **The only path past it** — run the reconcile gate and call `record-reconcile`. There is no override flag. This means the gate guard is a genuine enforcement mechanism, not a reminder. An agent mid-task cannot accidentally start writing code on a stale plan because a hook blocks the write at the tool level before any edit reaches the filesystem. <Note> The reconcile gate applies to all lanes whenever a detour is popped with `reconcileOnResume: true`. The OpenSpec two-gate review (Gate 1 / Gate 2) described below is a separate, additional mechanism specific to `openspec`-lane epics only. </Note> ## OpenSpec two-gate review For `openspec`-lane epics, PM enforces two separate gate reviews across the epic's lifecycle — independent of the detour reconcile gate: | Gate | When | Purpose | | ---------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------- | | **Gate 1** | Before code is written, after the spec is drafted | Fresh-context spec review. Catches design problems before any implementation investment. | | **Gate 2** | After implementation, before docs/archive | Fresh-context implementation review. Required to archive. | Both gates are recorded with: ```bash theme={null} node "$ENGINE" record-gate-review <epicId> --gate 1|2 --verdict pass|fail [--reviewer "<note>"] ``` This writes `{verdict, reviewedAt, note?}` onto `epic.gateReview.gate1` or `epic.gateReview.gate2` in `state.json`. Gate 2 is mechanically enforced: `update-epic <id> --status archived` **rejects** the transition for any `openspec`-lane epic that doesn't already have a `gateReview.gate2.verdict === "pass"` recorded. Gate 1 is not itself required at archive time (it gates code, which already happened earlier), though recording it is good practice. Non-`openspec`-lane epics (`superpowers`, `claude-code`, `decision`, `external`) are completely unaffected by the two-gate check. It never runs for them. An autonomous epic still requires `record-gate-review` to be called after each real gate review — narration alone in the conversation transcript does not satisfy the archive-time check, and there is no bypass flag. # State Files: How PM Persists Project Context Source: https://pm-plugin.dev/concepts/state-and-project PM persists all state in .conductor/state.json and renders PROJECT.md from it. Learn what each file contains and the rules around editing them. PM's source of truth lives in `.conductor/state.json`. Every epic, every detour stack frame, every link, every tracker configuration — it's all in that one JSON file. `PROJECT.md` is a generated view rendered from it and should never be hand-edited. Understanding what each file is for — and what the rules around touching them are — prevents the class of state corruption that's hardest to debug: a file that looks valid but disagrees with the real state. ## The .conductor/ directory Three files live here. Each has a distinct purpose and a distinct write policy. ```text theme={null} .conductor/ ├── state.json # state of record — never hand-edit ├── detours.log # append-only trail of all detour events └── honcho-memories.log # ready-to-copy Honcho memory lines ``` The directory is created by `/pm:init` and managed entirely by the PM engine after that. Only `state.json` is the authoritative source; the other two are logs and should never be edited directly. ## state.json structure The top-level fields of `.conductor/state.json` and what they mean: | Field | Type | Description | | --------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `active` | `string \| null` | The currently active epic id. Set by `set-active`; cleared by `clear-active`. Never hand-edit this pointer — `set-active` also keeps `status: "active"` in sync and demotes any prior active epic. | | `epics[]` | `array` | The full list of epics. Each entry has `id`, `title`, `lane`, `priority`, `status`, `role`, `parent?`, `links[]`, `reconcileNeeded?`, `autonomy?`, `gateReview?`, `externalId?`, `externalUrl?`, `planPath?`, and `stories[]?`. | | `detourStack[]` | `array` | Stack frames, LIFO order. Each frame has `pausedEpic`, `pausedAt`, `reason`, `spawnedDetour`, and `reconcileOnResume`. | | `tracker` | `object?` | Optional external tracker config (`system`, `instance`, `projectKey`, `mechanism`, `repo`, `statusIntent`). Set via `/pm:tracker`. | | `gateGuard` | `boolean?` | Repo-level PreToolUse guard toggle. Reserved for future hook generalizations — this flag no longer controls the reconcile-owed check, which blocks unconditionally whenever `reconcileNeeded: true` regardless of this setting. | | `reviewMode` | `"off" \| "standard" \| "thorough"` | Repo-level review intensity dial. Defaults to `standard`. A single epic can escalate above this with `update-epic <id> --review-mode`, but never de-escalate below it. | | `laneRouting` | `object?` | Per-repo lane-routing overrides: `{ overrides: [{ match, lane }] }`. Checked before the generic lane heuristic. Set via `set-lane-routing`; looked up via `suggest-lane`. | | `pmVersion` | `string` | The plugin version that last wrote this file. Set by `/pm:init` and `/pm:upgrade`. Used by `/pm:changelog` to compute the delta. | A minimal real example of a `claude-code`-lane epic with inline stories: ```json theme={null} { "id": "remove-epic-verb", "title": "Add a remove-epic CLI verb", "priority": "P2", "status": "archived", "role": "epic", "lane": "claude-code", "parent": "pm-plugin-improvements-2026-07-14", "links": [], "reconcileNeeded": false, "stories": [ { "title": "TDD: remove-epic hard-delete, --cascade, link-stripping, active-clear tests", "done": true }, { "title": "Implement removeEpic() + dispatch registration", "done": true }, { "title": "commands/epic.md + README.md docs", "done": true }, { "title": "Fresh-context code review (standard review mode)", "done": false } ] } ``` ## PROJECT.md `PROJECT.md` is a generated Markdown view that renders the full conductor briefing. It is re-rendered by `conductor.mjs render` after every state change. Never edit it by hand — `state.json` always wins, and the next render will overwrite any manual changes. The briefing shows: * **Active epic** — title, lane icon, priority, and current status. * **Detour stack** — each frame with its paused epic, reason, and spawned detour. * **NEXT UP queue** — highest-priority `queued` epics, P0→P3, skipping any epic starved on an unresolved `depends-on` link (with the blocker named explicitly). * **Per-lane counts** — how many epics are in each lane, by status. * **Tracker sync line** — any active-work epics missing `externalId` when a tracker is configured. Only honestly-computable drift is shown; PM never fabricates transition state it can't see. * **Hierarchy rollup** — for parent epics, an `X/Y children archived` progress indicator. The `SessionStart` hook re-injects the briefing via `additionalContext` every time a session opens or resumes after a compaction — this is how PM survives context loss without requiring you to re-read docs. ## detours.log `.conductor/detours.log` is an append-only trail of all detour events. One entry per line: ```text theme={null} 2026-07-15T14:32:00Z · a3f9c12 · minimal · fix-null-check · "fixed null guard in auth middleware" 2026-07-15T16:10:00Z · — · substantial-push · my-feature-epic → fix-auth-middleware · "auth rejects all requests" 2026-07-15T17:45:00Z · b7e2d44 · substantial-pop · fix-auth-middleware → my-feature-epic · "reconcile: valid" ``` Every minimal detour is logged here by the `log-detour` subcommand. Substantial pushes and pops are logged automatically. The `PostToolUse` hook also auto-detects unlogged minimal detours from commit shape (file count, commit prefix, whether an active detour is already open) and logs them without requiring a manual `/pm:detour --minimal` invocation. This log is never modified by hand. If you need to audit what happened during a session or trace when a particular change was introduced as a side-effect of a detour, this is the file to read. ## CLAUDE.md rules block PM writes and maintains a managed rules block in the project's `CLAUDE.md`. This is how the conductor discipline — the detour protocols, the reconcile gate, the tracker sync instructions, the lane workflow rules — becomes part of every Claude Code session automatically, without you re-reading documentation. The rules block is: * **Written by `/pm:init`** when a project is first set up. * **Re-injected by the `SessionStart` hook** via `additionalContext` on every session open, resume, and compaction recovery, so the rules survive context loss. * **Refreshable via `/pm:upgrade`** after a plugin update — run it to pull in any new rules or behavioral changes from the latest version. * **Idempotent** — deleting the block from `CLAUDE.md` and re-running `/pm:init` or `/pm:upgrade` restores it safely. To permanently opt out, delete the block and do not run upgrade. <Warning> Never hand-edit `state.json` directly. Use PM commands. Bypassing the engine means render timestamps, active-epic invariants, and cross-link consistency can silently diverge. If you must recover from a bad state, use `git checkout .conductor/state.json` to restore the last known-good version — PM's state changes are committed regularly, so git history is always the recovery path. </Warning> <Tip> `conductor.mjs verify-state` fails loudly if `state.json` has been modified more recently than the last render stamp — a mechanical check for accidental hand-edits. Run it any time you suspect the file has drifted, or wire it into your own pre-commit checks. A clean output means the state PM is working from matches what was last rendered. </Tip> # PM's Perfect Quartet: OpenSpec, Superpowers, and Honcho Source: https://pm-plugin.dev/guides/companion-plugins PM works standalone but was designed to pair with OpenSpec, Superpowers, and Honcho. Each companion adds a layer PM deliberately does not own. PM works completely on its own — install it and `/pm:init` gives you cross-epic priority ordering, an explicit detour stack, and the reconcile gate immediately, with no other plugin required. That said, PM was designed to sit above three companion plugins, and each one adds something PM deliberately leaves alone. The quartet covers every layer from raw memory through execution discipline without any two plugins owning the same thing. ## The Perfect Quartet <CardGroup> <Card title="PM (this plugin)" icon="list-check"> Cross-epic priority ordering, the explicit detour stack, the reconcile gate on resume, and the multi-agent dispatch harness for parent-child epic hierarchies. </Card> <Card title="OpenSpec" icon="file-lines"> Spec-driven proposal workflow — `proposal.md`, `design.md`, and `tasks.md` — with two mandatory gate reviews before a change can be archived. PM tracks the epic; OpenSpec owns what gets built and the durable spec record. </Card> <Card title="Superpowers" icon="bolt"> Execution discipline: TDD, brainstorming, subagent-driven development, and code review. PM tracks when and in what order epics run; Superpowers drives how well each one gets built. </Card> <Card title="Honcho" icon="brain"> Durable memory that survives outside any single repo or context window. PM's detour stack is the live working set for one project; Honcho is where that state goes so it outlives a compaction, a new machine, or a week away. </Card> </CardGroup> ## OpenSpec When an epic is in the `openspec` lane, PM tracks its priority and status while OpenSpec owns the full proposal lifecycle. That means a `proposal.md` is written and reviewed (Gate 1) before any code is written, and an implementation review (Gate 2) is completed before the epic can be archived. Gate 2 is enforced mechanically — `update-epic --status archived` on an `openspec`-lane epic is rejected by the engine unless a passing `gateReview.gate2.verdict === "pass"` has already been recorded via `record-gate-review`. This is not narration; it is a hard check that runs at archive time. Install OpenSpec: ```bash theme={null} npm install -g @fission-ai/openspec cd your-project openspec init ``` ## Superpowers When an epic is in the `superpowers` lane, PM tracks when it runs and in what order relative to the rest of the backlog. Superpowers drives everything about how well it gets built: brainstorming sessions, test-driven implementation, subagent-driven parallelism, and structured code review. The two plugins complement rather than overlap. PM answers "what is next and in what order." Superpowers answers "how do we build this well." Install Superpowers from the official Anthropic marketplace: ```bash theme={null} /plugin marketplace add anthropics/claude-plugins-official /plugin install superpowers@claude-plugins-official ``` ## Honcho PM's detour stack and reconcile gate are scoped to one project's live working set. Honcho extends that memory beyond the project: across repos, across sessions, and across machines. The practical use case: when you push a substantial detour onto the stack, PM can format a ready-to-paste Honcho memory line describing the pivot. When you resume and complete the reconcile gate, PM formats a corresponding pop memory line. Paste those lines into your Honcho MCP memory tool and the relationship between the interrupted work and the detour survives a context compaction, a `git clone` on a new machine, or coming back to the project a week later. This matters most once you are juggling more than one PM-managed repo. A single project's detour history lives fine in `.conductor/state.json`. Cross-project context, or context that needs to outlive the repo entirely, is what Honcho is for. For setup, start at [docs.honcho.dev](https://docs.honcho.dev) or the source at [github.com/plastic-labs/honcho](https://github.com/plastic-labs/honcho). Both a hosted option and self-hosted deployment are available. ## How they layer The four tools form a clean stack with no overlapping ownership: ``` Honcho ← durable memory across repos and sessions PM ← cross-epic ordering, detour stack, reconcile gate OpenSpec ← spec-driven proposal workflow (openspec lane) Superpowers ← execution discipline (superpowers lane) ``` Each layer depends only on the layers below it. PM doesn't know or care how OpenSpec enforces its gate discipline or how Superpowers structures a TDD session — it only tracks that an epic in that lane is `active`, `paused`, or `archived`. OpenSpec and Superpowers don't know or care about PM's queue ordering — they execute the work they were given. This separation is what makes the quartet composable. You can add or remove any companion without changing how the others behave. <Tip> PM's Honcho integration is opt-in and available through the `honcho-memory` subcommand, which formats a ready-to-paste memory line and appends a timestamped copy to `.conductor/honcho-memories.log`. The engine never calls Honcho directly — you paste the formatted line into your Honcho MCP memory tool. Run `node "$ENGINE" honcho-memory push <epic-id> "<reason>"` before a detour and `honcho-memory pop <epic-id> "<detour-id>; reconcile = valid"` after resuming. </Tip> <Note> None of the companions are required. PM works entirely on its own in `claude-code` and `decision` lanes — straight builds with no design gate and product decisions with no execution component. Install the companions when you need what they add, not before. </Note> # The Daily PM Workflow in Claude Code: Start to Commit Source: https://pm-plugin.dev/guides/daily-workflow A practical guide to using PM day-to-day: starting sessions, checking status, picking work, and keeping your epic queue healthy across context compactions. PM integrates into Claude Code at the session level — a `SessionStart` hook automatically injects the project briefing every time you start or resume, even after a context compaction. This guide covers the commands you'll use every day once your project is initialized with `/pm:init`. ## Starting a session The moment Claude Code opens, PM is already working. The `SessionStart` hook fires on `startup`, `resume`, and `compact` events and runs `conductor.mjs brief` automatically. Without typing a single command, you immediately see: * The **active epic** — its lane, priority, and current story progress * The **detour stack** — any paused work, with `⚠ reconcile-on-resume` flags where applicable * The **next-up queue** — your highest-priority `queued` epics ordered P0 → P3 If no project has been initialized with `/pm:init`, the hook is a complete no-op — it exits silently and does not affect the session in any way. ## The daily loop A typical working day with PM follows a clear rhythm: <Steps> <Step title="Open Claude Code"> The `SessionStart` briefing fires automatically. You see the active epic, any paused work, and your queue — no command needed. </Step> <Step title="Confirm with /pm:status"> Run `/pm:status` for a fresh-rendered view. This re-renders `PROJECT.md` from `.conductor/state.json` first, so the output always reflects the current state of record. </Step> <Step title="Get a work recommendation"> Run `/pm:next` to receive a concrete recommendation for what to build right now. PM applies the full priority algorithm and tells you exactly which epic to pick up and why. </Step> <Step title="Build the active epic in its lane"> Work through the epic using whatever workflow its lane requires — an OpenSpec proposal flow, a Superpowers plan, or a direct claude-code build. PM tracks status but stays out of your way while you build. </Step> <Step title="Commit and update status"> After each `git commit`, PM's `PostToolUse` hook nudges you to update the epic's status in `.conductor/state.json`. This keeps the index honest and re-renders `PROJECT.md` automatically. </Step> <Step title="Sync new work"> Run `/pm:sync` to register any new OpenSpec proposals or Superpowers plans that appeared on disk since your last session. If a `github-issues` tracker is configured, this also pulls open issues in as untriaged epics. </Step> </Steps> ## Checking status `/pm:status` re-renders the briefing on demand. What you see: * **Active epic** — the currently in-flight epic, its lane (e.g. `openspec`, `superpowers`, `claude-code`), and live story progress read directly from checkbox state in `tasks.md` or your plan file * **Detour stack** — every paused frame in order, with a `⚠ reconcile-on-resume` warning on any frame whose detour touched code the paused epic depends on * **Next-up queue** — the highest-priority `queued` epics sorted P0 → P3, with `depends-on` blockers named inline * **Per-lane counts** — how many epics are active, queued, or paused in each lane The underlying state of record is always `.conductor/state.json`. `PROJECT.md` is a generated view — re-render it any time by running `/pm:status` or the `render` subcommand directly. ## Deciding what's next `/pm:next` applies a strict priority algorithm so you never have to guess: 1. **If the detour stack is non-empty** — the top frame is the answer. Finish or resume that work before picking up anything new. 2. **Otherwise** — find the highest-priority `queued` epic, ordered P0 → P3. 3. **Ties** — if two epics share the same priority, PM surfaces both and asks you to decide rather than silently picking one. The `depends-on` link also shapes the queue: if an epic's declared dependency is not yet `archived`, that epic is skipped entirely and the blocker is named explicitly in the output. You always know *why* something was skipped, not just that it was. ## After a context compaction PM is designed around the assumption that context will compact. Two hooks collaborate to make the recovery seamless: * **`PreCompact`** fires right before the context window collapses. It runs `conductor.mjs snapshot`, which re-renders `PROJECT.md` and writes `.conductor/brief.txt` with the freshest possible state — so nothing is lost in the collapse. * **`SessionStart`** fires immediately after (on the `compact` event) and re-injects the full briefing via `additionalContext`. By the time you see the next response, PM has already re-oriented the session around the current queue. You do not need to do anything special after a compaction. PM handles the handoff. ## After every git commit The `PostToolUse` hook fires after every Bash tool use. PM runs `commit-nudge`, which inspects whether the invocation included a `git commit` and does two things: 1. Re-renders `PROJECT.md` so the index stays current. 2. Inspects the commit shape to detect whether it looks like an unlogged minimal detour — a small, self-contained fix that happened silently. If it does, PM suggests running `log-detour` to append a timestamped record to `.conductor/detours.log`. The nudge is non-blocking. It surfaces the suggestion and moves on — it does not pause execution or wait for a response. <Tip> Keep `PROJECT.md` open in a split pane. It updates after every `render` call so you can see the live queue, active epic, and detour stack at a glance without running a command. </Tip> # Connect PM to Jira, Linear, or GitHub Issues Trackers Source: https://pm-plugin.dev/guides/external-trackers Configure PM to mirror epics to an external issue tracker. PM shapes the instructions; your agent executes them with whatever tooling the project uses. PM can make your project aware that its epics mirror to an external issue tracker — Jira, Linear, GitHub Issues, or any other system. The engine never calls the tracker directly; it shapes instructions that your Claude Code agent executes using MCP servers, the GitHub CLI, or whatever tooling you have configured. Tracker awareness is optional and additive — PM already tracks everything locally in `.conductor/state.json` and `PROJECT.md` whether or not a tracker is configured. ## Instruction-layer philosophy PM is an instruction layer, not an integration layer. This is a deliberate architectural choice with a practical consequence: it works with any tracker regardless of how you connect to it. The engine never opens a network connection to an external system. It never calls a Jira API, fires a Linear mutation, or runs `gh issue create` itself. Instead, it writes rules into your `CLAUDE.md` and surfaces sync obligations in the session briefing. You — the interactive agent — act on those instructions using whatever tooling your project has: a Jira or Linear MCP server, the GitHub CLI, an Atlassian REST connector, a Python library. The tracker doesn't need special PM support. Any system works. ## Configuring a tracker <Steps> <Step title="Run /pm:tracker"> PM scans your project for tracker signals — connected MCP servers (`mcp__jira__*`, `mcp__linear__*`, GitHub issue tools), issue-key conventions in commit or branch history (e.g. `PROJ-123`, `#142`), or explicit statements in `CLAUDE.md` or `README` that "we track work in X". Hosting a repo on GitHub is NOT a signal by itself — PM only infers tracker intent from real evidence that work is actively managed there. </Step> <Step title="Confirm the system and project key"> PM presents what it detected and asks you to confirm or correct. You specify the `system` (e.g. `jira`, `linear`, `github-issues`), `projectKey` (e.g. `PROJ`), `instance`, and `mechanism` (e.g. `mcp` or `cli`). If you don't want to connect a tracker, declining changes nothing — PM continues tracking everything locally. </Step> <Step title="Map PM lifecycle statuses to semantic tracker targets"> Define `statusIntent` — a mapping from PM's lifecycle statuses to semantic descriptions of where a tracker issue should land. These are semantic targets, not literal workflow transition names. Your agent resolves the actual transition using its own knowledge of the tracker's workflow. </Step> <Step title="PM records the tracker block and updates CLAUDE.md"> PM calls `set-tracker` under the hood to write the tracker configuration into `.conductor/state.json` and refreshes the managed rules block in `CLAUDE.md` with an "External tracker sync" section. The `TRACKER SYNC` line appears in the session briefing from this point on. For reference, the underlying `set-tracker` command uses `--intent` flags (repeatable — one `<status>:<target>` per entry): ```bash theme={null} node "$ENGINE" set-tracker \ --system jira --instance your-company --project PROJ --mechanism mcp \ --intent untriaged:backlog --intent queued:todo --intent active:in-progress \ --intent paused:todo --intent planned:backlog --intent archived:done ``` Re-running `set-tracker` merges — only the flags you pass change. It also refreshes the CLAUDE.md rules block automatically. </Step> </Steps> ## Tracker configuration shape A fully configured tracker block in `.conductor/state.json` looks like this: ```jsonc theme={null} "tracker": { "system": "jira", "instance": "your-company", "projectKey": "PROJ", "mechanism": "mcp", "statusIntent": { "untriaged": "backlog", "queued": "todo", "active": "in-progress", "paused": "todo", "planned": "backlog", "archived": "done" } } ``` `statusIntent` maps PM's lifecycle to a *semantic* target — for example, `"active": "in-progress"` — never a literal tracker workflow transition name like `"Start Progress"`. Your agent resolves the real transition when it executes the sync instruction. ## Bidirectional mirroring (Jira, Linear, and others) For `jira`, `linear`, and any other non-`github-issues` system, the CLAUDE.md rules block tells your agent to: * **Create a tracker issue** for any epic that lacks an `externalId`, then record the returned key: `update-epic <id> --external-id <KEY> --external-url <url>` * **Transition the linked issue** toward the `statusIntent` semantic target on each status change * **Link parent and child tracker issues** for parent epics that have children The `TRACKER SYNC` line in the session briefing lists every active-work epic that still needs an issue created — it only reports honestly computable drift (epics missing `externalId`). It never fabricates transition state the engine cannot actually see. An epic that has been mirrored looks like this: ```json theme={null} { "id": "proj-504", "title": "[PROJ-504] Add OAuth flow", "status": "active", "lane": "external", "externalId": "PROJ-504", "externalUrl": "https://your-company.atlassian.net/browse/PROJ-504" } ``` ## GitHub Issues (inward-only sync) `github-issues` is deliberately asymmetric. It pulls open issues **in** as untriaged epics — it does **not** auto-file GitHub issues for local epics. The reasoning is intentional: silently creating a public GitHub issue for every unmirrored claude-code epic is a materially bigger and more consequential default than mirroring toward an internal Jira or Linear instance. The outward instruction is suppressed specifically for `github-issues`, while Jira and Linear keep full bidirectional behavior unchanged. Configure it with a `--repo`: ```bash theme={null} node "$ENGINE" set-tracker --system github-issues --repo owner/repo ``` Once set, the CLAUDE.md rules block gains a "GitHub issue sync" section. During `/pm:sync`, your agent runs: 1. `gh issue list --repo <repo> --state open --json number,title,url,labels` 2. For each issue, check whether an epic already has that issue number as its `externalId` — if so, skip it. Re-running sync must never create a duplicate epic for the same issue. 3. Register new issues: `add-epic --status untriaged --external-id <number> --external-url <url> --lane claude-code --priority P2` — unless the issue carries a `P0`/`P1`/`P2`/`P3` label, in which case use that priority instead. ## Primary + secondary trackers A repo has exactly one **primary** tracker — everything above — plus, optionally, one or more **secondary** trackers. Secondary trackers cover a different case: your real dev tracker is Jira, but you also want to watch a GitHub repo for inbound issues, for example from outside contributors, or from another internal repo publishing cross-project notifications (a service filing a GitHub issue in a downstream repo to flag a breaking change), without Jira losing its primary spot. A secondary tracker gets exactly two behaviors, both narrower than primary: 1. **Inward pull** — open issues become untriaged epics, the same shape as the `github-issues` inward sync above, but deduped by `externalUrl` (globally unique) rather than bare `externalId` (only unique within one tracker/repo — two secondary trackers can each have an issue numbered `#42` without colliding). 2. **Completion status writeback** — when an epic sourced from a secondary tracker reaches `archived`, your agent closes the linked issue there too. This capability is new: even the inward-only `github-issues` case above never wrote status back before this. A secondary tracker **never** gets outward-created issues — a new local epic, or any status change, never causes your agent to create or transition an issue there. That stays exclusive to the primary tracker. ```bash theme={null} # Add a secondary tracker (role defaults to primary, so this always needs --role secondary) node "$ENGINE" set-tracker --role secondary --system github-issues --repo acme/market-intelligence # A repo can have more than one node "$ENGINE" set-tracker --role secondary --system github-issues --repo acme/risk-engine # Remove one that's gone stale node "$ENGINE" set-tracker --role secondary --system github-issues --repo acme/decommissioned-repo --remove ``` Identify a secondary entry the same way you'd identify the primary tracker — `--system` plus `--repo` or `--project`. Re-running `set-tracker --role secondary` with a matching `system` + `repo`/`project` merges into the existing entry instead of adding a duplicate. `--remove` against a key with no match exits non-zero and leaves `secondaryTrackers` unchanged. Once configured, the `CLAUDE.md` rules block gains one "Secondary tracker sync" section per entry, in addition to — never instead of — the primary tracker's own "External tracker sync" or "GitHub Issues" section above. ## Resyncing after completion Whenever an inward-pull-capable tracker is configured — a `github-issues` primary, or any secondary tracker — the CLAUDE.md rules block also gains a "Sync after completing tracker-linked work" section. After your agent closes or transitions a tracker-linked issue as part of completing an epic, it re-syncs with your tracker(s) (`/pm:sync`) right away — it's already doing tracker I/O for that epic, so this is the cheapest moment to also pull in anything new that appeared while it was heads-down. The instruction is phrased tracker-count-agnostic — "re-sync with your tracker(s)" — so it reads correctly whether a repo has one tracker configured or several (e.g. Jira primary + GitHub Issues secondary). The session briefing mirrors this with a one-line, non-blocking nudge whenever any tracker is configured: "N tracker(s) configured (...) — consider `/pm:sync` this session to pull in any new issues." This is a reminder only — PM never runs a sync itself, and there's no `lastSyncedAt` timestamp behind it; the agent simply decides whether it's worth the round trip that session. ## What the TRACKER SYNC briefing line means The briefing's `TRACKER SYNC` section lists only epics where the engine can honestly compute drift — specifically, active-work epics that have no `externalId` recorded. It never guesses at transition state, and it never reports an issue as "needing a status update" based on anything the engine cannot directly see in `.conductor/state.json`. Status transition sync is your responsibility at the moment of each status change. The engine cannot observe the tracker's state from the outside. <Info> Hosting a repository on GitHub is NOT a tracker signal. PM only configures tracker awareness when there is real evidence you are actively managing work in an issue tracker — a connected MCP server, issue-key conventions in commit history, or an explicit statement in `CLAUDE.md` or `README`. If the evidence isn't there, PM will not suggest a tracker configuration. </Info> # Handle Mid-Build Interruptions Without Losing Your Place Source: https://pm-plugin.dev/guides/handling-detours Use PM's detour stack to park current work, build the interrupt, and resume cleanly — with a mandatory reconcile gate that re-validates your plan first. Mid-build interruptions are inevitable. PM turns them into a structured workflow: classify the interrupt, push current work onto the stack, build the detour in its own lane, then resume with a mandatory fresh-context review. The key insight is that the thing that got interrupted doesn't get to just "remember" — it gets re-validated before it resumes. ## Step 1: Classify before you act This is the most important step. Before touching a single file, run `/pm:detour "<what came up>"` and let PM classify the interruption. The classification determines everything that follows. **Minimal** — small, self-contained, no design ambiguity. The fix fits before the next compaction and doesn't reshape the current proposal. Fix it, test it, commit it, log it, and resume. No proposal needed. No stack entry. **Substantial** — needs its own design, changes shared behavior, or is multi-step. This becomes its own epic in the appropriate lane. PM runs the full PUSH flow. **When uncertain, treat as substantial.** A needless stack entry is cheap to clean up. A lost thread is exactly the problem PM exists to prevent. ## Minimal detour flow <Steps> <Step title="Fix the issue"> Make the targeted change. Keep the scope narrow — if it starts growing, stop and re-classify as substantial. </Step> <Step title="Test and commit"> Run your tests and commit the fix with a clear message. </Step> <Step title="Log the detour"> Record the fix in the append-only detour trail so it leaves a durable timestamp and commit SHA: ```bash theme={null} node "$ENGINE" log-detour "<what you fixed>" ``` This appends a line to `.conductor/detours.log`. No proposal, no state entry — just a trail. </Step> <Step title="Resume"> Continue where you left off on the original epic. No reconcile gate is required for a minimal detour. </Step> </Steps> ## Substantial detour flow <Steps> <Step title="Run /pm:detour"> Run `/pm:detour "<what came up>"`. PM pauses the active epic (setting its status to `paused`) and pushes a stack frame onto `.conductor/state.json`'s `detourStack`. </Step> <Step title="A new epic is created for the detour"> PM registers a new epic for the detour — `role: detour`, priority `P0` by default, in the appropriate lane for the scope of work. </Step> <Step title="Cross-links are recorded"> Two links are written automatically: the detour `resolves-blocker-for` the paused parent, and the parent `may-invalidate` the detour. These links are what the reconcile gate reads when you resume. </Step> <Step title="Build the detour"> Work through the detour epic using its lane's normal workflow — OpenSpec proposal flow, Superpowers plan, or a direct claude-code build. PM tracks it in the queue as active. </Step> <Step title="Archive the detour"> Once the detour work is done and committed, archive the detour epic through the standard path for its lane. </Step> <Step title="Resume with /pm:resume"> Run `/pm:resume`. PM pops the stack frame, restores the paused epic to active, and runs the mandatory reconcile gate before you write a single line of code. </Step> </Steps> ## Resuming after a detour `/pm:resume` is not just a pop — it is a structured re-entry with a mandatory checkpoint. The steps in order: 1. **Verify** the detour epic is `archived` and its work is committed. If it's not, it's not time to resume — finish the detour first. 2. **Pop** the top stack frame from `detourStack`. Set the paused epic's status back to `active` and update the `active` pointer. 3. **Run the reconcile gate** — if the stack frame had `reconcileOnResume: true`, PM delegates a fresh-context review to a dedicated reconcile agent via the Task tool, passing the paused epic id and the detour epic id. The agent re-reads the paused proposal cold, diffs what the detour actually shipped, and reports back a verdict. 4. **Write the verdict back durably** — this is what actually clears `reconcileNeeded`. The result is not just narrated in the transcript; it is attached to the paused epic's link in `.conductor/state.json` via `record-reconcile`. 5. **State the next story** — after a valid or amended reconcile, PM tells you exactly which story to build next on the resumed epic. ## What the reconcile gate checks The reconcile agent runs in a completely fresh context. It has no memory of the original build session. Given the paused epic id and the detour epic id, it: * Re-reads the paused proposal in full * Diffs what the detour actually changed against what the proposal assumed * Reports back with one of two verdicts: **`valid`** — the detour didn't affect the paused proposal's assumptions. Resume building as planned. **`invalidated`** — the detour changed something the paused proposal depends on. The agent lists specific amendments: stories to add, remove, or rewrite. Update the proposal and `tasks.md` before writing any code. Either way, the verdict plus any amendments are written back durably via `record-reconcile`, attaching `{verdict, amendments, reconciledAt}` to the paused epic's `may-invalidate` link. The judgment survives past this conversation and is visible in future briefings. ## Example detour stack frame This is what a substantial detour looks like in `.conductor/state.json` while work is paused: ```json theme={null} { "pausedEpic": "add-oauth-flow", "pausedAt": "2024-01-15T14:23:00Z", "reason": "login page throwing 500 on all POST requests", "spawnedDetour": "fix-login-500", "reconcileOnResume": true } ``` `reconcileOnResume: true` is the default whenever the detour touches code or behavior the paused epic depends on. Set it to `false` only when you are certain the detour is completely isolated. <Warning> The gate guard blocks `Edit`, `Write`, and `NotebookEdit` while `reconcileNeeded: true` is set on the active epic. This is unconditional — `set-gate-guard off` does not bypass it. Run `/pm:resume` and complete the reconcile gate first before attempting to write code. </Warning> <Tip> Use the `--minimal` flag to skip the classification prompt entirely when you already know the fix is small: `/pm:detour --minimal "fixed typo in auth header"` goes straight to the fast path — fix, test, commit, log, resume. </Tip> # Connect an AI Agent to PM's Documentation via MCP Source: https://pm-plugin.dev/guides/mcp-server PM's docs site hosts a free, no-auth search MCP server at pm-plugin.dev/mcp. Connect Claude Code, Claude, Cursor, or VS Code so your agent can search and retrieve PM documentation on demand. This site hosts a search [MCP](https://modelcontextprotocol.io) (Model Context Protocol) server at `pm-plugin.dev/mcp` — free, no authentication required. Any MCP-capable AI tool can connect to it and search or retrieve PM's documentation directly, instead of relying on training data or a generic web search. <Tip> This is a **search** MCP server — read-only. It lets an agent look things up in PM's docs; it does not let it edit anything or manage your project. Pair it with `llms.txt`/`llms-full.txt` (see the Introduction page) if you want an agent to load broader context up front rather than searching on demand. </Tip> ## What it exposes Two tools, both read-only: <CardGroup> <Card title="Search" icon="magnifying-glass"> Semantic search across PM's docs. Returns contextual content with titles and direct links to the matching pages. </Card> <Card title="Filesystem query" icon="folder-tree"> Run read-only, shell-like queries (`rg`, `head`, `cat`, `tree`, etc.) against a virtualized, in-memory filesystem containing PM's docs — for exact keyword/regex matches or reading a specific page's full content by path. </Card> </CardGroup> ## Connect to Claude Code Add PM's docs as an MCP server, naming it `pm-docs` so it's clear what it's for (a documentation server, not a project-management tool): ```bash theme={null} claude mcp add --transport http pm-docs https://pm-plugin.dev/mcp ``` Add `--scope user` instead of the default (`local`, this project only) to make it available across every project on your machine: ```bash theme={null} claude mcp add --transport http --scope user pm-docs https://pm-plugin.dev/mcp ``` Verify the connection: ```bash theme={null} claude mcp list ``` You should see `pm-docs: https://pm-plugin.dev/mcp (HTTP) - ✔ Connected`. ## Connect to Claude (claude.ai) <Steps> <Step title="Add pm-docs as a custom connector"> 1. Navigate to the [Connectors](https://claude.ai/settings/connectors) page in Claude settings. 2. Click **Add custom connector**. 3. Add the connector: * Name: `pm-docs` * URL: `https://pm-plugin.dev/mcp` 4. Click **Add**. </Step> <Step title="Use it in a chat"> Click the attachments button, then select `pm-docs`. Claude can now search PM's documentation while answering your prompt. </Step> </Steps> ## Connect to Cursor Add to your Cursor MCP config (Command Palette → **Open MCP settings** → **Add custom MCP**): ```json theme={null} { "mcpServers": { "pm-docs": { "url": "https://pm-plugin.dev/mcp" } } } ``` ## Connect to VS Code Create a `.vscode/mcp.json` file in your project: ```json theme={null} { "servers": { "pm-docs": { "type": "http", "url": "https://pm-plugin.dev/mcp" } } } ``` ## Other AI agents and tools Any MCP client that supports HTTP transport can connect using the same URL (`https://pm-plugin.dev/mcp`) and the `pm-docs` name — the connection steps above are Claude Code-specific, but the underlying server works identically for any compliant client. This page will grow to cover more tools as they're set up against this site. <Note> Connect only the MCP servers relevant to your current work, and disconnect ones you're not using — connected servers don't consume context until an agent actually calls a search tool, but keeping the list lean makes it easier for the agent to pick the right one. </Note> # Run Multi-Agent Epic Batches with PM's Hierarchy Harness Source: https://pm-plugin.dev/guides/multi-agent-hierarchy Dispatch a parent epic's children as worktree-isolated, unattended agents. PM converges their work back through sequential merge with zero data loss. When a parent epic has multiple children, PM can dispatch each child as its own agent in an isolated git worktree. They run unattended, converge back sequentially, and the orchestrator stays the sole writer of `.conductor/state.json` throughout. This is not a metaphor for parallel development — it is an actual dispatch-and-converge framework that PM has run through 21 agents across its own dogfooding batches with zero data loss and zero unresolvable conflicts. ## Prerequisites Every child epic must be granted autonomous execution trust before it can be dispatched. PM runs a mandatory preflight scan for each child: it reads the child's full source (proposal, design docs, plan, or inline stories depending on the lane) and produces a list of destructive-risk points and genuine unknowns to review with you. Only after you have answered those questions and the answers have been recorded via `set-autonomy` will the child show `autonomous: true` in the plan. PM blocks dispatch for any child that does not show `autonomous: true`. Do not attempt to dispatch a non-autonomous child — it will immediately hit the "no context to act on" decision rule and stop. ## Planning the hierarchy <Steps> <Step title="Register child epics under a parent"> Use `/pm:epic add --parent <parent-id> --id <child-id> --title "…" --lane <lane> --priority <P>` for each child, or bulk-create a parent and all children atomically with `add-many --from <path>`. </Step> <Step title="Set dependency links between children"> If execution order matters — for example, an auth epic must complete before an API epic can start — record the dependency with `update-epic <api-epic-id> --link depends-on:<auth-epic-id>`. Children with no dependencies within the same batch can run in parallel. </Step> <Step title="Run the preflight scan"> Compute the execution plan and verify readiness: ```bash theme={null} node "$ENGINE" plan-hierarchy --parent <parent-id> ``` This prints the full batch plan including autonomy status for every child. </Step> <Step title="Review the batch output"> Batches run in order; epics within a batch have no dependencies on each other and may run in parallel. Review the output to confirm ordering is correct before proceeding. </Step> <Step title="Confirm every child is autonomous"> Every child in the plan must show `autonomous: true`. Any that don't were not cleared in the preflight — run the autonomy scan for those children and record the results before dispatching. </Step> </Steps> ## The plan-hierarchy output `plan-hierarchy` produces a JSON structure that shows exactly which batches will run, in what order, and which children may dispatch in parallel within each batch: ```json theme={null} { "parent": "feature-sprint", "batches": [ { "batch": 1, "epics": [ { "id": "auth-epic", "priority": "P0", "autonomous": true, "dependsOn": [] } ] }, { "batch": 2, "epics": [ { "id": "api-epic", "priority": "P1", "autonomous": true, "dependsOn": ["auth-epic"] } ] } ] } ``` `dependsOn` lists sibling ids (within this hierarchy) that must be archived before the epic can run. Check it transitively — a dependency chain can be more than one hop deep. ## Dispatching Each child runs as its own isolated agent in a dedicated `hierarchy-child/<epic-id>` git worktree and branch. The orchestrator dispatches them via the Task tool. Within a batch, children with no dependencies on each other may be dispatched in parallel in the same turn. Children never write `.conductor/state.json` themselves. They execute their work and return a structured report. The orchestrator is the sole writer of state transitions, applied in one pass after each batch completes — never interleaved with dispatch. This is what makes parallel dispatch safe for the state file: there is only ever one writer. ## Merge convergence After each child completes, the orchestrator merges its worktree branch back. An ordinary merge conflict is never a hard stop — PM has a tiered resolution ladder: 1. **Normal `git merge`** — fast-path; most merges land cleanly 2. **Conflict-resolver agent** — dispatched automatically when a normal merge fails; reads both sides and the merge base to resolve the conflict 3. **Escalation** — if the resolver reports `STATUS: uncertain`, retry with a more capable model or consult the `advisor()` tool before finalizing 4. **Logged follow-up epic** — if still unresolvable, commit the best-effort resolution (still fully recoverable via git history) and log a new follow-up epic under the same parent The instruction "tell the human you can't merge this" is explicitly designed out of the process. Every conflict has a next step. After any conflict resolution — regardless of which rung resolved it — the orchestrator verifies every touched file for leftover conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) and runs `node -c <file>` on every touched `.mjs` or `.js` file before committing. Neither check is optional. ## Changelog fragments Dispatched children write their changelog entries to `.changesets/<epic-id>.md`, never to `CHANGELOG.md` directly. Writing to the shared `[Unreleased]` header is a guaranteed merge conflict across every parallel batch — this was confirmed empirically at a 100% collision rate across the first two PM dogfood batches. Each child touches only its own fragment file. The orchestrator remains the sole writer of `CHANGELOG.md` and consolidates fragments at release time using `/pm:changesets`. ## State transitions The orchestrator applies all state transitions in a single pass after each batch is fully merged — not interleaved with dispatch. Once every child in a batch has reported back and merged, the orchestrator marks each one `archived` in `.conductor/state.json`. The parent epic itself is never auto-archived — that is always a human call. ## Cleanup After all batches are merged, run: ```bash theme={null} node "$ENGINE" verify-worktrees ``` This cross-references `git worktree list` against epic status and flags any `hierarchy-child/*` worktree whose epic is already archived but was not cleaned up. Clean worktrees immediately after each child merges — never leave them dangling. <Note> `plan-hierarchy` is a pure read — it recomputes the execution plan fresh from `parent`, `priority`, `links[]`, and `autonomy` every time you run it. There is no "hierarchy in progress" flag that can get out of sync. Re-running it at any point reflects current reality. </Note> <Warning> A dependency cycle among children causes `plan-hierarchy` to exit non-zero, naming the specific cycle. This is a real data problem — two children have `depends-on` links pointing at each other, directly or transitively. Fix the offending `links` entries in `.conductor/state.json` before retrying. </Warning> # Project Manager (PM) — A Claude Code Project Management Plugin Source: https://pm-plugin.dev/index A lightweight harness above OpenSpec and Superpowers that keeps a Claude Code project on track across detours, context compaction, and multiple epics in flight. **Project Manager (PM)** is a lightweight harness above [OpenSpec](https://github.com/Fission-AI/OpenSpec) and [Superpowers](https://github.com/obra/superpowers) that keeps a Claude Code project on track — across detours, context compaction, and however many epics are in flight at once. Install it once, run `/pm:init`, and it stays oriented across every context compaction. Zero npm dependencies. Pure Node 18+ built-ins. <CardGroup> <Card title="Introduction" icon="circle-info" href="/introduction"> Why PM exists, the problem it solves, and real numbers pulled from its own history. </Card> <Card title="Installation" icon="download" href="/installation"> Install PM from the cfdude-plugins marketplace in under a minute. </Card> <Card title="Quick Start" icon="rocket" href="/quickstart"> Initialize PM in your project and run your first briefing in five steps. </Card> <Card title="Core Concepts" icon="book" href="/concepts/epics-and-lanes"> Understand epics, lanes, the detour stack, and the reconcile gate. </Card> </CardGroup> ## How It Works <Steps> <Step title="Initialize"> Run `/pm:init` in your project. PM scaffolds `.conductor/state.json`, writes a managed rules block into `CLAUDE.md`, and registers any existing OpenSpec proposals or Superpowers plans as epics. A `SessionStart` hook is installed that re-injects the full project briefing after every context compaction — automatically. </Step> <Step title="Work epics in lanes"> Every unit of work is an **epic** routed through a **lane** — `openspec` (spec-driven proposal workflow), `superpowers` (execution-focused TDD), `claude-code` (direct implementation), `decision` (lightweight ADR), or `external` (tracker-mirrored). `/pm:status` shows the current briefing; `/pm:next` picks the highest-priority item, respecting `depends-on` links and the detour stack. </Step> <Step title="Handle interrupts without losing context"> When something comes up mid-build, `/pm:detour` classifies it as minimal (fix-in-place, log it, resume) or substantial (PUSH the current epic, spin up a new one, build the interrupt). When the detour is done, `/pm:resume` POPs the stack and fires the **reconcile gate** — a fresh-context agent re-validates the paused epic against what the detour actually shipped before a single line of code is written. </Step> </Steps> ## The Detour Stack in Action Here is what a substantial interruption looks like before and after PM: **Without PM:** You're mid-build on `auth-refactor` when a prod bug comes in. You either abandon `auth-refactor` context or ignore the bug. After fixing the bug, you resume from memory — which may be wrong after a compaction. **With PM:** ```text theme={null} # A prod bug arrives while building auth-refactor /pm:detour "prod bug: login redirect loop on Safari" # PM PUSHes auth-refactor onto the detour stack, routes the bug to claude-code lane # → build the fix, commit, push /pm:resume # PM POPs auth-refactor, fires the reconcile gate: # A fresh reconciler agent re-reads the paused epic against what was just shipped. # Verdict written durably to state.json — then and only then does the build resume. ``` The reconcile gate is not a reminder — it is a hard `PreToolUse` block on `Edit`/`Write`/`NotebookEdit` until the gate clears. The agent cannot accidentally skip it. ## What PM Tracks <CardGroup> <Card title="Handling Detours" icon="code-branch" href="/guides/handling-detours"> Park current work, build the interrupt, and resume with confidence. </Card> <Card title="Multi-Agent Hierarchy" icon="diagram-project" href="/guides/multi-agent-hierarchy"> Dispatch child epics as worktree-isolated agents that merge back cleanly. </Card> <Card title="External Trackers" icon="link" href="/guides/external-trackers"> Mirror epics to Jira, Linear, or GitHub Issues without leaving Claude Code. </Card> <Card title="Daily Workflow" icon="calendar" href="/guides/daily-workflow"> How a full session looks from `/pm:init` to closing the last epic. </Card> </CardGroup> ## Key Features <CardGroup> <Card title="Detour Stack" icon="layer-group"> PUSH/POP your working context around any interruption. The stack survives compaction and is re-injected by the SessionStart hook on every resume. </Card> <Card title="Reconcile Gate" icon="shield-check"> A mandatory fresh-context review fires on every resume — a `PreToolUse` hard block, not a suggestion. No code is written until the gate clears. </Card> <Card title="Zero Dependencies" icon="feather"> The engine is pure Node 18+ built-ins. Nothing to `npm install`, ever. See the [Introduction](/introduction) for current test/line counts. </Card> <Card title="Session Briefing" icon="bolt"> A `SessionStart` hook re-injects the full project briefing after every context compaction — automatically, without any manual step. </Card> <Card title="Multi-Agent Dispatch" icon="network-wired"> Run parent epics as batched, worktree-isolated child agents that converge via sequential merge. The orchestrator is the sole writer of shared state. </Card> <Card title="Tracker Mirroring" icon="arrows-rotate"> Instruction-layer sync to Jira, Linear, or GitHub Issues. The engine never calls external APIs — it shapes the instructions that tell the agent to. </Card> </CardGroup> ## Concepts <CardGroup> <Card title="Epics and Lanes" icon="map" href="/concepts/epics-and-lanes"> How work units are defined, routed through lanes, and prioritized. </Card> <Card title="Detour Stack" icon="layer-group" href="/concepts/detour-stack"> The PUSH/POP mechanism that makes any interruption safely resumable. </Card> <Card title="Reconcile Gate" icon="shield-check" href="/concepts/reconcile-gate"> The fresh-context re-validation gate that fires on every resume. </Card> <Card title="State and Project" icon="database" href="/concepts/state-and-project"> How `.conductor/state.json` and `PROJECT.md` are structured and maintained. </Card> </CardGroup> ## Command Reference <CardGroup> <Card title="/pm:init" icon="play" href="/commands/init"> Scaffold the conductor, register epics, write the CLAUDE.md rules block. </Card> <Card title="/pm:status" icon="chart-bar" href="/commands/status"> Show the current briefing: active epic, detour stack, priority queue, lane counts. </Card> <Card title="/pm:next" icon="forward" href="/commands/next"> Pick the next highest-priority item, respecting the detour stack and dependency links. </Card> <Card title="/pm:detour" icon="code-branch" href="/commands/detour"> Classify and handle a mid-build interruption — minimal or substantial. </Card> <Card title="/pm:resume" icon="rotate-right" href="/commands/resume"> Pop the detour stack and run the reconcile gate before resuming. </Card> <Card title="/pm:epic" icon="list-check" href="/commands/epic"> Register, update, or remove epics directly. </Card> <Card title="/pm:hierarchy" icon="diagram-project" href="/commands/hierarchy"> Plan and dispatch a parent epic's children as a multi-agent batch. </Card> <Card title="/pm:sync" icon="arrows-rotate" href="/commands/sync"> Pick up new proposals, plans, and inbound tracker issues as epics. </Card> <Card title="/pm:tracker" icon="link" href="/commands/tracker"> Configure mirroring to Jira, Linear, or GitHub Issues. </Card> <Card title="/pm:upgrade" icon="arrow-up" href="/commands/upgrade"> Refresh the CLAUDE.md rules block and run any pending migrations. </Card> <Card title="/pm:feedback" icon="comment" href="/commands/feedback"> File a bug or feature request as a GitHub issue directly from a session. </Card> <Card title="All Commands" icon="terminal" href="/commands/init"> View the full command reference including gate-guard, lane-routing, and review-mode. </Card> </CardGroup> <Note> PM is Claude Code only today. Support for Codex, Gemini CLI, Grok Build, and generic `AGENTS.md`-based platforms is tracked under `multi-platform-agent-support` in PM's own backlog. </Note> # From Industry-Frontier Practice Source: https://pm-plugin.dev/industry-frontier-practice PM's design choices aren't novel in isolation — they're borrowed, deliberately, from patterns that already work at scale elsewhere and adapted to an agentic coding session. PM's design choices aren't novel in isolation — they're borrowed, deliberately, from patterns that already work at scale elsewhere and adapted to an agentic coding session. * **Policy-as-code, not policy-as-prose** — `/pm:gate-guard`'s reconcile-owed check is a mechanical `PreToolUse` hook, not a rule an agent might forget to re-read after compaction. Same idea as an admission controller: the guard blocks the write, it doesn't just ask nicely. * **Worktree isolation for parallel execution** — epic-hierarchy dispatch runs each child in its own git worktree/branch, merges sequentially, and treats the orchestrator as the sole writer of shared state — the same shape as isolating parallel CI jobs so they can't stomp on each other's output, applied to parallel *agent* execution instead. * **An explicit interrupt stack, not implicit memory** — the detour stack (PUSH/POP + a mandatory reconcile gate on resume) is the same discipline as saving and restoring context around a hardware interrupt: the thing that got interrupted doesn't get to just "remember" — it gets re-validated before it resumes. * **Instruction layer, never integration layer** — the engine never opens a network connection or calls an external system itself (the one documented exception is the opt-in gate-guard hook). External work — GitHub, Jira, Honcho — is always the interactive agent's job; the engine only shapes the instructions it emits. Same separation of concerns as a scheduler that never touches the resources it schedules. ## What You Can Learn * **How to make a detour genuinely resumable** — not "remember to come back to this," but a structured stack frame with a reason, a link, and a mandatory reconcile gate that a fresh agent can re-run cold. * **How to run multiple epics unattended without a shared-state race** — worktree isolation + sole-writer state transitions, discovered as a real gap during the plugin's own first live dogfood run and fixed the way you'd want any real bug fixed: in the open, with a design doc, not silently patched over. * **How to keep a hard architectural law honest** — "the engine never calls an external system" is enforced by review discipline, not a technical sandbox, and the CLAUDE.md constraints spell out exactly the one documented exception and why. * **How to turn a preflight scan into a real safety mechanism** — epic-level autonomy's decision rule (pre-authorized → proceed; no backup path → hard stop; destructive-but- restorable → warn and log; genuine unknown → stop) is designed to be followed by an agent mid-task, not just read once at the start. # Install the PM Project Management Plugin for Claude Code Source: https://pm-plugin.dev/installation Install the PM project-management plugin from the cfdude-plugins marketplace. Requires Node 18+ and Claude Code. No npm install needed. PM is distributed via the `cfdude-plugins` marketplace and requires no `npm install` — the engine is zero-dependency by hard rule. The entire conductor (`scripts/conductor.mjs`) is \~2,100 lines of Node 18+ built-ins, so there is nothing to install beyond the plugin itself. Add the marketplace, install the plugin, and you're ready to initialize your first project. ## Prerequisites <Info> **Node 18+** is required to run the conductor engine. If you're already using OpenSpec or Superpowers, Node 18+ is almost certainly present. **Claude Code** is the only supported platform today — Codex, Gemini CLI, and other platforms are on the roadmap. </Info> ## Installation steps <Steps> <Step title="Add the cfdude-plugins marketplace"> Register the `cfdude-plugins` marketplace with Claude Code so PM is discoverable: ```bash theme={null} /plugin marketplace add cfdude/cfdude-plugins ``` </Step> <Step title="Install PM"> Install the `pm` plugin from the marketplace you just added: ```bash theme={null} /plugin install pm@cfdude-plugins ``` </Step> <Step title="Reload plugins"> Reload the Claude Code plugin runtime so the new plugin and its hooks are active: ```bash theme={null} /reload-plugins ``` </Step> <Step title="Initialize PM in your project"> Navigate to your project directory and run the init command. This scaffolds the conductor state, registers any existing OpenSpec proposals and Superpowers plans as epics, and writes the managed rules block into `CLAUDE.md`: ```bash theme={null} cd your-project /pm:init ``` See the [Quick Start guide](/quickstart) for a full walk-through of what `/pm:init` creates and the triage flow that follows. </Step> </Steps> ## Companion plugins (optional) PM works completely standalone — install it, run `/pm:init`, and you immediately have cross-epic priority ordering, an explicit detour stack, and the reconcile gate with no other plugin required. That said, PM was designed to sit above three companions, and each one adds a distinct layer that PM deliberately doesn't own itself. <CardGroup> <Card title="OpenSpec" icon="file-lines" href="https://openspec.dev"> **Spec-driven proposal workflow.** OpenSpec owns the `proposal.md` / `design.md` / `tasks.md` artifacts and the two-gate review process. PM tracks the epic; OpenSpec owns what gets built and its durable spec record. ```bash theme={null} npm install -g @fission-ai/openspec cd your-project && openspec init ``` </Card> <Card title="Superpowers" icon="bolt" href="https://github.com/obra/superpowers"> **Execution discipline.** Superpowers drives brainstorming, TDD, subagent-driven development, and code review. PM tracks *when* and *in what order* an epic gets built; Superpowers drives *how well*. ```bash theme={null} /plugin marketplace add anthropics/claude-plugins-official /plugin install superpowers@claude-plugins-official ``` </Card> <Card title="Honcho" icon="brain" href="https://docs.honcho.dev"> **Durable memory across sessions and repos.** PM's detour stack is the live working set for one project; Honcho is where a PUSH/POP memory line goes so the relationship between projects — and between sessions — survives a compaction, a new machine, or a week away. See [docs.honcho.dev](https://docs.honcho.dev) for setup. </Card> <Card title="PM (standalone)" icon="check-circle"> **No companions required.** PM installs and initializes on its own. Each companion adds a layer PM intentionally doesn't own — but skipping them loses nothing from PM's core: priority ordering, the detour stack, and the reconcile gate all work without them. </Card> </CardGroup> ## Upgrading When PM releases a new version, the `SessionStart` briefing will tell you that a reload and upgrade are needed. The process is always the same two steps: ```bash theme={null} /reload-plugins /pm:upgrade ``` `/pm:upgrade` refreshes the `CLAUDE.md` rules block, runs any pending state migrations, re-renders `PROJECT.md`, and stamps the new `pmVersion` onto `.conductor/state.json`. It is idempotent — safe to run more than once. <Warning> Always run `/reload-plugins` **before** `/pm:upgrade` whenever you've updated the plugin itself (not just a project init). Running `/pm:upgrade` against a stale plugin cache can apply the wrong migration. The `SessionStart` briefing explicitly tells you when a reload is needed — watch for it at the start of your session. </Warning> # PM Plugin Source: https://pm-plugin.dev/introduction Keep Claude Code Projects (and other AI agents) on Track Across Sessions ![Project Manager](https://raw.githubusercontent.com/cfdude/pm/refs/heads/main/img/logo.png) PM is a Claude Code plugin that tracks epics, maintains a detour stack, and enforces a reconcile gate so nothing is lost across compaction or pivots. PM is a lightweight project-management layer that sits above [OpenSpec](https://openspec.dev) and [Superpowers](https://github.com/obra/superpowers) inside Claude Code. It doesn't duplicate what those tools already do — it fills the gap above them, owning cross-epic ordering, an explicit detour stack, and the reconcile gate that ties interrupted work back to the proposal it was built against. After any context compaction, PM answers three questions in seconds: what were we working on before the detour, what work is currently outstanding, and what is the next highest-priority item to tackle. ## The problem PM solves Agentic coding sessions are interrupted constantly — a bug surfaces mid-sprint, a new requirement lands, a context window fills up and collapses. Traditional task trackers live outside the session entirely and don't survive the compaction boundary. Notes in a conversation transcript vanish with the context. Even a carefully maintained `CLAUDE.md` doesn't tell you whether the proposal you were halfway through is still valid after the detour that interrupted it. PM solves this by living inside Claude Code as a plugin with its own hooks. A `SessionStart` hook re-injects the full briefing the moment a new context begins — so the agent picking up after compaction sees the active epic, the detour stack, and the next-up queue without any manual re-orientation. A `PreToolUse` gate-guard hook mechanically blocks writes while a reconcile is still owed. Nothing depends on the agent "remembering" the right thing. ## Core mechanisms PM is built on three interlocking mechanisms. Together they make project state durable across the events that normally destroy it: <CardGroup> <Card title="Epics & Lanes" icon="layers" href="/concepts/epics-and-lanes"> Every unit of work is an epic with a lane (`openspec`, `superpowers`, `claude-code`, `decision`, `external`), a priority (P0–P3), and a lifecycle status. Epics are lane-agnostic at the conductor level — PM tracks them regardless of which tool owns execution. </Card> <Card title="Detour Stack" icon="arrow-turn-down-right" href="/concepts/detour-stack"> When a mid-build interrupt arrives, PM classifies it as minimal (fix-and-resume, logged only) or substantial (PUSH the active epic, build the detour, POP and reconcile). The stack is durable in `.conductor/state.json` — it survives compaction and session restarts. </Card> <Card title="Reconcile Gate" icon="shield-check" href="/concepts/reconcile-gate"> Before a paused epic can resume, a fresh-context `reconciler` agent re-validates it against what the detour actually shipped. The verdict is written durably via `record-reconcile` — not left in the transcript — and a `PreToolUse` hook hard-blocks any write while the gate is still owed. </Card> <Card title="Quick Start" icon="rocket" href="/quickstart"> Install PM, run `/pm:init` in your project, and get your first status briefing in under five minutes. No `npm install`, no external dependencies. </Card> </CardGroup> ## What PM is NOT PM is not a replacement for OpenSpec or Superpowers. It sits deliberately above them and only owns what neither of those tools owns: * **OpenSpec** owns the spec-driven proposal workflow — `proposal.md`, `design.md`, `tasks.md`, gate reviews. PM tracks that an OpenSpec epic exists and its priority; it doesn't touch the spec artifacts themselves. * **Superpowers** owns execution discipline — brainstorming, TDD, subagent-driven development, code review. PM tracks *when* and *in what order* an epic gets built; Superpowers drives *how well* it gets built. * **PM** owns cross-epic ordering, the detour stack, and reconcile links. Nothing else. Stories stay wherever they already live — PM doesn't move them or replace them. <Note> PM runs exclusively in Claude Code today. Codex, Gemini CLI, Grok Build, and other `AGENTS.md`-based platforms are on the roadmap. </Note> ## Real numbers These aren't benchmarks — they're real figures pulled mechanically from PM's own repo (`grep`/`wc`/the test runner), refreshed every release, from the project that manages its own development through PM itself: | Metric | Value | | ----------------------------------------------------------------------- | ----------- | | Releases shipped end-to-end (spec → build → test → changelog → release) | **38** | | Tests in the engine | **250** | | Lines of engine code (`scripts/conductor.mjs` + `scripts/lib/*.mjs`) | **\~2,700** | | External dependencies | **0** | Every multi-agent hierarchy dispatch runs worktree-isolated and converges back through sequential merge — every conflict seen so far has been mechanical (a shared CHANGELOG header, a usage string), never a real logic collision. The engine is Node 18+ built-ins only. <Tip> PM manages its own development — the backlog, roadmap, and every release of PM itself run through PM. The `PROJECT.md` in the `cfdude/pm` repo is a live example of what PM produces. </Tip> <Card title="From Industry-Frontier Practice" icon="graduation-cap" href="/industry-frontier-practice"> PM's design choices aren't novel in isolation — they're borrowed, deliberately, from patterns that already work at scale elsewhere: policy-as-code, worktree isolation, an explicit interrupt stack, instruction-layer-only architecture. </Card> ## AI-agent reference This site publishes [`llms.txt`](https://pm-plugin.dev/llms.txt) — a lightweight (\~7KB) index of every doc page, meant for an AI agent to fetch on demand — and [`llms-full.txt`](https://pm-plugin.dev/llms-full.txt), the entire site as one document (\~200KB, tens of thousands of tokens). Use `llms.txt` by default; reach for `llms-full.txt` only when you genuinely need the complete reference in one shot. # PM Quick Start: Initialize, Triage, and Start Building Source: https://pm-plugin.dev/quickstart Initialize PM in your Claude Code project, triage your first epic, and get your first status briefing and work recommendation in under five minutes. After [installing PM](/installation), run `/pm:init` in any project to activate the conductor. PM wires up its hooks, scans for existing work, and writes the rules block that keeps it oriented across every future context compaction. This walk-through takes you from a fresh install to your first concrete work recommendation. <Steps> <Step title="Initialize the conductor"> Navigate to your project directory and run the init command: ```bash theme={null} cd your-project /pm:init ``` On first run, the conductor engine does four things: 1. Creates `.conductor/state.json` — the durable state of record for all epics, the detour stack, and reconcile links. 2. Scans for any existing OpenSpec proposals and Superpowers plans and registers them as untriaged epics. 3. Writes the **managed rules block** into your project's `CLAUDE.md`. This block is the recurring briefing carrier — it tells every future agent (including post-compaction agents) how to drive PM correctly without re-reading the full documentation. 4. Renders `PROJECT.md` — the generated human-readable view of the current project state. <Note> `/pm:init` is safe to run more than once. If the project is already initialized, it is a no-op. Re-running will not overwrite your existing state or duplicate the rules block in `CLAUDE.md`. </Note> </Step> <Step title="Triage your epics"> After scaffolding, PM will present any epics it discovered and walk you through triage. For each epic you'll set: * **Priority** — `P0` (critical, do now) through `P3` (low, do later). This is the primary sort key for `/pm:next`. * **Status** — `active` (currently being built), `queued` (ready to start), `later` (deprioritized, not yet ready), `planned` (roadmap item, not yet scaffolded), or `untriaged` (just discovered, needs review). If you have no existing OpenSpec proposals or Superpowers plans, PM starts with an empty backlog and you can add epics directly: ```bash theme={null} /pm:epic add my-feature "My first feature" claude-code P1 ``` Lanes tell PM which execution tool owns the work: `openspec` for spec-driven proposals, `superpowers` for Superpowers plans, `claude-code` for direct agentic work, `decision` for architecture decisions, and `external` for issues tracked outside the session. </Step> <Step title="Check your status briefing"> Run `/pm:status` to see the full conductor briefing: ```bash theme={null} /pm:status ``` The briefing shows: * The **active epic** — what PM considers currently in flight, with its lane and priority. * The **detour stack** — any paused epics awaiting reconcile, listed from most-recent PUSH to oldest. * The **next-up queue** — the top queued epics sorted by priority, with any blocked epics annotated with their blocker. * **Per-lane counts** — a summary across `openspec`, `superpowers`, `claude-code`, `decision`, and `external`. This briefing is also what the `SessionStart` hook re-injects automatically after every context compaction — so you will see this view at the start of every new context window, not just when you run the command manually. </Step> <Step title="Get a work recommendation"> Run `/pm:next` to get a concrete, unambiguous recommendation for what to work on: ```bash theme={null} /pm:next ``` PM applies a simple, deterministic rule: * If the detour stack is non-empty, the recommendation is to resume the top of the stack (and run the reconcile gate first). * Otherwise, the recommendation is the highest-priority `queued` epic (P0 before P1 before P2 before P3), skipping any epic blocked by an unresolved `depends-on` link and naming the blocker when it does skip. There is no ambiguity in the output — you either resume a paused epic or you start the top-priority queued one. </Step> <Step title="Start building"> Work in your chosen epic's lane. The conductor stays aware via hooks: * After each `git commit`, a `PostToolUse` hook nudges you to update the epic's status and auto-detects whether the commit shape looks like an unlogged minimal detour. * If an interrupt arrives mid-build, use `/pm:detour` to classify and handle it: ```bash theme={null} # Minimal detour — fix it, commit, log it, resume: /pm:detour --minimal "fixed null-check in auth middleware" # Substantial detour — push the current epic and spin up a new one: /pm:detour "payment processor returning 500 on retries" ``` When a substantial detour is complete and you're ready to return to the original epic, run `/pm:resume`. PM pops the detour stack, dispatches a fresh-context `reconciler` agent to validate the paused epic against what the detour shipped, and writes the verdict back durably before allowing any further writes to the original epic. When an epic is fully complete, run `/pm:sync` to pick up any new proposals or plans that arrived during the build. </Step> </Steps> ## Your project structure After `/pm:init`, PM creates the following files in your project: ```text theme={null} your-project/ ├── .conductor/ │ ├── state.json # epics, detour stack, links, autonomy grants │ ├── detours.log # append-only detour trail (timestamp · SHA · kind · epic · note) │ └── honcho-memories.log # ready-to-copy Honcho memory lines, timestamped ├── CLAUDE.md # managed rules block (idempotent; delete to opt out) └── PROJECT.md # generated view — never hand-edit ``` <Tip> `PROJECT.md` is a **generated view** — it is re-rendered from `.conductor/state.json` every time you run `/pm:status` or `/pm:sync`. Never hand-edit it. If you want to change epic state, use the PM commands (`/pm:epic`, `/pm:detour`, `/pm:resume`). Hand edits will be silently overwritten. </Tip> ## The basic loop Once initialized, the day-to-day PM workflow is a short cycle: ```text theme={null} /pm:init → /pm:status → /pm:next → (build) → /pm:sync ↑ │ └──── /pm:detour ────────┤ (minimal: fix → commit → log → resume) (substantial: PUSH → build → /pm:resume → RECONCILE GATE → POP) ``` Multi-epic batches follow a parallel track: use `/pm:hierarchy` to plan and dispatch a parent epic's children as worktree-isolated, unattended agents that converge back through sequential merge. *** Now that you have PM running, explore the full feature set: * [Core Concepts](/concepts/epics-and-lanes) — epics, lanes, the detour stack, and the reconcile gate in depth. * [Commands](/commands) — the complete reference for every PM command.