diff --git a/skills/create-issue/SKILL.md b/skills/create-issue/SKILL.md new file mode 100644 index 0000000..fd9600b --- /dev/null +++ b/skills/create-issue/SKILL.md @@ -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": ""}, +> "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 `` 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. diff --git a/skills/create-issue/evals/evals.json b/skills/create-issue/evals/evals.json new file mode 100644 index 0000000..0186853 --- /dev/null +++ b/skills/create-issue/evals/evals.json @@ -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" + ] + } + ] +} diff --git a/skills/create-issue/references/templates.md b/skills/create-issue/references/templates.md new file mode 100644 index 0000000..1e6e293 --- /dev/null +++ b/skills/create-issue/references/templates.md @@ -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` | `` | +| `dropdown` | `### Label\n\n` | 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 `` 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.