Skip to main content
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.
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: A minimal real example of a claude-code-lane epic with inline stories:

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:
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 the commit’s shape — file count, commit prefix, whether an epic is active at all, and whether an active detour is already open — and logs them without requiring a manual /pm:detour --minimal invocation.
Two corrections shipped in 0.32.0. The hook used to log a spurious minimal detour for a perfectly ordinary commit when no epic was active — there is no work to detour from in that case, so nothing is logged now. And the detection reads the repository rather than the command text, so a commit in any flag form is seen and a command that merely mentions git commit is not.
In 0.33.0 the trail stopped duplicating itself. A commit-derived row is refused when the trail already holds one for that (sha, kind) — which mattered because the fallback rung has no memory of what it already logged. A MINIMAL detour is deliberately exempt: it records what the agent declared, not what git observed, so two of them at one commit are two real events. A - sha means “cannot tell” and is never treated as an identity.That duplication was half of why PROJECT.md was never clean — a bookkeeping commit appended a row, which changed the file, which produced another commit. The other half was a bookkeeping filter that guarded one branch of the hook and had never been applied to the identical branch beside it.
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.
CLAUDE_PROJECT_DIR decides which repository every path below belongs to. When it is set, it overrides the working directory — which is correct and load-bearing for hooks and cross-repo dispatch, and silently catastrophic when the value is stale. As of 0.33.0 the engine warns, naming both repositories and how to undo it, when the variable resolves elsewhere and the directory you are standing in has a conductor of its own. It warns and never refuses: the defect was that a redirect looked identical in the output, not that redirects happen.
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.
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.