clud-fix
Drive single GitHub issues or meta/parent burn-down issues until PRs are merged, issues are closed, and reported reproductions are validated fixed on main.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Drive single GitHub issues or meta/parent burn-down issues until PRs are merged, issues are closed, and reported reproductions are validated fixed on main.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
File a deeply-researched GitHub issue via investigate → investigate → post, returning a summary plus the issue URL. Files without asking for confirmation.
Spin up a fast Linux build container for a Rust + soldr + zccache, Python (uv), or C++ (CMake + ccache) project using the bundled `docker-build` tool family. Uses anonymous Docker volumes for build state and a read-only bind for source — the one rule that turns Docker-Desktop's 20-minute cold-build into a sub-30-second warm cycle.
Diagnose and recover a wedged Docker Desktop (engine pipe/socket absent while the UI stays alive, WSL/Docker startup failures) and answer Docker VM disk-growth / memory-pressure questions. Read-only `doctor` first; every restart/reset is confirmation-gated and preserves images/volumes; storage disks are resolved from Docker Desktop's real config (never assumed) and never compacted or deleted automatically.
Coordinate dependent cross-repo changes under a repo-local .extern-repos/ checkout convention.
Show a git diff in a native OS webview window (Beyond Compare-style dual-pane with file picker on the left) via the bundled git/clud-git-diff.py tool. Invoke when the user asks to visually review changes between revisions.
Worktree, branch, process-audit, and quarantine playbook extracted from /clud-pr so /clud-fix-quick and other skills can reuse it. Use this when the user asks for worktree cleanup, stale-branch teardown, or a process audit on a leftover dir.
| name | clud-fix |
| description | Drive single GitHub issues or meta/parent burn-down issues until PRs are merged, issues are closed, and reported reproductions are validated fixed on main. |
| triggers | ["When the user says \"/clud-fix <issue-url-or-num>\"","When the user says \"$clud-fix <issue-url-or-num>\" from Codex","When the user asks to fix a GitHub issue and expects merged-and-validated, not just a PR","When the user points at a meta, parent, tracking, epic, or burn-down issue and asks for all sub-issues fixed","When the user invokes \"/goal $clud-fix <issue-or-issue-url>\""] |
Drive a GitHub issue until the real issue-level completion condition is true. For a single issue, that means PR(s) merged to the default branch, the issue closed, and the reported reproduction or acceptance check validated on current main. For a meta/parent/burn-down issue, that means every child issue is closed and validated, the parent checklist is updated where possible, and the parent issue itself is closed.
This skill is the outer issue orchestrator for both Claude and Codex through
clud. It delegates one-PR work and PR merge work to [[clud-pr]], but it owns the
issue-level /goal lifecycle. Do not invoke or depend on a standalone merge
skill.
For code changes, preserve RED -> GREEN: identify or add the focused failing test or executable reproduction first, implement the scoped fix, then rerun that focused signal until it passes before broad gates.
https://github.com/<owner>/<repo>/issues/<num>.https://github.com/<owner>/<repo>/pull/<num>.#<num> (issue) or !<num> (PR) only when the current checkout is the
right repository. Resolve <owner>/<repo> with gh repo view before acting.The argument can be a single issue, a meta/parent/burn-down issue that lists sub-issues, or a PR. Classify the mode before planning any implementation.
A PR URL input bypasses the single-issue / meta classifier entirely and
delegates to [[clud-pr]] PR Drive Mode: actively check CI builders + code-review
comments (CodeRabbit, GitHub Copilot review, human reviewers) + files needing
resolve, apply scoped fixes, push the new commits without force-push, and merge
when the PR is clean. Once [[clud-pr]] returns with the PR merged, this skill
validates against the underlying issue (if linked via Closes #<N>) and closes
it if validation passes.
Recognition rules for distinguishing PR URLs vs issue URLs vs bare numbers are documented under "Input Recognition" in [[clud-pr]] — same disambiguation logic applies here. See #395 for the spec.
This makes /clud-fix symmetric: issue URL → "fix this issue end-to-end";
PR URL → "drive this PR end-to-end through merge + validation."
This skill defaults to GitHub and the gh CLI for backwards compatibility. URL inputs from other forges are classified by URL prefix and routed to the matching native CLI. Bare numbers (#<N>) without an explicit prefix resolve their forge from the current worktree's git remote get-url origin.
| Forge | URL prefix(es) | Native CLI | Vocabulary |
|---|---|---|---|
| GitHub | github.com/<o>/<r>/(issues|pull)/<N> | gh | issue / PR (#N) |
| GitLab | gitlab.com/<g>/<p>/-/(issues|merge_requests)/<N> and self-hosted variants | glab | issue / merge request (MR) (!N) |
| Bitbucket | bitbucket.org/<o>/<r>/(issues|pull-requests)/<N> | none official; REST API | issue / PR (#N) |
| Gitea | <host>/<o>/<r>/(issues|pulls)/<N> | tea | issue / PR (#N) |
| Forgejo | <host>/<o>/<r>/(issues|pulls)/<N> (same patterns as Gitea) | forgejo-cli (early) or tea | issue / PR (#N) |
| Self-hosted GitLab / Gitea / Forgejo | same patterns under custom domains | same CLI | same vocabulary |
The classifier returns {forge, kind, owner, repo, number, host} for any URL input.
When the input is a bare #<N> or <N>:
git remote get-url origin in the current worktree.gh pr view for GitHub, glab mr view for GitLab, etc.).Prefixes in the invocation force a specific forge and skip remote inference: github:<N> / gitlab:<N> / bitbucket:<N> / gitea:<N> / forgejo:<N>.
All gh examples elsewhere in this skill are GitHub-specific. Substitute the matching native CLI per forge:
gh issue view <N> ↔ glab issue view <N> ↔ tea issues show <N> ↔ Bitbucket REST: curl ... /repositories/<o>/<r>/issues/<N>gh pr view <N> ↔ glab mr view <N> ↔ tea pulls show <N> ↔ Bitbucket REST: curl ... /pullrequests/<N>gh pr merge <N> --squash ↔ glab mr merge <N> --squash ↔ tea pulls merge <N> ↔ Bitbucket REST: PUT /pullrequests/<N>/mergegh issue create ↔ glab issue create ↔ tea issues create ↔ Bitbucket REST: POST /repositories/<o>/<r>/issuesInternal skill logic can keep saying "PR" generically. User-facing output uses the forge's native vocabulary:
PR #123 merged — unchanged.MR !123 merged (note the ! sigil GitLab uses instead of # for MR references).PR #123 merged.Never silently translate vocabulary in error messages — if a GitLab MR is mentioned, the message says MR !123, not PR #123.
Each forge has its own auth model:
gh auth status or GITHUB_TOKEN env var (default).glab auth status or GITLAB_TOKEN / GL_TOKEN.BITBUCKET_TOKEN).GITEA_TOKEN, FORGEJO_TOKEN).If the required CLI or token is missing, emit a clear refusal and stop:
forge-cli-missing: install <cli> to use clud against <forge>
forge-auth-missing: authenticate to <forge> via <cli> auth login
Don't log or persist tokens; rely on the user's existing auth.
gh / glab / tea / etc. is on PATH; refuse if not. Don't bundle tooling.MR !123, not PR #123.When the user invokes /goal $clud-fix <issue-or-issue-url>, this skill owns
the outer goal until the issue-level completion condition is proven.
For a single issue, use a goal equivalent to:
/goal Fix issue #N: all relevant PRs merged to main, any dependent issues closed (including their PRs), this issue closed, and the reported reproduction validated fixed on current main.
The "all relevant PRs" / "dependent issues" phrasing is deliberate. When a fix legitimately needs more than one PR — a foundation PR plus follow-up slice PRs — the inner /goal text must already authorize that scope so the Stop hook does not wedge on a single-PR literal reading. See the "Scope Expansion" section below for the mid-flight pivot mechanics that satisfy this broader goal.
For a meta/parent/burn-down issue, use a goal equivalent to:
/goal Complete meta issue #N: every child issue closed/validated, parent checklist updated, parent issue closed, and final evidence reported.
When delegating to [[clud-pr]], explicitly tell it that this is a delegated
clud-fix call. Delegated clud-pr work must not invoke a nested /goal,
replace the outer goal, or narrow success to "PR opened." It must return
structured evidence for clud-fix to evaluate: issue URL, PR URL(s), PR merged
state, tests run, validation notes, blocker reason if any, and issue closure
state.
Three legitimate /clud-fix runs reach an honest no-PR terminal: a single-issue
intake-failed investigation report, a meta empty-children investigation report,
and an unreachable-scope refusal (the upfront gate added in step 2 of the
single-issue workflow). In each case, emit a structured sentinel as the FINAL
line of the user-facing response so an outer-/goal evaluator can recognize
the terminal:
| Terminal | Sentinel |
|---|---|
| Single intake-failed | <clud-fix:terminal kind=investigation-report-posted reason=intake-failed url=<issue-url>> |
| Meta empty-children | <clud-fix:terminal kind=empty-children-report-posted reason=parent-roadmap-unfiled url=<parent-url>> |
| Unreachable scope | <clud-fix:terminal kind=unreachable-scope-refused reason=<closed-source-target|read-only-repo|...> url=<issue-url>> |
The sentinel is plain transcript text — no harness affordance is required to
emit it. Recognition by /goal evaluators is a separate upstream change
tracked at #367.
All three conditions are mandatory:
Missing any one means the goal is not done.
All conditions are mandatory:
Intake gate. Fetch the issue with:
gh issue view <num> --repo <owner>/<repo> --json number,state,title,body,labels,comments,url
If the issue is not open, stop and report the current state. Do not silently reopen or push.
Reachable-scope gate. This skill's terminal requires a merged PR. If the work needed to satisfy the issue cannot reach a merged PR in this repo, the run cannot terminate cleanly — refuse upfront rather than entering the intake-failure path mid-run (the original failure documented in #365).
Check both:
Repo push permission. If the issue lives in a third-party repo:
gh repo view <owner>/<repo> --json viewerPermission,isFork,parent
If viewerPermission is READ or TRIAGE AND no fork is configured for
this user (or the user has not opted into a fork-and-PR flow for this
repo), the run cannot reach "PR merged on <owner>/<repo>:main". Refuse
with: "Issue lives at <owner>/<repo> where viewerPermission is
<level>. /clud-fix cannot satisfy its 'PR merged' terminal here.
Open an issue or fork-and-PR via [[clud-pr]] instead."
Non-source-artifact heuristic. Scan the issue body and title for phrases that imply the fix lives outside the user's source tree:
@anthropic-ai/claude-code, claude-code harness, harness binary,
compiled into the harnessclosed-source, closed source, proprietary binary,
vendor binary, vendored library/usr/lib/<vendor>/, node_modules/@<vendor>/, etc.) being the
sole source of the bugHitting the heuristic is not proof — it is a stop-and-confirm prompt:
"Issue body suggests the fix targets <artifact>, which /clud-fix
cannot reach (no source tree to modify, no PR target). Refuse the run
unless the user confirms a reachable substitute scope (e.g. a clud-side
workaround, a runtime guard, or filing an upstream issue)."
When either branch trips and the user does not provide a reachable substitute, emit the unreachable-scope terminal sentinel as the FINAL line of the user-facing response:
<clud-fix:terminal kind=unreachable-scope-refused reason=<read-only-repo|closed-source-target|...> url=<issue-url>>
Then stop. Do NOT widen scope to manufacture a PR-able task that
satisfies the literal goal text but misses what the user actually asked
for; that pattern is exactly what made the /goal Stop-hook loop in
#365 wedge.
Readiness check. A fixable single issue needs:
Under-specified issues get investigation first. If any readiness item is missing, post an investigation report to the issue instead of opening a PR.
Lead the report with a hook-mismatch banner (Markdown blockquote, first
line) so an outer-/goal-following reader sees the no-PR terminal
explicitly:
> ⚠ **/clud-fix intake gate failed.** This comment is the deliverable, not
> a merged PR. If a session `/goal` hook references this issue URL, run
> `/goal clear` after reading — it will not auto-satisfy.
Then include root-cause evidence, reproduction status, planned fix, validation command, and open questions.
In the final user response, emit the terminal sentinel as the last line:
<clud-fix:terminal kind=investigation-report-posted reason=intake-failed url=<issue-url>>
Then stop with the blocker surfaced; do not manufacture a PR that cannot be validated.
Survey existing PRs. Search for PRs that mention or close the issue:
gh pr list --repo <owner>/<repo> --search "<num> in:body" --state all --json number,state,headRefName,mergedAt,url
If a merged PR already claims the issue, validate against current main and close the issue if validation succeeds. If an open PR exists, delegate to [[clud-pr]] PR merge mode, in delegated mode, to drive it through CI/review fixes and merge.
Plan validation before implementation. Identify files to touch, focused RED test/repro, and the post-merge validation command. For non-trivial design scope, check in with the user before opening a PR.
Delegate PR work to [[clud-pr]]. Hand off the issue URL and state:
"delegated from clud-fix; do not set a nested /goal; return structured
evidence." [[clud-pr]] owns the disposable worktree, RED -> GREEN cycle,
lint/test gates, PR creation, CI/review fix loop, and merge mode.
7a. Scope-expansion check. Before validating on main, inspect [[clud-pr]]'s
returned evidence. If the merged PR's body references the issue with
Refs #<num> instead of Closes #<num> — i.e. the work is foundation-only
and additional PRs are needed to ship the user-visible feature this issue
tracks — the single-issue goal is not satisfiable by this PR alone. Pivot
to meta mode per the Scope Expansion section below before continuing
to step 8. Do not silently declare the goal done; do not also try to close
the issue. Validation (step 8) still runs after the meta-mode burn-down
completes, against the final state of main.
Validate on main. After merge, run:
git fetch origin && git checkout main && git pull
Then run the issue's original reproduction or acceptance command. CI green is not enough; validation must exercise the reported behavior.
Close or confirm closed. Verify with:
gh issue view <num> --repo <owner>/<repo> --json state,closedAt
If the issue is still open after a validated merge, close it with a comment naming the merged PR and validation evidence.
Report. Return the merged PR URL(s), the closed issue URL, and validation evidence.
A single-issue run can discover mid-implementation that the user's stated goal
cannot be satisfied by one PR. The trigger is observable: [[clud-pr]] returns
evidence of a merged PR whose body has Refs #<num> instead of Closes #<num>
because the work is foundation-only and additional PRs are needed to ship the
user-visible feature the issue tracks.
When that happens, do not declare the goal done. Pivot to meta mode:
Surface the expansion explicitly. One-line user-visible report:
scope-expansion detected: <one-sentence reason>. Filing sub-issues and continuing in meta mode.
File sub-issues that decompose the remaining work. Each sub-issue gets:
Parent: tracked by #<N> pointer to the original issueOut of scope (handled in later slices) pointer to its successorsCloses #<sub-N> keyword in its eventual PR bodyConvert the parent into a meta. Update the parent issue's title prefix
to meta(...) and prepend a ## Slice burn-down checklist section pointing
at the new sub-issues. The parent now matches the meta-issue classifier so
subsequent runs route to the Meta workflow automatically.
Re-enter the Meta workflow against the parent. The outer /goal stays
installed and is now reachable because the meta workflow closes each
sub-issue in sequence, ticks the parent checklist, and closes the parent.
Per-sub-issue caps still apply. Runaway scope expansion is bounded by the existing per-sub-issue PR cap (10) and validation retry cap (2). The outer meta loop has no cap, same as today's meta workflow.
This pivot is the mid-flight equivalent of the meta workflow's enumeration step — scope discovered during implementation is no different from scope enumerated at intake. The distinction from manufactured meta-level work (forbidden — see Failure Modes) is that scope-expansion sub-issues correspond to observable, deferred work the parent issue's intent demands; manufactured sub-issues are fabricated to extend an idle loop.
This branch was added because of an incident where the foundation PR for a
multi-slice feature was opened with Refs #N (not Closes #N), merged, and
then the run stopped — leaving the outer user /goal ("issue closed +
feature verified fixed") wedged. The skill correctly recognized the literal
goal was unsatisfiable but did not take the obvious next step of filing the
follow-up sub-issues and continuing. The pivot above is that next step.
Fetch and classify the parent. Treat an issue as meta/parent/burn-down when labels, title, checklist body, linked issue references, GitHub sub-issue metadata, or explicit user wording identify a tracker.
Enumerate child issues. Take the union of every issue reference appearing anywhere in the parent body, regardless of the surrounding markdown structure (checklist, table cell, prose paragraph, bullet list, heading, blockquote). All of the following patterns count, and any single match makes that issue a child candidate:
- [ ] #123 or - [x] #124#123 references in tables, prose, or any other markdown structure
(e.g. a | **#3237** | ... | table cell, or see #123 inline)owner/repo#123 (e.g. FastLED/fbuild#627) and bare <repo>#123 when
the parent body or repo context disambiguates the ownerDo not require an issue reference to be inside a - [ ] #N checklist to
count it. Roadmap metas frequently catalog work in tables; treat each
tabled #N as an enumerated child. If a reference is cross-repo or
ambiguous (e.g. fbuild#627 with no owner prefix), record it in the ledger
with the resolved owner/repo you used and surface the resolution choice
in the status line so the user can correct it.
For each enumerated candidate, classify before queuing:
- [x] #N is not authoritative; fetch the issue's state.blocked with the resolution attempt noted, then surfaced.If after this union enumeration the open-children list is still empty (the parent is a roadmap whose child items have not been filed as issues yet, or every reference resolves to a closed/missing issue), do NOT proceed to ledger creation. Post the same investigation-report pattern as the single-issue under-specified branch — including the hook-mismatch banner — to the parent issue, listing every reference you found and its resolved state, and explaining which child issues need to be filed to unblock the burn-down. Emit the terminal sentinel as the last line of the user-facing response:
<clud-fix:terminal kind=empty-children-report-posted reason=parent-roadmap-unfiled url=<parent-url>>
Then stop. Do NOT auto-file phase items to extend the loop; see the "Manufacturing new child issues" failure mode.
Create/update the durable ledger. Store progress in:
.clud/fix/<owner>__<repo>__issue-<num>.json
Track parent issue URL/state, enumerated children, child status
(pending, in_progress, closed, skipped, blocked), PR URLs,
validation evidence, parent checklist update state, and final parent closure
evidence. Use the ledger to resume after context limits, process exits, or
manual interruptions.
Process children sequentially. Work one open child at a time, in listed order. Never parallelize child issues; parallel PRs make CI and status reporting incoherent.
Run the single-issue workflow for each child. Re-enter the single-issue
workflow from intake through validation and closure. Under-specified children
get an investigation report and are marked skipped or blocked in the
ledger; they are not retried indefinitely in the same run.
Update the parent after each child. When a child is closed and validated,
tick the parent checklist item if present. Post a concise status line:
[meta #N] child #X -> CLOSED (validated by <command/evidence>) or
[meta #N] child #X -> skipped (<reason>).
Refresh the parent between children. Re-fetch the parent body and metadata so newly added child issues are picked up and externally closed children are skipped.
Close the parent only when complete. When the refreshed child list has no open children and no unresolved blockers, close the parent issue with a summary of child outcomes and validation evidence.
Final report. Report parent URL and CLOSED state, child issue URLs, merged PR URLs, validation evidence, and any skipped/blocker details.
This skill must work the same through clud for Claude and Codex:
~/.codex/skills/clud-fix/SKILL.md.~/.claude/skills/clud-fix/SKILL.md.crates/clud-bin/assets/skills/clud-fix/SKILL.md is the
canonical workflow for both backends.clud-fix /goal./goal /clud-fix <url> wrap as authoritative.
This skill owns its /goal lifecycle (see Goal Ownership). An outer wrap
installs a parallel hook whose literal text the evaluator reads as a strict
"PR merged" terminal; the evaluator cannot see this skill's no-PR terminals
(intake-failed report, empty-children report, unreachable-scope refusal). On
detecting an outer wrap that conflicts with a legitimate no-PR terminal,
surface the conflict in the final user response and recommend /goal clear.
Do not widen scope to satisfy the outer hook./clud-fix in an outer /goal (e.g. /goal /clud-fix <url>). Just
invoke /clud-fix <url> directly. The skill owns its own /goal lifecycle
(Goal Ownership). Wrapping creates a parallel hook the skill cannot see,
which loops indefinitely when intake fails, children are empty, or scope is
unreachable. The skill's no-PR terminals emit a sentinel intended for the
inner goal to recognize; an outer wrap installed by the user cannot see it.