close-out-epic
Skill32 starsChanged 18 days agoMITView on GitHub
Close out an epic before it's released, so that its open-ticket count means something. Lists every open ticket under the epic and proposes, for each, fix before release, move to the epic's follow-up epic, or make standalone, then waits for the user's decisions. Moves the deferred tickets out of the epic with a link back, rewrites each one's description so it still makes sense outside the epic, posts one closing comment on the epic saying what was deferred and where it went, and checks the epic has no open tickets left. Run it again after the release ships, to confirm production runs it, check each release workflow and its tracker sync, close any ticket left waiting to ship with the version it shipped in, rewrite the epic's Release order and Close-out comments as shipped, and offer to draft the epic's release notes. Use when the user says "close out PROJ-X", "get PROJ-X ready to release", "move the leftovers out of the epic", "what's still open in this epic", "wrap up the epic" or "the epic shipped", and from build-epic right before release QA.
In this repository22 other files it gives its agents.
- automate-testsSkill
- automate-xray-testsSkill
- bug-bashSkill
- build-epicSkill
- create-xray-testSkill
- cross-repo-handoffSkill
- live-verified-bddSkill
- pair-runbookSkill
- release-notesSkill
- release-qaSkill
- retroSkill
- review-epicSkill
- roost-configSkill
- run-bugSkill
- run-sliceSkill
- setupSkill
- shape-epicSkill
- slice-handoffSkill
- stacked-prsSkill
- triage-ticketSkill
- verify-slice-testsSkill
- write-runbookSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 5 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 12
Do this at release time, not earlier.
- Distinctive: line 40
This is the only stop: Wait for the user's decisions, then carry them all out without asking again.
- Distinctive: line 50
Keep the rest of the description as it is.
- Distinctive: line 55
Standalone: remove the parent.
- Distinctive: line 63
Update the Carry-over comment, if the epic has one, so it says nothing is left over.
- Distinctive: line 64
Check that no ticket under EPIC is still open, at any depth, other than the "before release" ones being worked on, the deploy ticket with …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Close Out Epic
An epic released with tickets still open under it can mean two very different things: "we shipped and left work behind" or "we decided this was ready". Closing it out makes it the second one, on the record. Every ticket still under the epic at release is either done or being done before release; everything else has been moved somewhere it will be found, with a trail back.
First, load the team config with roost-config.
Do this at release time, not earlier. Until then, "later" items stay in the epic (slice-handoff tracks them in its Carry-over comment), because decisions can change.
Inputs
- EPIC: the epic's ticket key.
1. List what's open
Find every open ticket under EPIC, at any depth: its children of every type, and their sub-tasks. "Open" means it isn't closed (done, won't do, or any other closed state) and it isn't at tracker.statuses.ready_for_release (the tracker adapter's common searches show the query). Read the epic's Carry-over comment too, if it has one. Leave out the epic's deploy ticket and its sub-tasks: they're the release itself. Leave out the tests' shared setup, where it's a ticket (the tests adapter's "Shared setup"): it's part of the epic's tests, and closes with the last test that uses it; close any whose tests are all done. Leave out person-owned tasks (labelled tracker.person_task_label) and manual tests whose description says When: after release ("Manual tests" in the tests adapter) too: they stay in the epic with their owner. List the ones not done yet in the Close-out comment, with their owner and "When".
For each ticket, note what it's about (from its summary, description and links), where it came from (story, review finding, exploratory testing), and its Components.
2. Propose a place for each
| Place | When |
| Before release | It harms a customer at launch: security, data loss, a broken main flow, a 5xx on a public endpoint, or an accessibility failure in a main flow. It stays in the epic and gets fixed. |
| Follow-up epic | It's still about this epic's feature, and it's the kind of work you'd plan together with the rest of the feature's leftovers (hardening, edge cases, polish of the same screens and endpoints). |
| Standalone | It came up during the work but isn't about the feature: shared infrastructure, logging, tooling, lint, local development. It belongs with general engineering work. |
Judge each the triage-ticket way: is it real, who does it hurt, how badly. Show one table, with a recommendation and a one-line reason each:
| # | Ticket | Recommendation | Why |
| 1 | PROJ-2814 Onboarding loses focus on a 400 | Before release | Accessibility failure in sign-up, the epic's main flow |
| 2 | PROJ-2813 Page through more than 100 keys | Follow-up epic | API keys feature; no customer near 100 keys at launch |
| 3 | PROJ-2828 Fix the 44 lint errors | Standalone | Not about the feature |
This is the only stop. Wait for the user's decisions, then carry them all out without asking again. If any ticket is "before release", say the close-out finishes when those are done, and come back to step 5 then.
3. Make each moved ticket stand on its own
A ticket written inside an epic leans on things that only make sense there: review finding codes ("U9", "A5"), "the checkpoint", plan contracts ("C3"), slice names, and branch names that disappear once merged. Before moving a ticket, read its description and add a short Background paragraph at the top:
- which epic and feature it came from (with the epic's key), and what that epic shipped that this builds on;
- the code it's about now: file paths on
main(or the merged stack), not branch names or PR numbers that will be closed; - any shorthand replaced with plain words.
Keep the rest of the description as it is. If the description already stands on its own, add only the first line ("Came from PROJ-X, …").
4. Move them
- Follow-up epic: if any ticket goes there, create the follow-up epic once (reuse it if EPIC already has one): summary "<EPIC's summary>: follow-ups", the same Components as the tickets, a description that says it holds work deferred from EPIC at release, and a "relates to" link to EPIC. Set each ticket's parent to it.
- Standalone: remove the parent.
- Every moved ticket gets a "relates to" link to EPIC, in addition to the links it already has (the story it came from).
Set and clear parents as the tracker adapter says ("Set or clear a parent"). Read every ticket back afterwards: parent, links and description.
5. Close the epic out
- Keep one Close-out comment on EPIC, starting with the heading "Close-out": what shipped (the stories), and what was deferred, as a table of ticket, where it went (follow-up epic key, or standalone), and why. Link the follow-up epic. The first run creates it; a later run (for example after release QA defers more) finds it by that heading and rewrites it in place by its ID, as the Carry-over comment is kept. Never post a second one.
- Update the Carry-over comment, if the epic has one, so it says nothing is left over.
- Check that no ticket under EPIC is still open, at any depth, other than the "before release" ones being worked on, the deploy ticket with its sub-tasks, person-owned tasks, and after-release manual tests. Say the count.
6. After the release ships
Run this part again once production runs the epic's code, and confirm that first: the rollout's deploy step passed, or, for an epic with no rollout, the production deploy that carries its release has run (merging deploys nothing on its own, unless the repo's production is merge). For each repo with work in the epic, confirm production with the release-notes skill's script, ../release-notes/scripts/production_date.py from this skill's folder (skills/release-notes/scripts/production_date.py in the plugin), run as release-notes step 3 says, with the repo's production and the epic's merged PRs in that repo. The script decides where each PR landed (a PR merged into another branch, on a stack, lands only when a PR brings that branch onto the default branch, so its own merge doesn't count), takes the last to land, and applies the same rules as for a release note: for a workflow, that workflow's first successful run on the default branch or a tag whose commit contains the landing commit; for release, the first published release that contains it; for merge, the merge of the PR that landed it. status: dated means production runs it, with deploy saying what carried it. held means it doesn't yet, with reason saying why: when a PR hasn't reached the default branch, that repo isn't shipped, so say so, check again once it lands, and say the release note offered would be held. not_found means GitHub can't tell you: say the reason, and ask the user. When the user has told you what deployed, use that, and don't run the script for that repo: a deploy or release they say carries the epic's work in a repo (for example "its fix is in 3.21.0", and 3.21.0 deployed) confirms that repo; PRs they say merged, without naming another branch, merged into the default branch. When you can neither run the script nor tell from what you were given what deployed a repo's work, say so in the 🙋 Your turn block and ask; until the user answers, make no epic-wide tracker writes (the Release order and Close-out comment rewrites, closing the epic) and no writes to tickets with work in that repo, a hand-run tracker sync included; writes to tickets that touch only confirmed repos go ahead. A repo without production: confirm it as you would otherwise, and if you can't tell, ask the user. Until production runs it, the epic isn't shipped. Closing out before release leaves tickets at tracker.statuses.ready_for_release; shipping should move them to tracker.statuses.done, and it doesn't always. If the config has no ready-for-release status, check only that every ticket is done.
- Check each release's workflow run. If the repos release with
deploy.release_tool(for example Release Please), check in each repo that released that the run that published the release succeeded, including any tracker sync job it has (gh run list --workflow <its workflow file>). If a run failed or its sync job was skipped, run the repo's tracker sync by hand for that tag (a dry run first), and file a Bug for the workflow, linked to EPIC. - Person-owned tasks due after release: remind each owner in the 🙋 Your turn block. The epic closes when they're done; until then, say which are open.
- Manual tests due after release (
When: after release): ask the session of the repo that owns the work each checks to run it and record amanual run:comment, with the steps it can't take as 🙋 Your turn actions ("Manual tests" in the tests adapter). Close each only on a passing run; until then it stays open, and so does the epic. - Every other ticket under EPIC is Done, at any depth (manual tests close only as above). A fix that shipped in the other repo's commit, or one that no commit names, can still sit at
tracker.statuses.ready_for_release: close it by hand, add the version it shipped in as its fix version, and say in a comment where it shipped and how it was verified. - Rewrite the epic's comments as shipped: the Release order comment says every PR is merged and in which release, with the deploy dates, and the Close-out comment says what's in production. Add the tickets found during the rollout to the Close-out comment, under their own heading.
- Offer the release note. Once production runs the epic, ask whether to draft its release notes with the
release-notesskill (one per feature it shipped; usually one). Only offer: don't write the note unless the user asks. Offer it even while a repo is waiting for the user to say where its PRs landed or what deployed them (above): say its date may change, or it may be held, depending on their answer.
Report
Anything the user must do first, in a 🙋 Your turn block (leave it out when there's nothing). Then one line: "PROJ-2306 closed out: 9 tickets to PROJ-2900 (follow-ups), 5 standalone, 0 left open." Then the deferred table from the closing comment. After the release ships: "PROJ-2306 shipped in API 3.20.0 and UI 3.3.0; 0 tickets left open; release syncs checked. Want me to draft its release notes?"
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

