Triage a SkiaSharp GitHub issue or PR into structured JSON with classification (type, area, platform, severity), suggested response, and automatable actions. Triggers: "triage #123", "triage issue", "classify issue", "analyze issue", "what's this issue about". Also triggered when an issue number is given after the issue-triage skill is already mentioned.
Resources
2Install
npx skillscat add mono/skiasharp/issue-triage Install via the SkillsCat registry.
Triage Issue
Issue pipeline: Step 1 of 3 (Triage). See `documentation/issue-pipeline.md`.
Analyze a SkiaSharp GitHub issue and produce a structured, schema-validated triage JSON.
⛔ MANDATORY FIRST STEPS (do not skip)
- Read THIS entire SKILL.md before any investigation
- Read references/schema-cheatsheet.md for required fields and enums
- Read references/anti-patterns.md for critical rules
These 3 reads are REQUIRED. Do not proceed to Phase 1 until all three are loaded.
Quick flow:
- Setup cache worktree
- Load issue data (cache first, GitHub API fallback)
- Read references: schema-cheatsheet, labels, triage-examples, anti-patterns
- Create brief plan (5-10 lines)
- Investigate code — READ-ONLY, never edit source files
- Generate JSON
- Validate with script
- Persist to data-cache
Data sources
Local cache first. Issue data is pre-cached on the docs-data-cache branch (synced hourly). The cache contains full issue JSON with comments, labels, and timeline — use it as the primary source. You can grep across all cached items for duplicate detection and cross-referencing.
GitHub CLI fallback. If the issue is not in the cache (too new, or cache stale), use gh CLI or the GitHub MCP tools (issue_read, get_file_contents) to fetch it directly. Local cache is faster and searchable; API is the fallback, not forbidden.
Phase 1 (Setup) → Phase 2 (Preprocess + Investigate) → Phase 3 (Analyze) → Phase 3.5 (Workaround Search) → Phase 3.7 (Validate Code) → Phase 4 (Validate) → Phase 5 (Persist)Phase 1 — Setup
Run once per session:
pwsh --version # Requires 7.5+
# Cache worktree
[ -d ".data-cache" ] || git worktree add .data-cache docs-data-cache
git -C .data-cache pull --rebase origin docs-data-cache
CACHE=".data-cache/repos/mono-SkiaSharp"
# Docs worktree (optional — for question/docs research)
if git show-ref --verify --quiet refs/heads/docs 2>/dev/null; then
[ -d ".docs" ] || git worktree add .docs docs
fiPhase 2 — Preprocess
1. Read the issue
cat $CACHE/github/items/{number}.jsonIf not in cache, fetch via GitHub CLI or MCP tools:
gh issue view {number} --repo mono/SkiaSharp --json title,body,labels,comments,state,createdAt,closedAt,author2. Convert to annotated markdown
If using cached JSON:
pwsh .github/skills/issue-triage/scripts/issue-to-markdown.ps1 $CACHE/github/items/{number}.json > /tmp/skiasharp/triage/{number}.mdIf fetched via API, work directly from the gh output (skip the script).
3. Code Investigation (MANDATORY)
Scope: READ code, don't WRITE code. Grep, read files, trace call chains. Never create files, compile, or execute.
Before ANY classification, search the source code for the types, methods, APIs, or behaviors mentioned in the issue. Read the relevant files. Record every finding in analysis.codeInvestigation as {file, finding, relevance} (with optional lines).
Do NOT classify until you have examined source code. For bugs, include at least one codeInvestigation entry. Close-* actions should include at least two.
Steps:
- Grep for the types/methods/APIs mentioned in the issue
- Read the relevant source files (platform handlers, core APIs, etc.)
- Check if the reported behavior matches current code
- For bugs: trace the code path — does the issue still exist?
- For feature requests: has it been implemented since filing?
- For questions: does the source confirm or contradict the assumption?
- Search for related PRs — check data-cache first, then fall back to CLI:
Include ALL related PRs in# Data-cache lookup (fast, offline) ls $CACHE/github/items/ | head -5 # check cache structure # Fall back to GitHub CLI gh pr list --search '{keywords from issue}' --state all --repo mono/SkiaSharp --limit 10 --json number,title,state,mergedAtevidence.reproEvidence.repoLinks— especially closed/unmerged PRs, as they reveal prior attempts and maintainer decisions.
4. Additional Research
| Signal in issue | Source to consult |
|---|---|
| NativeAssets, DllNotFoundException, container, WASM | documentation/packages.md |
| Platform quirks, common traps | references/skia-patterns.md |
| Specific SkiaSharp types or methods | docs/SkiaSharpAPI/*.xml |
| How-to about drawing, paths, bitmaps | .docs/docs/docs/ |
| Non-SkiaSharp tech (MAUI, Blazor, WPF) | mslearn/microsoft_docs_search MCP tool |
Pre-flight — confirm before analyzing:
- Cache worktree is set up and pulled
- Issue data loaded (cache JSON or GitHub API)
- Read references/schema-cheatsheet.md for required fields and enums
- Read references/labels.md for valid label values
- Read references/triage-examples.md for calibration
- Read references/anti-patterns.md — at least the critical rules
- Created a brief plan (5-10 lines: what to investigate, what type you suspect)
Reminder: Triage is READ-ONLY. Do NOT edit any source files (.cs, .cpp, .csproj, .json).
Phase 3 — Analyze
First triage in session
Read references/labels.md for valid label values and cardinality, references/triage-examples.md for calibration, and references/schema-cheatsheet.md for required fields.
Classify and generate JSON
Write brief internal analysis (3–5 sentences), classify the type, then read references/research-by-type.md for type-specific research. Conduct the research, then generate the JSON. Write to /tmp/skiasharp/triage/{number}.json — use this exact literal path, do NOT substitute $TMPDIR or any other variable.
⚠️ Schema Compliance:
- Read references/schema-cheatsheet.md — This is the authoritative source for structure, fields, and enums.
- Review references/labels.md — Use only valid label values.
- Follow these critical constraints:
meta.schemaVersionmust be"1.0"- Optional fields: OMIT entirely if not applicable. Do NOT set to
null.- String Arrays:
platforms,backends,tenetsare simple string arrays (no confidence wrapper).- Investigation:
analysis.codeInvestigationis MANDATORY. At least one entry for bugs, two for close-* actions.- Rationale:
analysis.rationaleis a single summary string (not per-field).- Validation: No extra properties allowed (
additionalProperties: false).
JSON Groups Overview
| Group | Content |
|---|---|
summary |
One-sentence description of the issue (top-level string, required). |
meta |
Version "1.0", issue number, repo, analyzedAt (ISO 8601). |
classification |
type and area (required objects with confidence). platforms, backends (optional string arrays). |
evidence |
bugSignals (for bugs), reproEvidence (all attachments/links), regression (if claimed), fixStatus (if fixed). |
analysis |
summary (required), codeInvestigation (findings from Phase 2), keySignals (quotes), rationale (decision summary), resolution (proposals). |
output |
actionability (suggested action + suggestedReproPlatform) and actions (automatable tasks). |
Refer to the cheatsheet for the exact field structure and enum values.
Phase 3.5 — Workaround Search
For bugs, questions, and feature requests: actively search for workarounds the reporter can use now. Follow references/workaround-search.md — 9 sources in priority order (cached triages → closed issues → known patterns → source code → docs → web).
- Set proposal
categoryto"workaround"/"fix"/"alternative"/"investigation" - Include
codeSnippeton any proposal with copy-paste-ready code - Set
validatedto"untested"initially (upgraded in Phase 3.7)
Skip this phase for duplicates and abandoned issues (omit analysis.resolution).
Phase 3.7 — Workaround Validation (conditional)
If any proposal description, codeSnippet, or add-comment comment contains fenced code blocks or SK* API calls: validate with 3 parallel agents per references/workaround-validation.md.
Gate: No code blocks → skip (set validated: "untested"). ~60% of triages skip this step.
Agents (parallel explore type, Haiku model):
- API correctness — do the SK* types/methods exist with correct signatures?
- Behavioral correctness — disposal, null-checks, threading, does it solve the problem?
- Platform safety — will it work on the reporter's platform?
Synthesis: All pass → validated: "yes". Any warn → add caveats to comment, reduce confidence. Any fail → fix or strip code, set validated: "no".
Phase 4 — Validate
🛑 PHASE GATE: You CANNOT proceed to Phase 5 without passing validation.
Skipping validation = INVALID triage. The task is incomplete.
# Try pwsh first, fall back to python3
pwsh .github/skills/issue-triage/scripts/validate-triage.ps1 /tmp/skiasharp/triage/{number}.json \
|| python3 .github/skills/issue-triage/scripts/validate-triage.py /tmp/skiasharp/triage/{number}.json- Exit 0 = ✅ valid → proceed to Phase 5
- Exit 1 = ❌ fix the errors listed in the output, then re-run. Repeat up to 3 times.
- Exit 2 = fatal error, stop and report
⚠️ NEVER hand-roll your own validation. NEVER assume it passes. RUN THE SCRIPT.
Phase 5 — Persist & Present
🛑 PHASE GATE: Phase 4 validator MUST have printed ✅ before you reach this step.
If you have not run the validation script, GO BACK and run it now.
1. Persist
🛑 MANDATORY: Use the persist script. NEVER manually
cp,git add,git commit, orgit push.
The script handles copying, committing, and pushing with retry logic. Manual git commands
will leave unpushed commits that are lost when the runner shuts down.
pwsh .github/skills/issue-triage/scripts/persist-triage.ps1 /tmp/skiasharp/triage/{number}.jsonThis copies the JSON to data-cache and handles git commit + push automatically (skips in benchmark mode).
2. Present summary
✅ Triage: ai-triage/{number}.json
Type: type/bug (0.98) Area: area/SkiaSharp
Severity: critical Action: needs-investigation
Actions:
labels-1 update-labels [low] Add type/bug, area/SkiaSharp
comment-1 add-comment [high] ⚠️ requires human edit
link-1 link-related [low] Cross-ref #1234Pipeline hint:
- If
classification.type.value == "type/bug"andoutput.actionability.suggestedAction == "needs-investigation": next step is issue-repro (ai-repro/{number}.json). - If
classification.type.valueistype/enhancementortype/feature-requestandsuggestedAction == "needs-investigation": next step is also issue-repro, but repro will useconfirmed/not-confirmedinstead ofreproduced/not-reproduced. output.actionability.suggestedReproPlatformtells CI which runner to use for reproduction:macos— for os/iOS, os/macOS, os/tvOS, os/watchOS issueswindows— for os/Windows-Classic, os/Windows-WinUI, os/Windows-Universal-UWP, os/Windows-Nano-Server issueslinux— for everything else (os/Linux, os/WASM, os/Android, os/Tizen, or no platform specified)- Note: For platform-independent API bugs (e.g., SVG output, stream handling), prefer
linuxeven if the reporter tests on other platforms.
- If repro already exists and reproduces: next step is issue-fix (consume both JSONs).
If add-comment exists, show comment in a copy-paste block. ⚠️ NEVER post via GitHub API.
Anti-Patterns
See references/anti-patterns.md — read this file on first triage in session.
#0 (CRITICAL): Triage is READ-ONLY. If you edit a source file during triage, you have FAILED. See the anti-patterns reference for the full list.
#1 (CRITICAL): NEVER use store_memory during triage. Triage produces JSON artifacts, not memories. Storing unverified facts pollutes all future sessions.
#2 (CRITICAL): NEVER skip the validation script. You MUST run validate-triage.ps1 (or .py fallback) and see ✅ before persisting. Mentally checking fields is not validation. If the script isn't run, the triage is invalid.
Scripts
scripts/issue-to-markdown.ps1 <file.json>— Preprocess cached issue → annotated markdownscripts/validate-triage.ps1 <triage.json>— Validate against schema + rationale coverage + action integrity