| name | epic-critic-loop |
| description | Drive a repository on autopilot through its GitHub issue tracker. Pick the next ordered epic/child issue, or seed a new epic only from a real code/spec/research gap, implement it on a branch, run an adversarial critic/fix loop until no actionable findings remain, verify with the repo's full gates, sync the issue tracker and roadmap, and merge only when authority is granted. Use when the user asks to autopilot a repo or epic, "run the loop", "go on" through issues, seed-and-ship work, or grind an epic to completion in your repos that follow repo AGENTS files and a shared canonical rule set. |
Epic Critic Loop
Follow the shared conventions in ../conventions.md.
Overview
This is the single, self-contained top-level autonomous loop. It works a repository the way a disciplined maintainer would: take the next real piece of work from the issue tracker, implement it, harden it with an adversarial critic loop, verify it against the repo's own gates, keep the tracker honest, and merge when allowed. Then repeat.
It owns the whole cycle end to end: issue selection, branching, the inner critic/fix/verify loop, verification, tracker hygiene, merge, and iteration. It does not depend on any other skill.
The one rule that makes this loop trustworthy: never manufacture work. When the tracker is empty and there is no genuine, evidence-grounded gap, the loop stops and says so. It does not invent ceremony to stay busy.
Inputs and authority
Establish these before the first iteration, and treat them as standing for the whole run:
- Target repo. The current repository unless the user names another path. Run
git status --short --branch first; never discard uncommitted user changes.
- Merge authority. Default OFF. The loop opens and verifies PRs but does not merge. The user grants merge authority explicitly ("merge", "merge and go on", "autopilot", "do the whole workflow"). Record it. Without it, stop at the merge step and report the green PR.
- Scope guards. The project's non-goals, read from its README, roadmap, epics, and
docs/research/ if present. Examples seen in practice: "Markdown-only; no PDF, HTML, ATS scoring, or static-site generation", "Linux-safe", "no renderer-generated scores or demographic fields". Every issue the loop seeds or implements must stay inside these.
- Remote policy. Per conventions.md § Remote policy: verify the remote before any push.
Validate the instruction before acting
If the triggering prompt is a placeholder, template, or otherwise unresolved (for example Write tests for @filename with no filename, an empty target, or a contradictory ask), do not guess. Stop and ask one concrete question. A long autopilot run on a garbled instruction is the worst failure mode.
The loop
Each iteration:
1. Load rules
- Read repo-local
AGENTS.md / CLAUDE.md for the repo and the paths you will touch.
- Read the shared Swift rule index and the canonical rule files it names. For Swift work load at least
general.md, repo-structure.md, gof-di-rules.md, code-style.md, namespacing.md, testing.md, verification-before-completion.md, github-discipline.md, and testing-discipline.md; add concurrency.md and cross-platform.md when those topics are touched.
- If the canonical path is missing, search for the shared rule set locally; if unavailable, continue with repo rules and report the gap.
- Emit the confirmation phrase
rules-loaded once per iteration in the working notes.
2. Select the next work item
Query the tracker as the single source of truth:
gh issue list --state open --json number,title,labels,url --limit 100
gh issue list --state open --label epic --json number,title,url --limit 50
gh pr list --state open --json number,title,headRefName,url --limit 50
Then choose, in this order:
- An open PR that is not yet green or not yet merged belonging to this run. Finish it before starting new work. Never leave a half-landed PR to start another issue.
- The next ordered child of an open epic. Read the epic body for the landing order; take the first unfinished child.
- A standalone open issue, oldest meaningful first, or by stated priority.
- Seed a new epic only if 1 to 3 are empty. See the seeding gate below.
The tracker is also the steering wheel. A human can add or reprioritize issues out of band while the loop runs; honor new open issues over seeding. This is how the loop is redirected without interrupting it.
3. Seeding gate (only when the queue is empty)
This is the step that separates a useful loop from a make-work loop. Observed failure mode: once real work runs out, an unconstrained loop invents plausible "hardening" (release reconciliation, publish proofs, a guard for a guard) and grinds forever.
To seed a new epic:
- Analyze the actual repo: code, tests, docs, scripts,
docs/research/, roadmap, and any spec or contract files. Look for a gap that is real and grounded, not aesthetic:
- a stated requirement, research rule, or contract with no implementation or no enforcing test;
- a documented promise the code does not keep;
- a correctness, cross-platform, or data-loss risk;
- a divergence between code and its own spec or research.
- If you cannot point to such a gap with a specific file, rule ID, or contract line, STOP. Report: queue empty, no genuine gap found, loop idle pending human direction. Do not seed.
- When you do seed, create an epic plus ordered child issues. Each issue must carry: a short problem statement, the grounding (file path, rule/evidence ID, or contract), explicit acceptance criteria, and the scope guards. Keep each child small and independently shippable.
- Prefer a few high-confidence issues over a long speculative list. Log explicitly anything you considered and rejected as make-work.
When filing issues from a script, pipe heredocs to gh issue create --body-file - or pass --body "$VAR"; do not leave *.tmp.md body files in the working tree.
4. Implement on a branch
- Branch from the up-to-date default branch:
feat/<n>-<slug> or fix/<n>-<slug>.
- Read the issue's acceptance criteria and scope guards. Implement the focused change only. No unrelated refactors.
- Touch only what the issue needs. Respect file-ownership rules (do not edit screens/views or unrelated packages unless the issue says so).
5. Critic and fix (inner loop, runs until clean)
Run a closed critic/fix/verify loop on the working change (see conventions.md § The critic / fix loop). Treat the critic as adversarial and first-principles driven, but keep fixes pragmatic and tightly scoped. Repeat the three sub-steps until a critic pass yields no actionable findings ("critic loop till regressed").
a. Critic pass. Produce findings before fixing, ordered by severity. Be harsh about correctness, regressions, public API shape, cross-platform behavior, data loss, security, invalid assumptions, flaky or missing tests, rule violations, and user-visible quality. Tie every finding to an exact file:line and explain from first principles why it fails, with a minimal reproduction or command when practical. Do not list style preferences unless they violate loaded rules or create real maintenance cost. If there are no actionable findings, say so and exit the inner loop.
b. Fix pass. Make a short checklist from the findings and fix all actionable ones. Keep each edit scoped to its finding; no unrelated refactors. Add or update a test for every behavior change or bug fix. A behavioral fix without a relevant test is incomplete. Update docs, changelog, or issue links when loaded rules require it.
c. Verify pass. Run the narrow test that proves each fix, then proceed to the full gates in step 6. Ignore findings already resolved unless a fix regressed them.
If the same blocker survives three consecutive critic/fix passes and cannot move without human input or external state, stop and report it (see Stop conditions).
6. Verify against the repo's own gates
Run the project's real gates, not a subset. For Swift packages that means, from a clean state where the change is build-visible (UI, generated output, browser behavior):
swift build and swift test (full suite, report counts).
- Formatter and linter in lint mode (
swiftformat --lint, swiftlint --strict).
- Repo scripts: namespacing, style, schema-drift, byte-for-byte fixture checks.
- Any browser/Playwright gate when the change is browser-visible; wipe the build dir first when output is generated.
- The pre-push hook if one exists.
State the actual results (exit codes, pass counts), never a guess.
7. Push and watch CI
- Push the branch and open a PR (
gh pr create) if none exists. Use a clear title and a body that closes the issue.
- Watch CI to green. Note:
gh pr checks --watch can show a stale pending after the run already succeeded. If checks look stuck, confirm against the workflow run itself (gh run view <id> --json status,conclusion,jobs) and treat the run result as the gate.
8. Sync the tracker and roadmap
- Update the issue body and the epic with the merged or in-review state and the verification evidence (commit SHA, gate results, CI state).
- Update README and
docs/roadmap.md if present. When a roadmap uses Mermaid, move the node text and its color class together in the same edit; a node marked done in prose but still colored review is a defect.
- Keep status honest: an open PR is in review, not done.
9. Merge (only with authority)
- If merge authority was granted and CI is green:
gh pr merge <n> --squash --delete-branch, then fast-forward local default branch.
- If authority was not granted: stop at the green PR and report it. Do not merge.
- Close the issue only when the merged or pushed change actually addresses it and verification passed.
10. Iterate
- Return to step 2. Mark the child done in the epic; when an epic's children are all done, close it, then re-evaluate the queue (which may legitimately end the run via the seeding gate).
Stop conditions
Stop and report, rather than continue, when any of these holds:
- The queue is empty and the seeding gate finds no genuine gap. (Idle is a valid, correct end state.)
- Merge is required next but authority was not granted.
- The same blocker survives three consecutive critic/verify passes and needs human input or external state.
- A change cannot stay inside the scope guards without a product decision.
- The triggering instruction is unresolved or self-contradictory.
- Verification fails and the fix is outside the issue's scope or the loaded rules.
Hygiene
- No leftover artifacts: remove temp files, derived-data logs, and scratch bodies before finishing an iteration. The working tree should be clean apart from intended, committed work.
- One concern per branch and PR. One issue per child.
- Remote policy and output discipline per conventions.md: verify the remote before pushing, and keep all output human-authored.
Output shape
Keep iteration updates short and concrete. Per iteration report:
Iteration N - issue #<n>: <title>
rules-loaded
Branch: <branch>
Critic: <passes>, final = no actionable findings
Verify: build ok, test <pass>/<total>, lint ok, gates ok
CI: <state>
Tracker: issue/epic/roadmap updated
Merge: merged <sha> | held (no authority) | n/a
At the end of a run report: issues completed, PRs merged or left in review, epics closed, any seeded epic with its grounding, and the stop condition that ended the run. If the run ended idle, say so plainly: there was no real work left, and that is the correct outcome.