Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions skills/create-issue/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
name: create-issue
description: Creates a GitHub issue from a natural language prompt. Discovers repo templates, fills the best match, posts via gh CLI. Use this skill whenever the user wants to create an issue, open a bug report, file a feature request, submit a ticket, log a bug, report a problem, track something as an issue, or add a ticket — even if they don't say "issue" explicitly.
---

# Create Issue

Two-phase: **discover** (cheap model) → **draft + post** (you).

Flags: `--confirm` (review before posting), `--web` (open in browser), `-R owner/repo` (target repo).

## Phase 1 — Discover (delegate to Haiku)

Spawn a subagent with `model: "haiku"` to handle all mechanical work. Give it this prompt, filling in the repo if the user specified one:

> Discover issue templates for a GitHub repo and return structured JSON.
>
> 1. Resolve repo: use `-R {owner/repo}` if provided, else run `gh repo view --json nameWithOwner -q .nameWithOwner`.
> 2. List `.github/ISSUE_TEMPLATE/` — locally if the repo is the cwd, else via `gh api repos/OWNER/REPO/contents/.github/ISSUE_TEMPLATE --jq '.[].name'`.
> 3. If `config.yml` or `config.yaml` exists, read it and extract `blank_issues_enabled`.
> 4. For each template file (not config), extract `name`, `about`/`description`, and `labels` from the front-matter or YAML top-level fields.
> 5. Read the full content of the template that best matches the issue type hint: `{type_hint}`.
> 6. Return ONLY a single JSON block — no commentary:
> ```json
> {
> "repo": "owner/repo",
> "blank_issues_enabled": true,
> "templates": [{"file": "bug_report.yml", "name": "Bug Report", "about": "File a bug", "labels": "bug"}],
> "selected": {"file": "bug_report.yml", "content": "<full template content>"},
> "default_labels": "bug"
> }
> ```
> If no templates exist, return: `{"repo": "owner/repo", "blank_issues_enabled": true, "templates": [], "selected": null, "default_labels": ""}`

Replace `{type_hint}` with the issue type you parsed from the user's prompt (bug/feature/task/question).

## Phase 2 — Draft and post (you)

Using the JSON from Phase 1:

1. **Draft** title + body from user prompt and conversation context:
- If `selected` has content, fill its template sections. See `references/templates.md` for YAML form → markdown rendering rules.
- If `selected` is null, use plain title + body.
- If `blank_issues_enabled` is false and no template matched, fall back to `--web`.
- Use `<!-- TODO: fill in -->` for required fields that can't be inferred.
- Include fix suggestions only when root cause is clear from context.
- Match template structure — don't add extra sections.

2. **Post** (skip confirmation unless `--confirm`):
- Write the body to a temp file using the Write tool (e.g., `tmp_issue_body.md` in the repo root).
- Run: `gh issue create --title "TITLE" --body-file tmp_issue_body.md [--label x] [-R repo]`
- Delete the temp file after successful creation.
- Never use `--body` flag or stdin piping (`--body-file -` / heredocs) — they break on special characters across shells.
On metadata error → retry without it, report what was dropped. On total failure → offer `--web`.

3. **Output**: issue URL + one-line summary. Nothing else.
44 changes: 44 additions & 0 deletions skills/create-issue/evals/evals.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"skill_name": "create-issue",
"evals": [
{
"id": 1,
"prompt": "Create an issue for the login page — when you enter a wrong password it just shows a blank screen instead of an error message. The console shows 'TypeError: Cannot read properties of undefined (reading message)' in ErrorHandler.tsx line 42.",
"expected_output": "A well-structured bug report issue created via gh CLI with title, reproduction steps, error details, and the issue URL returned",
"files": [],
"expectations": [
"The issue title is concise and describes the blank screen / missing error message problem",
"The issue body includes the TypeError and ErrorHandler.tsx reference",
"The issue body includes reproduction steps mentioning wrong password entry",
"gh issue create was called with --body-file - to handle multiline body",
"The output ends with the issue URL"
]
},
{
"id": 2,
"prompt": "I've been debugging this for a while. The problem is in src/api/rateLimiter.ts — the sliding window counter uses Date.now() but the Redis TTL is set in seconds, so there's a units mismatch. Requests that should be rate-limited at 100/min are actually getting through at ~100000/min because the window comparison is off by 1000x. The fix is to divide Date.now() by 1000 before comparing with the TTL. Can you file an issue for this?",
"expected_output": "An issue that incorporates debugging context from the conversation, not just a vague placeholder",
"files": [],
"expectations": [
"The issue body mentions the units mismatch between Date.now() milliseconds and Redis TTL seconds",
"The issue body mentions the 1000x rate limit bypass (100/min intended vs ~100000/min actual)",
"The issue body references rateLimiter.ts or the sliding window counter",
"The issue body mentions the fix (divide by 1000) or describes the root cause clearly enough to act on",
"gh issue create was called and the output includes the issue URL"
]
},
{
"id": 3,
"prompt": "open a feature request in microsoft/vscode for adding native support for .jsonc files in the search results preview — right now it just shows raw text with comments and it's hard to read",
"expected_output": "A feature request issue created in the microsoft/vscode repo using -R flag, with clear description of the desired behavior",
"files": [],
"expectations": [
"gh issue create uses -R microsoft/vscode",
"The issue type is feature request, not bug",
"The title mentions JSONC support in search preview or similar",
"The body describes current behavior (raw text) and desired behavior (rendered preview)",
"The output includes the issue URL"
]
}
]
}
22 changes: 22 additions & 0 deletions skills/create-issue/references/templates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Issue Templates — Rendering Rules

`gh issue create --body` accepts markdown, not structured form data. YAML form fields must be rendered as markdown sections.

## Rendering

| Field type | Render as | If required + unknown |
|------------|-----------|----------------------|
| `textarea` / `input` | `### Label\n\n<content>` | `<!-- TODO: fill in -->` |
| `dropdown` | `### Label\n\n<chosen option>` | Fall back to `--web` |
| `checkboxes` | `- [x] Option` per checked item | Auto-check universal items (CoC); `--web` for rest |
| `markdown` | Skip — informational only | — |

If 3+ required fields can't be inferred, prefer `--web` over a low-quality submission.

## Markdown templates

Front-matter: `name`, `about`, `title`, `labels`, `assignees`. Body below `---` is the template — fill each section, replace `<!-- placeholder -->` comments.

## Template selection

Match by `name` and `about`/`description` fields against the issue type. Use template's default `labels`. Only ask user when genuinely ambiguous.