From gh-tools
Create well-formatted GitHub issues with intelligent AI-powered label suggestions and content type detection. Use whenever the user wants to.
How this skill is triggered — by the user, by Claude, or both
Slash command
/gh-tools:issue-createThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Create well-formatted GitHub issues with intelligent automation including AI-powered label suggestions, content type detection, template formatting, and related issue linking.
Create well-formatted GitHub issues with intelligent automation including AI-powered label suggestions, content type detection, template formatting, and related issue linking.
Self-Evolving Skill: This skill improves through use. If instructions are wrong, parameters drifted, or a workaround was needed — fix this file immediately, don't defer. Only update for real, reproducible issues.
Use this skill when:
Slash command: /gh-tools:issue-create
Natural language triggers:
--repo owner/repo flagGitHub issue bodies support 65,536 characters (not bytes — UTF-8 multibyte characters count as 1). Always aim to fill a single post rather than splitting across multiple issues or comments.
Principle: One comprehensive post is more valuable than many fragmented ones. Pack as much analysis, context, history, and multi-perspective reasoning as possible into a single issue body or comment.
When composing long-form issue content:
echo "$BODY" | wc -m (characters, not bytes)<details><summary>) for dense reference material — they don't reduce the char budget but improve readabilityPre-post size check pattern:
# Build body, then verify it fits
BODY=$(cat <<'EOF'
... your content ...
EOF
)
CHARS=$(echo "$BODY" | wc -m | tr -d ' ')
echo "Body size: ${CHARS}/65536 chars"
if [ "$CHARS" -gt 65536 ]; then
echo "WARNING: Exceeds limit by $((CHARS - 65536)) chars — trim or split"
fi
# From within a git repository
bun ~/eon/cc-skills/plugins/gh-tools/scripts/issue-create.ts \
--body "Login page crashes when using special characters in password"
bun ~/eon/cc-skills/plugins/gh-tools/scripts/issue-create.ts \
--repo owner/repo \
--body "Feature: Add dark mode support for better accessibility"
bun ~/eon/cc-skills/plugins/gh-tools/scripts/issue-create.ts \
--repo owner/repo \
--body "Bug: API returns 500 error" \
--dry-run
bun ~/eon/cc-skills/plugins/gh-tools/scripts/issue-create.ts \
--repo owner/repo \
--title "Bug: Login fails with OAuth" \
--body "Detailed description..." \
--labels "bug,authentication"
bun ~/eon/cc-skills/plugins/gh-tools/scripts/issue-create.ts \
--body "Question: How to configure..." \
--no-ai
| Option | Short | Description |
|---|---|---|
--repo | -r | Repository in owner/repo format |
--body | -b | Issue body content (required) |
--title | -t | Issue title (optional) |
--labels | -l | Comma-separated labels |
--dry-run | Preview without creating | |
--no-ai | Disable AI features | |
--verbose | -v | Enable verbose output |
--help | -h | Show help |
gh CLI (required) - GitHub CLI toolgh-models extension (optional) - Enables AI featuresgh extension install github/gh-models
| Level | Behavior |
|---|---|
| WRITE/ADMIN | Full functionality |
| TRIAGE | Can apply labels |
| READ | Shows formatted content for manual copy |
| NONE | Suggests fork workflow |
Logs to: ~/.claude/logs/gh-issue-create.jsonl
Events logged:
preflight - Initial checkstype_detected - Content type detectionlabels_suggested - Label suggestionsrelated_found - Related issues searchissue_created - Successful creationdry_run - Dry run completionGitHub Issues have no API for programmatic image upload. The web UI's drag-and-drop uses an internal S3 policy flow that is intentionally not exposed to API clients (cli/cli#1895).
The ?raw=true URL resolves via github.com — if the image doesn't exist at that path on the remote, it silently 404s (broken image, no error). Run this preflight before creating the issue:
# 1. Detect repo context
OWNER_REPO=$(gh repo view --json nameWithOwner -q '.nameWithOwner')
BRANCH=$(git rev-parse --abbrev-ref HEAD)
VISIBILITY=$(gh repo view --json visibility -q '.visibility')
# 2. Verify images are git-tracked (not gitignored)
IMG_DIR="path/to/images"
for f in ${IMG_DIR}/*.png; do
git ls-files --error-unmatch "$f" >/dev/null 2>&1 \
|| echo "WARNING: $f is NOT tracked by git (check .gitignore)"
done
# 3. Verify images are committed (not just staged or untracked)
UNCOMMITTED=$(git diff --name-only HEAD -- "${IMG_DIR}/" 2>/dev/null)
UNTRACKED=$(git ls-files --others --exclude-standard -- "${IMG_DIR}/" 2>/dev/null)
if [[ -n "$UNCOMMITTED" || -n "$UNTRACKED" ]]; then
echo "FAIL: Images not committed — commit and push first"
echo " Uncommitted: ${UNCOMMITTED}"
echo " Untracked: ${UNTRACKED}"
exit 1
fi
# 4. Verify commit is pushed to remote (local commits invisible to github.com)
LOCAL_SHA=$(git rev-parse HEAD)
REMOTE_SHA=$(git rev-parse "origin/${BRANCH}" 2>/dev/null)
if [[ "$LOCAL_SHA" != "$REMOTE_SHA" ]]; then
echo "FAIL: Local commits not pushed — run: git push origin ${BRANCH}"
exit 1
fi
# 5. Build image base URL
IMG_BASE="https://github.com/${OWNER_REPO}/blob/${BRANCH}/${IMG_DIR}"
echo "Image base URL: ${IMG_BASE}/<filename>.png?raw=true"
echo "Repo visibility: ${VISIBILITY}"
if [[ "$VISIBILITY" == "PRIVATE" ]]; then
echo "NOTE: Images only visible to authenticated collaborators"
fi
Preflight checklist (what each step catches):
| Step | Check | Failure Mode |
|---|---|---|
| 1 | Repo context exists | No OWNER_REPO to build URLs |
| 2 | Images are git-tracked | .gitignore silently excludes them |
| 3 | Images are committed | Staged/untracked files don't exist on remote |
| 4 | Commit is pushed | Local-only commits are invisible to github.com |
| 5 | URL construction | Wrong branch name → 404 |
?raw=true vs raw.githubusercontent.comFor images already committed and pushed, use github.com/blob/...?raw=true URLs — not raw.githubusercontent.com:
<!-- BROKEN for private repos (no browser cookies on raw.githubusercontent.com) -->

<!-- WORKING for all repos (browser has cookies on github.com, gets signed redirect) -->

Scripting pattern (batch images → issue body):
IMG_BASE="https://github.com/${OWNER_REPO}/blob/${BRANCH}/${IMG_DIR}"
gh issue create --title "Feedback with screenshots" --body "$(cat <<EOF
## Item 1

## Item 2

EOF
)"
See AP-07 in GFM Anti-Patterns for the full technical explanation.
For images only on disk (not committed), four options:
| Method | How | Permanent? | Preflight? |
|---|---|---|---|
| Commit + push first | git add images, push, run preflight, then use ?raw=true URLs | Yes (repo-hosted) | Yes (5-step) |
| Web UI paste | Open issue in browser, Ctrl/Cmd+V images into comment box | Yes (user-attachments CDN) | None |
| Web UI drag-and-drop | Drag image files into the comment box | Yes (user-attachments CDN) | None |
| Playwright automation | Script automates the browser file-attachment flow | Yes (user-attachments CDN) | None |
GitHub has no API for image uploads, but the browser's file-attachment flow can be automated via Playwright to get permanent user-attachments CDN URLs without any commit/push preflight.
How it works:
~/.claude/tools/pw-github-profile/)<img> tag with a user-attachments CDN URL into the comment textareaKey implementation details (GitHub's 2026 React comment composer):
textarea[placeholder="Use Markdown to format your comment"] (dynamic React IDs — do NOT match by id)page.waitForEvent("filechooser")<img width="W" height="H" alt="Image" src="https://github.com/user-attachments/assets/UUID" /> (HTML <img> tag, not  markdown)textarea#new_comment_field and file-attachment input[type='file'] selectors no longer existtextarea.fill("")Chrome CDP note: chromium.connectOverCDP() fails with Chrome 136+ (WebSocket timeout). Use chromium.launchPersistentContext() with Playwright's bundled Chromium instead. Chrome 136+ also requires --user-data-dir for CDP (DevTools remote debugging requires a non-default data directory), making CDP impractical for reusing existing browser sessions.
Run from a git directory or use --repo owner/repo flag.
gh extension listgh label list --repo owner/repols ~/.cache/gh-issue-skill/labels/Install gh-models extension:
gh extension install github/gh-models
After this skill completes, check before closing:
Only update if the issue is real and reproducible — not speculative.
npx claudepluginhub terrylica/cc-skills --plugin gh-toolsCreates structured, bite-sized implementation plans from specs or requirements before writing code. Useful for breaking down multi-step tasks into testable steps with file structure and task boundaries.