PRD Skill - Create Agent-Friendly Tickets
You are an expert at breaking down features into well-structured, agent-friendly Linear tickets.
When to Use
Use this skill when:
- Planning a new feature
- Breaking down a large task into sub-issues
- Creating tickets that AI agents will implement
Process
-
Understand the Request
- Ask clarifying questions if the scope is unclear
- Identify the core problem being solved
-
Create the Epic/Parent Issue Give it a clear, action-oriented title and a body following the canonical spec template in standards/issue-spec.md — problem, desired outcome, requirements (must-have vs nice-to-have), testable success criteria, boundaries.
Create it through
~/.claude/scripts/linear-create-child.shwith-for the parent (top-level), never a barelinear-cli issues create. A bare create passes no workflow state, and on a triage-enabled team the team default is Triage — wherenext-candidates.sh'sWORKABLE_STATES(Backlog/Planned/Todo) cannot see it, so a certified epic is invisible to/nextand/autowith nothing reporting the omission. The helper resolves a workable state and verifies it landed.On a run that will create sub-issues, pass the workspace
epiclabel in the helper's label slot — the parent is a delegated epic whose work its children carry, and certification (Step 5) leaves that slot free on batch runs. Neither the epic nor its sub-issues carries a routing label at create on such a run, so each create passes the leading--allow-unrouted: the helper refuses a label slot with no routing label otherwise, and the flag records that Step 5 certifies. A single-issue run is not an epic: noepiclabel, its slot carriesspecifiedper Step 5, and it needs no flag. -
Break Down into Sub-Issues Each sub-issue body is itself a spec (same template) and should:
- Be completable in one focused session (<150k tokens of context)
- Have clear success criteria stated as observable outcomes
- Define boundaries (what's in/out of scope — deliverable exclusions, not mechanism guesses; a mechanism-exclusion only records containment the human in this conversation chose, marked
(decided: <who/why>)— standards/issue-spec.md § Out of Scope bounds the deliverable, never the evidence) - Be executable by exactly one kind of worker: an unattended agent (a repo-shaped deliverable whose success criteria the project's quality gates can verify) or a human (outreach, ops, confirmation passes — labeled
humanat Step 5). Never bundle both: an issue that fuses a fully-specified schema to a confirmation pass the plan itself calls human-in-the-loop work is declined whole by/auto, and the shippable slice sits idle. When a flow needs both, split at the handoff and wire the edge by what the downstream step does without the human's:blockswhere it would be wrong (confirm → enforce — enforcing an unconfirmed registry acts on data nobody vetted),relatedwhere it merely waits (build → confirm) — thehumancarve-out in standards/issue-spec.md § Certification includes collision edges. - Depend on no unstated mapping or unenumerated scope: "the appropriate owner" and "everywhere transactions name an organization" are decisions wearing requirement clothes, and
/autodeclines them — enumerate or decide them in this conversation, before the issue exists; criteria that assert production state no test suite can verify belong on ahumanissue, not an agent one.
-
Set Up Dependencies Use
linear-cli relations add <BLOCKER> <BLOCKED> -r blocksto create dependency chains (see Example Commands).Then wire each chain-tail sub-issue as a blocker of the parent epic —
relations add <SUB> <PARENT> -r blocksfor every sub-issue nothing else in the batch depends on (the rest reach the parent transitively, so more edges would be the redundant A→C Step 5's doctrine forbids). An epic's requirements are pointers at its sub-issues, andnext-candidates.sh's delegated de-rank fires only once NO child is workable — the end of an epic's life, not its start — so an unwired epic ranks alongside its own open children at full priority and a session that picks it finds nothing to implement. Wired this way the epic surfaces exactly once: after every sub-issue ships, annotated as likely needing closure. -
Certify First run a collision pass over the batch — every producer attaching
specifiedowes one at attach time (standards/issue-spec.md § Certification includes collision edges). Run the Discovering Related Work searches (the section below) now if they have not been run this session, then check each new issue against its siblings and against the open issues those searches surfaced, at the granularity this skill has: component and feature decomposition, never files, since /prd reads no code.blocksonly where the pair is a prerequisite, a same-method collision, or a deliberate increment (the three meanings — standards/issue-spec.md § Certification includes collision edges); at this skill's granularity that is nearly always the prerequisite, one sub-issue building on what another delivers. A pair merely sharing a component, and so likely files, takesrelatedplus a comment. So does a prerequisite whose open collider is uncertified,needs decision,solo, orhuman— an issue in that state never ships unattended, and ablocksedge behind it strands the new issue invisibly — except ahumanact the new issue would be wrong without, which blocks it on purpose (the standard'shumancarve-out; sibling-vs-sibling edges within the batch are unaffected, since every sibling certifies together at this same step); disjoint areas sharing a mechanism →relatedplus a comment naming the mechanism; no overlap → nothing. Edges step 4 already wired count as resolved here — this pass covers colliding pairs step 4 left unserialized, and never duplicates or reverses a chain edge step 4 already set.Then apply the
specifiedlabel to every created issue — parent and each sub-issue:~/.claude/scripts/linear-add-label.sh ENG-100 specifiedspecifiedmarks a certified spec — the gate/autopicks up (standards/issue-spec.md). Label post-create rather than viaissues create -l, so a label problem can never fail issue creation. On exit 2, surface the helper's create-label pointer and tell the user certification is incomplete.One class of sub-issue certifies gated: work only a human can perform — customer outreach, vendor contact, production data remediation, a confirmation pass the body itself assigns to a person. The quality bar tests spec shape, not agent capability, so these pass it and then sit rankable in the certified pool until a fleet session picks one and declines it. Attach
humanalongsidespecifiedhere, naming the owner when known — the spec is right, the executor is a person (standards/issue-spec.md);needs decisionis the wrong gate for these, since it advertises a pending decision that would hand the issue back to agents./auto-prepStep 2 applies the identical disposition later, but only after the issue has already spent time rankable.A second class certifies cheap: a sub-issue meeting the
simplesemantics (standards/issue-spec.md § Thesimplelabel — risk-low, no open decision) additionally takessimple, which selects/quality-review's lighter tier when a run ships it. Apply it from the decomposition's own reading — a schema-description fix, a locale consolidation, a dead-code deletion — never on asecurity,human,needs decision, orepicsub-issue;/auto-prepre-audits both directions later.linear-create-child.sh's optional label argument already attaches post-create with those same best-effort semantics (id on stdout either way, exit 2 when the attach fails), so passingspecifiedthere satisfies this step on a single-issue run only — a run that creates exactly one issue total (an epic with no sub-issues) and so may certify on create; a run creating two or more issues (epic + sub-issues) is a batch and certifies here, at Step 5, after the collision pass. A single-issue run still owes the collision pass — run it (the Discovering Related Work search against open issues; the sibling-vs-sibling half is vacuous with no siblings) immediately after the create that certified it, wiring edges per the same calibration above. This is the accepted attach-then-wire residual window that standards/issue-spec.md § Certification includes collision edges describes, not a gap. When the run creates several issues (an epic with sub-issues), passepicfor the label at create (Step 2) and certify here instead —specifiedis the pickability gate, so a fleet can pick a sub-issue seconds after it is created, before its siblings exist and before any edge is wired; sequencing has to be mechanical before the label attaches. Re-running the helper above on an issue that already carries it is idempotent — this step is the backstop, not a second mechanism.
Spec Shape
The canonical template and quality bar live in standards/issue-spec.md: Problem → Desired Outcome → Requirements (Must/Nice checkboxes) → Success Criteria (testable checkboxes) → Boundaries (In/Out of Scope). The Problem is a story — a named actor, what they saw, the stake in their units, then the mechanism, sized to the stake, with the measurements it does not carry under ## Evidence (that standard's § The Problem is a story); an epic's Problem leads with the named people its counts summarize.
Specs are problem + outcomes + success criteria only — no implementation planning (/start Step 6 designs the how, in plan mode, at execution time) and no verification-command blocks (project quality gates own that). Checkboxes are load-bearing: /start treats them as requirements and /finish checks them off.
Example Commands
# Create the top-level epic — `-` as the parent means no parent. Same helper as the
# sub-issue below: it resolves and verifies the workflow state, so the epic cannot land
# in Triage and fall out of /next's WORKABLE_STATES unnoticed. `epic` in the label slot:
# this run creates a batch, so the parent is a delegated epic and certification waits for
# step 5, after the collision edges are wired. A single-issue run passes `specified` in
# that position instead (a standalone issue is not an epic) and drops --allow-unrouted,
# which a batch create needs because its routing label arrives at step 5.
# ...write the description to tmp/prd-description.md via the Write tool...
~/.claude/scripts/linear-create-child.sh --allow-planned --allow-unrouted - ENG Planned "User Authentication System" tmp/prd-description.md epic 2
# Create a sub-issue linked to a parent. `linear-cli issues create` has no --parent
# flag (set the parent's UUID via `--data` parentId instead), but prefer the helper — it
# links via `relations parent` and verifies the link, failing on an orphan. Write the body to a file first.
# ...write the description to tmp/sub-issue-description.md via the Write tool...
~/.claude/scripts/linear-create-child.sh --allow-planned --allow-unrouted ENG-100 ENG Planned "Add JWT refresh tokens" tmp/sub-issue-description.md
# Set a blocking dependency: ENG-101 blocks ENG-102 (i.e. ENG-102 is blocked by ENG-101).
# Use `-r blocks` with the blocker FIRST — `-r blocked-by` 400s (linear skill gotcha #10).
linear-cli relations add ENG-101 ENG-102 -r blocks
# Certify each created issue (read-merge-set — `issues update -l` alone would replace the label set)
~/.claude/scripts/linear-add-label.sh ENG-100 specified
~/.claude/scripts/linear-add-label.sh ENG-101 specified
Body text longer than one line goes to tmp/ and in through ~/.claude/scripts/linear-stdin.sh, never via <, cat |, $() or a heredoc into linear-cli — permission wildcards do not match through shell operators (standards/linear-workflow.md § Passing File Content to Linear CLI). Piping linear-cli output to jq is fine.
Discovering Related Work
Before creating tickets, search for existing related work:
# Find existing work on this topic. NOTE: `search issues` has no --team flag — it
# searches the whole workspace. Scope by team with `issues list --team ENG` or the api.
linear-cli search issues "authentication"
# Look for related work / potential blockers, then inspect dependencies via the graph
linear-cli search issues "user database"
~/.claude/scripts/linear-deps-graph.sh --team ENG # {nodes, edges} — filter with jq (linear skill gotcha #2); blocked chains: scripts/fleet-blockers.sh
Pro tip: After creating tickets, establish dependencies directly with linear-cli relations add <BLOCKER> <BLOCKED> -r blocks (blocker first; -r blocked-by 400s — linear skill gotcha #10).
Best Practices
- Size tickets appropriately - Each should be 1-4 hours of focused work
- State success criteria as observable outcomes - Verification commands and technical approach belong to
/start, not the ticket - Be explicit about scope - Prevent scope creep with clear boundaries
- Certify every ticket - Process step 5 applies the
specifiedlabel;/autoonly ships certified issues - Establish dependencies - Use
linear-cli relations add <BLOCKER> <BLOCKED> -r blocksto show work order - Search first - Check for existing related issues before creating duplicates