GitHub Issue Creator
Create and update GitHub issues from screenshots, emails, messages, and other unstructured input sources.
Repo Sync Before Edits (mandatory)
This skill creates issues on a remote GitHub repo, so always verify connectivity first:
bash
gh auth status
gh repo view --json name,owner,url
If
is not authenticated or the current directory is not a GitHub repo, stop and tell the user what's missing before continuing.
Workflow
Follow these three phases strictly. Do not skip the approval step — the user must confirm before any issue is created or updated.
Phase 1: Extract Information
Read the user's input carefully. Input can be:
- Screenshots / images: Read the image file to extract text, error messages, UI state, stack traces, and any visible context. Pay attention to browser URLs, error codes, timestamps, and user-visible symptoms.
- Pasted text: Bug report emails, Slack messages, support tickets, error logs, user complaints.
- Verbal descriptions: The user describing a bug or feature request conversationally.
- Multiple sources: The user may provide several screenshots plus some context text. Combine all of them.
For each distinct issue you identify, extract:
- Title: A clear, concise summary (imperative or descriptive — e.g., "Login button unresponsive on mobile Safari")
- Description: What's happening, including any error messages, stack traces, or reproduction context from the source material
- Steps to reproduce: If inferable from the input
- Expected vs actual behavior: If inferable
- Environment details: OS, browser, app version — anything visible in the input
- Severity/priority signal: If the source indicates urgency ("critical", "blocking", "P0", etc.)
- Labels: Suggest appropriate labels based on content (e.g., , , , , )
It's fine if not all fields are available — extract what you can. Don't fabricate details that aren't in the input.
Phase 1.5: Sanitize Sensitive Information
GitHub issues are typically public (or at least visible to the whole team). Bug reports from emails, screenshots, and support tickets often contain personal or confidential data that should never end up in a GitHub issue. Before composing any issue content, scan everything you extracted and redact the following:
Personal Identifiable Information (PII):
- Names of end users or reporters — replace with generic references like "a user", "the reporter". Keep names only if the person is a team member the user explicitly wants tagged.
- Email addresses — redact entirely (e.g., or just remove)
- Phone numbers — remove
- Physical addresses — remove
- User IDs / account names of end users — replace with or
Credentials and secrets:
- API keys, tokens, passwords — if visible in screenshots or logs, replace with , , etc. Flag these to the user as a heads-up ("I noticed an API key in the screenshot — I've removed it from the issue.")
- Session IDs, cookies, auth headers — redact
- Database connection strings — redact
Infrastructure details (redact unless clearly needed for the bug):
- Internal IP addresses — replace with
- Internal hostnames / URLs that expose infrastructure — replace with
- Database names, table names — keep only if directly relevant to the bug
Other sensitive content:
- Customer data visible in screenshots (financial info, health info, private messages) — describe the data type without reproducing the actual values (e.g., "the user's transaction history was visible" instead of listing actual transactions)
- Proprietary business logic visible in error details — summarize rather than quote verbatim if it reveals trade secrets
How to handle it in practice:
- After extracting information in Phase 1, do a sweep for all of the above before composing the issue body.
- When you redact something, note it briefly in the proposal so the user can see what was removed and override if needed (e.g., "Note: removed reporter's email address and an exposed API key from the issue body").
- If the input is heavily loaded with sensitive data and redacting it would make the bug report meaningless, flag this to the user: "This report contains a lot of sensitive details. Want me to create a more generic description, or would you prefer a private/internal issue?"
- When in doubt, redact. It's easy for the user to add information back; it's hard to un-leak something posted publicly.
Phase 2: Detect Templates and Propose Issues
Template Detection
Check the repo for issue templates:
bash
# Check for issue templates in common locations
ls .github/ISSUE_TEMPLATE/ 2>/dev/null
cat .github/ISSUE_TEMPLATE/*.md 2>/dev/null
cat .github/ISSUE_TEMPLATE/*.yml 2>/dev/null
# Also check for a simple issue template
cat .github/ISSUE_TEMPLATE.md 2>/dev/null
If templates exist, read them and use their structure for the proposed issues. Match each issue to the most appropriate template (e.g., bug report template for bugs, feature request template for enhancements).
If no templates exist, use this default structure:
markdown
## Description
[Clear description of the issue]
## Steps to Reproduce
1. [Step 1]
2. [Step 2]
3. [Step 3]
## Expected Behavior
[What should happen]
## Actual Behavior
[What actually happens]
## Environment
- OS: [if known]
- Browser/Version: [if known]
- App Version: [if known]
## Additional Context
[Screenshots, logs, related issues]
Check for Existing Issues
Before proposing new issues, search for potentially related open issues:
bash
gh issue list --state open --limit 30
If any existing issues look related to the extracted information, propose updating them instead of creating duplicates. Use keyword matching on titles and bodies — err on the side of flagging potential duplicates for the user to decide.
Present the Proposal
Show the user a clear, numbered list of proposed actions. For each:
### Issue [N]: [Create new | Update #existing-number]
**Title**: [issue title]
**Labels**: `bug`, `ui` (etc.)
**Template**: [template name if using repo template, or "default"]
**Body preview**:
> [Show the full issue body as it will appear on GitHub]
---
If proposing updates to existing issues, show what will be added (as a comment or body edit) and link to the existing issue.
End with a clear prompt:
Does this look right? You can:
- Say "go" or "approve" to create/update all issues as shown
- Say "skip 2" to exclude a specific issue
- Ask me to modify any issue before creating it
- Say "cancel" to abort
Do not proceed until the user explicitly approves. This is critical — creating issues is a visible action that others will see.
Phase 3: Create / Update Issues
Once approved, execute the actions using
:
Creating a new issue:
bash
gh issue create --title "TITLE" --body "$(cat <<'ISSUE_BODY'
... issue body ...
ISSUE_BODY
)" --label "bug,ui"
Updating an existing issue (add a comment):
bash
gh issue comment ISSUE_NUMBER --body "$(cat <<'COMMENT_BODY'
... update content ...
COMMENT_BODY
)"
Adding labels to an existing issue:
bash
gh issue edit ISSUE_NUMBER --add-label "label1,label2"
After each action, confirm success and report the issue URL back to the user. At the end, provide a summary:
Done! Created/updated the following issues:
- #42: Login button unresponsive on mobile Safari
- #38: (updated) Add dark mode support — added reproduction details
Expected Output
After the user approves the proposal, the skill creates the issue and reports:
Done! Created/updated the following issues:
- #47: Login button unresponsive on mobile Safari
https://github.com/acme/webapp/issues/47
Labels: bug, ui, mobile
The created issue body looks like:
markdown
## Description
The login button does not respond to taps on mobile Safari (iOS 17). Tapping the
button produces no visual feedback and the login flow never initiates.
## Steps to Reproduce
1. Open https://app.example.com on iPhone with Safari (iOS 17)
2. Enter valid credentials
3. Tap the "Log In" button
## Expected Behavior
The login flow initiates and the user is redirected to the dashboard.
## Actual Behavior
Nothing happens. No spinner, no error message, no navigation.
## Environment
- OS: iOS 17.4
- Browser: Safari (mobile)
- App Version: 2.3.1
## Additional Context
Reported via screenshot on 2026-04-19. Note: reporter email and user ID were
redacted before filing.
Edge Cases
- No repo access / gh not authenticated: Run at the start; stop and tell the user what's missing before extracting any data.
- Duplicate issue: Search open issues for keyword matches before proposing creation; if a near-duplicate is found, offer to update it with a comment instead.
- Missing required fields: If the input lacks enough detail to write a meaningful description or steps to reproduce, ask clarifying questions rather than filing a skeletal issue.
- PII-heavy input: If redacting sensitive data would make the report meaningless, flag this to the user and offer to create a private/internal issue or use generic descriptions.
- Multiple issues in one input: Extract each distinct problem as a separate numbered proposal; let the user approve, skip, or modify each independently.
- YAML issue templates: Parse templates with structured fields and map extracted data to the template's field IDs and types; respect required fields.
- User drops image without context: Read the image to extract all visible text, UI state, error codes, and URLs; infer the issue from the visual context before asking for clarification.
Acceptance Criteria
Step Completion Reports
After completing each major step, output a status report in this format:
◆ [Step Name] ([step N of M] — [context])
··································································
[Check 1]: √ pass
[Check 2]: √ pass (note if relevant)
[Check 3]: × fail — [reason]
[Check 4]: √ pass
[Criteria]: √ N/M met
____________________________
Result: PASS | FAIL | PARTIAL
Adapt the check names to match what the step actually validates. Use
for pass,
for fail, and
to add brief context. The "Criteria" line summarizes how many acceptance criteria were met. The "Result" line gives the overall verdict.
Phase-specific checks
Phase 1 — Extract
◆ Extract (step 1 of 3 — [input type: screenshot/email/text])
··································································
Input parsed: √ pass | × fail — [parse error]
Data extracted: √ pass ([N] issues identified)
PII redacted: √ pass | × fail — [what was found/removed]
____________________________
Result: PASS | FAIL | PARTIAL
Phase 2 — Template Detection & Proposal
◆ Template Detection (step 2 of 3 — [repo name])
··································································
Templates found: √ pass ([N] templates) | × fail — using default
Fields mapped: √ pass | × fail — [unmapped fields]
____________________________
Result: PASS | FAIL | PARTIAL
Phase 3 — Create / Update
◆ Create/Update (step 3 of 3 — [N issues])
··································································
Issue created: √ pass (#[number]: [title])
Labels applied: √ pass | × fail — [labels missing]
Assignees set: √ pass | × fail — [assignees not set]
____________________________
Result: PASS | FAIL | PARTIAL
Important Guidelines
- Never create issues without approval. The proposal step is not optional.
- Preserve original context. When the input is a screenshot or email, mention the source in the issue body (e.g., "Reported via email on 2026-03-17" or "From screenshot of error dialog"). Don't attach the screenshot itself to the issue unless the user asks — just describe what's visible.
- One input can yield multiple issues. A single screenshot might show several problems. A forwarded email might contain a list of bugs. Extract them all as separate issues.
- Be conservative with labels. Only suggest labels that clearly apply. If the repo has existing labels, prefer those over inventing new ones. Check with:
- Handle ambiguity by asking. If you're not sure whether something is a bug or a feature request, or whether two things should be one issue or two, ask the user.
- YAML template parsing. Some repos use templates with structured fields (type: input, type: textarea, etc.). When you encounter these, map your extracted data to the template's field IDs and format the issue body accordingly, respecting required fields and field types.