/done — close a journal entry
SkillMonitoring & opsMark journal work complete, close an existing followup by its fid, acknowledge or complete an upstream-version signal, or ship the in-flight `running` cursor. Companion to /log (which captures NEW entries, /done closes EXISTING entries). Finds the entry, proves the work actually landed, then close
Use /done — close a journal entry in Claude, ChatGPT or Ahel Desktop
Free. Sign in, add /done — close a journal entry and connect your AI. About a minute.
Also: Claude Code · Cursor · Codex
Then ask your AI: use the /done skill
Details
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; Ahel provides instructions and does not run this skill.
No other account needed.
Add Ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
What this skill tells your AI
The instructions your AI receives, as published by jellyrock/jellyrock in .claude/skills/done/SKILL.md and read by Ahel’s review.
Contract
Goal. Be the single closure entry point for every kind of journal entry this repo keeps. When a piece of work lands — a followup is done, an upstream-version signal is acknowledged or completed, the in-flight cursor shipped — the user types /done <thing> and the skill detects what kind of thing it is, finds the existing entry in the right journal (docs/progress.md or docs/signals-backlog.md), and applies the closure writes (bullet-remove + Recently-shipped move / signal-field flip / cursor promote) directly via Edit — no per-invocation diff-then-confirm gate (see Success criteria). Companion to /log: same journal system, different moment — /log captures NEW entries; /done closes EXISTING ones. The reasoning load is not uniformly mechanical, and the tier follows the riskiest step rather than the average one. Locating an entry and applying the closure writes are mechanical. But deciding that the work actually landed (Success criteria: "Closure writes reflect reality, not optimism") is a judgment call with an asymmetric downside: a wrong close deletes a known gap and leaves no trace that anything was lost, whereas a wrong capture only adds noise a later reader can discard. The signals-backlog.md dual-lifecycle adds a second trap — acknowledging a perpetual upstream watch is not completing a one-off signal, and the auto-fetched last_checked field is off-limits — which rewards careful instruction-following over a tier that just does the "obvious" closure. So this skill ships at the Sonnet tier with effort: low — low because the verdict correlates evidence already in front of it (the entry's own closing clause, plus the command output) rather than generating anything absent.
Inputs. The arguments are <slug-or-keyword>, required. The literal token running is a reserved keyword that maps to the ## Currently running cursor and short-circuits the polymorphic match. Otherwise the input is matched polymorphically, first hit wins: a case-insensitive substring against open-followup bullet text in docs/progress.md, then an exact ### <slug>: heading match in docs/signals-backlog.md. If there are no arguments, the skill lists the top pending followups + the action_pending signals and asks which one. If the input matches more than one entry, the skill surfaces the candidates and asks — it never silently picks.
Outputs.
- The closure writes applied directly via
Edit: for a followup — remove the bullet from## Open followups(restore the(none)placeholder if the area empties), prepend a dated- YYYY-MM-DD — <text>entry to## Recently shipped(onmainonly; see Step 2-F), bumplast-updated:; for a signal — the auto-managed-vs-manual field updates (see Success criteria); for running — promote the cursor paragraph to a dated## Recently shippedbullet (onmainonly), clear the cursor body, bumplast-updated:. - A one-line confirmation after the writes, so the user can see what landed.
- A verification pass (
npm run lint:docs) confirming the file stays lint-clean (staleness gate + signals schema). - No commit.
/doneis edit-only — it surfaces "edited<path>— review and commit when ready." The commit (carrying the actual code change that closed the work) is the user's call.
Success criteria.
- The closure is applied directly via
Edit— no per-invocation diff-then-confirm gate. The skill is dead-simple closure; trust it, and if outputs go wrong, run/audit-skill doneto fix the SKILL.md. Per-invocation confirmation is the wrong corrective loop for systematic issues — it adds friction every session and the user can alwaysgit reset --soft HEAD~1to recover a rare mis-closure. - Closure writes reflect reality, not optimism. If the journal claim depends on the work actually shipping, the skill verifies it BEFORE drafting the writes — the commit that did the work is in this branch's history (or on
main), or the PR carrying it is merged — and surfaces an inconclusive check as a question rather than closing on it. Pre-marking optimistically is the failure shape/doneexists to prevent. - Closed followups are REMOVED from
## Open followups(and recorded in## Recently shipped— by/doneonmain, by journal-sync after merge on a branch), never annotated in place with a✅-style marker — git is the shipping history; the open section tracks open work. - Auto-managed signals (
jellyfin-server-stable,jellyfin-server-rc,roku-os) are ACKNOWLEDGED — clear the stale flag, setlatest_acknowledgedto the currentlatest_upstream, flipaction_pending→watchingif set — and are NOT flipped tocompleted(they are perpetual), andlast_checkedis left untouched (it is the aggregator's field). Only manually-managed signals flip tocompleted. - Disambiguation surfaces candidates and asks ONLY when the input genuinely matches more than one entry; unambiguous pointers apply directly. The skill never silently picks among ambiguous matches, but it also doesn't gate unambiguous ones with a confirmation prompt.
- Pure local-file edits — the only remote-ish calls are the landing check and the lint verify, which read but never write.
Failure modes to avoid.
- Pre-marking optimistically. "I think it shipped, let me close it." NO. If the closure depends on the work landing, run the landing check (the commit is in this branch's history or on
main, or the PR is merged) BEFORE drafting the closure — a premature/doneis a future audit failure. - Flipping a perpetual signal to
completed(or touchinglast_checked). The signals dual-lifecycle trap: for an auto-managed slug,/donemeans "I reviewed the new upstream" — acknowledge, don't complete; never bumplast_checked(the aggregator owns it). Flipping it tocompletedcorrupts the watchlist that drives/catchupbanners and/server-upgrade. - Replacing a closed followup with a
✅-marked line. Closed work is REMOVED from the open section (Recently shipped records it — see Step 2-F for who writes that line). A✅annotation in the open list breaks the open/closed distinction and fails the docs-lint. - Skipping the load-bearing side effects. A closure that doesn't bump
last-updated:leaves a stale-looking journal and a phantom staleness banner on the next/catchup; an area emptied without its(none)placeholder fails the docs-lint. Apply the per-type side effects every time. - Silent ambiguous-pointer resolution. When the input matches multiple candidates, surface them and ask. Picking the first match, the most recent, or the highest-priority is silent corruption — the user knew which one they meant.
- Adding friction prompts in place of audit-driven fixes. If closures consistently land wrong, the corrective loop is
/audit-skill done→ fix the SKILL.md → re-dogfood — NOT bolting a per-invocation confirmation prompt back on. Per-session friction is a worse pathology than rare mis-closures (git reset --soft HEAD~1recovers those). - Committing from inside
/done. The skill is edit-only; the commit (with the code change that closed the work) is the user's call. Bundling a journal closure into the skill's own commit is the wrong shape here. - Editing
progress.md/signals-backlog.mdwith rawWrite/Editoutside this skill./done(closure) and/log(capture) are the only sanctioned write paths for these journals.
When NOT to use.
- The work hasn't actually shipped yet — capture it via
/log followupfirst; close via/donelater when it lands. - The followup is deferred, not closed — leave it in place (optionally revise its body with
/log followup --replace=<substring>), or record the deferral decision via/log decision. - A multi-step landing where some pieces are still in flight. Wait until all pieces land before
/done(or revise the bullet to the remaining step with/log followup --replace); otherwise the closure record is misleading. - An open GitHub issue closed in the PR →
gh issue close <N>(or "Closes #N" in the commit body)./donedoesn't touch GitHub state. - A tech-debt entry to remove →
/tech-debt-scanwalks tech-debt entries one-by-one and applies removals. - A
decisionentry to revise → decisions are append-only; file a new/log decisionwith**supersedes**: <old-slug>(which flips the old entry tosuperseded). - The capture is a NEW entry, not a closure of an existing one. That's
/log, not/done. - The thing to close is a project's PLAN.md milestone (a phase shipped, a slice landed). That's handled by
/end-sessionon the project's PLAN.md, not by/done.
Implementation
The completion side of the capture/completion ritual. /log adds; /done closes. Operates on progress.md (followups → recently shipped) and signals-backlog.md (status flip). Tech-debt removal stays via /tech-debt-scan; GitHub issues stay via gh issue close.
Auto-close-loop note: the running cursor close-loop fires automatically when a PR merges to main via .github/workflows/journal-sync.yml. You only need to invoke /done running manually when the work shipped via a path that bypasses the workflow (direct push to main, squash-merge with a heavily edited title, the workflow being skipped by label). For the normal /pr → review → merge path, the cursor close happens for you.
Inputs
$ARGUMENTS: a slug or keyword identifying what's done. Must be present.
- For followups: the input is matched as a case-insensitive substring against bullet text under
## Open followups. So/done aggregator perfmatches- Verify aggregator perf on slow networks. - For signals: the input is matched as an exact
### <slug>:heading insignals-backlog.md. So/done jellyfin-server-stablematches### jellyfin-server-stable: Jellyfin server stable channel.
If $ARGUMENTS is empty: list pending followups (top 5) + signals with status: action_pending (top 5) and ask which one.
The capture rule
Same as /log: this skill is the ONLY sanctioned write path for docs/progress.md and docs/signals-backlog.md completion edits. Agents do NOT use raw Write / Edit on those files outside this skill — closures flow through /done, captures through /log. Within the skill, the closure applies directly (no per-invocation confirmation prompt); systematic wrongness is fixed via /audit-skill done, and git reset --soft HEAD~1 recovers a rare mis-closure. (A sub-agent invoking /done is the exception — it surfaces the proposed edit and never auto-applies, because its context dies at exit; see Sub-agent invocation.)
Step 1 — Match polymorphically
The literal token running is a reserved keyword that maps to the Currently-running cursor (Step 2-R below); it short-circuits the polymorphic match. Otherwise, search in this order; first hit wins:
Running keyword (progress.md ## Currently running)
If $ARGUMENTS is exactly the token running (case-insensitive, optionally with trailing whitespace): proceed to Step 2-R. Skip the followup / signal searches entirely — running never matches a followup bullet by accident because it isn't typical bullet text, and reserving it as a keyword keeps the contract clean.
Followup match (progress.md)
grep -in '<keyword>' docs/progress.md
Restrict matches to lines BETWEEN ## Open followups and the next ## heading. Skip any (none) placeholder lines. If exactly 1 bullet matches, proceed. If 0 matches, fall through to signal match. If >1 matches, surface all matches and ask which one.
Signal match (signals-backlog.md)
grep -n '^### <slug>:' docs/signals-backlog.md
Exact match on the ### <slug>: heading. If 1 hit, proceed. If 0 hits, fall through to the no-match branch.
No match
Tell the user no journal entry matched, then suggest:
- For internal tech debt:
/tech-debt-scan(handles add + remove fordocs/architecture/tech-debt.md) - For GitHub issues:
gh issue close <N>(the closed issue is its own audit trail) - For arbitrary file edits: just edit the file directly —
/doneis journal-scoped
Step 1.5 — Landing check (followups and the running cursor)
Before drafting any closure for a followup or running, check that the work actually landed. Signals skip this: acknowledging one means "I reviewed the upstream", not "work shipped".
- The entry or the session names a commit →
git merge-base --is-ancestor <sha> HEAD(in this branch) orgit branch -r --contains <sha>listsorigin/main. - It names a PR →
gh pr view <N> --json state -q .stateisMERGED, or the PR is the one open for this branch and its commits are here. - Nothing to check against, or the check is inconclusive (a commit not found, a PR still open for another branch) → say what was checked and ask whether to close anyway. Never close on an inconclusive check.
Step 2-F — Followup completion (when a followup matched)
Compose the diff:
- Remove the matched bullet from the area subsection under
## Open followups. If removing the bullet leaves the area subsection empty, restore the(none)placeholder line. If the bullet was the LAST line of the file, make sure the file still ends with a single newline — removing a final line takes its newline with it, andmarkdownlint's MD047 fires on the next edit rather than on this one, so the breakage surfaces attached to unrelated work. - Only if
git branch --show-currentismain, prepend a new bullet at the top of## Recently shipped:- YYYY-MM-DD — <followup text>using today's ISO date and the followup's text verbatim. On any other branch skip this step: the work ships in a PR, and the post-mergejournal-sync.ymlwrites its one Recently-shipped line from the PR title, so a line here is a duplicate. That sync skips some PRs by label, author or title (shouldSkip()inscripts/journal-sync.jsholds the rules), so a followup closed in one of those leaves no Recently-shipped line at all — git history is its record, by that skip's own intent. - Bump
last-updated:in the frontmatter to today.
Verbatim has one exception, and it is not a style call. A followup that states a PROBLEM rather than a deliverable — "X has no sanctioned way to do Y", "Z cannot be verified" — reads as a live complaint when copied verbatim under a today's date, i.e. it asserts the problem still exists on the very day it was fixed. That fails this skill's own "closure writes reflect reality, not optimism" criterion in the honest direction rather than the optimistic one, but it fails it. For those, write a one-line RESOLUTION naming what shipped and the followup it closes, which is the shape docs/progress.md already uses — see its run-meta.json and registry-restore entries. Deliverable-shaped bullets ("Expand automated store screenshots to all ~99 locales") are unaffected: verbatim is already the resolution, and rewriting them would just be drift.
Apply directly via Edit (no confirmation prompt — trust the skill; /audit-skill done is the corrective loop for systematic issues).
Step 2-S — Signal completion (when a signal matched)
Two distinct lifecycles depending on whether the signal is auto-managed or manually-managed.
Auto-managed slugs (jellyfin-server-stable, jellyfin-server-rc, roku-os)
These signals are perpetual — the upstream isn't going to stop existing. /done here means "I've reviewed the new upstream version", which clears the stale flag. It does NOT flip status to completed.
Compose the diff:
- Find the
### <slug>:block insignals-backlog.md. - Read the row's current
**latest_upstream**:value. - If
**latest_acknowledged**:already equals**latest_upstream**:, tell the user "nothing to acknowledge — already up to date" and stop. - Otherwise update fields:
**latest_acknowledged**:→ the current**latest_upstream**:value- If
**status**:isaction_pending, flip towatching(the work that the action_pending tracked has presumably shipped).
- Bump file frontmatter
last-updated:to today.
Note: this skill does NOT bump **last_checked**: — that's the aggregator's territory and reflects "last time we asked upstream", not "last time we acknowledged". Don't overwrite it.
Manually-managed slugs (any other slug added via /log signal)
The original close-loop lifecycle — flip status to completed and the row stays as a historical record.
Compose the diff:
- Find the
### <slug>:block insignals-backlog.md. - Update fields:
**status**:→completed**latest_acknowledged**:→ the current**latest_upstream**:value (so the historical record is consistent)- Optionally update
**latest_upstream**:and**current**:if the user provides new values; otherwise leave unchanged.
- Bump file frontmatter
last-updated:to today.
Apply directly via Edit (no confirmation prompt — trust the skill; /audit-skill done is the corrective loop for systematic issues).
Note: a signal in completed status stays in the file as a record of past work. If the file accumulates many completed rows over time, archive them by hand (move to a "## Completed" subsection) — not yet automated.
Step 2-R — Running cursor completion (when $ARGUMENTS == running)
The in-flight cursor shipped — promote it to ## Recently shipped and clear the cursor.
Compose the diff:
- Read the current paragraph between
## Currently runningand the next##heading indocs/progress.md. If the paragraph is empty (already cleared), tell the user "no Currently-running cursor to close" and stop — don't pad Recently shipped with a blank entry. - Only on
main(same reason as Step 2-F), prepend a new bullet at the top of## Recently shipped:- YYYY-MM-DD — <currently-running text>using today's ISO date and the paragraph verbatim. If the paragraph is multi-line, collapse internal whitespace to single spaces so the bullet stays one line. - Replace the
## Currently runningbody with a blank-line pair (clears the cursor; leaves the section heading intact). - Bump
last-updated:frontmatter to today.
Apply directly via Edit (no confirmation prompt — trust the skill; /audit-skill done is the corrective loop for systematic issues).
If the in-flight work was multi-step and only part of it shipped, ask the user: "Promote the whole cursor to Recently shipped, or replace it with a follow-on description?" The latter is /log running "<new text>" — /done running only handles full closure.
Step 3 — Verify
npm run lint:docs
Both edits should keep the file lint-clean: progress.md staleness gate passes (last-updated bumped to today); signals schema validator passes (all required bullets still present, valid status enum).
Step 4 — Don't commit
/done drafts + applies but does NOT git commit. Surface "edited <path> — review and commit when ready." The commit (with the actual code change that closed the followup or moved the signal) is the user's call.
Sub-agent invocation
Read .claude/skills/done/SKILL.md and surface the proposed completion edit for $ARGUMENTS=; do NOT apply the edit — return the proposed diff for the parent to confirm.
Signals
- GitHub stars
- 45
- Forks
- 2
- Last commit
- Oct 2026
Advanced
- Item type
- skill
- Key
done-jellyrock- Source
- github.com/jellyrock/jellyrock
github.com/jellyrock/jellyrock
Related picks
Skill · larksuite
The pick for Markdownmarkdown-formatter
Skill · nvidia
The pick for Markdowninternal-comms
Skill · anthropics
More in Monitoring & opsagent-eval
Skill · affaan-m
More in Monitoring & opspricing
Skill · coreyhaines31
More in Monitoring & opslark-okr
Skill · larksuite
More in Monitoring & ops