Dev Workflow Triage

SkillAI & models

Triage open issues in the retrospective issue repo populated by the dev-workflow producer (v1 and v2 issue formats). Read each open issue, judge each Finding (accept / reject), apply accepted fixes to the triage-scope skills (the bundle skills dev-workflow, ask-peer, extract-rules, rules-review, tidy, prose-polish, mobpro, kabeuchi, artifactor, furikaeri; plus dev-workflow-triage itself for self-targeted findings from its own self-retrospective), post a triage comment, and close the issue; after the per-issue loop, run a once-per-run rules-compliance detection pass (Step 3.8) over the run's diff via Skill(rules-review). Designed for non-interactive routine execution (no plan mode, no user prompts) on Claude Code on the Web.

Available today. Use it from your connected AI after setup.

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 Dev Workflow Triage skill

What this skill tells your AI

The instructions your AI receives, as published by hiroro-work/claude-plugins in .claude/skills/dev-workflow-triage/SKILL.md and read by ahel’s review.

Non-interactive daily triage of the dev-workflow-bundle retrospective issues. Designed for routine execution. See § No-Stall Principle below for the only permissible exits.

No-Stall Principle

This skill has no user-confirmation gates. The run executes to completion or aborts to the Step 4 summary. Every other transition — sub-skill returns, loop boundaries, non-fatal error records, phase / per-issue status flips — continues without user confirmation; the only stopping points are the two exits listed below.

Permissible fatal-abort exits (both emit the Step 4 summary and stop without entering the per-issue loop; § Step 5 — Self-retrospective is skipped on these exits):

  • Step 1 pre-flight failures (defined in Step 1)
  • Step 2 issue-list call failure (defined in Step 2)

Whole-issue parse-error is not an abort; the issue is left open with a triage comment and the run continues.

No pause at sub-skill returns. When Skill(verify-diff), Skill(skill-review), or Skill(publicity-review) returns, parse the result and follow the existing branch logic immediately. Long reasoning prose in the response is not a stopping signal — do not insert a "let me summarize what just happened" turn before the next action. All three callees terminate with a single fenced JSON verdict (verify-diff § Step 5 — Emit structured summary, skill-review § Return contract, publicity-review § Step 4 — Emit structured summary); branch on that block directly. Concretely: the assistant response that contains the parsed JSON verdict MUST also contain the next Skill(<callee>) / Edit / Bash tool call. If the response ends right after the JSON block — even with no prose in between — the No-Stall Principle is violated.

