Playbook: Memory Lint
Keeps the principal's memory/ accurate as it grows. Runs on /lint, when the principal asks you to "clean up / check my memory", or as an opt-in periodic routine (brain/integrations/routines.md). This audits memory only — never brain/ (that's what the test suite is for).
Read-only by default: you diagnose and propose; you don't rewrite memory until the principal says so. This mirrors brain/role/principles.md — edit memory surgically, and mention stale or duplicate memory rather than silently deleting it.
Scope
Lint all of memory/ by default. If $ARGUMENTS (or the request) names a subpath (memory/people/, a single file, a project), scope to that. Always start from memory/index.md, then read the pages it lists.
What to check
- Stale claims — dates/deadlines now in the past, or a status a newer entry has superseded (e.g. a project still "on track" while a later
log/note says "at risk"; a commitment past itsduestillopen). Reason against today (seebrain/schemas/memory-file.mdon absolute dates). Also flag an action-gating condition past its date or with its condition already met (seebrain/schemas/capture-rules.md→ "Facts that gate action") — propose resolving the line (confirm the gate lifted, or extend it), not just flagging it as stale. Also flag a standing-rule directive whoseexpires:date is now past (seebrain/schemas/memory-file.md→ "Preference directives") — propose flipping it tosuperseded(principal's OK) or renewing the date. - Contradictions — two files (or two rows) that assert conflicting facts. Follow
brain/schemas/capture-rules.md→ "Contradictions": name both claims, both dates/sources, and which is newer. Never silently pick one. - Reachability (high severity) — from
memory/index.md, follow links transitively (through sub-indexes —overrides/index.md,team/index.md, a member's ownmemory/index.md, its charter, itsledger.md, etc.) and report everymemory/**/*.mdfile not reached this way. The exemptions arememory/_quarantined/files (plus uncited archived originals undermemory/_processed/) — these are deliberately out-of-graph, so do not report them as unreachable or offer to link them in. Legacy exception: a member subtree may still containAGENTS.md/CLAUDE.mdfrom a release before 0.22.0. Those are dead boot files, not memory — propose deleting them; never offer to link them into the index (brain/schemas/team-member.md→ "Why a member has no boot files of its own"). This subsumes check #4 (orphan files) below — an unindexed file is just one way to be unreachable; a file that's listed somewhere but reachable through no unbroken link chain (a dead sub-index link, an orphaned member directory) is equally a finding here./lintis the standing enforcement of the memory-reachability invariant (brain/schemas/memory-file.md→ "Reachability invariant"). For each unreachable file outside the exemptions, offer to link it in — the root index, a sub-index, or a parent page. - Orphan files — a file not listed in
memory/index.md, or an indexed file with no inbound links from any other memory file. Also flag the reverse: an index entry pointing at a file that doesn't exist. (The narrower, most common case of #3.) - Broken links — a markdown link to a relative path with no file at the other end (a dangling
[text](../path.md)). - Uncited durable facts — a material fact with no provenance where one would help (see
brain/schemas/memory-file.md→ "Provenance"). Don't demand a source for everything — flag only where not knowing the origin would undermine trust (a surprising claim, a number, a sensitivity). - Duplicates — two files covering the same subject that should be merged (dedup, per capture rules).
- Missing cross-references — two clearly related pages (a person who owns a project; a decision that drives a commitment) with no link between them. (Deep connection-finding is
explore.md; here, only the obvious missing link.) - Log window / index rollup — the root
memory/index.mdlists log entries outside the recency window (older than 30 days, beyond the 5-most-recent floor) whilememory/log/index.mdis missing or doesn't carry them. The root index is a router, and an unbounded dated list crowds out the hooks that do the routing. Propose rolling the out-of-window lines intomemory/log/index.md(every entry, newest first), leaving the root with the window plus one link to it. Flag the reverse too: alog/index.mdthat exists but is missing entries, or isn't linked from the root index (that second case is also a reachability finding, #3).log/only — never propose a sub-index forpeople/,projects/,context/, orpreferences/, whose per-file hooks are the routing signal and belong in the root index however long the list gets (seebrain/schemas/memory-file.md→ "Log rollup").
Team integrity (10–19) — only when a roster is linked (memory/index.md → memory/team/index.md, brain/schemas/team-member.md). Normal Chief of Staff operation is link-only — the filesystem checks below (especially #19) are exactly the sanctioned exception, alongside the versioned migration (brain/playbooks/team.md → "Migrate a pre-roster team"); never promote a filesystem finding into the active graph without the principal's OK.
- Roster unlinked or missing —
memory/index.mdclaims a team (linksmemory/team/index.md) but the roster file doesn't exist, or the roster exists with no link frommemory/index.md(seebrain/schemas/team-member.md→ "The roster"). - Dead roster link — an
## Active(or## Inactive) entry inmemory/team/index.mdwhose charter link doesn't resolve. - Unlinked active charter — a charter with
status: activethat the roster's## Activedoesn't link — found only via the sanctioned filesystem check in #19, never assumed reachable otherwise. - Status/roster mismatch — a charter's
status:disagrees with the roster section it's linked under (e.g. linked under## Activebutstatus: inactive). - Missing member-memory link — a charter with no
[Member memory](memory/index.md)link, leaving its own notes unreachable. - Unreachable member notes — a note under a member's
memory/notes/that its ownindex.mddoesn't link. - Real identity in a member file — a confidential project's real name (rather than its code name) appears in a charter, a member's memory, or a deliverable. Members work in code names; flag as a leak (
brain/schemas/team-member.md→ "Access control"). - Registry reachable from any shared page —
memory/confidential/registry.mdlinked from any page undermemory/other than the single root-index link — a project, person, preference, or context page, a roster, a charter, any member page. Since every member reads the whole shared brain, each such link opens a page → registry hop straight to the real identities; the registry must be reachable by no member path (brain/schemas/confidentiality.md→ "Reachability"). Flag as severity-one. (This is the broad net; #18 is the narrower team-subgraph case within it — a registry link from the roster/charter/member subgraph trips both, so report it once as the team leak.) - Registry linked from the team subgraph —
memory/confidential/registry.mdlinked from any roster, charter, or member page (the team subgraph specifically). This must never happen — flag as severity-one. - Orphan member directory — a
memory/team/<slug>/on disk but linked from neither## Activenor## Inactivein the roster. Report this only inside an explicitly requested filesystem audit (or the versioned migration) — never surface it as a routable member, and never auto-link it without the principal's OK.
Always on (20–21).
- Contradictory active directives — two
active-status preference bullets (in one file, or acrossmemory/preferences/) that assert conflicting instructions. Flag both and propose resolving perbrain/schemas/capture-rules.md→ "Preference changes — supersede in place" (rewrite the current one, flip the other tosuperseded, keep both — never delete). Also note the reverse defects: asupersededentry that's been deleted instead of retained (breaks the trail — propose restoring it if recoverable), and an un-annotated legacy bullet (noobserved:/status:comment), which is low-severity — propose annotating it asactive(legacy bullets read as implicitly active) the next time the file is touched, not an urgent fix. - Oversized always-load file / multi-line index hook — a file under
## Always load(orprofile/, or a tracker) that's grown well past the ~100-line soft target, or amemory/index.mdentry that's spilled past one line. Propose the specific demotion — which section moves to which linked on-demand file (perbrain/schemas/memory-file.md→ "Size discipline (always-load files)") — never auto-trim or silently shorten the file. - Stale capability inventory —
memory/integrations.mddisagrees with what's actually available: a connector listed as live that discovery no longer finds, one that's live but unlisted, or a browser/terminal line that no longer holds. Low severity — the inventory is a cached snapshot, so propose reconciling the row and note when it was last verified; never conclude an integration is gone from this file alone (brain/integrations/connectors.md— absence is inconclusive). - Roster pointer names a specialization — the
memory/team/index.mdhook under## Always loadinmemory/index.mdmentions any member'sspecialization(or the domain of one) instead of the fixed generic line.memory/index.mdis always-loaded, so it carries that detail into every session and goes stale as soon as the roster changes. Low severity — propose restoring the verbatim pointer (brain/playbooks/team.md→ "Onboard a member", build step 4); the roster's own entries are where a member's domain belongs.
Distill (log → durable memory)
A /lint pass also looks for durable facts still sitting in memory/log/ that were never routed into people/projects/preferences/context/trackers — the "dreaming" sweep that keeps the log from becoming a second, un-indexed memory.
- Find the starting point. Read
memory/ledger.mdfor the lastlintline; distill everything inmemory/log/since that date. If there's no priorlintline, cover the whole log, or the last ~90 days if the log is long. - Re-scan those entries for durable facts that never made it into a proper memory file — a decision only mentioned in passing, a person or project detail buried in a dated note, a preference stated once and never filed.
- Propose promotions, don't apply them. For each candidate, name the fact, its origin class (principal-stated, derived, or generated —
brain/schemas/capture-rules.md→ "Origin classes"), where it currently lives (thelog/entry), and where it should be promoted to — with provenance back to the log entry, perbrain/schemas/memory-file.md→ "Provenance". Call out a derived or generated promotion explicitly, so the principal's OK is an informed one. This check is read-only, same as the rest of lint; promotions apply only on the principal's OK, via the existing## After.
Produce
Deliver the report in this turn — a grouped findings list, bottom line first (brain/role/voice.md):
- Open with a one-line health read ("12 files; 3 issues — 1 contradiction, 2 stale").
- Group by check; for each finding give the file(s) (and row/line), what's wrong, and a proposed fix (one line).
- Order by severity: contradictions and stale-and-acted-on facts first; cosmetic (missing link, uncited) last.
- Report Distill candidates as their own group — each a fact, its
log/source, and the proposed promotion target — since a promotion is a different shape of finding than a fix. - If memory is clean, say so plainly — don't invent findings.
After
- Offer to apply the fixes — as a batch or one by one. Apply only on the principal's OK, edit surgically, update
memory/index.mdfor any file/link you change, and confirm what you changed (brain/role/principles.md→ "Be transparent about memory"). - For a confirmed contradiction, resolve per capture rules (default to the newer fact, keep the principal informed); for a genuine duplicate, merge then dedup the index.
- Distill promotions apply the same way, on OK — write the fact into its proposed target file with provenance back to the
log/entry and today'supdated:, then updatememory/index.md(brain/schemas/capture-rules.md→ Procedure). - If lint keeps surfacing the same class of issue, offer to schedule it as a periodic (e.g. monthly) routine via
/routines. - Ledger. Append one
lintline tomemory/ledger.md— the run and its headline findings (brain/schemas/capture-rules.md→ "Action ledger").