|
| 1 | +--- |
| 2 | +name: sdlc:create-issue |
| 3 | +description: Use when creating a GitHub issue from a brief -- bug, feature, epic, or spike -- against the repo's GitHub issue templates via gh CLI. |
| 4 | +--- |
| 5 | + |
| 6 | +# /sdlc:create-issue |
| 7 | + |
| 8 | +Create a well-structured GitHub issue using the repo's own templates and `gh` CLI. |
| 9 | + |
| 10 | +**Core principle:** Templates own the format. Skill owns the behavior. A human has to read this -- keep it short. |
| 11 | + |
| 12 | +## Core Pattern |
| 13 | + |
| 14 | +1. **Classify** -- Determine type from the brief: bug / feature / epic / spike. |
| 15 | +2. **Read** -- Load `.github/ISSUE_TEMPLATE/<type>.yml`. Extract all fields, required vs optional, and labels. Do this every time -- never reconstruct from memory. |
| 16 | +3. **Draft** -- Fill every required field from the brief, inside the body budget. Sections follow template field order using `label` as heading. |
| 17 | +4. **Ask** -- One batched `AskUserQuestion` round, only for what the brief cannot answer. |
| 18 | +5. **Confirm** -- Show the full draft including labels. Everything is editable here. Wait for explicit approval. |
| 19 | +6. **Create** -- Write body to temp file, run `gh issue create` with all labels, report the URL. |
| 20 | + |
| 21 | +## Body Budget |
| 22 | + |
| 23 | +The reader is a person triaging a backlog. Optimise for their time, not for completeness. |
| 24 | + |
| 25 | +| Rule | Limit | |
| 26 | +|------|-------| |
| 27 | +| Prose (every paragraph in the body, combined) | 150 words target, **200 words hard cap** | |
| 28 | +| Any list item | one ultra brief line, no sub-bullets, no trailing period | |
| 29 | + |
| 30 | +The word limit above is a hard cap, not a guideline. A body that exceeds it is not ready to post. |
| 31 | + |
| 32 | +- One idea per section. If two sections say the same thing, cut one. |
| 33 | +- No preamble, no restating the title, no "this issue tracks...". Start with the fact. |
| 34 | +- Omit optional fields entirely rather than filling them with `N/A` or filler. |
| 35 | +- Over the hard cap means delete content, never compress it into one long sentence. |
| 36 | +- Steps and criteria are for a human to execute: numbered, imperative, one ultra brief line each, no assumed context. |
| 37 | + |
| 38 | +## Writing Style |
| 39 | + |
| 40 | +Avoid dense technical writing. Use clear, concise, and non-redundant prose. Examples: Simple English Wikipedia, Mr. Rogers, Ernest Hemingway. |
| 41 | + |
| 42 | +Banned vocabulary: do not invent abbreviations, compound labels, framework names, or domain terms. |
| 43 | + |
| 44 | +List of usual words to avoid: |
| 45 | + |
| 46 | +- load-bearing |
| 47 | +- blast radius |
| 48 | +- footgun |
| 49 | +- yak shaving |
| 50 | +- belt-and-suspenders |
| 51 | +- smoking gun |
| 52 | +- spine |
| 53 | +- seams |
| 54 | +- gate |
| 55 | +- substrate |
| 56 | + |
| 57 | +If writing documentation pay special attention to use words a maintainer would search for in the codebase. |
| 58 | + |
| 59 | +If something can be made a list, make it a list. It's easier to read. Prefer avoiding walls of text. |
| 60 | + |
| 61 | +## Step 1: Classify |
| 62 | + |
| 63 | +| Signal | Type | |
| 64 | +|--------|------| |
| 65 | +| Something works incorrectly today | Bug | |
| 66 | +| New capability or improvement to existing behavior | Feature | |
| 67 | +| Needs several PRs or several deliverables | Epic | |
| 68 | +| A question to answer, no code shipped | Spike | |
| 69 | + |
| 70 | +Decide from the brief. Only ask when two types are genuinely defensible, and batch it with Step 4. |
| 71 | + |
| 72 | +## Step 2: Template Map |
| 73 | + |
| 74 | +| Type | File | Type label | Additional labels | |
| 75 | +|---------|-----------------|---------------|---------------------------| |
| 76 | +| Bug | `1-bug.yml` | `bug` | `priority: <level>` | |
| 77 | +| Feature | `2-feature.yml` | `enhancement` | `priority: <level>` | |
| 78 | +| Epic | `3-epic.yml` | `epic` | `priority: <level>` | |
| 79 | +| Spike | `4-spike.yml` | `spike` | -- | |
| 80 | + |
| 81 | +## Step 3: Draft |
| 82 | + |
| 83 | +### Title |
| 84 | + |
| 85 | +Natural language, sentence case (code terms and command names keep their canonical casing). No conventional commit prefixes, no scope tags. |
| 86 | + |
| 87 | +Conventional commit format (`type(scope): subject`) is for **commits and PR titles only**. Issue titles appear in GitHub's issue list and must be scannable at a glance. |
| 88 | + |
| 89 | +**Good:** |
| 90 | +- `Issue skill defaults to conventional commit format for titles` |
| 91 | +- `mktemp fails with .md suffix` |
| 92 | +- `Add natural language title guidance to issue skill` |
| 93 | + |
| 94 | +**Bad:** |
| 95 | +- `fix(skills): mktemp fails with .md suffix` |
| 96 | +- `fix: issue skill defaults to conventional commit format` |
| 97 | +- `feat(issue): add title guidance` |
| 98 | + |
| 99 | +Rule: if a reader has to mentally strip a prefix to understand the title, the title is wrong. |
| 100 | + |
| 101 | +### Body |
| 102 | + |
| 103 | +Required fields are the floor. Include an optional field only when the brief already supplies its content -- never to look thorough. |
| 104 | + |
| 105 | +| Field kind | How to draft it | |
| 106 | +|------------|-----------------| |
| 107 | +| Description / problem statement | 1-3 sentences on what is wrong or missing, and for whom | |
| 108 | +| Steps to reproduce | Numbered, one ultra brief line each, starting from a clean state; last step is the failure | |
| 109 | +| Expected vs actual | One line each | |
| 110 | +| Acceptance criteria | One ultra brief checkbox each, independently testable | |
| 111 | +| Scope (epics) | Two bullet lists, in scope and out of scope, one ultra brief line each | |
| 112 | +| Issue breakdown (epics) | One line per future issue, unchecked | |
| 113 | +| Investigation approach (spikes) | Numbered steps the investigator follows | |
| 114 | + |
| 115 | +Never invent specifics the brief did not provide: no fabricated version numbers, error strings, file paths, or timelines. A field with no basis in the brief is either omitted (optional) or asked about (required). |
| 116 | + |
| 117 | +## Step 4: Ask |
| 118 | + |
| 119 | +One batched round. Include only the questions that survive the filter: |
| 120 | + |
| 121 | +| Question | Ask when | Options | |
| 122 | +|----------|----------|---------| |
| 123 | +| Issue type? | Two types are genuinely defensible | The candidate types, most likely first | |
| 124 | +| Priority? | Always for bug / feature / epic; never for spike | Critical / High / Medium / Low, with the level inferred from the brief pre-selected | |
| 125 | +| Time-box? | Spike, and the brief implies no duration | 2 hours / Half day / 1 day / 2 days / 3 days | |
| 126 | +| `<required field>` | The brief gives no basis for it at all | 2-3 drafted candidates + Other | |
| 127 | + |
| 128 | +**The filter:** never ask what the brief already answers, and never ask what the user could fix just as fast in Step 5. The draft is the question. |
| 129 | + |
| 130 | +Priority is applied as a label, not a form dropdown -- the body carries no Priority heading. See the Label Conventions section in `CLAUDE.md` for the full table. |
| 131 | + |
| 132 | +## Step 5: Confirm |
| 133 | + |
| 134 | +Show the title, the complete body, and every label. Report the prose word count when it exceeds 150. Accept edits to any section. Loop until approved. |
| 135 | + |
| 136 | +## Step 6: Create |
| 137 | + |
| 138 | +```bash |
| 139 | +BODY_FILE=$(mktemp /tmp/gh_issue_body_XXXXXX) |
| 140 | + |
| 141 | +cat > "$BODY_FILE" << 'EOF' |
| 142 | +<body> |
| 143 | +EOF |
| 144 | + |
| 145 | +gh issue create \ |
| 146 | + --title "<title>" \ |
| 147 | + --label "<type-label>" \ |
| 148 | + --label "<priority-label>" \ |
| 149 | + --body-file "$BODY_FILE" |
| 150 | +``` |
| 151 | + |
| 152 | +**Spike exception:** omit the `--label "<priority-label>"` line -- spikes carry only the `spike` type label. |
| 153 | + |
| 154 | +Multiple `--label` flags can be chained. The type label is always present. The priority label is added for bugs, features, and epics. |
| 155 | + |
| 156 | +Optional flags: `--assignee "<username>"`, `--milestone "<name>"`, `--project "<name>"` |
| 157 | + |
| 158 | +## Common Mistakes |
| 159 | + |
| 160 | +- **Skipping the template read** -- field names and order come from the YAML, not assumptions. Read it every time. |
| 161 | +- **Interviewing field by field** -- draft first, then ask one batched round for what is genuinely missing. |
| 162 | +- **Pre-emptively filling optional fields** -- an empty optional field costs the reader nothing; a padded one costs them time. |
| 163 | +- **Blowing the word budget** -- 200 words of prose is a hard cap, not a target to fill. |
| 164 | +- **Reproduction steps that are not steps** -- "it fails when saving" is not reproducible. Write what the reader types and clicks. |
| 165 | +- **Acceptance criteria that are not testable** -- "works well" cannot be checked off. |
| 166 | +- **Creating before confirmation** -- never run `gh` without explicit approval. Always show the full draft first. |
| 167 | +- **Omitting priority labels** -- form dropdowns do not survive `gh` CLI creation. Always apply these as labels. |
0 commit comments