Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,28 @@ All notable changes to the `pm` plugin, mirroring [CHANGELOG.md](https://github.

---

<Update label="0.24.0" description="2026-07-30">
### Added

- **Platform-aware rules block.** The managed rules block is no longer Claude-Code-only. The host agent declares itself via `--platform <claude-code|hermes|codex>` in the hook command pm authors for that platform, and the active platform is recorded in `.conductor/state.json`. pm never runs on its own — a host agent always triggers it, through a hook whose command string pm itself wrote — so the platform is _declared_, not detected: no markers, no filesystem archaeology, no precedence heuristic to get wrong.
- **Per-platform slash-command form**: `/pm:status` on Claude Code and Hermes, `/pm-status` on Codex. The `pm:` namespace is retained wherever supported for a concrete reason, not aesthetics — Hermes _silently skips_ a plugin command that collides with one of its built-ins, and it ships a built-in `status`, so a bare `/status` would be dropped with no signal. Codex derives command names from prompt-file stems, so it is flat and hyphenated. Every value verified against the installed CLIs rather than documentation.

### Changed

- **The test suite is now `scripts/test/*.test.mjs` (11 files) instead of one `scripts/conductor.test.mjs`, cutting a full run from ~118s to ~46s.** Contributor-facing: the command is `node --test scripts/test/*.test.mjs`. Measured rather than guessed — one engine spawn costs ~73ms and the suite makes 676 of them, so ~49s was pure `node` startup, serialized in a single file on a 16-core machine; `node --test` parallelizes across _files_ only. The split is verbatim, verified by test-name-set equality (255 → 255). Note `node --test scripts/test` (a directory) does **not** work — Node treats the argument as a module to execute and dies with `MODULE_NOT_FOUND` while reporting "1 test".
- **`.githooks/pre-commit` now aborts if the suite runs fewer tests than are declared.** The glob makes a partial-suite pass possible in a way the single file never did: if a file stops matching, everything still goes green, just on a subset. The hook cross-checks the runner's count against `grep -Hc '^test('` across the files — self-maintaining, with no constant to bump as tests are added.

### Fixed

- **The rules block is now written to the file the host platform will actually read.** Hermes resolves project context first-match-wins over `HERMES.md` \> `AGENTS.md` \> `CLAUDE.md`, so in a repo already carrying an `AGENTS.md` — from a prior Codex attempt, say — the block was _silently invisible_: no error, no warning, just an agent running without the conductor's instructions. Writing to a file a platform is _capable_ of reading is not enough; it must win that platform's precedence chain.
- **The auto-detour hook no longer writes a `detours.log` entry for a commit that did not land in this repo** (closes [#65](https://github.com/cfdude/pm/issues/65) and [#68](https://github.com/cfdude/pm/issues/68)). `PostToolUse` fires when the Bash tool _returns_, which is not the same as "a commit landed here." Three divergences were observed live, each writing a false line attributed to this repo's **stale HEAD**: the commit was rejected by `pre-commit` so HEAD never advanced; the commit was backgrounded and still running; or the commit landed in a _different_ repo — a paired repo, a submodule, `git -C elsewhere` — leaving our HEAD untouched. An exit-code check would have closed the first but not the second, since a backgrounded commit has no exit code yet; that is why two independently-reported issues share one fix.
- Comparing subjects is subtler than it looks, and getting it wrong is worse than the original bug. `git log -1 --format=%s` yields only the **first line**, while a `-m` capture spans newlines and swallows the whole message — so a naive comparison suppresses every commit that has a body, silently disabling the hook for the common case. The comparison is therefore first-line-to-first-line, and a message the shell assembled (`-m "$(…)"`, a heredoc, `-m "$MSG"`) is treated as _unverifiable_ rather than mismatched, because the command string holds the shell source rather than the text git received.

### Migration

- `0.24.0` stamps `platform` on existing state files, defaulting to `claude-code`. Additive and idempotent; a `0.23.1` state file still loads.
</Update>

<Update label="0.23.1" description="2026-07-23">
### Fixed

Expand Down
8 changes: 5 additions & 3 deletions commands/upgrade.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ If you skip step 2, Claude Code is still executing the old plugin code and the u
## 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 title="Refreshes the managed rules block">
The managed PM section 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.

As of 0.24.0 the target file is platform-aware: `CLAUDE.md` on Claude Code, and on a platform that resolves project context through a precedence chain, whichever file that platform will actually read. Upgrading from a pre-0.24.0 release also migrates the block's own delimiter wording in place — detection keys on a stable prefix, so an older block is found and refreshed rather than duplicated.
</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.
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. The `0.24.0` migration stamps a `platform` field on repos that predate it, defaulting to `claude-code`.
</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.
Expand Down
6 changes: 3 additions & 3 deletions introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ PM is not a replacement for OpenSpec or Superpowers. It sits deliberately above
- **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.
PM runs exclusively in Claude Code today. Hermes, Codex, and other `AGENTS.md`-based platforms are on the roadmap — as of 0.24.0 the engine's rules block is platform-aware groundwork for that (the host declares itself via `--platform`, and the block is written to the file that platform actually reads), but no second platform's commands or hooks ship yet.
</Note>

## Real numbers
Expand All @@ -56,8 +56,8 @@ These aren't benchmarks — they're real figures pulled mechanically from PM's o
| 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** |
| Tests in the engine | **282** |
| Lines of engine code (`scripts/conductor.mjs` \+ `scripts/lib/*.mjs`) | **~2,900** |
| 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.
Expand Down