| name | pm-prep |
| description | Use this skill to prepare an existing hitl (human-in-the-loop) issue for autonomous execution and promote it to afk — interactively resolving the human-judgment gaps (design decisions, ambiguous file targets, untestable acceptance criteria), writing the resolved answers into the issue body, and retagging hitl→afk once it clears an explicit readiness bar. It is the bridge between pm-triage (which assigns the hitl/afk label) and the autonomous pm-issue-to-pr pipeline (which only works the afk backlog). Trigger when the user says "prep this issue", "prep the hitl backlog", "make FUNC-12 afk-ready", "promote this to afk", "/pm-prep", or whenever an already-hitl issue needs to be specified well enough to run unattended; also proactively before handing a hitl issue to pm-issue-to-pr. NOT for classifying a brand-new issue as hitl vs afk at creation (that is pm-triage), and NOT for issues already labeled afk (nothing to promote). |
| version | 0.44.4 |
PM Prep
Take a hitl issue — one that needs a human at the wheel — sit with the operator long enough to resolve what needs the human, write those resolutions into the issue body, and once the issue is specified well enough to run unattended, promote it hitl → afk.
Usage
/pm-prep [<issue-id>]
<issue-id> (issue key, optional) — the hitl issue to prepare, e.g. FUNC-12 (Linear) or #42 (GitHub). Omit to discover the whole hitl backlog and walk it one issue at a time.
No flags. The two writes — the body edit, then the hitl→afk retag — are each confirmed interactively; nothing is written without approval.
Why this skill exists
The plugin already has the two ends of this pipeline:
pm-triage → ??? (the gap) → pm-issue-to-pr
(assigns hitl|afk (promote hitl→afk (autonomously works
at triage time) once it's ready) the afk backlog)
pm-triage labels an issue hitl when it needs design judgment, manual verification, or has gaps that block mechanical execution. pm-issue-to-pr only picks up afk issues, and bounces anything underspecified back to hitl with a comment. Nothing in between moves an issue across that line. That promotion has always been a manual judgment the operator makes in their head and applies with a label.
The thing that actually makes an issue afk-ready is content in the body: filled-in sections, testable acceptance criteria, pinned-down file targets, a chosen design path. And no existing skill writes to the body — pm-review scores it, pm-improve drafts questions as a comment, pm-triage only labels. pm-prep fills exactly that gap: it's the interactive, body-editing, promotion-gated workflow that turns "a human needs to think about this" into "an agent can grind through this."
When NOT to use it
- The issue is already
afk — nothing to promote. (Offer pm-review if they want a structural check, or just hand it to pm-issue-to-pr.)
- The issue has no execution-mode label at all — that's a triage gap, not a prep job. Route to
pm-triage first; come back once it's labeled hitl.
- The operator only wants a review or only wants enrichment — that's
pm-review / pm-improve directly. pm-prep is the whole interactive promotion pass, not one slice.
The afk-readiness bar
This is the contract the whole skill turns on. An issue is afk-ready when an agent could pick it up cold and finish it without stopping to ask a human. Concretely, mirror what pm-issue-to-pr needs to call an issue "actionable":
-
Every required section is filled with real content — not a bracketed placeholder, TBD/TODO, an empty - [ ], or just the heading. (Required sections come from the issue's type tag in the templates manifest.)
-
Acceptance criteria are mechanically verifiable — each item names a behavior a test or a reviewer could check pass/fail. Vague verbs with no target ("improve performance", "clean up the UX", "handle edge cases") fail the bar. The test: would a tester know whether this passed?
-
File targets are unambiguous — if the work touches code, the issue points at the files/modules or describes them specifically enough that an agent isn't guessing which foo.js is meant.
-
The design path is chosen — no "we could do A or B, depends what we want." If there were forks needing a preference, the operator's choice is now written down.
-
No dependency on a human-only or inaccessible step — no "needs UX sign-off", "wait for the vendor", "verify on the physical device", "reconcile against the finance ledger" baked into the critical path. Watch for these disguised as verification steps: an acceptance criterion that reads like an automatable check ("confirm the output matches the records") but actually needs a human or a system the agent can't reach is still a human gate.
-
The premise holds against the code — if the issue asserts a cause ("the filter isn't escaped", "there's no retry logic", "the function ignores X"), check it against the actual source before writing acceptance criteria around it. This is the highest-leverage check on the whole list, because a confident-but-wrong premise is the most dangerous thing you can hand an autonomous agent: it has no human to sanity-check it mid-run, so it will faithfully implement a fix for a bug that doesn't exist, or rebuild a feature that's already there. When the code contradicts the issue, that's a gap to resolve — not something to paper over by writing the issue's wrong assumption into the AC.
A false premise does not automatically mean "hold" — it means "decide based on whether an agent can still finish unattended":
- Reproducible + behavioral AC → promote (with the premise corrected). If the bug reproduces deterministically and you can write the acceptance criteria around the observable behavior ("delta-sync returns the project's real issue set for an apostrophe-containing name, asserted by a test") instead of the wrong mechanism, an agent can reproduce → diagnose → fix → verify on its own. Correct the premise in the body, frame the AC behaviorally, and it earns
afk.
- Can't be reproduced without a human → hold. If the real failure is intermittent, environment-specific, or nobody yet knows how to trigger it, then diagnosis itself is the human work — no behavioral AC can rescue it, because an agent can't even get to a red test. It stays
hitl until someone pins down a deterministic repro.
If all of these hold, the issue earns afk. If even one irreducibly needs a human at execution time, it stays hitl — and the skill says exactly which one and why. That honesty is the point: a wrongly-promoted issue wastes an autonomous run and lands a bad PR.
The prep pipeline (one issue)
Steps 1–6 are read-only and run without confirmation — they cost only tokens, and the operator needs the full picture before deciding. Steps 7–8 are the writes, each confirmed on its own.
Step 1: Fetch the issue (live)
Read it fresh from the tracker — the same fetch pm-review uses (linear issue view <ID> --json via the GraphQL helper / gh issue view <NUM> --repo <org/repo> --json ...). Never prep from cache: the cache can carry a stale body or label set, and every decision here hinges on the current content.
If the tracker is unreachable, stop with a transport error. Do not prep from stale state.
Step 2: Confirm it's a hitl issue
Check the labels:
- Has
hitl → continue.
- Has
afk already → nothing to promote. Tell the operator; offer a pm-review pass if they want to double-check it's actually ready.
- Has neither → this is a triage gap. Don't guess the mode. Route to
pm-triage and stop.
Step 3: Assess readiness — find the gaps
Run pm-review against the issue at its type tag. Capture which required sections are present / missing / placeholder-only, and whether the acceptance criteria are testable.
Then add the judgment layer pm-review deliberately won't: read the body and name what specifically requires a human — an unmade design decision, an ambiguous target, a verification that can't be automated. These are the items the interactive loop has to resolve. Hold them as the gap list.
Crucially, also check the issue's premise against the actual code here, while you have the repo open. If the issue claims a root cause or a missing capability, open the file it points at (or grep for it) and confirm the claim is true. A surprising amount of the time it isn't — the "unescaped filter" is already parameterized, the "missing retry" already exists, the "function that ignores X" already handles X. When the code contradicts the premise, that contradiction is itself a gap (often the most important one): surface it to the operator rather than dutifully writing the wrong assumption into the acceptance criteria, because that wrong assumption is exactly what an autonomous agent will run with.
Step 4: Draft the questions
Run pm-improve against the issue. Capture its clarifying questions and repo context (related files, recent commits, prior-art issues). These questions, plus the gap list from Step 3, are what you'll walk the operator through. Don't post the enrichment as a comment — pm-prep is going to fold the answers into the body instead, which is more durable than a comment thread.
Step 5: Resolve interactively — the human-in-the-loop part
This is where the human actually supplies the judgment. Walk the gaps and questions with the operator, grouped so it's a conversation, not an interrogation. Lead with the ones that block afk (a missing design decision, untestable AC) before nice-to-haves.
Use AskUserQuestion when a gap is a real fork with discrete options (which approach, which file, which behavior on an edge case) — give your recommended option first with a one-line reason, so the operator can confirm in one click. Use open prose questions when the answer is free-form (the actual acceptance criteria, repro steps).
The operator's answers are the raw material for the body. If an answer is itself vague ("make it faster"), push once: "faster than what, measured how?" — because a vague answer written into the body just relocates the gap, it doesn't close it.
Step 6: Draft the afk-ready body
Fold the answers into the issue body:
- Fill the empty/placeholder required sections with the resolved content.
- Rewrite vague acceptance criteria into testable ones, using the operator's answers.
- Pin the chosen design path and file targets where the body was ambiguous.
Preserve the operator's voice and structure — you're closing gaps, not rewriting their issue from scratch. Keep the existing headings and prose; add and sharpen, don't replace wholesale. Surprising someone with a reworded issue is the same anti-pattern pm-triage avoids; the difference here is the operator is in the loop and approves the result.
Step 7: Show the body diff and apply (write #1)
Show a before → after diff of the body (or the changed sections, if the body is long) and apply only on confirmation.
- Linear — there is no
pm-issue.js flag for the body, so write it through the GraphQL helper directly:
node -e "
const { runQuery } = require('\$CLAUDE_PLUGIN_ROOT/hooks/lib/linear-graphql.js');
const desc = require('fs').readFileSync('<path-to-new-body.md>','utf8');
runQuery('mutation(\$id:String!,\$d:String!){ issueUpdate(id:\$id, input:{description:\$d}){ success } }',
{ id: '<ISSUE_ID>', d: desc }, {})
.then(r => console.log(r.issueUpdate.success ? 'OK' : 'FAILED'))
.catch(e => { console.error('FAIL', e.code||e.message); process.exit(1); });
"
Write the new body to a temp file first and pass it in — avoids shell-escaping a multi-paragraph markdown body.
- GitHub —
gh issue edit <NUM> --repo <org/repo> --body-file <path-to-new-body.md>.
The body write is its own confirmation because the operator may want the gaps filled even if the issue isn't going to be promoted (Step 8 might gate it back to hitl).
Step 8: Re-check the bar, then promote or hold (write #2)
Re-evaluate the now-filled body against the afk-readiness bar.
The promotion is earned, never automatic. An afk label is a promise to the autonomous pipeline that no human is needed; honor it.
Batch mode — prepping the hitl backlog
With no specific issue named, discover the hitl backlog and walk it. Get the set from pm-status (it owns the triage/label computation — don't re-derive it), filtered to open issues carrying hitl. Show the operator the list with a one-line readiness estimate per issue (how far each looks from the bar), so they can pick where to spend time.
Then run the per-issue pipeline (Steps 1–8) one issue at a time — prep is inherently interactive, so unlike pm-triage's one-confirmation batch, each issue gets its own resolution conversation and its own two confirmations. Offer to skip issues that are far from ready (a fresh issue with three empty sections wants a pm-issues body draft first, not a prep pass). Track progress so the operator can stop after any issue and resume later.
What this skill does NOT do
- It does not assign the initial hitl/afk label — that's
pm-triage. pm-prep only promotes an existing hitl.
- It does not create or close issues — that's
pm-issues.
- It does not promote without the bar being met — the retag is gated on readiness, and it says why when it holds.
- It does not reimplement review or enrichment — it sequences
pm-review (gaps) and pm-improve (questions), and adds the two things they don't: interactive resolution and a body write. When they improve, pm-prep inherits it.
- It does not touch the body without showing a diff and getting confirmation — the operator's issue is theirs; prep proposes, the operator approves.
Where pm-prep sits
pm-triage → pm-prep → pm-issue-to-pr
(label hitl|afk) (resolve human judgment, fill the (autonomously work
body, promote hitl→afk when ready) the afk backlog)
When pm-prep holds an issue at hitl, the reason it gives is the operator's cue for what human step is still outstanding. When it promotes to afk, the issue is now a clean input for pm-issue-to-pr.