wrap
Skill2 starsChanged 2 months agoMITView on GitHub
Use at session end when the friend wants to consolidate what happened. Triggers on the /ren:wrap slash command. Writes an L1 narrative summary (always, auto-quarantined as unreviewed) and gates candidate durable items through a fail-closed classifier, auto-applying them (revertible) unless held for a contradiction or surfaced as a promotion suggestion. Most sessions produce zero durable candidates — the discipline is bias toward NOT durable, per spec §3.1.
45 other projects use a version of this.
Adopted by
Most recently taken up by
- rhasselle-oddball/claude-skillstheir own version, first seen Nov 8, 2026
- jolleyDesign/claude-skillstheir own version, first seen Nov 8, 2026
- fjwood69/moritheir own version, first seen Nov 8, 2026
- egregore-labs/egregoretheir own version, first seen Nov 6, 2026
- mag123c/toktracktheir own version, first seen Nov 3, 2026
- AcKeskin/contexturetheir own version, first seen Nov 1, 2026
Used with
Projects with it also use start, build and 7 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
AnthropicSkillstart
Set up your bio-research environment and explore available tools. Use when first getting oriented with the plugin, checking which literature, drug-discovery, or visualization MCP servers are connected, or surveying available analysis skills before starting a new project.
Also in 5 projects that use this
Microsoft AzureSkillbuild
Build the TypeSpec Rust emitter from source. Run this after cloning the repo, after pulling changes, or when TypeScript source files have been modified.
Also in 3 projects that use this
SentrySkillreview
Fixture review skill.
Also in 7 projects that use this
SentrySkillspec
Produce a verified spec — problem, desired outcome, and acceptance criteria — before building. Use when given a GitHub/Linear issue link, when starting from a fuzzy in-conversation idea, or asked to "figure out what to do" / "scope this" / "what should I build" — whenever the *what* isn't yet pinned down. Grills the ambiguities, checks the premise against the code, and produces acceptance criteria you sign off on — then hands to design-first.
Also in 3 projects that use this
Microsoft AzureSkillreflect
Learning capture system that extracts HIGH/MED/LOW confidence patterns from conversations to prevent repeating mistakes. Use after user corrections ("no", "wrong"), praise ("perfect", "exactly"), or when discovering edge cases. Complements .squad/agents/{agent}/history.md and .squad/decisions.md.
Also in 3 projects that use this
nicolasestremSkillbrainstorm
Structured idea generation and solution exploration with systematic analysis.
Also in 3 projects that use this
Other versions45 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 45
- UniClipboard/UniClipboard★ 2ksame name
- team-attention/stanford-cs146s-kr★ 294same name
- egregore-labs/egregore★ 293same name
- mag123c/toktrack★ 196same name
- neurofoo/agent-skills★ 111same name
- lsnackerman/raw-clauding-skills★ 45same name
- fjwood69/mori★ 32same name
- YahyaLendani/opus-tuner-claude-skill★ 14same name
- jackjin1997/ClawForge★ 12same name
- ucsandman/claude-skills★ 5same name
35 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository19 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- backupSkill
- bootstrap-projectSkill
- code-mapSkill
- distillSkill
- doctorSkill
- ingest-projectSkill
- installSkill
- interviewSkill
- metric-watchSkill
- pinSkill
- recallSkill
- rememberSkill
- retrospectiveSkill
- routine-initSkill
- suggestionsSkill
- updateSkill
- wiki-healthSkill
- wiki-migrationSkill
The file
We split this skill into the rules it gives an agent
10 rules. 0 are common, 3 are distinctive, and 7 are very specific to this project.
0
Common
Most of the 40 edited versions we read keep these.
3
Distinctive
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 65
No session content exists yet (this is the very first turn) → nothing to wrap.
- Distinctive: line 82
Classify via ONE classifier-class subagent (batched): When there are candidate items, do not omit the classifier and do not classify inline:
- Very specific: line 120
If the spawn fails or the reply is not a JSON array of the right length, call wrap_session(...) with NO verdicts and NO llm_call: the lib …
- Very specific: line 127
Phase 2 — merges (spec 2026-08-21 §5.3): When any verdict came back durable with action: "update", those items need a merged page body, and …
- Very specific: line 144
ALWAYS pass cwd= explicitly, set to the session's actual working directory — the Python process's own cwd may be the plugin cache dir …
- Very specific: line 148
Every page wrap creates now carries the 2026-09-04 link convention: a Parent: [[<stem>]] line naming its folder-note hub (or the concept …
- Very specific: line 164
If fail_closed is true: tell the friend the classifier fell back for at least one item — those items were held as suggestions, not silently …
- Very specific: line 169
Open-work ledger: BEFORE calling wrap_session (step 3), gather two lists from this session and pass them through as keyword arguments:
- Distinctive: line 183
On request, list ALL pending suggestions: If the friend asks to see the full pending list (e.g.
- Very specific: line 188
Every write here goes through lib.memory.queue — no direct wiki writes, no donor-style CONTEXT.md rewrite machinery.
“Common” is measured: kept by at least 6 in 10 of the 40 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
wrap
End-of-session consolidation. The friend runs /ren:wrap; this skill writes the session's L1 narrative summary (always — quarantined as unreviewed LLM-auto content, never treated as instruction) and gates any candidate durable items through the classifier, auto-applying them (revertible) unless held for a contradiction or surfaced as a promotion suggestion. Per spec §3.1's discipline, most sessions should produce zero durable candidates — the classifier biases hard toward "not durable."
When to use this skill
- Friend invokes
/ren:wrapat (or near) the end of a session. - Friend says something like "let's wrap up", "consolidate this session", "what should we remember from today."
When NOT to use this skill
- Friend wants to pin one specific fact mid-session →
/ren:pin, not/ren:wrap. - Friend wants to look something up →
/ren:recall. - No session content exists yet (this is the very first turn) → nothing to wrap.
Behavior
- Compose the L1 narrative. The live session writes this ITSELF — never a subagent (
execution_tier: judgment; the exception to worker delegation: only the main model holds the conversation being summarized in context). A short narrative markdown summary of what happened this session — what was done, what's open, what changed. Lead with outcomes. Target ≤1,000 tokens. This is data, not doctrine; it always gets quarantined on write (queue Task 2.4 wiring), so nothing here needs to hedge its own confidence. - Extract candidate durable items. The live session identifies zero or more candidate strings that MIGHT be worth durable, cross-session memory (a decision, a lesson, a reusable pattern). When in doubt, extract fewer, not more — the classifier gate is the second line of defense, not the first.
- The classifier's verdict, when "durable", also carries placement:
scope("project"vs"global"),action("create"vs"update", plus atarget_pagefor updates), and akind("concept"vs"lesson"— see below for what a"concept"create does differently). A"lesson"createlands underprojects/<slug>/knowledge/lessons/<slug>.mdfor a project-scoped item (globallessons/otherwise), with a folder-note hub (<dir>/lessons.md) auto-maintained alongside it — created in full the first time, and thereafter only APPENDED to (a human's prose on the hub is never re-rendered away, and a hub whoseren_trustis"user"is left alone entirely). Anupdatemay ONLY target a page from this session's own eligibility set (wake-up injections plus/ren:recallfetches, verified on disk) and is merged in via a strict merge call that never touches frontmatter and routes to suggestions (never gated out) on any merge failure (spec 2026-08-21 §5.2). Either way, an update to a page whoseren_trustis"user"is NEVER auto-applied — it's routed to the suggestions store for the friend to approve instead. - Extraction floor: before settling on zero candidates, check the session for
(a) recorded rulings or decisions made in chat, (b) issues closed or filed,
(c) releases cut, (d) lessons stated after a failure. Each of those is a
candidate by default. "When in doubt, extract fewer" applies to judgment
calls, not to these mechanical triggers. If the session had commits, closed
issues, or releases and you still extract zero candidates, say why in one
line on the wrap screen — a silent
seen=0on a working session is the defect the 2026-08-18 spec exists to prevent.
- The classifier's verdict, when "durable", also carries placement:
- Call
skills.wrap.lib.wrap_session(narrative_md, durable_items, session, verdicts=..., cwd=Path("<absolute session working dir>")). (llm_call=...remains supported for callers with a live callable — see step 3.4 below — butverdicts=...is the standard kwarg for the batched-subagent path this SKILL drives.)sessionis just a LABEL for this session's records — you are not expected to know Claude Code's realsession_id, and nothing depends on you guessing it. (The 0.6.1 estimator-calibration harvest resolves the transcript from the id the wake-up hook itself recorded, never from this label.)Classify via ONE classifier-class subagent (batched). When there are candidate items, do not omit the classifier and do not classify inline:
Build the per-item prompts mechanically — including the project's taxonomy block, so the classifier can actually propose a
conceptplacement instead of being told "kind must be lesson" every time. Passtaxonomy_block=Nonewhen there is no taxonomy object at all (no project, orschema.mdfailed to load/parse — blind), andtaxonomy_block=render_block(tax)whenever one loaded — including when it parsed to zero nodes (""), which the classifier reads as "defined but empty, propose a new root" rather than "no taxonomy":uv run python -c " from skills.wrap.lib import eligible_update_targets from skills.wrap.lib.classifier import build_classifier_prompt from lib.memory.taxonomy import load_taxonomy, render_block, TaxonomyError import json, sys items = json.load(sys.stdin) el = eligible_update_targets('<session-id>') project = <project-or-None> tax = None if project: try: tax = load_taxonomy(project) except TaxonomyError: tax = None tb = render_block(tax) if tax is not None else None print(json.dumps([build_classifier_prompt(i, eligible_targets=el, project=project, taxonomy_block=tb) for i in items])) " <<< '<JSON array of candidate strings>'- Spawn ONE classifier-class subagent (cheapest rung — never worker- or orchestrator-class) whose task is: "Answer each of the following N prompts independently. Return ONLY a JSON array of N objects, one per prompt, in order." Include the prompts verbatim.
- Parse its reply as a JSON array and pass it to
wrap_session(..., verdicts=<the array>). Order = candidate order — verdicts are index-keyed. - If the spawn fails or the reply is not a JSON array of the right
length, call
wrap_session(...)with NOverdictsand NOllm_call: the lib routes every candidate to the suggestions store (die loudly) rather than discarding them. Tell the friend this happened.
llm_callremains supported for callers that have a live callable; the subagent +verdictstransport is the standard path for/ren:wrap.- Phase 2 — merges (spec 2026-08-21 §5.3). When any verdict came back
durablewithaction: "update", those items need a merged page body, and theverdicts=path has no livellm_callto produce one. Callskills.wrap.lib.eligible_update_targets(session)for the eligible set, then dispatch ONE batched worker-class subagent (a bounded text transformation over one page — never orchestrator-class) over the update-verdicts whosetarget_pageis in it, giving each the item text plus the target page's current text and asking for the COMPLETE merged page back — it must copy the YAML frontmatter verbatim and change only the section(s) the learning affects. Assemble the results into an array index-aligned with the candidate list,nullwherever no merge came back, and pass it aswrap_session(..., verdicts=<array>, merges=<array>). - An update whose merge is missing or fails validation is NOT discarded:
it routes to the suggestions store for the friend to place, same as an
unplaceable item. Passing no
mergesat all is safe — every update-verdict simply routes to suggestions instead of auto-applying. - ALWAYS pass
cwd=explicitly, set to the session's actual working directory — the Python process's own cwd may be the plugin cache dir rather than the project checkout (the documented invocation pattern), and defaulting to it silently misfiles the L1 under globall1/(#45). - Do NOT pass
project=yourself — leave it unset.wrap_sessionderives the current project fromcwdvia the samelib.ren_paths.detect_projecthelper the wake-up hook's read path uses, so the L1 page lands exactly where the NEXT wake-up for this project will read it (codex D4 wiring). Non-project cwds (or a cwd that doesn't match anywiki/projects/<slug>/) fall through to the original globall1/path unchanged —render_wrap_screenshouts about this on the close-out screen so it's never silent. Concept-tree routing (spec 2026-08-31 §3). A durable candidate the classifier marked
kind: "concept"(structural knowledge about the system being studied — how a component works, what connects to what;scopemust be"project", concepts have no global taxonomy) carries aplacement: the best-matching node path inprojects/<slug>/schema.md's fenced taxonomy block, or an existing node plus one new child segment together with atitle. This is validated and applied in CODE (lib.memory.taxonomy.classify_placement, called fromskills.wrap.lib) — the live session never readsschema.mditself to decide where a page goes. An existing node accretes: the item is appended as a new## Factsbullet on the node's own content page — NEVER its folder-note hub, which is never a Facts target; a legacy/hand-seeded node whose directory holds only the hub gets a fresh content page MINTED instead (same shape as a new-leaf create, minus theschema.mdedit — the node already exists). A node whose Facts pass 40 bullets raises a split suggestion — never auto-applied. A new leaf mints the node's own content page (type: project-knowledge, same as any project page) underprojects/<slug>/knowledge/<placement>/, then refreshes the leaf's and its parent's folder-note hubs and additively splices the new leaf intoschema.md's taxonomy fence — the schema.md edit routes to the suggestions store instead of auto-applying whenschema.mdis human-owned (ren_trust: "user"). An invalid placement (no matching node, a missing new-leaf title, or any other rejected concept placement) NEVER discards the item: it falls back to an ordinarykind: "lesson"create and records aplacement_eventmetric. Ifprojects/<slug>/schema.mdis missing or its taxonomy fence fails to parse, concept routing goes BLIND for the rest of this wrap — everykind: "concept"verdict falls back to a lesson create rather than guessing a placement, and the close-out screen says so explicitly ("concept routing blind: ..."). Akind: "lesson"item — the common case, and every item whenever concept routing is blind — still lands under that project'sprojects/<slug>/knowledge/lessons/<slug>.md, with the relevant hub (the folder note named after its directory,<topic>/<topic>.md) auto-maintained alongside it. Never a root-tier page for one project's fact.Every page wrap creates now carries the 2026-09-04 link convention: a
Parent: [[<stem>]]line naming its folder-note hub (or the concept page that is its real conceptual parent) directly after the H1, and a## Relatedsection — rendered even when empty, a visible "nothing linked yet". After the page actually LANDS (never for a held write),lib.memory.fanout.fan_outranks up to 12 of the project's other knowledge pages against it and asks one classifier call which should now mention it; every resulting edit goes through the write door and is revertible. If that classifier's output does not parse, nothing is edited and the close-out says⚠ fan-out unknown: …— Unknown is an outcome, never a silent skip.- The judge (Task 4/0.5.0) runs over this session's applied writes (Task 11/0.5.2's
shortlist_pairs, restricted viafocus_pagesto the pageswrap_sessionjust applied) — ONLY when a caller supplies a livellm_call. Under the standard subagent +verdictspath, there is nollm_call, so the judge degrades tosemantic_findings: []by design — expected, not an error, same fail-closed discipline as the classifier. The wrap screen's "Possible connections (unverified)" section simply renders empty/omitted; this never blocks or delays a write.
- Present results to the friend:
- L1: "session summary saved (quarantined, unreviewed)."
- Durable candidates: qids + pages, saved this session (revertible) unless held for a contradiction or surfaced as a promotion suggestion.
- Gated out: verdict + one-line reason each.
- Refused: any candidate the queue itself rejected (e.g. a planted secret) — surfaced explicitly, not silently dropped.
- If
fail_closedis true: tell the friend the classifier fell back for at least one item — those items were held as suggestions, not silently dropped.
- Harvest instruction suggestions. Call
skills.wrap.lib.harvest_suggestions(session). This runs the wrap-time suggestion producers (promotion candidates, doctrine shaping, wiki-health critical contradictions — the retrospective producer runs inside/ren:retrospective, not here) and records any new ones intolib.suggestions. Never raises; nothing in the end screen below depends on its return value — pending suggestions surface to the friend at the NEXT wake-up (suggestion_line()'s store pointer) or via/ren:suggestions, not on this screen. - Session journal.
wrap_sessionappends one append-only summary line to the journal (pages touched, counts) — automatic, no action needed.ren-wiki-lintuses these lines to lint incrementally. - Wiki lint (non-blocking). Spawn the
ren-wiki-lintagent in the background. Do not wait for it; its findings surface via the suggestions store. - Open-work ledger. BEFORE calling
wrap_session(step 3), gather two lists from this session and pass them through as keyword arguments:open_threads=[{"desc": "<one line>", "ptr": "<pointer>"}, ...]— threads this session OPENED and left open. A pointer is one ofplan:<path>#task-N,issue:#N,spec:<path>§<section>,repo:<ref>. Only real, still-open work — an item you cannot point at is not a thread, it's a feeling.completed_ptrs=["<pointer>", ...]— pointers this session finished. Only what you actually know closed;wrap_sessionALSO closes any ledger line whose pointer target is a page this session wrote, so you never need to guess.wrap_sessionthen reconcilesprojects/<slug>/open-work.md(result["open_work"]={"closed", "opened", "carried"}). It never deletes a line — closed lines age out into an archive section — and a failure there never breaks the wrap.
- Link duties (#54).
wrap_sessionweaves the pages it just wrote into the graph automatically — the session author never hand-writes any of these links: the L1 gains a "## Touched pages" section listing every other page this session's own writes touched;log.mdgets one line pointing at the new L1; the project map's "## Sessions" section gets this session; and every newly-added durable page under the project gets an auto-pointer from the map plus a spine pointer fromindex.md. Each duty is isolated — a missinglog.mdor map, or any other failure, degrades to a warning inresult["links"]["warnings"]rather than breaking the wrap.result["links"]is always present:{"l1_touched", "log_entry", "sessions_entry", "auto_pointers", "warnings"}.
End screen
After wrap_session() returns (and harvest_suggestions() has run), call skills.wrap.lib.render_wrap_screen(wrap_result, session) and print its output VERBATIM as the close-out — do not re-summarize or re-format it. The screen is pure presentation (spec §3.8's unified wrap surface): "What I learned" (the L1 summary's status), "Saved this session (revertible)" (this session's auto-applied entries — auto-tier or model-resolved — each with a spoken one-step revert hint, e.g. say "undo <write_id>" to revert — plus, when wrap_session()'s decayed list is non-empty, an "N stale page(s) archived — revertible" line for Task 17's 90-day decay sweep: up to DECAY_MAX_PER_WRAP stale, unrecalled, non-salient data-plane pages moved to archive/ this wrap, never deleted), "Held — contradictions to resolve" (still-pending entries with a detected contradicts conflict, omitted entirely when there are none), "Possible connections (unverified)" (Task 12: judged semantic findings — {page, with, verdict, confidence, reason} — over this session's applied writes; purely informational, omitted entirely when empty, no apply/consolidation action attached — that's 0.5.3's job), "Live pins" (issue #25: every applied producer="pin" page still on disk and unarchived, ANY session, each with a one-line preview — omitted entirely when there are none; the follow-up ask is below), and "Suggestions" (pending entries targeting an instruction-plane global/ page, or any other pending residue, rendering - (none) when empty), plus a one-line links: summary of the #54 link duties (touched-pages count, log/sessions ✓/✗, pointer count) with a ⚠ line per warning, and a refused note when the classifier gate or the secrets scan turned something away — even though risk tiers fragment the underlying writes across auto-applied and pending state, the friend sees one legible screen with no slash-command hints anywhere.
Then, ask about Live pins in chat (issue #25). If the rendered screen's "Live pins" section is present, review each listed pin against what happened this session (and what its own text says). For any pin that looks acted-on — its task done, its plan executed, its "next session" already here and past — ask the friend conversationally: "this pin looks acted-on — delete it, or keep?" On "delete", call skills.pin.lib.correct(<page>, None, session, approved_by=<friend's handle>) — the normal correction path (producer="pin", writer="human"), proposed through the queue like any other write, with approved_by carrying the approval the friend just gave in chat: for a pin under an instruction-plane prefix (global/, decisions/, patterns/, research/) the plain DELETE would hold pending at the data-plane door and the confirmed delete would be silently swallowed; approved_by completes it via queue.approve_and_apply. Spine pages — log.md, identity.md, index.md, and any map.md — are refused by skills.pin.lib.correct itself regardless of approved_by (issue #58), so never offer delete for them. Then report status honestly from the returned entry: applied → confirm the delete (with the undo <write_id> revert hint); still pending (a contradicts conflict — deliberately not auto-completed) → NEVER say deleted; report Queued as <qid> — held and the resolution path, mirroring skills/pin/SKILL.md's held-case copy. Never delete without asking; no answer means keep. A pin that still looks live is simply left alone — this gate exists to close the loop on finished task-pins, not to nag about every pin.
Then, ask about Suggestions in chat. If the rendered screen's Suggestions section is non-empty, ask the friend about each one conversationally — e.g. "Suggest promoting X because <reason + evidence> — yes/no?" Never auto-answer a suggestion. On "yes", call queue.approve_and_apply(qid, who=<friend's handle>); on "no", call queue.reject(qid, why=<their words>). Skipping is fine — a skipped suggestion just persists to the next session's screen.
On request, list ALL pending suggestions. If the friend asks to see the full pending list (e.g. after wake-up's "ask me to list them"), call skills.wrap.lib.render_pending_list() and print its output VERBATIM — every pending entry across all sessions, not just this one.
Design notes
- Adapted from donor
skills/wrap/lib/classifier.py's KEY 0.1 finding: an LLM prompt/parse path was built but never wired in, while a deterministic heuristic quietly did all the real work. 0.2 swaps the roles on purpose — seelib/classifier.py's module docstring. - Every write here goes through
lib.memory.queue— no direct wiki writes, no donor-styleCONTEXT.mdrewrite machinery.
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.

