milestone-wrap
Skill1 starsChanged 3 months agoMITView on GitHub
The interactive half of closing a milestone — the two steps the wrap playbook can't do for you: triage deferred/pending gate items with the operator (which ones carry forward vs. stay closed), then update the Notion master page + context.md bookkeeping. Everything else (terminal check, gate/seed green check, DB wrapped_at, auto-launch repoint, advance dev->main, cut the release tag) is the automated `wrap` playbook, launched via POST /api/wrap/launch (no dashboard UI yet). Use when the user says "wrap up milestone X", "close M11", "let's close out the milestone", or "triage the deferred items for the wrap". Distinct from /wrap (which closes a SESSION, not a milestone).
In this repository10 other files it gives its agents.
- deploySkill
- designSkill
- docsSkill
- gateSkill
- groomSkill
- investigateSkill
- milestone-seedSkill
- opsSkill
- sync-guidelinesSkill
- wrapSkill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 2 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 44
Verify by reading, act via sanctioned surfaces: Read the actual state (gate items, Notion pages) before asserting a step is done or needed.
- Distinctive: line 88
Don't blanket-carry; don't blanket-drop.
≈ “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
Milestone Wrap
Closing a milestone is now mostly the automated wrap playbook (terminal check,
gate/seed green check, wrapped_at, auto-launch repoint, advance dev->main, cut
the release tag). Launch is POST /api/wrap/launch (device-authed) — there is no
dashboard UI for it yet (WrapSection.tsx hasn't landed). Until the playbook's
integrate-milestone-branch step is made conditional on two-tier branching, a
flat-branching project's wrap doesn't run through the playbook end-to-end; do it
through the sanctioned per-step surfaces instead: POST /api/milestones/:id/wrapped,
PATCH /api/projects/:id (autoLaunchMilestoneId), and the release merge + tag by
hand from a throwaway clone — same throwaway-clone, --no-ff origin/<base> into
main, tag, and GitHub-release shape the playbook itself uses (see the
/milestone-wrap-playbook carve-out in procedures.md § Hard rule). This skill
covers the two things that stay human-driven because they need operator judgment
or live outside the playbook's sanctioned surfaces:
- Triage deferred + pending gate items — deciding which ones are genuinely resolved (leave them) vs. real postponements (carry forward) is a judgment call, not something the playbook can safely automate.
- Notion master-page row +
context.mdedits — the master page's Project Milestones table / Active Task Board callout / Project Summary, plusconfig/projects/<dir>/context.md's Active Task Board line and milestone-history list.
Not
/wrap./wrapsweeps a session for unpersisted residue. This closes a milestone. Don't conflate them.
Doctrine (same spine as /gate and /ops)
- Verify by reading, act via sanctioned surfaces. Read the actual state (gate
items, Notion pages) before asserting a step is done or needed; make every change
through the project's sanctioned surface (
notion-update-page,Editoncontext.md, the gate-state client), never a raw DB write. - Don't hand the work back. Find the "several places" yourself (they're enumerated below); don't ask the operator where they are.
Step 0 — Resolve the milestone + load project context
Determine the milestone being closed and the next one. Read
config/projects/<dir>/context.md for the board IDs, the master Notion page, and the
project id-space. Project-specific values live there; this skill is the universal
shape.
Step 1 — Carry deferred + pending gate items forward to the next milestone
Green is not "all verified." readiness counts deferred (and, for an item
awaiting its not-yet-triggerable condition, pending) as resolved
(RESOLVED_STATES = {pass, deferred} in gateService.ts, pending non-blocking by
its own backoff semantics), so a milestone with deferred or pending gate items reads
green and wraps clean — but neither state means resolved. deferred means
postponed / not-yet-verified; pending means the item's trigger genuinely
hasn't happened yet and the item is backing off, waiting for another look. Left
untouched, those items die under the closed milestone: nothing ever surfaces them
again. Every deferral (and every still-waiting pending item) was a promise to verify
later — this step keeps it. (Gate-only: seed's sole resolved state is confirmed —
there is no deferred-or-pending-green seed state, so seed-green already implies no
postponed seeds. Nothing to carry on the seed side.)
Enumerate the deferred and pending items —
readinesswon't show them (it lists only blocking items, and neitherdeferrednorpendingblocks). Read them directly (LEFT JOIN — a sourceless item has zerogate_item_sourcerows and must not be dropped by the query); reads of the live DB are sanctioned (only writes are barred):SELECT gi.id, gi.classification, gi.state, gi.text, s.source_task_id, s.source_task_title FROM gate_item gi LEFT JOIN gate_item_source s ON s.gate_item_id = gi.id WHERE gi.project='<projectId>' AND gi.milestone='<closingM>' AND gi.state IN ('deferred', 'pending')- Triage each with the operator. A deferred or pending item is either (a) genuinely won't-verify / obsolete → leave it (its current state is correct closed-milestone history), or (b) a real postponement → carry it forward. Don't blanket-carry; don't blanket-drop.
Re-home the carry set to the next milestone — a fresh copy, never a move. Raw-DB moves are barred, so every carry is a fresh-copy insert into the next milestone; the original stays
deferred/pendingunder the closing milestone (immutable closed-milestone history) while a deferred copy landsopenfor a fresh gate run. Which verb mints the copy depends on whether the item has a source:Has a source (
source_task_idis non-null). Group the carry set by(source_task_id, classification)and useaccrete— it takes one classification per call and mints onegate_itemperitems[]entry, sourced to that task (classification, incl.needs-triage, is preserved):node ~/.claude/scripts/gate-state-client.mjs accrete \ '{"project":"<projectId>","taskId":"<source_task_id>","title":"<source_task_title>", "milestone":"<nextM>","classification":"<classification>","items":[{"text":"…"}, …]}'No source (
source_task_idis null) — the item was itself hand-carried from an earlier milestone and has no single owning task left to cite. Usecarry-forwardinstead: an item-level re-home, one call per item, that copies the item's own text/classification/full sources array (empty, here) straight to the target milestone. Never invent a placeholder taskId and force it throughaccrete— it validates the id against the task board and 400s on anything synthetic, and a truncated/prose-embedded id you resolve by hand risks a silent mis-attribution (a short id prefix can collide across unrelated tasks). If you really can trace a sourceless item's prose back to one exact, full task id and want provenance restored, that is a manual accrete-with-caution; otherwise default tocarry-forwardand accept the item stays sourceless in the next milestone too — correct, not a downgrade:node ~/.claude/scripts/gate-state-client.mjs carry-forward <gateItemId> <nextM>
Either way,
<nextM>is the display name (e.g.M12), never the milestone UUID — same id-space rule as the rest of the gate client. A carriedpendingitem stayspendingin the copy, with its backoff schedule (next_attempt_at, attempt count, dispositions) preserved, so the pending re-check owns it from the first tick and it doesn't block the next milestone. A carrieddeferreditem still lands as a freshopenitem for a fresh gate run.carry-forwardis idempotent by (project, milestone, text) — re-running it for the same item and target milestone returns the copy already carried there rather than duplicating it, so a retried call is safe.- Verify the carry. Re-read the next milestone's
gate_itemrows; confirm each carried item is present (open/runnable, orpendingfor a carried pending item) and that no text duplicates an item already there (guards against a double-carry). The originals must still readdeferred/pendingunder the closing milestone.
This is the step whose absence stranded 18 deferred M11 items when M11 closed (re-homed to M12 by hand on 2026-07-20). Do it before (or independently of) the automated wrap playbook run, so the next milestone is fully populated when it goes live.
Step 2 — Notion master-page row + context.md edits
The playbook handles milestones.wrapped_at and the auto-launch repoint; the
Notion master page and context.md bookkeeping stay manual. Update all of the
following (they drift independently) — reversible bookkeeping, unconditional, do it
and report it:
| Place | Change | Sanctioned mechanism |
| Notion master page — Project Milestones table | old → ✅ Done (<date>); next → 🔄 Active | notion-update-page update_content |
| Notion master page — "Active Task Board" callout | phase line + board link → next milestone | notion-update-page update_content |
| Notion master page — Project Summary (if stale) | refresh Status/Next lines | notion-update-page update_content |
config/projects/<dir>/context.md | "Active Task Board" line + milestone-history list (old → done, add next as active) | Edit |
⚠️ Notion table cells: match on the cell's unique text (e.g.
🔄 Active), not a full pipe row — markdown table rows don't match Notion's serialization. Add a table row only via a reliable anchor; skip the Key-Decisions-Log row (that log is for architectural decisions, not routine completions — the Milestones table records the completion).
Reporting
Report both steps as a table with the concrete result of each (the deferred and
pending items carried forward + their new milestone, the Notion sections updated,
the context.md diff). Separate "done" from "already true." Never claim a place was
updated without reading it back.
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.

