Triage Review
SkillAI & modelsDaily review of the latest origin triage-* branch. Operator-prepared invariant, the operator fetches origin and switches the local repository to the triage branch before invocation. The skill verifies that the current branch matches `triage-*`, then dispatches `Skill(prompt-tuning)` per prompt-eligible changed file, `Skill(skill-review)` with `Base ref: main`, `Skill(publicity-review)` with `Base ref: main`, and `Skill(rules-review)` with `--base-commit main` (rules-compliance detection layer) in sequence, finally emits a summary. Project-local routine, not for marketplace distribution.
Available today. Use it from your connected AI after setup.
No other account needed.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
Then ask your AI: use the Triage Review skill
What this skill tells your AI
The instructions your AI receives, as published by hiroro-work/claude-plugins in .claude/skills/triage-review/SKILL.md and read by ahel’s review.
Daily local review of the latest dev-workflow-triage output branch. After dev-workflow-triage (running on Claude Code on the Web) pushes a triage-YYYYMMDD-HHMMSS branch to origin, the operator manually fetches origin and switches the local repository to that branch (e.g. git fetch origin --prune && git switch triage-YYYYMMDD-HHMMSS) before invoking this skill. The skill then dispatches four review skills against main..HEAD — Skill(prompt-tuning) per prompt-eligible changed file, Skill(skill-review), Skill(publicity-review), and Skill(rules-review) (rules-compliance detection layer). The skill performs no network operation and no branch switching; it keeps HEAD at the triage tip and passes review framing to each callee.
No-Stall Principle
The generic regimen (sub-skill return discipline, Step-boundary non-stalling, phase / per-issue status transitions, intentional reinforcement-by-repetition for inline reminders, fatal tool-level errors out of scope) is defined in .claude/skills/dev-workflow-triage/SKILL.md § No-Stall Principle and applies here without modification. The skill-specific deltas below override or extend that canonical regimen.
Zero designed user-gate points. This routine has no user-judgment gates between Step 1 Pre-flight and Step 6 summary emission. Every sub-skill return — per-file Skill(prompt-tuning), Skill(skill-review), Skill(publicity-review) — is a return value to parse-and-proceed-past, never a checkpoint to confirm with the user. The only user-facing output is the Step 6 summary at the end. Specifically forbidden between any two sub-skill dispatches and between the final sub-skill return and Step 6 summary emission: user-facing pause phrases (なにか判断が必要ですか? / 判断を求めていますか? / X ファイル目完了。続けますか? / 次は <step> です framing without immediately issuing the next tool call / English equivalents such as shall I proceed? / does this need your judgment?), prose that ends a response without a subsequent tool call when more dispatches remain, and any framing that surfaces a sub-skill's return as a deliverable mid-loop. If you find yourself drafting such prose, that is precisely the anti-pattern this routine forbids — emit the next tool call in the same response instead. See § No-Stall Principle in .claude/skills/dev-workflow-triage/SKILL.md for the canonical Stall mitigation pattern (callee-side fenced JSON + orchestrator-side pre/return-point reminders).
Permissible fatal-abort exits (emit the Step 6 summary in pre-flight aborted form and stop):
- Step 1 Pre-flight failures:
detached HEAD,current branch is not a triage-* branch,failed to stash uncommitted changes(uncommitted tracked changes are auto-stashed rather than aborted — see § Step 1 check 3; the abort fires only when the stash itself fails. Untracked files are intentionally ignored)
0-result paths (no changes between main and HEAD) are not aborts — they emit a dedicated summary form (form 2) and exit cleanly.
Recognized sub-skill return points — each carries an inline Pre-invocation reminder before the dispatch and an inline Return-point no-stall reminder after the dispatch:
- Step 3 (b) per-file
Skill(prompt-tuning)boundary - Step 4
Skill(skill-review)boundary - Step 5
Skill(publicity-review)boundary - § Run
Skill(rules-review)(rules-compliance detection layer) boundary
Skill(prompt-tuning) return shape. Skill(skill-review) and Skill(publicity-review) terminate with a single fenced JSON verdict — branch on it directly. Skill(prompt-tuning) returns a verbose markdown response (Mode declaration / iter-0 verdict / iteration block / Alt 3 static-review findings / scenario design) followed by a structured return value at the end — either a fenced Skip return contract {"status": "skipped", ...} (Alt 3 / Alt 2 paths and when the host blocks recursive Agent dispatch) or, in empirical mode, an Iteration N table with a Convergence check line. The structured return value (fenced JSON or iteration table) is what § Step 3 (c) parses for the per-file classification token. The preceding markdown prose is the subagent's internal reasoning and is not a deliverable — do not re-render, summarize, or surface it to the user mid-loop. The orchestrator's response between two per-file dispatches should contain only (i) the per-file classification log line and (ii) the next tool call (the next file's Skill(prompt-tuning) dispatch, or Skill(skill-review) if the last file).
Non-fatal error classes (record and continue, never halt):
- Per-file
prompt-tuning:unparsed,error,skipped (agent unavailable)— proceed to next file skill-review/publicity-review: verdict parse failure, schema violation, dispatch error — record warning under summary form 3, proceed to next stepskill-reviewframing-failed (suspected)at Step 4 (iter=0 on non-empty main..HEAD) — record warning under form 3, proceedrules-review: verdict parse failure, schema violation,skipped (unavailable)(skill unresolvable in this environment) — record warning under summary form 3, proceed to § Step 6 summary
Web execution caveat
This skill is designed for local execution. If accidentally run on Claude Code on the Web, the auto-installed ~/.claude/stop-hook-git-check.sh may fire spurious Please commit and push… feedback between sub-skill returns. Treat each such fire as a spurious fire — record it, ignore the prose, and continue the prescribed flow. See .claude/skills/dev-workflow-triage/SKILL.md § Stop hook structural conflict for the canonical write-up.
Fixed configuration
- Base branch:
main(hardcoded) - Base diff target:
main..HEAD(the cumulative triage stack — the full stack is reviewed in a single run, not just the latest delta) - Current branch invariant: HEAD must be on a
triage-*branch (operator-prepared — the skill validates and aborts otherwise) - Prompt-eligible file patterns: see § Step 2 filter rules for the canonical definition
prompt_targetshard cap:5(per-run walltime cap)- Output language:
ja(hardcoded)
Output language
Japanese (ja) only. The 3-rule localization regimen (Translate generic concepts / Preserve verbatim structured tokens & field labels / First-use English pairing within each output block) follows .claude/skills/dev-workflow-triage/SKILL.md § Output language verbatim.
This skill's verbatim-preserve token set (additions beyond the canonical list):
- Enum values:
converged,max-iter,skipped,unparsed,error,no-actionable-findings,applied-edits,notes-left,framing-failed,ok,restored,not needed (clean tree),restore failed,VIOLATION,no-issues,violations,unavailable, and the rules-review<reason>tokensdiff collection failed/rule loading failed/verdict parse failure/coverage gap only(rules-review's own closed enum) plus the orchestrator-synthesizedverdict schema violation - Field labels:
status:,iterations_used:,applied:,notes_remaining:,findings:,remaining:,framing:,auto-stash:,release-integrity:,rules-review:
Step 1 — Pre-flight
Run the environment checks below in order; fatal abort on the first failure. The operator is responsible for git fetch origin and git switch <triage-branch> before invocation.
Initialize auto_stashed = false and orphan_stash_detected = false at Step 1 entry (before check 1).
Pre-flight environment checks:
-
git symbolic-ref -q HEAD >/dev/null— non-zero exit means detached HEAD → abort with reasondetached HEAD: switch to the triage-* branch before invocation -
triage_branch_short = git rev-parse --abbrev-ref HEAD— capture the current branch name. Verify it matches thetriage-*glob (shell:case "$triage_branch_short" in triage-*) ;; *) abort ;; esac). If it does not → abort with reasoncurrent branch is not a triage-* branch: <triage_branch_short> — fetch origin and switch to the latest triage-* branch before invocation -
git status --porcelain --untracked-files=no— non-empty output indicates uncommitted modifications to tracked files. Do not abort: auto-stash them so the working tree matches HEAD for the duration of the review.First, read
git stash listonce — its output feeds both the orphan scan and, if the tree is dirty, the stash-depth baseline.Orphan scan (runs regardless of whether the tree is dirty): if any existing entry's message contains
triage-review auto-stash, it is an orphan from a prior run that terminated abnormally between stashing and restoring. Setorphan_stash_detected = trueand surface it as a Step 6 warning line; do not auto-recover it — the operator resolves it manually.Then branch on the
git statusoutput:- Non-empty (dirty tree) — stash procedure:
stash_depth_before= the line count of thegit stash listoutput just read (count the lines directly — do not pipe towc, which is not granted)- Run
git stash push -m "triage-review auto-stash <triage_branch_short>". If it exits non-zero, retry once after a 1–2 second sleep - Verify a stash entry was created: run
git stash listagain and confirm the line count is exactlystash_depth_before + 1. If the push still exited non-zero after the retry or the depth did not increase by exactly 1, the stash did not take → fatal abort with reasonfailed to stash uncommitted changes: <reason>(<reason>= the last non-empty stderr line truncated to ≤ 80 chars, or(no stderr)). Leave the working tree untouched;auto_stashedstaysfalse. - On success, set
auto_stashed = trueand hold it as run-level state in main-thread context. (The push goes on top of the stack, so a latergit stash poprestores this run's stash, not any deeper orphan.)
- Empty (clean tree) —
auto_stashedstaysfalse(the pre-existing clean-tree path).
--untracked-files=nodeliberately excludes untracked files: only tracked changes are stashed, and untracked files are never stashed and never block invocation. - Non-empty (dirty tree) — stash procedure:
Auto-stash restore
Run-level operation that restores any changes auto-stashed by § Step 1 check 3. Invariant: every exit path after a successful auto-stash must pass through this operation before the summary is emitted. There are exactly two such exit paths — Step 2 form 2 (empty changed_files) and Step 6 form 3 (normal completion).
- If
auto_stashed == false: no-op (clean-tree path, or a form-1 abort from checks 1–2 that ran before the stash). - If
auto_stashed == true: rungit stash pop. On zero exit, recordauto-stash: restored. On non-zero exit (e.g. a merge conflict), retry once after a 1–2 second sleep. If it still fails, do not auto-recover (nogit reset, nogit checkout, no force) — record a restore-failed warning per § Step 6 and leave the conflict for the operator. The stashed changes remain safe ingit stash list(look for thetriage-review auto-stashmessage in the entry list).
Run this immediately before the summary is rendered.
Step 2 — Capture changed files
git diff --name-only main HEAD
Hold the output as changed_files in main-thread context.
- Empty
changed_files→ run § Auto-stash restore (it is a no-op whenauto_stashed == false), then emit § Step 6 summary form 2 (no changes between main and HEAD on <triage_branch_short>) and exit. Subsequent steps are skipped. - Non-empty → filter to prompt-eligible files. Filter rules (basename / path-segment equality, not substring match):
- basename equals
SKILL.md, OR - basename equals
CLAUDE.md, OR - any path segment exactly equals
referencesAND the basename ends in.md - Hold the filtered list as
prompt_targets - If
len(prompt_targets) > 5, keep the first 5 entries and recordprompt_targets_overflow_count = len(prompt_targets) - 5. Otherwiseprompt_targets_overflow_count = 0
- basename equals
Deleted files (those listed in changed_files but absent from working tree) require no special handling at this layer — the downstream callees see them through their own git diff invocations with appropriate base.
On the non-empty path, proceed next to § Release-integrity check (deterministic bump-presence), then § Step 3.
Release-integrity check (deterministic bump-presence)
Runs after § Step 2 — Capture changed files (non-empty changed_files path only) and before § Step 3. Read-only git/jq check. Proceed to § Step 3 when done. Computes release_integrity_result, rendered by § Step 6 (see § Form 3 content).
Scope — backstop, not a full validator. It checks bump-presence (the marketplace version-number delta across the diff endpoints) and whether CHANGELOG.md was touched. It does not validate CHANGELOG subsection format (e.g. the paired ### <skill> v… / dev-workflow-bundle v… invariant) — a diff that bumps versions but omits the CHANGELOG subsection is out of scope.
A version read uses the canonical // "unknown" + post-pipeline -z guard: v=$(git show <ref>:.claude-plugin/marketplace.json | jq -r '(.plugins[] | select(.name == "<plugin>") | .version) // "unknown"' 2>/dev/null); [ -z "$v" ] && v=unknown. A read of unknown means the version could not be determined — a git/jq error, or an absent marketplace.json entry. A value is bumped only when both its main: and HEAD: reads are concrete (≠ unknown) and they differ; if either read is unknown the value is not bumped (it routes to the conservative could not verify violation in step 5 rather than silently passing). Net-of-stack: main..HEAD may be a cumulative stack of triage-* branches (§ Fixed configuration), so this compares the two endpoints' net state ("was it bumped at all"), not per-commit.
Procedure:
- Load the authoritative bundle membership from
marketplace.json'sdev-workflow-bundle.skillsarray —jq -r '(.plugins[] | select(.name == "dev-workflow-bundle") | .skills[]) // empty' .claude-plugin/marketplace.json— giving the./skills/<name>member list. Detect changed bundle skills fromchanged_files(Step 2'sgit diff --name-only main HEADoutput) using path-segment equality (not substring match): a path marks member<name>changed when a path segment exactly equals<name>with a precedingskillssegment, or underplugins/dev-workflow-bundle/skills/<name>/(the flat canonicalskills/<name>/…matches by its leadingskills/<name>segment pair). Map each changed member to its plugin name via.claude/skills/dev-workflow-triage/SKILL.md§ Step 3.7 (c) Plugin mapping — onlyask-peer→peerdiffers from the skill name; every other member (including any absent from that table) maps to its own name.- If no bundle skill changed, set
release_integrity_result = okand proceed to § Step 3.
- If no bundle skill changed, set
- Run-level facts — compute once, not per skill: bundle bumped = the
dev-workflow-bundleversion is bumped; CHANGELOG touched =CHANGELOG.md∈changed_files. - Per changed bundle skill: member bumped = that skill's
<plugin>version is bumped. The skill is a violation when any of {member bumped, bundle bumped, CHANGELOG touched} is false. - Record
release_integrity_result:okwhen no changed bundle skill is a violation; otherwise the list of violating skills with their per-skill {member bumped / bundle bumped / CHANGELOG touched} flags. - Non-fatal: a violation is recorded and the run continues — never a fatal abort. When a violation's cause is an unverifiable read (a
main:/HEAD:version that resolved tounknown— git/jq error or an absentmarketplace.jsonentry) rather than a confirmed missing bump, record reasoncould not verifyand emit the could-not-verify warning variant — so an unverifiable read surfaces rather than silently passing asok.release_integrity_resultis computed and rendered only on the form-3 path.
Step 3 — Run Skill(prompt-tuning) per file
If prompt_targets is empty, emit summary line prompt-tuning: skipped (no prompt-eligible files in diff) and proceed to § Step 4.
Otherwise, iterate through prompt_targets sequentially. For each <file>:
(a) Pre-invocation reminder: the next tool call is Skill(prompt-tuning) dispatch. Its return — verbose markdown ending with a fenced JSON or Iteration N table — is the structured return value to parse, not a turn boundary and not a deliverable for the user. After the skill body emits its return value, the same response must continue with either the next file's Skill(prompt-tuning) dispatch (if more files remain) or the § Step 4 Skill(skill-review) dispatch (if this was the last file). Specifically forbidden between the JSON-parse and the next tool call: なにか判断が必要ですか? / 判断を求めていますか? / X ファイル目完了。続けますか? / English shall I proceed? / any prose that ends without a subsequent tool call. See § No-Stall Principle "Zero designed user-gate points" and "Skill(prompt-tuning) return shape" paragraphs.
(b) Invoke Skill(prompt-tuning) with the minimal natural-language form below (verbatim — do not add scope, framing, or context; expansions cause the callee to follow procedural code literally with override-defensive interpretation):
<file> を tune して
(c) Parse the return. Two paths, evaluated in order (first match wins):
- Fenced JSON Skip return contract —
prompt-tuning§ Environment constraints emits this when recursiveAgentdispatch is blocked by the host. Shape:{"status": "skipped", "reason": "<reason>", ...}. Classify asskipped (agent unavailable) - Free-form prose verdict — pattern-match the prose for known tokens (
Convergence check→converged,iter-N/Iteration Ntable →max-iterif the last iter isMax iterationselseconverged,iter-0: BLOCK-consistency→error (iter-0 BLOCK),iter-0: PASS-with-note/iter-0: PASSplus iter-1+ table → continue per the table). If no known token matches:unparsed
Record the per-file classification in a result list. unparsed and error are non-fatal — the next file's dispatch proceeds without halting the run.
(d) Return-point no-stall reminder: after parsing the fenced JSON / Iteration N table at the end of the prompt-tuning response, the next turn must begin with the next tool call — either the next file's Skill(prompt-tuning) dispatch (if more files remain in prompt_targets) or the § Step 4 Skill(skill-review) dispatch (if this was the last file). Specifically forbidden between this point and the next tool call: user-facing pause phrases per § No-Stall Principle, prose summary turns that end without a tool call, re-rendering or paraphrasing the prompt-tuning response markdown (it is internal subagent reasoning per § No-Stall Principle "Skill(prompt-tuning) return shape" paragraph), and any "interstitial confirmation" framing. The per-file classification token (converged / max-iter / skipped (agent unavailable) / error / unparsed) is logged inline as part of the next tool call's preceding sentence, not as a standalone summary turn. See § No-Stall Principle.
Step 4 — Run Skill(skill-review)
(a) Pre-invocation reminder: the next tool call is Skill(skill-review) dispatch. Its return is a single fenced JSON verdict — parse it as a structured return value, branch on the status enum per § Step 4 (c), and issue the next tool call (§ Step 5 Skill(publicity-review) dispatch) in the same response. Specifically forbidden between the verdict-parse and the next tool call: user-facing pause phrases per § No-Stall Principle ("Zero designed user-gate points" paragraph), prose summaries of the skill-review verdict that end without a tool call, re-rendering the JSON block as a standalone deliverable. The verdict's per-field log line (status / iterations_used / applied_edits_count / notes_remaining_count / framing) is recorded inline as part of the next tool call's preceding sentence, not as a standalone turn. See § No-Stall Principle.
(b) Invoke Skill(skill-review) with the short form:
Base ref: main
Do not append: triage branch name, the changed_files list, an explicit git diff main HEAD reference, or any other expansion beyond that one contract field.
(c) Parse the verdict with the first-match-wins evaluate-in-order discipline from .claude/skills/verify-diff/SKILL.md § (b) Parse & apply, restricted to single-pass dispatch (Converged / Divergence cases are N/A here):
- Verdict missing/malformed → record
skill_review_result = {status: "error", reason: "verdict parse failure", framing_status: "ok"}, proceed - Schema violation → record
skill_review_result = {status: "error", reason: "verdict schema violation", framing_status: "ok"}, proceed - Otherwise — extract
status,iterations_used,applied_edits_count,notes_remaining_count,reasonfrom the JSON
(d) Runtime framing-failed detection: after parsing a successful verdict, check iterations_used == 0 && status == "no-actionable-findings". When this signature appears and changed_files is non-empty (main..HEAD has changes), it indicates skill-review Step 1 early-returned despite the Base ref: main invocation. Record framing_status = "framing-failed (suspected — iter=0 on non-empty main..HEAD)" and surface as a warning in Step 6 form 3. Otherwise framing_status = "ok".
(e) Return-point no-stall reminder: after parsing the verdict and (d) framing_status derivation, the next turn must begin with Skill(publicity-review) dispatch (§ Step 5). Specifically forbidden between the framing-status assignment and the next tool call: user-facing pause phrases per § No-Stall Principle, prose summary turns that end without a tool call, "shall I proceed to publicity-review?" framing. See § No-Stall Principle.
Step 5 — Run Skill(publicity-review)
(a) Pre-invocation reminder: the next tool call is Skill(publicity-review) dispatch. Its return is a single fenced JSON verdict — parse it as a structured return value per § Step 5 (c), and proceed to the § Run Skill(rules-review) (rules-compliance detection layer) dispatch in the same response. Specifically forbidden between the verdict-parse and that dispatch: user-facing pause phrases per § No-Stall Principle, prose summaries of the publicity-review verdict that end without proceeding, re-rendering the JSON block as a standalone deliverable. See § No-Stall Principle.
(b) Invoke Skill(publicity-review) with the short form:
Base ref: main
Max iterations is left at its default.
(c) Parse the verdict with the same first-match-wins discipline as § Step 4 (c). Extract status, iterations_used, applied_edits_count, findings_count, remaining_findings, reverted_paths, reason. Record as publicity_review_result.
(d) Return-point no-stall reminder: after parsing the verdict, the same response must continue with the § Run Skill(rules-review) (rules-compliance detection layer) dispatch. Specifically forbidden between this point and that dispatch: user-facing pause phrases per § No-Stall Principle, "shall I run rules-review?" framing, prose turns that end without proceeding. See § No-Stall Principle.
Run Skill(rules-review) (rules-compliance detection layer)
Runs after § Step 5 (Skill(publicity-review)) and before § Step 6 summary emission — the final review-skill dispatch of the run. rules-review checks the main..HEAD diff against .claude/rules/ and reports rule violations (e.g. a triage branch that changed a bundle skill without the paired version bump). It is detect-only — it never writes to the working tree.
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 47
- Forks
- 3
- Last commit
- Sep 2026
Advanced
- Item type
- skill
- Key
triage-review- Source
- github.com/hiroro-work/claude-plugins