.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 runsgh 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
1
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.2
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.3
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.4
PM records the tracker block and updates CLAUDE.md
PM calls Re-running
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):set-tracker merges — only the flags you pass change. It also refreshes the CLAUDE.md rules block automatically.Tracker configuration shape
A fully configured tracker block in.conductor/state.json looks like this:
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)
Forjira, 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
statusIntentsemantic target on each status change - Link parent and child tracker issues for parent epics that have children
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:
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:
/pm:sync, your agent runs:
gh issue list --repo <repo> --state open --json number,title,url,labels- 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. - Register new issues:
add-epic --status untriaged --external-id <number> --external-url <url> --lane claude-code --priority P2— unless the issue carries aP0/P1/P2/P3label, in which case use that priority instead.
What the TRACKER SYNC briefing line means
The briefing’sTRACKER 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.
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.