End-of-session wrap-up — saves a session note to the hub, updates CONTEXT.md, and commits hub changes. Use this skill whenever the user types `/done`, `/wrap`, says "wrap up the session" / "save the session", or signals the conversation is ending and they want it documented. Also use when the user is closing a coding/research session and wants the work captured before they walk away — even if they don't say "/done" explicitly. Do NOT auto-trigger; wait for an explicit closing signal from the ...
Scanned 9/5/2026
Install to Claude Code
npx -y skills add ManceRayder42/jarvis-os --skill done --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Done?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/mancerayder42-done)More formats (shields.io, HTML) on the badges page.
---
name: done
description: End-of-session wrap-up — saves a session note to the hub, updates CONTEXT.md, and commits hub changes. Use this skill whenever the user types `/done`, `/wrap`, says "wrap up the session" / "save the session", or signals the conversation is ending and they want it documented. Also use when the user is closing a coding/research session and wants the work captured before they walk away — even if they don't say "/done" explicitly. Do NOT auto-trigger; wait for an explicit closing signal from the user.
---
# /done — Session Wrap-Up
Save a durable record of this session into the hub (see the plugin's hub concept — resolved from `JARVIS_HUB` env, then `~/.jarvis-hub-path`, then `~/jarvis-hub`). **Scale effort to session weight**: light/conversational → minimal note; substantial work (commits, decisions, multi-step) → structured note. Don't fabricate. Don't pad.
## Token discipline (read this first)
This skill runs at the end of every session, so cost compounds. Four rules to keep it cheap:
1. **No narration between tool calls.** Don't write "Running command...", "Edit succeeded, continuing...", "Now committing..." — those are wasted tokens. Run tools silently. Only the final confirmation is shown to the user.
2. **One bash call for context.** The resolver script bundles every piece of prep info you need. Don't make additional `git log`, `ls`, or `cat` calls unless the resolver output is genuinely missing something.
3. **Skip steps when they don't apply.** If the resolver printed no `dirty:` lines → no commit step. If session was light → no patterns scan. If `today_daily_note=(none)` → no link to it.
4. **Never full-Read `CONTEXT.md` or `patterns.md`.** Both can grow large over a long-lived hub. Step 4 updates `CONTEXT.md` via a script (no read); step 5 dedups patterns via `grep` (no read). If you ever must touch them directly, use `offset`/`limit` — never load the whole file.
## Workflow
### 1. Resolve context
```bash
bash "${CLAUDE_PLUGIN_ROOT}/skills/done/scripts/resolve-context.sh"
```
The output is a flat key=value block. Key fields you'll use:
- `hub`, `sessions_dir`, `project` — where the session note goes and what the work belongs to
- `hub_is_git` — `no` means the hub isn't a git repo at all; skip the commit step entirely (see edge cases)
- `hub_dirty` — any uncommitted changes anywhere in the hub
- `sessions_dirty`, `wiki_dirty`, `memory_dirty`, `other_hub_dirty` — per-area dirt flags
- `dirty:hub:<path> <count>` lines — every dirty top-level path in the hub. This is the authoritative list for what to stage; don't guess from the flags alone.
- `hub_branch/_remote/_upstream/_ahead` — push state. See step 6.
- `wiki_recent_count` — wiki files modified in the last 24h (informational only)
- `current_branch` — branch of the repo you were *working* in (not the hub) — note it in the session note if relevant
- `today_daily_note` — path to today's daily note, or `(none)` (most hubs won't have this — that's fine, skip the line)
- `last_session_note`, `last_session_date` — for continuity context
- `today_session:<path>` lines — existing session notes for today (idempotency)
- `commit:<hash> <msg>` lines — commits in the hub since last session date
### 2. Decide session weight
- **Light** — purely conversational, no code changes, < 5 substantive turns, no decisions worth keeping. → 3-line note. Skip patterns.
- **Substantial** — code/files changed, real decisions, multi-step work. → Structured note + patterns scan.
Weight decides how much you *write*, never whether you commit. Step 6 is driven by the resolver's `dirty:` lines alone — a light session that still left `patterns.md` or `CONTEXT.md` dirty gets committed, because the alternative is drift that compounds silently.
When unsure, lean light. A thin honest note beats an inflated one.
### 3. Write the session note
Path: `<sessions_dir>/YYYY-MM-DD-<slug>.md`. Slug = 2-5 word kebab-case describing topic.
**Idempotency**: check the `today_session:` lines from the resolver. If one matches your slug → read that file, append `## Part 2 — HH:MM` with new content. Different slug, same date → new file (fine). Never overwrite.
**Substantial-session structure**:
```markdown
---
type: session
date: YYYY-MM-DD
project: <project>
status: <completed | in-progress | blocked>
tags: [session, ...]
---
# Session: YYYY-MM-DD — <Title>
**Goal:** <one sentence>
**One-line takeaway:** <single most important thing for future-you>
**Branch:** <current_branch> (only include if not main/master)
## Work done
- <commit-hash> <message> — <context if non-obvious>
## Decisions
- **<decision>** — <reasoning>
## Open threads
- <thread> — <what's blocked or pending>
## Next steps
- <concrete action>
```
For **light sessions**, drop the structured sections — frontmatter + Goal + 2-3 bullets is enough.
If `today_daily_note` exists, you may add a one-line `**Daily note:** [link](daily-notes/YYYY-MM-DD.md)` near the top. Skip if `(none)`.
Use the `commit:<hash> <msg>` lines from the resolver to populate "Work done" — those are real commits since the last session note.
### 4. Update CONTEXT.md
**Do NOT Read `CONTEXT.md`** — reading the whole file every run is the cost this step exists to avoid on a long-lived hub. Pipe a one-line entry to the updater instead; it prepends it, keeps the newest 12, and auto-archives the overflow — the model never loads the file:
```bash
python3 "${CLAUDE_PLUGIN_ROOT}/skills/done/scripts/update-context.py" <<'ENTRY'
- Date: YYYY-MM-DD (topic) — one-line summary of what happened. Open: <blocker if any>. Note: `sessions/YYYY-MM-DD-<slug>.md`
ENTRY
```
You already have the content — you just wrote the session note. One line, newest-first. The script owns the `## Recent Sessions` region between the `SESSIONS:START/END` markers and creates `CONTEXT.md` from a minimal scaffold if it doesn't exist yet — the `## Active Projects` / `## Open Threads` / `## Recent Decisions` sections above that region are untouched by this script.
Re-running `/done` in the same day is safe: the script matches on the `sessions/…md` path in your entry and **replaces** the existing line instead of stacking a duplicate (it reports `replaced=1`). So keep the note path in the entry — it's what makes the update idempotent.
Exit code `2` means you piped an empty entry, which means step 4 didn't actually happen — fix the entry and rerun.
**State sections** (Active Projects / Open Threads) update separately and only when something genuinely changed: edit in place with a targeted `offset`/`limit` Read around that section, never a full-file Read.
### 5. Patterns (substantial sessions only)
Only if a *real* lesson surfaced — user corrected you, non-obvious tooling discovery, failure mode worth remembering. **Before appending, dedup**: grep `patterns.md` for similar phrasing — if the same lesson is already there, skip.
```bash
grep -i "<key-phrase>" "<hub>/patterns.md" 2>/dev/null
```
If `patterns.md` doesn't exist yet, don't create it from `/done` — that's a job for a memory-consolidation pass, not this skill. Skip step 5 silently in that case.
If no match, append under `## YYYY-MM-DD` heading:
```
- **Pattern**: <one-line>. **Why it matters**: <one-line>. **Trigger**: <when this applies>.
```
If nothing genuinely new, skip step 5 entirely. Manufactured patterns silently bias future decisions — worse than missing ones.
### 5.5. Wiki auto-update
**The contract:** after `/done`, the hub's wiki reflects this session's work. `/done` doesn't hand the work back to the user; it **detects what the wiki owes and writes it automatically**, then reports what changed.
Runs after the session note is written, BEFORE the commit in step 6.
**Step 5.5a — detect.** Run the freshness detector (pass nothing; it auto-finds this session's transcript):
```bash
bash "${CLAUDE_PLUGIN_ROOT}/skills/done/scripts/wiki-check.sh"
```
Parse the `WIKI_*` block from stdout:
- `WIKI_VERDICT` — `update_owed` | `up_to_date` | `skipped`
- `WIKI_REASON` — one-line explanation of the verdict (quote it if you report "skipped")
- `WIKI_PROJECT` — the project (hub subdirectory) the work touched
- `WIKI_FILES` — comma-separated basenames of the non-wiki files edited this session (targeting hint)
- `WIKI_EDITS` / `WIKI_DISCOVERY` — counts (real file edits / discovery actions)
- `WIKI_TARGET` — suggested article path skeleton
The detector locates this session's transcript itself: `$PWD` with `/`, `_` and spaces flattened to `-` under `~/.claude/projects/`, newest `.jsonl`. It **fails open** — any problem finding or parsing the transcript yields `skipped`, never a blocked `/done`.
One blind spot to cover yourself: it only classifies paths **inside the hub**. A session that spent its time editing this plugin's own skills/hooks/settings returns `up_to_date` because nothing hub-shaped was touched — if that's the kind of work this session actually did and it's worth remembering, write an article regardless of the verdict.
Trigger model: **any changed files**. If the session edited/created real files in a hub-tracked project (or did ≥3 discovery actions on one) and did NOT already write a wiki article, `WIKI_VERDICT=update_owed`.
- `up_to_date` → nothing owed. Skip to step 6.
- `skipped` → escape flag was set or transcript missing. Note "wiki-check skipped" in the confirmation and skip to step 6.
- `update_owed` → **continue to 5.5b. Do not skip. Do not ask the user first** — if the user prefers to review before writing, that's a one-time setting, not a per-session question.
**Step 5.5b — write the wiki (automatic).**
Articles live at `<hub>/wiki/<project>/<topic>/<article>.md`, indexed by `<hub>/wiki/<project>/index.md`. See the `wiki-article` skill for the template and the anti-fabrication guard.
1. Look at what changed. The session note you just wrote (step 3) + the `WIKI_FILES` hint + the work you actually did this session tell you which component/concept needs a wiki article.
2. Decide **update vs create**. List the project's existing articles:
```bash
ls "<hub>/wiki/<project>"/**/*.md 2>/dev/null
```
- If an existing article already covers this component → **Read it and update in place** (refresh `How it works`, `Code references`, bump `last-updated`, add new failure modes). Don't create a duplicate.
- If nothing covers it → **create** using the `wiki-article` skill's template.
3. **Update the index.** Add or refresh the `[[topic/article|Title]]` line in `<hub>/wiki/<project>/index.md` so the new/changed article is discoverable.
4. Multiple distinct components touched → write/update one article each (don't cram unrelated work into one).
**Anti-fabrication guard (hard rule).** The wiki must never contain invented content. If the work was too shallow to write ≥200 honest words (1–2 file reads, a one-line tweak, no real structural understanding gained), do NOT manufacture an article. Instead append a 5-line *"what's missing for a wiki article"* stub to `<hub>/wiki/<project>/index.md` naming the component and where the next session should start. A thin honest stub beats a padded fake article. Note this choice in the confirmation.
**Manual opt-out** still exists: passing `/done --skip-wiki-check` sets `DONE_SKIP_WIKI_CHECK=1` in front of the detector call (or `touch /tmp/done-skip-wiki`) so it returns `skipped`.
The articles you just wrote are uncommitted; step 6 re-reads git state at commit time and picks them up (the resolver's `wiki_dirty` from step 1 predates them — don't read it as "nothing to commit"). Record which articles you wrote/updated; you'll list them in the confirmation and in the session note's "Work done".
### 6. Commit the hub (only what's dirty)
The point of this step is that nothing you just wrote stays unversioned. Always run it when there's anything to commit — `hub_is_git=no` from step 1 is no longer a reason to skip: `commit-hub.sh` initializes the hub as a git repo on its own the first time it has something real to stage (see the edge cases entry). It only reports `nothing:hub` when there is genuinely no dirt.
One call does the whole step — staging, the push decision:
```bash
bash "${CLAUDE_PLUGIN_ROOT}/skills/done/scripts/commit-hub.sh" --slug <the-slug-you-used>
```
Add `--dry-run` first if you want to see the file list without committing.
It re-reads git state *at commit time* rather than trusting the step-1 snapshot — which matters because everything you wrote in steps 3–5.5 came into existence after the resolver ran. Staging by hand from the stale `dirty:` lines is exactly how freshly-written wiki articles used to get left behind.
Parse its output for the confirmation:
| Line | Meaning |
|---|---|
| `initialized:hub <path>` | this was the hub's first commit ever — it just became a git repo |
| `cleaned:hub <files>` | one-time placeholder removal fired this run (see below) — name the files in the confirmation |
| `committed:hub <hash> <n> files` | landed |
| `nothing:hub` | clean, nothing owed |
| `pushed:hub <branch> -> <remote>` | synced |
| `nopush:hub <reason>` | deliberately not pushed — report the reason verbatim |
| `error:hub <msg>` | say so plainly in the confirmation; don't retry, don't force |
What it guarantees, so you don't have to re-verify:
- **Allowlist only** — `sessions wiki patterns.md conversation-log.md CONTEXT.md daily-notes ideas research learning`. Any file that looks hand-curated (`MEMORY.md`, any `user_*`/`project_*`/`feedback_*`/`reference_*` memory file) can never be staged by this script — those are the user's own edit-in-progress, same reasoning as never touching `CLAUDE.md` in a code repo.
- **One narrow, deliberate exception to the line above:** the very first time a run has real content to commit, it also retires `memory-template`'s seeded `example-*.md` placeholders (`example-feedback-rule.md`, `example-project-note.md`, `example-user-fact.md`) and their index lines in `MEMORY.md` — but only files that still contain the literal placeholder marker text, so a file you kept and genuinely repurposed under that name is never touched. Rationale: those three files exist only to show the memory format; shipping forever, they'd get injected into every session's context alongside your real memory. "The hub's first real commit" is the natural signal that you're actually using it now. In practice this fires once, ever, per hub.
- **Initializes the hub as a git repo on first use** if it wasn't one already, instead of silently doing nothing — a hub with no version history was the old failure mode (see edge cases).
- **Checks git identity before committing.** If `user.name`/`user.email` were never set (local or global), it reports `error:hub git identity not set — run: git config --global user.name "Your Name" && git config --global user.email "you@example.com" ...` — surface that verbatim; there is nothing to retry until the user runs it.
- **Refuses to commit mid-rebase/merge** — reports `error:` instead of burying an unfinished operation.
- **Never auto-pushes** — the hub holds personal memory by definition, so pushing requires an explicit `JARVIS_HUB_PUSH=1` opt-in even when a remote and upstream exist. See the script's own comment for the reasoning.
**`conversation-log.md`, if present, is typically owned by a scheduled memory-consolidation pass, not `/done`.** Two writers on a rolling-window file produce duplicate entries and a corrupt boundary. `/done` commits whatever consolidation left there; it doesn't author it.
`git push` from a *code* repo is a separate, higher-stakes operation than this — this exception covers the hub only, and only with the explicit opt-in above.
### 7. Confirm
Short. Skip lines that don't apply.
```
Saved.
Session: sessions/YYYY-MM-DD-<slug>.md
Wiki: <article(s) written/updated> / up to date / stub added / skipped
Patterns: +N / nothing added
Context: updated
Hub: <N files> committed / clean
Commit: <hash> / no changes
Push: <branch> -> <remote> / no remote / skipped — <reason>
```
The `Wiki` line is required. State exactly what happened: which articles you wrote or updated (by path), or "up to date" if nothing was owed, or "stub added" if the anti-fabrication guard fired, or "skipped" if the detector was skipped.
If something failed, say so explicitly: `Missed <X> because <reason>.`
---
## Edge cases (load only when hit)
For unusual cases — detached HEAD, no git repo, write errors, hub-not-found, conflicting today files — read `references/edge-cases.md`. Don't preload it.
## What this does NOT do
- Push a hub with no upstream, or push without the explicit `JARVIS_HUB_PUSH=1` opt-in (see step 6).
- Modify or stage `MEMORY.md` or any hand-curated memory file.
- Write `conversation-log.md` (typically owned by a memory-consolidation pass, if the user has one configured).
- Send anything to a chat bridge, Telegram, or any other notification channel — this skill reports into the session only.
- Close tasks in daily notes (separate concern).
- Auto-trigger — only on explicit closing signal.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!