Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Create GitHub issues using repo templates (feature, bug, spike)
.claude/skills/nudgebee-create-github-issue/SKILL.md| Model | Eval pass | Runs |
|---|---|---|
| gemini-3.6-flash | 100% | 18 |
| gemini-3.1-pro-preview | 100% | 1 |
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 629% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 127% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 309% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 381% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 291% | 0% |
Create a GitHub issue using the repository's issue templates. Optional argument: $ARGUMENTS (issue type: feature, bug, or spike).
| Type | Template | Title Format | Labels | |------|----------|--------------|--------| | feature | FEATURE-REQUEST.yml | [REQUEST] - <title> | — | | bug | BUG-REPORT.yml | [BUG] - <title> | bug | | spike | SPIKE-REQUEST.yml | [REQUEST] - <title> | — |
Binding style contract: docs/writing-for-readers.md. Read it before drafting. The rules below are its issue-specific application; where they seem to disagree, that file wins.
Issues are read by a mixed audience: PMs, support, QA, and engineers. Most readers skim the title and the first paragraph before deciding whether to care. Write the top of every issue for that reader, not for the engineer who will eventually fix it.
Budget: the form fields above ## Technical Details total ≤ 200 words. Technical Details has no limit — over-budget prose gets demoted there, never trimmed to nothing. If the top of the issue does not fit one screen, it is not finished.
Two-layer structure for every issue:
## Technical Details. Code paths, error messages, commit SHAs, library names, struct fields, migration IDs, log fragments. This is for whoever picks up the work.Rules of thumb:
## Technical Details.None / N/A / Negligible under a heading — delete the heading instead.A good title names what is broken from the outside, not what the code is doing wrong inside.
Rule: if a non-engineer reading the title can't tell what the user notices, it's too technical.
Things that almost never belong in a title:
Before writing, answer for yourself:
Open the description with those three things in plain English. Then, only after that, you may say "Internally, the cause is…" with a one-sentence summary. Save the deep dive for ## Technical Details.
Reproduction steps should be something a tester, support engineer, or PM could follow without opening the codebase. Use UI flows, settings, and observable behaviour. If the bug genuinely has no user-visible surface (a background job, a silent data drift), say so explicitly in the description, then put the developer-level probe (SQL, log query, kubectl command) under ## Technical Details.
Before drafting anything, search for an existing issue that already covers this — open and closed:
bashgh issue list --state all --search "<keywords>" --limit 10 --json number,title,state gh issue list --assignee "@me" --state open --limit 30 --json number,title
Reference Issues section or Part of #<n> in the description) AND be linked as a native sub-issue in Step 6.5, so traceability is preserved.Never skip this step — orphan issues with no link to the work that spawned them are the failure mode this skill must avoid.
If $ARGUMENTS specifies a type (feature, bug, spike), use that. Otherwise, ask the user:
What type of issue would you like to create?
- feature: New feature or enhancement request
- bug: Report a bug or defect
- spike: Exploratory work to answer a questionAsk or infer from context. The web form is the source of truth for this schema — these mirror .github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml one for one.
#<n>Part of #123 · Blocked by #123 · Blocks #123 · Related to #123 · Duplicates #123 · Supersedes #123If you cannot answer 5, 6 or 7 from context, ask rather than filling them with plausible-sounding text. An invented customer or a fabricated metric is worse than an empty field, because it survives into prioritisation as if it were evidence.
Ask or infer from context. Separate user-facing info from technical info up front — you will need both, and they go in different sections of the body.
Form fields (top of body — these mirror BUG-REPORT.yml one for one):
Technical (bottom of body, under ## Technical Details — no counterpart in the form):
Link, so code pointers belong here instead.Ask or infer:
The web form is the source of truth for this schema. GitHub renders .github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml as ### headings whose text matches each field's label. Match them exactly so form-filed and skill-filed issues parse the same.
markdown### Function {function} ### Who asked for this {source} ### Summary {summary — what capability is missing, who needs it, plain language} ### What this unblocks {unblocks — the account, deal, renewal or support load; or the stated bet} ### How we will know it worked {success — observable change, ideally a number} ### What we are not doing instead {tradeoff — or "Nothing" if the work is genuinely small} ### Basic Example {basic_example — user-side flow, screenshots or pseudo-UI welcome, or "None"} ### Drawbacks {drawbacks or "None"} ### Unresolved questions {unresolved_questions or "None"} ### Parent / epic {parent or "None"} ### Related work {related — one relationship-prefixed link per line, or "None"}
The web form is the source of truth for this schema. GitHub renders .github/ISSUE_TEMPLATE/BUG-REPORT.yml as ### headings whose text matches each field's label exactly. Emit the same headings, in the same order, with the same capitalisation — an issue filed by this skill must be indistinguishable from one filed through the form, so that anything parsing the corpus sees one schema rather than two. Do not use ## for these, and do not rename them.
markdown### Environment {Exactly one of: Production | QA / Test | Dev | Local only | Not sure} ### Description {One paragraph, plain language, what the user observes is wrong. No internal symbol names. If you must reference an internal concept, gloss it in plain English first.} ### Impact - **Who is affected**: {all tenants / specific feature users / dev-only / etc.} - **Severity**: {what the user can't do, or what they see incorrectly} - **Since when**: {date or version, "unknown" if not known} ### Link {URL to the affected page, resource, conversation or dashboard — whatever gets a reader to the problem fastest. Optional; omit the heading entirely if there is nothing useful to link.} ### Reproduction steps {Numbered steps a tester or support engineer could follow without reading the codebase. If the bug has no user-visible surface, say so and explain how to detect it — then put the probe in Technical Details.} ### Logs {Raw log lines, stack traces, SQL errors. Omit the heading if none.} ### Screenshots {Omit the heading if none.} ### Client details {Browser / OS, e.g. "Chrome 128 / macOS". Only for UI bugs where the client is actually relevant — omit the heading for backend bugs.} --- ## Technical Details {Free-form for engineers, and the one section with no counterpart in the form. It is additive: it sits after every form field, so the form-shaped part of the body still parses cleanly. Include any of: root-cause analysis, code paths with file:line, commit SHAs, migration IDs, library names and versions, struct/field names, SQL queries used to confirm the bug. Be as deep as helpful — this section has no audience constraint.}
> Notes for the agent generating this: > - Omit optional headings entirely rather than writing "N/A" or "None" — an empty section is worse than an absent one. This applies to Link, Logs, Screenshots, and Client details. > - Environment, Description, Impact, and Reproduction steps are required by the form. Always emit all four, even when you have to write "unknown". > - Environment must be one of the five literal dropdown options, spelled exactly as above — it is a dropdown, and any other string will not match what the form produces. > - The ## Technical Details heading is mandatory whenever you have any internal information to convey. If genuinely none, omit it. Keep it at ##, not ### — that is what marks it as the non-form appendix. > - If you change the form, change this block in the same PR. The two drifting apart is what made half the bug corpus unparseable in the first place.
markdown## Summary {summary} ## Objectives {objectives — the specific questions this spike answers} ## Result Summary {deliverable format — doc, prototype, decision memo} ## Next Steps {what this unblocks} ## Unresolved Questions {unresolved_questions or "None"} ## Reference Issues {reference_issues or "None"}
Before showing the user the draft, re-read your own title and first paragraph and ask:
kubectl, log query) under Technical Details. Never invent a UI flow to fill the field.wc -w on everything above ## Technical Details must be ≤ 200. Over budget means demote into Technical Details, not compress into vagueness.If any test fails, fix it before Step 5.
Show the user the formatted issue:
Title: {title_with_prefix}
Labels: {labels}
Body:
---
{body}
---
Create this issue? (yes/no)Use GitHub CLI to create the issue. Always assign the creator (@me):
bashgh issue create \ --title "{title}" \ --body "$(cat <<'EOF' {body} EOF )" \ --assignee "@me" \ --label "{labels}" # Only if labels exist
If Step 0 identified a parent/original ticket (epic, sprint ticket, or the bug this work spun out of), create a native sub-issue link — not just a body mention. The body reference is for readers; the native link is what makes the relationship visible on the parent, the board, and in tracking views.
bashPARENT_NUMBER={parent_issue_number} REPO_OWNER=nudgebee REPO_NAME=$(gh repo view --json name -q .name) ISSUE_ID_QUERY='query($owner: String!, $name: String!, $number: Int!) { repository(owner: $owner, name: $name) { issue(number: $number) { id } } }' PARENT_ID=$(gh api graphql -f query="$ISSUE_ID_QUERY" -f owner="$REPO_OWNER" -f name="$REPO_NAME" -F number="$PARENT_NUMBER" --jq '.data.repository.issue.id') CHILD_ID=$(gh api graphql -f query="$ISSUE_ID_QUERY" -f owner="$REPO_OWNER" -f name="$REPO_NAME" -F number="$ISSUE_NUMBER" --jq '.data.repository.issue.id') gh api graphql \ -f query='mutation($parentId: ID!, $childId: ID!) { addSubIssue(input: {issueId: $parentId, subIssueId: $childId}) { subIssue { number } } }' \ -f parentId="$PARENT_ID" -f childId="$CHILD_ID"
A closed parent is a valid link target (follow-up work). If the parent is a PR rather than an issue, skip the native link — sub-issues only accept issues — and keep the body reference. If the mutation fails, report it in Step 8; do not drop the link silently.
After creating the issue, add it to the org-level nudgebee project (#1) and set the current iteration and Story Point.
> The project is org-level (nudgebee org, project #1) and shared across all repos including nudgebee-enterprise, so these commands are the same regardless of which repo the issue lives in. Pass the issue's actual repo in the --url.
Story Point — before running the commands, ask the user to pick a value (1, 2, 3, 5, 8, 13). If they skip, omit the Story Point edit.
bashISSUE_REPO="nudgebee/nudgebee-enterprise" # or nudgebee/nudgebee, whichever the issue is in ISSUE_NUMBER={extracted_issue_number} STORY_POINT="{user_choice_or_empty}" # one of 1/2/3/5/8/13, or empty to skip PROJECT_ID="PVT_kwDOCG7t1c4ATt4G" ITER_FIELD_ID="PVTIF_lADOCG7t1c4ATt4GzgMmEFQ" SP_FIELD_ID="PVTSSF_lADOCG7t1c4ATt4GzgPeoDE" # Add to project gh project item-add 1 --owner nudgebee --url "https://github.com/${ISSUE_REPO}/issues/${ISSUE_NUMBER}" # The board has >1000 items and new items land at the end, so `gh project item-list` # with any --limit never finds a fresh item. Resolve the item id via the issue itself: ITEM_ID=$(gh api graphql \ -f query='query($owner: String!, $name: String!, $number: Int!) { repository(owner: $owner, name: $name) { issue(number: $number) { projectItems(first: 5) { nodes { id project { number } } } } } }' \ -f owner="${ISSUE_REPO%/*}" -f name="${ISSUE_REPO#*/}" -F number="$ISSUE_NUMBER" \ --jq '.data.repository.issue.projectItems.nodes[] | select(.project.number == 1) | .id') # Resolve the CURRENT iteration id (gh does NOT support an "@current" token — # it requires a literal iteration node id). Pick the latest iteration whose # startDate is on or before today. CURRENT_ITER=$(gh api graphql -f query=' query { organization(login: "nudgebee") { projectV2(number: 1) { field(name: "Iteration") { ... on ProjectV2IterationField { configuration { iterations { id startDate } } } } } } }' | jq -r --arg today "$(date +%Y-%m-%d)" \ '[.data.organization.projectV2.field.configuration.iterations[] | select(.startDate <= $today)] | sort_by(.startDate) | last | .id') gh project item-edit --project-id "$PROJECT_ID" --id "$ITEM_ID" \ --field-id "$ITER_FIELD_ID" --iteration-id "$CURRENT_ITER" # Story Point (single-select) — only if the user chose one if [ -n "$STORY_POINT" ]; then SP_OPTION_ID=$(gh project field-list 1 --owner nudgebee --format json \ | jq -r ".fields[] | select(.name==\"Story Point\") | .options[] | select(.name==\"${STORY_POINT}\") | .id") gh project item-edit --project-id "$PROJECT_ID" --id "$ITEM_ID" \ --field-id "$SP_FIELD_ID" --single-select-option-id "$SP_OPTION_ID" fi
Verify — this is NOT best-effort. An unassigned issue with no iteration is invisible on the sprint board, which defeats the point of filing it. After the commands above, confirm all three fields actually landed:
bashgh issue view "$ISSUE_NUMBER" --json assignees --jq '.assignees | length' # must be >= 1 # Do NOT use `gh project item-list --limit 1000` here — the board has >1000 items and # fresh items are appended at the end, so a new issue never shows up in the first page. # Query the issue's own project items instead: gh api graphql \ -f query='query($owner: String!, $name: String!, $number: Int!) { repository(owner: $owner, name: $name) { issue(number: $number) { projectItems(first: 5) { nodes { project { number } fieldValueByName(name: "Iteration") { ... on ProjectV2ItemFieldIterationValue { title } } } } } } }' \ -f owner="${ISSUE_REPO%/*}" -f name="${ISSUE_REPO#*/}" -F number="$ISSUE_NUMBER" \ --jq '.data.repository.issue.projectItems.nodes[] | select(.project.number == 1) | {iteration: (.fieldValueByName.title // null)}'
gh issue edit "$ISSUE_NUMBER" --add-assignee "@me".iteration null → re-run the item-add / item-edit commands once; if it still fails, report the failure explicitly in Step 8 with the error text so the user can fix it — do not silently declare success.Issue created: {url}
Title: {title}
Type: {type}
Number: #{number}
Assignee: @me
Iteration: {current_iteration_title} (if project assignment succeeded)
Story Point: {value or "unset"}If the user is working on code changes and asks to create an issue, try to infer the type:
When inferring, still apply the audience/tone rules above. A bug discovered by an engineer is still read by PMs.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 15,085 | 23,522 | +56% | 1 | 1 | 0% | 662 | 6,112 | +823% | 0 | 0 | — |
case-02 | fail→fail | 10,840 | 24,256 | +124% | 1 | 1 | 0% | 542 | 6,051 | +1016% | 0 | 0 | — |
case-03 | fail→fail | 8,252 | 18,253 | +121% | 1 | 1 | 0% | 457 | 6,394 | +1299% | 0 | 0 | — |
case-04 | fail→pass | 9,059 | 31,405 | +247% | 1 | 1 | 0% | 1,374 | 10,020 | +629% | 0 | 0 | — |
case-05 | pass→fail | 18,156 | 19,411 | +7% | 1 | 1 | 0% | 1,288 | 6,183 | +380% | 0 | 0 | — |
case-06 | pass→fail | 3,986 | 18,165 | +356% | 1 | 1 | 0% | 482 | 6,432 | +1234% | 0 | 0 | — |
case-07 | fail→fail | 31,759 | 17,399 | -45% | 1 | 1 | 0% | 1,816 | 6,130 | +238% | 0 | 0 | — |
case-08 | pass→pass | 10,179 | 8,977 | -12% | 1 | 1 | 0% | 513 | 6,108 | +1091% | 0 | 0 | — |
case-18 | pass→pass | 15,015 | 7,268 | -52% | 1 | 1 | 0% | 1,196 | 6,148 | +414% | 0 | 0 | — |
case-09 | fail→pass | 18,708 | 10,923 | -42% | 1 | 1 | 0% | 2,845 | 6,449 | +127% | 0 | 0 | — |
case-10 | fail→pass | 11,336 | 8,994 | -21% | 1 | 1 | 0% | 1,535 | 6,282 | +309% | 0 | 0 | — |
case-11 | fail→pass | 9,026 | 16,141 | +79% | 1 | 1 | 0% | 1,291 | 6,214 | +381% | 0 | 0 | — |
case-12 | pass→pass | 15,458 | 10,330 | -33% | 1 | 1 | 0% | 1,351 | 6,359 | +371% | 0 | 0 | — |
case-13 | pass→pass | 15,078 | 14,365 | -5% | 1 | 1 | 0% | 1,382 | 6,346 | +359% | 0 | 0 | — |
case-14 | pass→pass | 17,392 | 12,651 | -27% | 1 | 1 | 0% | 2,091 | 7,043 | +237% | 0 | 0 | — |
case-15 | pass→pass | 17,585 | 12,201 | -31% | 1 | 1 | 0% | 1,897 | 6,927 | +265% | 0 | 0 | — |
case-16 | fail→pass | 14,057 | 12,781 | -9% | 1 | 1 | 0% | 1,774 | 6,931 | +291% | 0 | 0 | — |
case-17 | fail→pass | 16,095 | 10,850 | -33% | 1 | 1 | 0% | 1,708 | 6,238 | +265% | 0 | 0 | — |
case-19 | fail→pass | 11,792 | 8,254 | -30% | 1 | 1 | 0% | 768 | 6,128 | +698% | 0 | 0 | — |
case-20 | pass→pass | 12,482 | 10,587 | -15% | 1 | 1 | 0% | 994 | 6,538 | +558% | 0 | 0 | — |
case-21 | fail→fail | 12,039 | 7,490 | -38% | 1 | 1 | 0% | 934 | 6,005 | +543% | 0 | 0 | — |
case-22 | fail→pass | 19,615 | 11,128 | -43% | 1 | 1 | 0% | 2,372 | 6,663 | +181% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 16 counted toward the lift figure. The other 6 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +27 percentage points is the difference between those two pass rates over the 16 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 8/27/2026 | +23% |
| gemini-3.6-flash | verified | 8/22/2026 | +59% |
Other measured skills in the registry, with their headline benchmark lift.