Install
$ agentstack add skill-agent-rig-rig-rig-epic ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
rig-epic — integration-branch workflow
For multi-item arcs where landing each item directly on the trunk would temporarily break the runtime contract, stack child PRs on a shared integration branch and squash that branch into the trunk as one PR at the end. Each child PR is reviewed as the step it actually is; the trunk-bound delivery is one squashed rebase.
Configuration
Reads .rig/config.json (defaults in parentheses):
tracker.provider—linear|github|none(none). How parent/child
items are stored. none → items live only in the epic state file (below); no tracker calls.
tracker.team/tracker.project/tracker.ticketPrefix/tracker.githubIntegration.tracker.shapeLabels.epic(epic) — GitHub-only label put on the parent at
creation so a Project board / dispatcher can distinguish the epic from child feature issues. Omit shapeLabels to skip.
tracker.board— GitHub Projects v2 identity. When set, the parent's board
transitions and each child's Done move go through the rig-tracker adapter (gh issue edit can't touch a ProjectV2 Status field). Resolver used below: ` = .rig/rig-tracker if executable else /scripts/rig-tracker.sh (see [docs/tracker-adapter.md](../../docs/tracker-adapter.md)). Absent → skip the board moves; the linear/none` paths are unchanged.
vcs.baseRef(origin/main),vcs.defaultBranch(main),
vcs.protectedBranchMergeQueue (false).
sourceScope[0]— where to explore duringplan.agents.architect/agents.reviewer(defaultrig-) — for the
fresh-context review panel.
Delegates to /rig-task (per child), /rig-worktree (checkouts), /rig-review
/rig-review fix(the combined-diff review),/rig-tidy(optional).
Epic state file (replaces any external memory)
Each active epic is tracked in a repo-local JSON file at .rig/epics/.json:
{
"parent": "ABC-42 or a slug in tracker=none",
"parentTitle": "…",
"integrationBranch": "abc-42-",
"whyEpic": "which children interleave and why",
"children": [
{ "id": "ABC-43", "title": "…", "blockedBy": [], "branch": null, "status": "todo|merged" }
]
}
Where the truth lives. On tracker: github, the source of truth is the parent issue and its native sub-issues on the tracker — not this file. The JSON is a local cache rebuilt from the tracker (gh api repos//issues//sub_issues), and it is gitignored — never committed (.rig/epics/ is in .gitignore). On linear the parent/children live in Linear; on none the file is the only record. Either way it's throwaway coordination state, rebuildable from the tracker at any time — the board is the shared brain, not the repo.
next/run/review/finish/prune read the reconstructed set. Parent inference (when ` is omitted): on github, the open issue labelled shapeLabels.epic that has sub-issues; else if exactly one .rig/epics/*.json` exists, use it; if zero or many, ask.
Intent banner: every invocation MUST print one line first — mode, what branch PRs target, what it won't do:
rig-epic: — . PRs target . Will not .
status (default, report-only)
Read the epic state file(s). Report: integration branch + commits ahead of vcs.baseRef; open child PRs (gh pr list --base ) and their state; each child's tracker status (if a tracker); leftover merged/deleted worktrees (suggest /rig-epic prune); and a one-line recommendation (open child PR X, ready for /rig-epic next, or ready for /rig-epic finish). Modify nothing; spawn nothing.
plan
Decompose a feature into a parent + 3–8 children, write the state file, then chain into start.
Use this only when the work is genuinely epic-shaped (children interleave — at least one child's runtime contract depends on another being partially complete). If the items are independent and each can land on the trunk alone, stop and tell the user to run /rig-sprint plan instead — same decomposition, no integration branch.
Procedure
- Read context. Product/spec docs if the project has them (ask if unsure);
explore the codebase (sourceScope[0]) to see what exists. If a tracker is configured, search it for near-duplicate items first.
- Sanity-check it's an epic (per the interleave test above). If not → send
to /rig-sprint plan.
- Create the parent.
tracker: linear/github→ create the parent item (team/project from
config); description covers Overview, why-it's-an-epic, and the planned children.
- GitHub only — mark the shape. After creating the parent, apply the epic
shape label so a Project board / dispatcher can tell the parent apart from the child feature issues: gh issue edit --add-label "" where ` = tracker.shapeLabels.epic (default epic). Ensure the label exists first (gh label create "" --force). Skip entirely if tracker.shapeLabels` is absent. (Linear needs no label — native parent grouping already distinguishes the epic.)
tracker: none→ the parent is a slug + title recorded in the state file only.
- Create each child with its dependency edges.
- Small enough for one agent session (1–3 files); concrete, testable
acceptance criteria; foundational work first.
- Record
blockedByfor every real dependency — this is whatnext
reads to pick the next unblocked child. Without it the pick falls back to declaration order and gets interleaved epics wrong.
tracker: github: create each child as its own issue, then **link it as
a native sub-issue of the parent — gh api repos//issues//sub_issues -F sub_issue_id=$(gh api repos//issues/ -q .id) — and write "Blocked by #" in the child body (GitHub has no native blockedBy). The sub-issues are** the epic on the board; the .rig/epics cache is derived from them, never the other way around.
tracker: linear: set the native parent + blocked-by relations.none: the state file is the only record.
- Show a summary table (ID · Title · Depends On).
- Chain into
start—planis plan-and-start; don't stop to ask. - Stop after
start. Report the integration branch, the children, and the
next step (/rig-epic next for one, /rig-epic run for the loop). Never auto-start run — execution is an explicit opt-in.
start
Pre-flight: git fetch origin; confirm the parent and at least one child exist (in the tracker, or as arguments for none).
Rebuild the cache from the tracker (github). If ` is an existing GitHub epic (e.g. /rig-epic 42 or /rig-epic run), reconstruct the children from its **sub-issues** rather than trusting any local file: gh api repos//issues//sub_issues → each becomes a child (id = issue number, blockedBy parsed from "Blocked by #n" in the body, status from open/closed + board column). Write that to .rig/epics/.json` (gitignored). This is what makes an epic you were handed on the board runnable — no committed state required.
- Integration branch name:
-(kebab, e.g.
abc-42-agent-as-definition).
- Cut the integration branch from
vcs.baseRefwithout a local checkout:
``bash git fetch origin git push origin :refs/heads/ `` Non-destructive. If the branch already exists, leave it (never overwrite — could destroy in-flight work).
- Write
.rig/epics/.json(schema above) with the
parent, why-epic, and every child + blockedBy. This is what makes each /rig-task target the integration branch instead of the trunk.
- If a tracker is configured, add an "Integration branch: target
`, not the trunk" note to each child so the next agent doesn't re-read this skill, and ensure the **parent** is In Progress (adaptive: move it only if not already started; defer if a live integration did). On a **tracker: github board**, do the parent move through the adapter: set-status "". Children get their own In Progress from their /rig-task` Step 1.
- Name the session
"EPIC: ()"via
scripts/set-session-name.sh (Claude-Code-only; no-ops elsewhere) so the background-job list reads as the epic. Children set their own FEAT:/CHORE: names with --skip-if-prefix "EPIC:", so this epic label stays on top.
- Report the branch, the children, and the next step.
next (single child)
- Resolve the active integration branch (one expected; ask if many). If the
session isn't already EPIC:-named (i.e. next invoked directly, not via start), name it "EPIC: ()" (Claude-Code-only).
- Pick the next unblocked child: the first not-done child whose
blockedBy
are all merged into the integration branch. State the pick + reasoning in the banner.
- Ensure the previous child has landed. With
--auto-merge(Step 4) each
child's PR merges into the integration branch on its own once CI passes, so the integration tip advances automatically — just git fetch origin and confirm. (Fallback for a child run without --auto-merge: fast-forward the branch over its tip — git push origin origin/:refs/heads/, which auto-closes that PR as MERGED. Safe to re-run.)
- Run
/rig-task --base --auto-merge(add
--spec-cleared when run's front-loaded spec review already cleared the specs) — --base makes the child's worktree branch from, and its PR target, the integration branch; --auto-merge makes the child enable gh pr merge --squash --auto on its own PR once its review is clean, so CI lands it into the integration branch (always squash — don't rebase-merge; many repos disallow it. If the integration branch has no required checks, the child merges directly). Run one-shot (start→finish); it returns a single outcome string for the merge gate.
- Merge gate — only
cleanis merge-green:
clean→ the child enabled auto-merge, so its PR lands when CI passes.
Wait for it: poll gh pr view --json state (~60s, up to ~30min) until MERGED, then git fetch origin and confirm the tip advanced. Record the child merged + its branch in the state file, and ensure the child ticket is Done (adaptive — move only if not already Done; defer if a live integration closed it). On a tracker: github board, move it via the adapter: set-status "". (The child'"'"'s PR merged into the integration branch, not the default branch, so its Closes # has not fired — the adapter move is what marks it Done now; the issue itself closes when the epic squashes to trunk.) If CI fails / it never merges → treat as not-clean.
- anything else (
actionable/timeout, or a tracker-parked state) → the child
did not enable auto-merge; stop. Surface the outcome, the PR URL, and any reviewer summary. Wait for the user; don't retry a parked review.
next does exactly one child. Use run for the loop.
run [--advisor]
Front-loaded spec review — once, before the loop. Review all children's specs together, up front, instead of discovering blockers one child at a time mid-run. A child that pauses on a spec question stalls the whole epic (and under parallel or durable execution, a paused child can fail the batch outright), so resolve the specs before any child starts coding:
- Fan out
agents.architect+agents.qaover every child's spec, read
against the integration branch; each returns its blockers.
- Consolidate into one blocker list and resolve it once — clarify in the
tracker, or decide with the user. This is the epic's single spec decision point.
- Then run each child with its own spec gate pre-cleared:
/rig-task --base --auto-merge --spec-cleared, so no child re-pauses on a question already answered.
This is the pre-coding spec pass; the combined-diff review (below) is the post-merge code pass — different gates.
--advisor (unattended). Decide that front-loaded gate with an advisor pass instead of a human: a delegated agents.architect review reads the architect + QA specs and either proceeds with synthesized per-child direction (handed verbatim to each child's coder), or halts with a blocked report naming what a human must decide. No human waits, so the epic runs hands-off to child PRs; a genuine blocker still stops it rather than fanning out on a bad spec. (The paired Smithers durable workflow implements this with a cheap model — the "Fable advisor" — so kicked-off epics never park at the gate.)
Then loop next until no unblocked child remains:
while an unblocked child exists:
run /rig-epic next # children run --spec-cleared (spec was front-loaded)
if it stopped without merging (outcome ≠ clean) → stop, hand back
else → re-evaluate unblocked children
When the queue empties, report "epic ready for /rig-epic finish."
review []
Run after the last child merged into the integration branch, before finish. Per-PR review (/rig-review inside each /rig-task) sees each child in isolation; this sees the combined shape and the simplification only visible once everything is in. Fresh-context sub-agents (input = the squashed diff + child PR titles) can't inherit the implementer's remembered rationalizations.
Run before prune — the review sub-agents need a working checkout; reuse a child worktree if one still exists (avoids a fresh install + env re-symlink).
- Resolve the integration branch;
git fetch origin. - Ensure an integration-branch worktree (
$WT). Reuse a merged-child
worktree fast-forwarded to the integration tip, else create one with /rig-worktree (--base --reuse).
- Fan out three sub-agents in parallel (one message, three
Agentcalls),
each cd-ing into $WT with the integration tip checked out:
- Lens 1 — Simplification (
agents.architect): diff
git diff ...HEAD; child PR list via gh pr list --base --state merged. Mandate: find abstractions to collapse, helpers one PR added that another PR's final shape made redundant, config knobs nobody sets, code paths the combined diff made dead, one-caller types. Concrete deletions/merges, file:line, highest-impact first. Skip correctness.
- Lens 2 — Cross-PR correctness (
agents.reviewer): walk the project's
review-pattern catalog (review.patternsFile) against the combined diff. Per-PR review already ran; catch interactions only visible at the merged shape (PR-A's helper vs PR-D's stale caller; PR-B removed a knob PR-F still reads). P0/P1/P2 with file:line + category.
- Lens 3 — Dead code & stale refs (
agents.reviewer): for every symbol
the diff added, is it called elsewhere? For every symbol removed, grep the tree (workflows, manifests, IaC, scripts, docs) for residual refs. Report with file:line.
- Consolidate — dedupe, produce one P0/P1/P2 list grouped by lens, print
counts.
- Triage:
- 0 items →
clean — ready for /rig-epic finish, stop. - findings → ask via
AskUserQuestion:apply now/ `skip and finish
anyway (downgrade to follow-ups) / pause. On apply now, run /rig-review fix --source local in $WT (spawns agents.coder, re-reviews to clean), commit + git push origin , re-run review` once to confirm convergence.
- Outcome string (for
finish):clean — …/applied — …/paused — ….
finish [] [--merge]
Squashes the whole integration branch into a single PR to the trunk. Default: open the PR and stop — this is the one PR to eyeball.
review is a hard gate. finish always runs review first; the squash PR opens only on clean or applied. On paused, stop and wait.
- Run
review(gate) inline; branch on its outcome (clean/applied→
proceed; `paus
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: agent-rig
- Source: agent-rig/rig
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.