Weekly harvest of the archive into routed outputs. Distill is a router, not a destination: every item lands in the system of record that already owns it, and the digest is an index pointing at those destinations. It never creates or edits KNOWLEDGE notes (mutations belong to develop/contradictions/ingest), and it never re-surfaces an item a previous run already routed.
Done looks like: a dated digest at ~/.claude/LIFEOS/MEMORY/DIGESTS/YYYY-MM-DD-distill.md with ≤10 items across three lanes, every item citing its source notes and linking its routed destination; ≤5 content-idea issues filed; ≤5 upgrades filed; all surfaced items marked in state. Overflow is named with a dropped-count, never silently truncated.
Step 1 — Gather (deterministic)
bun ~/.claude/LIFEOS/TOOLS/KnowledgeDistill.ts gather --days 7
Returns JSON: in-window notes (created/updated, minus previously surfaced), hot tag clusters (window count vs archive baseline), seedling and contradiction stats.
Step 2 — Synthesize (the model leg)
Cluster the candidates into digest items. Quality bar per item: ≥2 source notes, a why-now line (recency, cluster growth, or TELOS relevance), and a one-sentence pitch in plain language. Three lanes:
- Content candidates — ideas that could become a post, newsletter section, or video. Bias toward the principal's TELOS content goals.
- System improvements — anything that smells like a LifeOS upgrade.
- Archive health — contradiction pairs and seedling counts, report-only; deeper action routes to
/knowledge contradictions or /knowledge develop.
Step 3 — Route to systems of record
Content lane (≤5). The destination repo and label come from LIFEOS/USER/CUSTOMIZATIONS/SKILLS/Cortex/DistillConfig.json (contentRepo, contentLabel) — never hardcoded here:
gh issue create --repo <contentRepo> --label <contentLabel> \
--title "<pitch>" --body "<why-now + source note paths + suggested format>"
No config file → skip the issue lane and list content candidates in the digest only.
System lane (≤5; dedupe is claim-hash based, duplicates exit 0 silently):
bun ~/.claude/LIFEOS/TOOLS/Upgrades.ts add --claim "<one sentence>" --source autonomous \
--recommendation "<proposed encoding>" --target <hook|doctrine|rule|skill|settings|context> \
--evidence "<source note path>"
Step 4 — Digest + mark
Write the digest file (lanes as sections; every item: pitch, sources, destination link or "empty — "), then:
bun ~/.claude/LIFEOS/TOOLS/KnowledgeDistill.ts mark --digest <digest-path>
which records surfaced slugs and item hashes in MEMORY/STATE/distill.json.
Headless / scheduled
bun ~/.claude/LIFEOS/TOOLS/KnowledgeDistill.ts run --headless [--dry-run] performs all four steps unattended (synthesis via Inference.ts, never a nested claude session). The weekly launchd job com.lifeos.distill (Sun 09:00) runs exactly this. --dry-run prints the full routing plan and writes nothing.
Present in NATIVE mode.