agentleFS
muratsilahtaroglumuratsilahtaroglu/claude-code-starter-kit/.claude/skills/keel-distill/SKILL.md

keel-distill

Skill9 starsChanged 51 days agoMITView on GitHub

Consolidate project memory — rotate old HANDOVER blocks to the archive, promote critical facts to LESSONS.md, dedup/merge, and lint for contradictions. Run when caps are exceeded.

The file

We split this skill into the rules it gives an agent

5 rules. About 0 are common, 2 are distinctive, and 3 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.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Run when HANDOVER.md exceeds 3 session blocks / ~150 lines, when LESSONS.md exceeds ~250 or TASKS.md ~100 lines, or when any of them is …

    line 8
  2. Distinctive:

    Verify done items were deleted (their one-liner lives in HANDOVER (a)).

    line 77
  3. Very specific:

    A move is git mv + citation rewrite, one pass: Before moving, grep the repo for BOTH the full path and the bare filename.

    line 93
  4. Distinctive:

    Strip noise: delete VCS/ritual bookkeeping ("pushed N commits", sha ranges, "ran /keel-distill") and conversational meta ("user asked if I …

    line 104
  5. Very specific:

    LESSONS ## Index router mirror: every Index line's target file exists, and every graduated-lesson rule/skill/doc has its ONE Index line — …

    line 127

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

/keel-distill — the memory consolidation ritual ("sleep" for the project)

Run when HANDOVER.md exceeds 3 session blocks / ~150 lines, when LESSONS.md exceeds ~250 or TASKS.md ~100 lines, or when any of them is over its KB cap (one long line can overflow a file that is green on lines — the SessionStart hook warns on all of these), or every ~5 sessions as hygiene — that cadence is yours to keep, the hook only detects cap overflows. Memory that is written but never reviewed degrades the project — consolidation is what keeps it useful (rules.md §9).

Propose the full plan, get user approval, then apply. Never lossy-delete. (File-TREE clutter — stray scripts, logs, dead code — is not this ritual's job: that is /keel-tidy, §3.10.)

1. Rotate HANDOVER blocks (oldest first, until ≤2 blocks AND under the line cap AND the KB cap)

For each block being rotated, triage by criticality — content-aware, not age-blind:

  • (b) Tried, didn't work → PERMANENT: distill each to one LESSONS.md [fail] line (<date> — <approach> → FAILED: <reason>. (full trace: docs/handover-archive.md, block <date>)).
  • Open questions live in HANDOVER's global section, not in blocks — leave them until resolved.
  • (a) Completed → nothing to move: git history + the archive keep it.
  • (c) Latest updates → superseded by newer blocks — nothing to promote; the verbatim archive keeps it.
  • (d) Next steps of an old block → dead (that work is done or re-planned) — no promotion.
  • Then move the WHOLE block verbatim to the TOP of docs/handover-archive.md (prepend, newest first — restorable compression: the distilled lines keep pointers back to it).

2. Consolidate LESSONS.md (write-policy: add / update / retire / promote-and-delete — never LOSSY delete)

  • Scope-triage every entry first (A/B/C/D — the LESSONS header defines the tiers): always-relevant stays; file-scoped graduates (below); a permanent domain fact → docs; superseded/closed/already- promoted → DELETE. Field measurement behind the triage: in a mature file ~52% of entries were file-scoped and any one task needed ~15% of the file — the always-on core is the minority (reports/2026-08-17-lessons-scope-audit.md).
  • Merge duplicates and near-duplicates into the stronger phrasing (keep the earliest date).
  • Start where the SessionStart hook pointed: above 70% of the cap it names the OLDEST unpromoted entries and the inflow since the last distill. Those are the triage queue — ask of each: still true → promote (below) · proven wrong → retire · resolved → delete. A file with an inflow valve and no worked exit sits at its cap forever (measured: three distills in four days, count still rising 123 → 129, not one entry ever retired).
  • Retire what proved WRONG — move the entry VERBATIM to the top of docs/lessons-retired.md with a RETIRED <date>: <what refuted it · what is true instead · evidence path> line, and leave ONE corrective line here ("believed X — measured Y → retired"). Never a SUPERSEDED stub: the original text keeps paying rent in an always-loaded file for knowledge known to be false, while the one-line correction is what stops a session re-learning it.
  • Promote what has graduated: a lesson applied 3+ times is no longer a lesson — move it into rules.md (conduct), a .claude/skills/ skill (procedure), an ADR (decision), or — for a permanent DOMAIN fact (a data quirk, an API contract) — the relevant docs (docs/architecture.md "known limitations" / a guide). A lesson CLUSTER that binds only SPECIFIC files (a must-run test after touching X, an append-only dir, a never-hand-edit generated file) becomes a path-scoped rule — .claude/rules/<name>.md with paths: frontmatter: it loads ONLY when a matching file is touched, so it is cheaper than both rules.md and this file — or a paths:-scoped SKILL (.claude/skills/<name>/SKILL.md, same paths: format) when the cluster must SURVIVE a mid-task compaction: invoked skill bodies are the one scoped mechanism re-injected after compaction (≈5k tokens/skill, 25k total, truncation keeps the TOP — put the load-bearing lines first), while a path rule waits for the next file match. Never put must-always-hold discipline in either (that stays in LESSONS tier A / rules.md). The new rule/skill is shown as its FULL text in the distill plan and lands owner-approved, written self-contained — constraint + why + check inline, evidence pointing only to permanent artifacts, never to TASKS/PLAN live state (.claude/rules/README.md "Writing discipline").
  • Promotion DELETES the LESSONS entry — lossless: the content lives in its target and git keeps the history. Never leave a "moved to X" stub (field case: 10 promoted entries left 42 lines of stubs, taxing every session). The ONE surviving pointer is a line in LESSONS ## Index (what → where → when it loads) — add or refresh it in the same pass. This is the main pressure valve on a long project's [gotcha] list: reference facts belong in docs, file-scoped stock behind its trigger — not in the always-loaded core.
  • COOL what is still true but no longer cited — the third exit, for the entry that is neither wrong (retire) nor applied often enough to promote, yet earns no line in a file every session pays for. Proxy criterion, labelled as one: is the entry cited from ## Index or from any report / spec / ADR (grep -rl its key phrase)? Not cited → move it VERBATIM (with its date) to docs/retro/<YYYY-MM>.md and leave ONE router line in ## Index. Cooling is not deletion and not retirement (docs/retro/README.md). Field origin: a file stuck at 1000/1000 for weeks because the entry budget throttled the inflow while nothing opened an outflow; 82 of its 132 entries were single-copy knowledge, so the exit had to be worked per entry, never as a bulk sweep.

3. Prune TASKS.md

  • Verify done items were deleted (their one-liner lives in HANDOVER (a)); delete any stragglers.
  • Drain ## Discovered to convergence (incl. project variants like ## Discovered-team) — it is an INBOX, not storage: each line → ## Next (real task, with done-when) · docs/ known-limitations / R-request doc (domain/provider fact) · LESSONS.md (lesson) · an ADR (design decision) · DELETE (resolved/superseded — git keeps it). One line per entry; longer → a report/ADR + pointer here. A line surviving TWO distills is in the wrong file — after this step the section holds only the current week's untriaged finds. Refill ## Now (max 3–5, per person on teams).

4. Sweep closed team reports to done/ (folder hygiene — orchestrator/owner only)

A long-running author folder drowns its open work: dozens of spec/fix files, no visual way to tell finished from in-flight. The valve: a report whose task reached closed <date> accepted|rejected in the index moves to its author's reports/team/<@tag>/done/ — the flat folder then holds only live work, and "what is @X still carrying?" becomes a directory listing again.

  • Only closed moves. wip · delivered · verified are in flight — on the board, cited from ## Review (the reground hook checks those paths against disk), never swept.
  • A move is git mv + citation rewrite, one pass. Before moving, grep the repo for BOTH the full path and the bare filename; rewrite every hit (index line, LESSONS, ADRs, other reports) to the done/ path in the same commit. A move that breaks one citation is worse than the clutter — this sweep is the ONE sanctioned exception to §10.40's "never moved", and the rewrite is what keeps the exception honest. Evidence subfolders (<task>_<what>/) move with their report.
  • Stays in the index, same section. The [x] closed line keeps its status and history; only its file path gains done/. Throughput counting is untouched — done/ is INSIDE the author's folder.
  • Same write authority as every shared-file transition: the ORCHESTRATOR/owner sweeps; workers never move files out of their own delivered set (§10.42).

5. Lint the memory set (drift check)

  • Strip noise: delete VCS/ritual bookkeeping ("pushed N commits", sha ranges, "ran /keel-distill") and conversational meta ("user asked if I saved", "don't rush") from HANDOVER — it's git-log / ritual-log-derivable, and it's usually what pushed the file over cap (keep decisions + their WHY).
  • Header hygiene (every memory file, not just HANDOVER). A header is DOCTRINE — how the file works, written once, frozen. Move OUT anything that is state: a date or changelog line, a measurement ("file is 202 lines"), a debt or pending decision (nobody triages a header, so it becomes a permanent complaint — send it to ## Discovered, then a ## Next item with a done-when), a cap NUMBER (write "cap: .claude/keel-caps" — a copy drifts from the file that sets it, which is why the stale-cap-header lint below exists), a chat quote. Also collapse teaching prose that merely restates rules.md: it is paid in every session by an @-imported file and the two wordings drift — the detail lives in docs/memory-files.md. What EARNS a header line is a timeless, non-obvious invariant (field example: "this file is @-imported IN FULL — a lane heading is a WRITE boundary, not a context boundary"). Measured on the template itself: the three imported files carried 110 header lines, 55 after this rule. (The SessionStart hook flags dated lines and hard-coded caps in a header.)
  • Contradictions between rules.md / LESSONS.md / CLAUDE.md — flag, ask the user which wins.
  • Decision/constraint drift (docs/adr/ + .claude/rules/): an Accepted ADR contradicted by a newer decision, a measurement, or the code as it now stands → PROPOSE Superseded (by ...) — the OWNER flips the status, never this ritual; a path-scoped rule whose constraint has been overtaken → propose rewrite or retirement the same way. Also verify each rule's/skill's paths: globs still match existing files (a glob matching nothing = the rule silently never loads — a dead rule; brace expansions past the documented 1,000-pattern budget and malformed [ brackets ALSO match nothing, silently), and the ADR README index still mirrors the folder.
  • LESSONS ## Index router mirror: every Index line's target file exists, and every graduated-lesson rule/skill/doc has its ONE Index line — an orphan cluster is invisible to sessions whose trigger hasn't fired; a dead line hides lessons that still exist. (The reground hook flags dead targets at session start; the missing-line direction is checked here.) Same mirror check for reports/team/README.md: every INDEXED report — live status, or cited by a permanent record (the template's scope line) — has exactly ONE index line (an orphan = unfindable evidence; a duplicate diverges — field case: the same report indexed twice with two different status texts), statuses use only the controlled vocabulary (wip · delivered · verified — owner part: <…> · closed <date> accepted|rejected, [x] only at closed), and the mirror counts done/ files too — a closed line whose path lacks done/ is a §4 sweep candidate, a non-closed line pointing INTO done/ is a bug.
  • Stale claims (files/commands/paths that no longer exist) — fix or mark superseded. Resolve bare BASENAMES against the tree before flagging: field measurement found ~54% of citations are basename-only and DO resolve — a naive path check reports them as false staleness.
  • Language drift (rules §9.31): HANDOVER/LESSONS/worker boards are ENGLISH on every project. Convert only the lines this run already rewrites/merges/rotates (gradual, no bulk-translation pass: a mass rewrite risks meaning loss and buries the real diff) — quoted user wording stays as-is.
  • Stale cap HEADERS in the memory files themselves (e.g. a LESSONS.md header still quoting an old "~100"): correct to the current thresholds below — headers are prose, the SessionStart hook is the authority; they drift in adopted projects because /keel-update never touches PROTECTED memory files.
  • Cap check (solo defaults — the project's .claude/keel-caps overrides them, rules §10.40): HANDOVER.md ≤ ~150 lines, LESSONS.md ≤ ~250, TASKS.md ≤ ~100, CLAUDE.md ≤ ~200, rules.md ≤ ~400 — of which the stock template is what wc -l rules.md says on a fresh clone, so the project's own rules get the REMAINDER (rule budget §10.38 — measure it, never copy a number; merge/retire/promote to a hook, don't just append). Every file also has a KB cap (<FILE>_KB).

6. Report → approve → commit

Summarize: N blocks archived, M lessons added/merged/superseded/promoted, lint findings. On approval, apply + propose a commit (rules.md §6.15). Never push without user approval.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.