| name | pm-templates |
| description | Use this skill when creating, editing, or removing **issue** templates (bug / feature / task / spike), resolving which template applies to a given issue type tag, customizing the issue-template registry for a project, or when another pm-* skill needs the body of an issue template. **For project-type templates** (feature-epic / migration / research-track / integration), use `pm-project-templates` instead. Trigger phrases "issue template", "template for a bug", "list issue templates", "add an issue template", "edit the bug template", "remove the X template", "what sections should bugs have", "what issue template should I use", "register a new issue type", or when pm-issues / pm-review / pm-improve need a template body. Also use proactively when the user describes a bug / feature / task / spike and the matching tag has no template registered. Tag-keyed registry; in-repo `.claude/pm/templates/` is canonical, plugin defaults are the fallback. |
| version | 0.44.4 |
PM Templates
Issue templates indexed by type tag. One canonical template per tag. Every other PM skill that touches issue bodies (pm-issues, pm-review, pm-improve, pm-agent) resolves through this registry — so when you change a template, every downstream skill picks it up.
Why a registry
The old pm-issues skill hard-coded Bug / Feature / Task as inline markdown. That made the templates invisible to the reviewer (it had nothing to validate against) and impossible to extend without forking the skill. Putting them in a registry means:
- Reviewer compares the issue body against the template for the issue's tag and flags missing sections.
- Projects can override a single tag (
feature.md) without touching the rest.
- Adding a new type (e.g.
spike, refactor, chore) is a one-file change, not a skill edit.
Where templates live
Two layers — repo first, plugin defaults as fallback. The PM config principle is "all config in one place" (<repo>/.claude/pm/); a per-machine template overlay would split the config dir, so v0.20.0 drops it.
<repo-root>/.claude/pm/templates/ ← canonical, checked into git
├── _manifest.json
├── bug.md
├── feature.md
├── task.md
└── spike.md # any tag the project uses
| Layer | Path | When it applies |
|---|
| 1. In-repo (canonical) | <repo-root>/.claude/pm/templates/<tag>.md | Project has opted into customization (/pm-setup initializes this) |
| 2. Plugin defaults | ${CLAUDE_PLUGIN_ROOT}/skills/pm-templates/templates/<tag>.md | Bundled starters — applied when the in-repo file doesn't exist |
First file that exists wins. Never merge bodies across layers.
If an operator wants a one-off personal tweak that they don't want to commit, they edit the in-repo file and leave it uncommitted (or stash it). v0.20.0 deliberately doesn't offer a "user overlay" file location — the result is fewer places to look, less confusion about which file is authoritative.
The manifest
The manifest at <repo-root>/.claude/pm/templates/_manifest.json defines:
- which tags this project recognizes
- what each tag means
- which
## Section headings are required vs optional per tag (the reviewer reads the same file)
- the tracker labels that map to each tag
The in-repo manifest fully replaces the plugin manifest if present — projects can drop tags they don't use and add tags the plugin doesn't ship with. Lookup order for the manifest:
<repo-root>/.claude/pm/templates/_manifest.json (if present, authoritative)
${CLAUDE_PLUGIN_ROOT}/skills/pm-templates/templates/_manifest.json (plugin defaults)
This means a project that wants only bug and feature can ship a 2-tag manifest, and pm-review will refuse to classify anything as task or spike for that project — taxonomy drift is structurally prevented.
Why replacement, not overlay. Most config systems merge — but merging is wrong here. If a project intentionally drops a tag (say, removes spike because they never run time-boxed investigations), an overlay would re-introduce it the next time the plugin updates and adds a new tag the project wants. Worse, the operator can't tell which tags came from where, so deciding "is this in my taxonomy?" requires reading two files and reconciling. Replacement keeps the rule simple: the in-repo manifest is the project's taxonomy, full stop. The plugin defaults are a starter, not a floor.
Workflow
Resolve a template body
When another skill asks "give me the bug template":
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
TAG=bug
for path in \
"${REPO_ROOT}/.claude/pm/templates/${TAG}.md" \
"${CLAUDE_PLUGIN_ROOT}/skills/pm-templates/templates/${TAG}.md"
do
if [ -f "$path" ]; then
echo "$path"; break
fi
done
First hit wins. If no file matches and the tag isn't in the active manifest, the tag is unknown — report it and offer to register one (next section). Do not silently fall back to a generic template; that hides taxonomy drift.
Resolve the manifest
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
REPO_MANIFEST="${REPO_ROOT}/.claude/pm/templates/_manifest.json"
PLUGIN_MANIFEST="${CLAUDE_PLUGIN_ROOT}/skills/pm-templates/templates/_manifest.json"
if [ -f "$REPO_MANIFEST" ]; then
cat "$REPO_MANIFEST"
else
cat "$PLUGIN_MANIFEST"
fi
The in-repo manifest is replacement, not overlay — see "The manifest" section above for why.
List available tags
Read the active manifest (resolved as above). tags is an array of { tag, description, required_sections, optional_sections, priority_hint?, hitl_default_hint?, labels? }. Show a one-line summary per tag when asked "what templates are available?".
The hitl_default_hint field
Optional per-tag string: "hitl" or "afk". Indicates the default execution mode for issues of this tag — whether the work typically needs a human-in-the-loop (hitl) or can run away-from-keyboard by an agent (afk).
This is a hint, not a requirement. When pm-issues drafts an issue of a given tag, it pre-fills the HITL/AFK label with this hint, and the operator confirms or overrides during create. The labels themselves (hitl and afk) are tracker-level — the manifest just suggests which one fits this category of work.
Sensible defaults:
- bug →
hitl — bugs usually need a human to verify the fix worked
- feature →
hitl — design decisions and acceptance-criteria validation belong with a human
- task →
afk — refactors, cleanups, and infra work are often agent-completable end-to-end
- spike →
hitl — the outcome of a spike is a decision, which is a human's call
If a tag has no hitl_default_hint, pm-issues asks the operator without a pre-fill.
Classify an issue's tag
Given a user description like "the login button crashes when..." or an existing issue body:
- Read the active manifest.
- Look for explicit signals first — a leading
[bug] / [feature] prefix, a Linear/GitHub label that matches an entry's labels.<tracker> array, or the user saying "this is a feature."
- Otherwise, match against each tag's
description field and propose the best fit. Confirm before treating it as classified — do not silently pick one.
The reviewer skill (pm-review) uses this classifier too; keep the logic here so both skills agree.
Modifying templates — guided workflows
When the user wants to add, edit, or remove a template, your job is to guide them through the design decisions — not just point at files and call it done. Walk one question at a time, surface the trade-offs, show a diff before writing. New users get the full walkthrough; after two or three rounds they know the routine and you can drop the coaching.
The three flows below cover every modification. Each one is a sequence of decisions, not a single command.
Adding a new tag
Triggered by phrases like "add a template for migrations", "we need a tag for X", "can you register a new issue type". Walk the user through 9 steps in order.
Step 0 — Make sure the project has an in-repo manifest. (First-time customizers only.)
Before anything else, check whether <repo>/.claude/pm/templates/_manifest.json exists.
-
If it exists: skip to Step 1; the project is already set up for customization.
-
If it doesn't: the project is currently running on plugin defaults, and adding a tag means committing to the in-repo layout. Bootstrap by copying the plugin manifest as a starting point — it gives the project the default 4-tag taxonomy as the floor, which the operator can then trim or extend:
mkdir -p <repo-root>/.claude/pm/templates
cp "${CLAUDE_PLUGIN_ROOT}/skills/pm-templates/templates/_manifest.json" \
<repo-root>/.claude/pm/templates/_manifest.json
Also copy any default template bodies the project will use (bug.md, feature.md, etc.) so the in-repo manifest's tag set has matching bodies on disk. Tell the operator what just happened: "You didn't have an in-repo manifest yet, so I bootstrapped one from plugin defaults. Edit .claude/pm/templates/_manifest.json to trim tags you don't use, then we'll add your new one." Then proceed to Step 1.
This precondition catches the most common stall point: first-time customizers hit Step 1-7 of design before realizing the file they're editing doesn't exist yet.
Step 1 — Check for overlap with what's already there.
Read the active manifest first and show the user the current tag list with descriptions. Then reframe: "We already have these N tags. Would your new category fold into one of them, or is it genuinely distinct?" Most "new tag" requests collapse into an existing tag once the user sees what's there — that's a win, not a failure. Taxonomy stays tight.
Step 2 — Pick the slug.
Coach:
- Lowercase, hyphen-separated, no spaces (
migration, plugin-new ✓; migration_required ✗; Migration ✗)
- One concept per tag (
docs ✓; release-and-publish ✗ — split into release and publish)
- Doesn't collide with an existing tag in the manifest
Step 3 — Pick required_sections. This is the most consequential decision.
- Aim for 2-4 required sections. Five-plus turns the template into a form. One-or-fewer means the template adds no shape. Three is the sweet spot.
- Each required section should answer a question that's specific to this category and easy to skip.
What's Broken for bugs is good — it forces a one-sentence problem statement before anyone reaches for "let me investigate." Description is bad — too generic, lets weak issues through.
- Headings should be short concrete noun phrases.
Time box beats Time-boxing the investigation. The reviewer literally greps for the heading, so consistency and brevity matter more than prose.
Step 4 — Pick optional_sections.
Scaffolded into the template body but not enforced by the reviewer. Use for content that's situationally useful but not universally needed (Rollback plan for some tasks, Workaround for some bugs, Open questions for most kinds).
Step 5 — Pick labels.<tracker> aliases.
For each tracker the project uses (Linear, GitHub, both), list the labels that actually exist in that tracker today and map to this tag. The reviewer round-trips through these when classifying by label. Don't invent new labels here — only register ones the tracker already has, or create them in the tracker first (then come back and add the alias). A label that's in the manifest but not the tracker matches nothing.
Step 6 — Pick priority_hint.
Default priority when issues of this tag get created: 1=urgent, 2=high, 3=normal, 4=low. Operators can override per-issue; this is just the starting point. Pick what fits the typical case for this tag — bug defaults high because most bugs are urgent-ish; docs defaults low because doc work rarely blocks releases.
Step 7 — Write the template body.
Markdown with ## <Section> headings exactly matching required_sections + optional_sections (the reviewer greps for an exact match). Under each heading, include bracketed placeholder text — [One sentence: what fails and the user impact]. The reviewer treats unmodified placeholders as "not filled", which is load-bearing for the validation flow.
Save to <repo>/.claude/pm/templates/<tag>.md.
Step 8 — Add the manifest entry.
Edit <repo>/.claude/pm/templates/_manifest.json and append the new tag entry:
{
"tag": "<slug-from-step-2>",
"description": "<one-sentence description from step 1>",
"required_sections": [],
"optional_sections": [],
"priority_hint": ,
"labels": {
"linear": [],
"github": []
}
}
(If _manifest.json doesn't exist yet, you should have caught that in Step 0 and bootstrapped — Step 8 expects the file to be there. If it's still missing here, go back to Step 0.)
Step 9 — Show the result.
List the active tags after addition so the user sees that the registry recognizes the new one. Optionally cat the rendered template body so they can confirm the headings match.
Editing an existing tag
Triggered by "edit the bug template", "change the bug acceptance criteria", "make feature require Non-Goals". Clarify which side they're editing — body or manifest — because the files have different consequences.
Body edits (<repo>/.claude/pm/templates/<tag>.md): change the markdown the operator sees when filing a new issue. Existing issues already filed under this tag are not updated — only future ones see the new shape. The reviewer applies the new shape on the next review.
Manifest edits (<repo>/.claude/pm/templates/_manifest.json): change the contract. Each kind of change has a different blast radius — coach the user before they commit:
| Change | Effect on existing issues | When it's safe |
|---|
| Add a required section | Existing issues fail the next review until backfilled | Only when you want to force a backfill. Safer: add as optional first, promote to required later. |
| Remove a required section | No-op for existing; future ones won't be flagged | Safe — use freely. |
| Add an optional section | No-op until next body-template update scaffolds it | Safe. |
Change description | Affects classification of NEW issues only | Safe — clarification is cheap. |
Change labels.<tracker> | Reviewer re-classifies issues with old/new labels on next run | Safe IF the tracker's labels match the new aliases. |
Change priority_hint | New issues get the new default | Cheap. |
Always show a diff before writing the file. Manifest edits land in git and ripple through every future review.
Removing a tag
Triggered by "we don't use spikes", "drop task", "remove the X template".
Step 1 — Check for orphans. Query the tracker for open issues currently classified under this tag (by labels.<tracker> match). If any exist, surface them and ask: "These N issues are currently tagged <tag>. If you remove the tag, the reviewer will fail to classify them. Re-tag them under another category first, or remove now and clean up?" Don't proceed silently — orphans are how taxonomies decay.
Step 2 — Remove the manifest entry. Delete the object from _manifest.json's tags array.
Step 3 — Decide on the body file. Either delete <repo>/.claude/pm/templates/<tag>.md or leave it as a soft-deprecation reference (a paper trail of what the tag used to mean). The manifest is authoritative — without the entry, the body file is invisible to the rest of the plugin regardless of whether it sits on disk.
Design principles for good templates
Use these to evaluate proposals — both yours and the user's — when the call is unclear.
What makes a useful tag:
- Maps to a recognizable, recurring category of work — not "things I find annoying this week"
- The required sections force the operator to write down what's hardest to remember (acceptance criteria, reproduction steps, success conditions, time bounds)
- The label aliases match what the tracker actually has on disk today
What makes a useful required section:
- It has a specific answer the operator can give in one sentence or three bullet points
- A reviewer can tell at a glance whether it's filled — not "is this comprehensive enough?", just "is there content beyond placeholder?"
- The heading is short and concrete — avoid
Description, Details, More info, Notes
What makes a useful optional section:
- It captures content that's helpful when present but reasonable to omit
- Don't add it just because it sounds nice — every section is a small tax on the issue author. If 80% of issues would leave it blank, it doesn't belong
What this skill does NOT do
- It does not create or modify issues. That's
pm-issues.
- It does not post review comments. That's
pm-review.
- It does not enrich issue bodies with research. That's
pm-improve.
- It is a registry — body content + lookup + manifest, nothing more.