Concretely, the recognized return points are the (d) Skill(verify-diff) empirical check, the (d2) Skill(skill-review) polish bullets, and the (d3) Skill(publicity-review) empirical check inside the Apply accepted Findings sub-flow (§ 3.4 Apply accepted Findings). Each of these three carries both an inline **Pre-invocation reminder** (placed before the Skill(<callee>) dispatch — frames the upcoming dispatch as "parse a return value, not a turn boundary") and an inline **Return-point no-stall reminder** (placed after the dispatch — fires the named next action). Entry + return coverage is intentional reinforcement-by-repetition at the decision moment (same regimen as the 3-paragraph ## Dispatch discipline repetition rule in .claude/rules/project.rules.local.md); both must survive any future Simplify pass. The (d)/(d2)/(d3) reminders are scoped to mid-Finding workflow AND mid-issue workflow — i.e. they cover both same-Finding sub-step transitions (e.g. (d) → (d2) → (d3) → (f) → (g)) and same-issue sub-step transitions (e.g. 3.4 → 3.5 → 3.6) so no separate inline reminder is needed at 3.4 → 3.5 or 3.5 → 3.6.

No pause at issue-loop / Step boundaries. Four additional return-point reminders cover the boundaries the (d)/(d2)/(d3) reminders do not reach: the issue boundary (3.6 → next issue), the last-issue → Step 3.7 boundary, the Step 3.7 → Step 3.8 boundary, and the Step 3.8 → Step 4 boundary. Each boundary has its own inline reminder — same closed-list shape as (d)/(d2)/(d3), placed at the decision moment.

The bookkeeping-commit sub-step sequence (Step 3.7) is non-stalling. Run the entire sub-step sequence (version-skew guard → marketplace.json bump → jq empty validate → CHANGELOG.md Read → CHANGELOG prepend Edit → scope check → bookkeeping commit) as a single continuous tool-call burst — do not insert any interstitial user-confirmation turn between consecutive sub-steps. The Read of CHANGELOG.md immediately before the prepend Edit is not a turn boundary; issue the Edit in the same burst as the Read. Apply this equally to every consecutive pair in the sub-step sequence — including jq-validate → Read, Read → Edit, Edit → scope check, and scope check → commit.

Phase / per-issue status transitions are non-stalling. Marking a phase row or per-issue row completed and the next row in_progress must happen as part of the same tool-call burst that produces the next concrete action — never as a standalone summary turn. The status-write itself — whether via the Task tools (TaskCreate / TaskUpdate) or the TodoWrite fallback — is allowed (it's a status-only side effect, not a sensitive-path file write, so no permission dialog fires in routine execution), but no user-facing prose is emitted between the status flip and the next non-status-write tool call.

Non-fatal errors are recorded and skipped, not stops. Per-Finding / per-issue errors (comment-failed, close-failed, commit-failed, label-failed) continue with the next Finding or issue. A char-budget defer (§ 3.4 sub-step (a.5)) is likewise non-fatal — it downgrades the single Finding to conflict and continues with the next Finding, the same disposition an ordinary conflict receives. Step 2 records overflow=true and the run keeps going on the truncated list. Step 3.7 errors (release-bookkeeping=failed (commit error|scope leak|version skew|json invalid|changelog edit error)) fall through to Step 4 — Step 3.7 runs once per run after the per-issue loop, so "next Finding" is not a possible recovery there. Step 3.8 rules-review non-clean outcomes (error (<reason>) / skipped (unavailable)) are recorded in rules_review_result and fall through to Step 4 — Step 3.8 also runs once per run, so there is likewise no per-Finding recovery path. Step 4 push errors (push-failed (<reason>)) fall through to summary emission — push runs once per run after auto-cleanup, so there is no per-Finding recovery path either; the operator can git push manually post-run. See § Push triage branch to origin for the <reason> extraction spec. Step 5 errors (self-retrospective-failed (<reason>)) fall through to the Step 5 terminal line — Step 5 runs once per run after Step 4, so there is no per-Finding recovery path; the staging file is kept for manual retry. references/triage-criteria.md § Edge-case dispatch table is the authoritative list of dispositions.

Stop-hook spurious fires are also non-fatal. ~/.claude/stop-hook-git-check.sh (auto-installed by Claude Code on the Web — see § Stop hook structural conflict) fires on every Stop event during the (b)→(g) per-Finding flow because uncommitted state is normal mid-flow. The hook's exit 2 injects a Please commit and push… feedback string but does not block — record the spurious fire and continue with the prescribed flow ((b)→(c)→(d-loop)→(f)→(g), where (d-loop) iterates (d)→(d2)→(d3) up to 3 times). Do not jump ahead to (g) commit on hook feedback alone; that bypasses verify-diff / skill-review / publicity-review / scope check and is a misbehavior.

Operator interventions are tallied at Step 5, not re-litigated mid-run. In this non-interactive routine, any user message that arrives mid-run (after the invocation itself) is evidence that the run may have stalled at the immediately-preceding return point. The correct behavior on resuming is to issue the prescribed next action immediately — and nothing else. Apology prose, a recap of what stalled, and any interruption to record the intervention are all forbidden: the recording act itself would create a new stall-inducing decision moment at exactly the point this skill works hardest to keep frictionless. Tallying and classifying interventions is § Step 5 — Self-retrospective's job, performed once at the end of the run from the in-context evidence.

Resuming after context compaction is not a confirmation gate. When the session context is compacted mid-run (between any two tool calls), the run resumes as if no boundary occurred: (i) reconstruct what can be recovered — per-Finding dispositions already applied (from the issue's posted triage comment — see § Post triage comment), triage_commit_count (from git log commit count on the triage branch), and triage_branch_name (from git rev-parse --abbrev-ref HEAD) — then reset in-memory-only counters to their safe defaults: verify_diff_disabled / skill_review_disabled / publicity_review_disabled reset to false (the consecutive-error counts that drove these flags are not recoverable after compaction — resetting the flags to false is sufficient and the counts need not be reconstructed); (ii) issue the prescribed next action immediately — no recap, no confirmation, no "shall I continue?"; (iii) external / irreversible operations (issue comment, issue close, version bump, git push) are already authorized by the routine invocation; context compaction alone does not revoke that authorization.

(d-loop) outer iteration boundaries are non-stalling. When (d-loop) (see § 3.4 Apply accepted Findings) re-enters the next outer iter (k → k+1) after (d3)'s return, the next tool call must directly issue iter k+1's (d) Skill(verify-diff) dispatch — never an interstitial summary or "let me decide whether to continue" turn. Conversely, when the loop terminates (early-exit on zero edits, callee-abort downgrade, or k=3 reached), the next tool call must directly issue (f) Scope check + stage (or skip to next Finding's (a) on the conflict-downgrade path). Both transitions follow the same closed-list shape as the (d)/(d2)/(d3) return-point reminders. A net-empty diff after (d-loop) terminates — including the case where the review loop reverted all of its own edits — is still a non-stalling transition: issue (f) immediately; (f) finds nothing to stage, skips the commit, and continues to the next Finding or per-issue step in the same turn.

Workload-anxiety mid-flow abort is forbidden. This skill has exactly three scale-management gates: (i) the 50-issue cap at § List open issues, (ii) per-callee consecutive-error disable flags (verify_diff_disabled / skill_review_disabled / publicity_review_disabled) that silently degrade callee coverage when consecutive non-healthy verdicts (errors, repeated skipped / conflict) accumulate, and (iii) the (d-loop) per-Finding cap (max 3 outer iters with early-exit on zero edits) that bounds outer-iter count per Finding. Aborting the routine mid-flow because cumulative Skill() loads "feel expensive", because the per-Finding sub-flow "looks long", or because of any equivalent operational anxiety is a No-Stall Principle violation. If you find yourself reasoning "X Findings × Y callees would consume too much context — let me stop here", that is precisely the anti-pattern this clause forbids. The scale-management gate list above is closed; if a future change introduces a new gate, append it here so the canonical enumeration stays exhaustive.

Fatal tool-level errors are out of scope — irrecoverable Edit / Read / Bash failures halt with a diagnostic regardless.

Triage branch isolation

Each run creates its own branch named triage-YYYYMMDD-HHMMSS so per-Finding commits and the Step 3.7 release-bookkeeping commit do not land directly on main (or whatever branch the operator was on at run start). The base for the new branch is the most recent existing triage-* branch — if a prior triage branch is still open (unmerged) the new run continues from where it left off, so two runs against partially-overlapping issue sets never produce conflicting marketplace.json / CHANGELOG.md edits at PR-merge time. With no prior triage branches the base is the branch the operator was on (typically main).

Eager creation, lazy cleanup. The branch is created in Step 1 Pre-flight regardless of whether any Findings will be accepted. A 0-commit run (no open issues, every Finding rejected, every accept downgraded to conflict, etc.) is auto-cleaned in Step 4: switch back to original_branch and git branch -D <triage_branch_name>. Lazy creation (deferring the git switch -c until the first commit) was rejected because § 3.4 Apply accepted Findings sub-step (g) and § Step 3.7 Release bookkeeping sub-step (j) each have their own commit-failure recovery paths (git reset + git checkout HEAD -- <paths>); injecting branch-creation hooks into both sites would multiply the recovery branches without removing the cleanup obligation. Eager + single-site cleanup keeps the control flow flat.

Same-day re-run by design stacks. The 2nd run of a single day picks the 1st run's triage-YYYYMMDD-HHMMSS branch as its base because refname sort = chronological. Per-run isolation (each run still has its own branch) is preserved while the chain reflects the review history. The single-writer constraint (don't run two dev-workflow-triage invocations in parallel against the same target repo) still applies — concurrent runs sharing the same latest base would conflict at PR-merge time on marketplace.json / CHANGELOG.md. The same stacking applies when original_branch itself is a triage-* branch (re-running on a previously-created triage branch); see Step 1 Pre-flight and § Auto-cleanup of empty triage branch for the bookkeeping.

Stop hook structural conflict (Claude Code on the Web)

Claude Code on the Web's container auto-installs ~/.claude/stop-hook-git-check.sh (mode 755) at startup and registers it under ~/.claude/settings.json hooks.Stop with an empty matcher (matches every Stop event). This is part of the Web environment's standard setup, not a user-defined hook.

What it does: on every Stop event, the hook checks the git working tree (recursion guard via stop_hook_active, then git-repo / remote / uncommitted / untracked / unpushed in order). If any of the last four trip, it exit 2s and injects a stderr feedback string (Please commit and push…) so the agent's turn continues — the hook does not block execution.

Conflict mechanism: the per-Finding flow in § 3.4 Apply accepted Findings runs (b) Edit → (c) frontmatter check → (d-loop) outer review loop × up to 3 iterations of [(d) Skill(verify-diff) → (d2) Skill(skill-review) → (d3) Skill(publicity-review)] → (f) scope check + stage → (g) commit. Each Skill dispatch (verify-diff, skill-review, publicity-review — multiplied by up to 3 outer iters) creates a turn boundary, and uncommitted working-tree state between (b) and (g) is normal — that is the design. The hook fires at every boundary and feeds back Please commit and push… each time.

Correct behavior: see § No-Stall Principle's "Stop-hook spurious fires are also non-fatal" paragraph for the disposition. The cross-references in verify-diff SKILL.md (§ Stop hook structural conflict (caller-side note)), skill-review SKILL.md (§ Stop hook structural conflict (caller-side note)), and publicity-review SKILL.md (§ Stop hook structural conflict (caller-side note)) all point back here so the same disposition is applied caller-agnostic. When a Stop hook fires immediately after a callee's JSON verdict block, this is the most common stall-inducing combination — the feedback lands exactly at the moment the agent decides whether to close the turn. The disposition is unchanged — emit the next tool call in the same turn anyway. The count and approximate positions of spurious fires are tallied from in-context evidence by § Step 5 — Self-retrospective for its Run context section.

Bypass / disable guidance:

  • Permanent removal is discouraged — the hook serves other Web-environment purposes (e.g. nudging users about uncommitted state on conventional sessions)
  • Per-routine bypass is unnecessary because the hook does not block (exit 2 is a continue signal). Following the No-Stall Principle is sufficient
  • Step 1 Pre-flight detects the hook's presence and surfaces it in the Step 4 summary as observability. Detection is warning-only — never an abort

Fixed configuration

  • Target issue repository: SonicGarden/dev-workflow-issues (hardcoded — change this line to retarget)

  • Triage scope — target table:

    TargetEdit rootBundle memberRelease bookkeepingSize gate
    dev-workflowskills/dev-workflow/yespaired with dev-workflow-bundletests/dev-workflow/skill-size.test.mjs
    ask-peerskills/ask-peer/yespaired with dev-workflow-bundlegeneric headroom
    extract-rulesskills/extract-rules/yespaired with dev-workflow-bundlegeneric headroom
    rules-reviewskills/rules-review/yespaired with dev-workflow-bundlegeneric headroom
    tidyskills/tidy/yespaired with dev-workflow-bundlegeneric headroom
    prose-polishskills/prose-polish/yespaired with dev-workflow-bundlegeneric headroom
    mobproskills/mobpro/yespaired with dev-workflow-bundletests/dev-workflow/skill-size.test.mjs
    kabeuchiskills/kabeuchi/yespaired with dev-workflow-bundlegeneric headroom
    artifactorskills/artifactor/yespaired with dev-workflow-bundlegeneric headroom
    furikaeriskills/furikaeri/yespaired with dev-workflow-bundlegeneric headroom
    dev-workflow-triage.claude/skills/dev-workflow-triage/nonone (project-local)generic headroom

    This table is the single source of truth for target membership. Every other site in this skill and in references/triage-criteria.md refers to "§ Fixed configuration's target table" instead of re-enumerating targets; a site names a column only where it branches on that column (paired vs alone bump, bundle copy sync, size gate). Bundle membership mirrors marketplace.json's dev-workflow-bundle.skills array. Edits land in <Edit root>/SKILL.md or <Edit root>/references/*.md (the flat direct-skill layout) — never in .claude/skills/<target>/... symlinks; the dev-workflow-triage root is a project-local real directory, not a symlink. mobpro has no references/ directory. dev-workflow-triage is not registered in .claude-plugin/marketplace.json, hence none (project-local)

  • Self-retrospective issue title prefix: [triage-self-retrospective] — informational display prefix on issues filed by § Step 5 — Self-retrospective. The consumer does not filter on it: self-targeted issues are triaged like any other open issue. Source of truth for the prefix string is this line; keep § Step 5 — Self-retrospective's title template in sync

  • Output language: ja (hardcoded). Applied per § Output language below

The issue body format (### Finding <N> headings and 4 required fields per Finding) is produced by one external producer: skills/dev-workflow/references/self-retrospective.md (v2). It adds two extra optional bold fields (**Fix kind:**, **Size delta:**) that the consumer tolerates without validating; issues filed by its v1 predecessor (four fields, # dev-workflow-bundle retrospective (auto-generated) header) still parse. § Step 5 — Self-retrospective of this skill emits the same shape (minus the **Producer version:** line) for self-targeted issues. Producers may also emit a trailing Findings: N line as a self-consistency cross-check, but the ### Finding heading count is the canonical Finding count on the consumer side. Parse and reject conditions in the "Parse body" step below and in references/triage-criteria.md must stay aligned with both producers.

Output language

User-facing prose produced by this skill is always in Japanese (ja). This is a project-local skill with no configurable language setting.

Localization boundary (mirrors skills/dev-workflow/SKILL.md § Settings, its language paragraph):

  • Translate: generic technical concepts — e.g. "Open issues received" → 受信した未解決 issue 数; "Counts per outcome" → 結果別の件数; "Accepted-and-committed files" → accept 済み・コミット済みファイル
  • Preserve verbatim: structured tokens (accept / reject / conflict / parse-error / converged / unresolved, the rules-review verdict statuses no-issues / violations / error plus the orchestrator-side rules_review_result dispositions skipped (no commits) / skipped (unavailable), and the rules-review <reason> tokens diff collection failed / rule loading failed / verdict parse failure / coverage gap only (rules-review's own closed enum) plus the orchestrator-synthesized verdict schema violation, and all other machine-parsed enum values), field labels in the per-Finding execution log (target: / outer-loop: / verify-diff: / skill-review: / publicity: / commit:) and the Step 4 aggregate summary (release-bookkeeping: / rules-review: / triage-branch: etc.), file paths, commit hashes, config key names, skill names (Skill(verify-diff) etc.), § section references
  • First-use pairing: on the first occurrence of a translated concept within each output block (Step 4 summary, GitHub issue comment), pair the localized phrasing with the original English term in parentheses (e.g. 受信した未解決 issue 数(Open issues received)). Subsequent occurrences within the same block use the localized form alone

GitHub issue comments (§ Post triage comment): the comment Reasoning field is in Japanese. Template structure labels (Target, Category, Applied changes, Notes, Result) and enum tokens stay English for cross-language searchability.

Triage classes

Every Finding ends in one of four states: accept, reject, parse-error, or conflict. See references/triage-criteria.md for the conditions behind each and the disposition table.

Commit policy

One accepted Finding = one commit. Each commit is scoped to the target skill's directory. Message format:

fix(<target-skill>): <Finding 1-line summary> (auto-triage #<issue-N>)

<optional 1-2 line body: Finding Category, brief reason>

git push is run by this routine — see § Push triage branch to origin under § Step 4 — Emit summary (once per run at end of Step 4). Per-Finding (g) Commit and Step 3.7 (j) bookkeeping only commit to local HEAD.

Execution flow

Step 1 — Pre-flight (abort with 0 findings on any failure)

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
47
Forks
3
Last commit
Sep 2026

ahel review

  • K4binfo
    destructive-scoped

Automated review, not a security audit. Ruleset v1+k2.

Advanced
Item type
skill
Key
dev-workflow-triage
Source
github.com/hiroro-work/claude-plugins