skills/flow-hygiene/SKILL.md
Audit instruction corpus health — CLAUDE.md, rules, and memory for staleness, misplacement, duplication, and contradictions.
npx skillsauth add benkruger/flow flow-hygieneInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Audit the health of the project's instruction corpus. Reads CLAUDE.md,
.claude/rules/*.md, and auto-memory files, then checks for six types
of drift: stale references, orphaned content, unenforced claims,
misplaced content, duplicated constraints, and contradictions. Read-only
— reports findings but does not fix anything.
Complements /flow:flow-doc-sync, which compares code behavior against
documentation. This skill compares instruction surfaces against each
other and against the codebase structure they reference.
/flow:flow-hygiene
At the very start, output the following banner in your response (not via Bash) inside a fenced code block:
```text
──────────────────────────────────────────────────
FLOW v2.6.1 — flow:flow-hygiene — STARTING
──────────────────────────────────────────────────
```
Eight finding types, each with a severity tag:
| Tag | Severity | Meaning |
|-----|----------|---------|
| [STALE] | High | A file path, function name, test name, or command referenced in an instruction surface no longer exists in the codebase |
| [ORPHANED] | Medium | A rule file or CLAUDE.md section describes a feature, hook, or pattern that no longer exists — the content itself is orphaned, not just a single reference |
| [UNENFORCED] | Medium | An instruction claims enforcement ("CI enforces via X", "hook blocks Y") but the named enforcer does not exist or does not check the claimed condition |
| [MISPLACED] | Low | Content is stored in the wrong persistence layer per the routing decision tree — e.g., an imperative constraint in CLAUDE.md instead of a rule, or a project fact in memory instead of CLAUDE.md |
| [DUPLICATE] | Low | The same constraint or fact appears in multiple surfaces with identical or near-identical wording — creates update burden when the constraint changes |
| [CONTRADICTION] | High | Two surfaces prescribe opposite behavior for the same situation — one says "always do X", another says "never do X" |
| [CLAUDE_MD_MANDATE] | High | A project-local rule file mandates that descriptive content be documented in CLAUDE.md — the mandate is itself the misclassification per .claude/rules/persistence-routing.md "Cross-Surface Application". Fix routes the mandated prose to a feature-specific .claude/rules/<feature>.md file plus a one-line CLAUDE.md index entry. |
| [SIZE_BUDGET] | Medium | CLAUDE.md exceeds the configurable size budget (claude_md_budget in .flow.json, defaults 12000 chars / 400 lines). Descriptive prose should land in feature-specific rule files, not in CLAUDE.md itself, so the budget overrun signals that recent additions failed the obey-vs-describe gate. |
Instruction surfaces are scattered across multiple files and formats. Before any analysis can happen, the skill needs a complete inventory of what exists and what each surface claims.
Identify and read all instruction surfaces in the project.
Use the Glob tool to find:
CLAUDE.md in the current working directory.claude/rules/*.md in the current working directoryRead each discovered file using the Read tool. For each file, note:
For auto-memory: read the memory index (MEMORY.md) from conversation
context if it is loaded. If individual memory files are referenced in the
index, read them using the Read tool. Memory files live at
~/.claude/projects/*/memory/ and are user-scoped — they may not exist
for every project.
CLAUDE.md size budget check. A CLAUDE.md that grows unchecked
signals that descriptive content is being added where only behavioral
content belongs, per .claude/rules/persistence-routing.md "Cross-
Surface Application". Read .flow.json from the project root using
the Read tool. If the file exists and contains a claude_md_budget
object, parse its chars and lines fields. If the file is missing
or the field is absent, use the defaults: 12000 chars and 400 lines.
Fail safe to the defaults whenever the input is unreliable: if
.flow.json is present but is not valid JSON, or claude_md_budget
is present but is not an object, or chars/lines is present but
is not a positive integer, use the defaults rather than prompting
or erroring.
Measure CLAUDE.md by reading the file with the Read tool — character
count is the byte length of the content, line count is the count of
newlines plus one for the final line. Emit a [SIZE_BUDGET] finding
when either count exceeds its budget. The finding's body cites the
measured value, the budget, the override path (.flow.json field
claude_md_budget), and the recommended fix (route descriptive prose
to feature-specific .claude/rules/<feature>.md files plus one-line
CLAUDE.md index entries).
Instruction surfaces routinely drift from the codebase they describe as files are renamed, functions deleted, and commands refactored. A mechanical reference check is the only way to detect this without reading every file manually.
Verify that references in instruction surfaces point to things that exist. This is a mechanical pass — each check is a Grep or Glob call.
File path references. For each file path mentioned in backticks in
any surface, use the Glob tool to verify the file exists in the current
working directory. Tag missing files as [STALE].
Function and test name references. For each function name or test
name mentioned in backticks, use the Grep tool to verify it exists as a
definition in the codebase. Tag missing definitions as [STALE].
Command references. For each bin/flow subcommand mentioned (e.g.,
bin/flow check-phase, bin/flow tombstone-audit), use the Grep tool
to verify the subcommand is registered in the dispatcher or source. Tag
missing commands as [STALE].
Enforcement claims. For each claim that names a specific enforcer:
test_name" — Grep for the test function definitionhooks/hooks.jsontests/file.rs enforces" — verify the test file existsIf the named enforcer does not exist, tag as [UNENFORCED]. If the
enforcer exists but does not check the claimed condition (requires
reading the test or hook body), tag as [UNENFORCED] with a note
explaining the gap.
Orphan detection. After all reference checks, identify rule files
or CLAUDE.md sections where the majority of references are stale. If a
rule file's primary subject (the feature, hook, or pattern it describes)
no longer exists, tag the entire file as [ORPHANED].
Content placed in the wrong persistence layer creates maintenance burden — a constraint in CLAUDE.md instead of a rule file must be updated in two places when it changes, and a memory entry that duplicates a rule silently diverges over time.
Apply the persistence routing decision tree to each content block.
The decision tree (from .claude/rules/persistence-routing.md):
CLAUDE.md audit. Read each section of CLAUDE.md. For each content
block, apply the imperative test: "Can you phrase this as an imperative
('do X', 'never Y', 'when X do Y')?" If yes, it belongs in a rule
file, not CLAUDE.md. Tag as [MISPLACED] with a recommendation to
move it to .claude/rules/<topic>.md.
Exclude sections that are genuinely project knowledge even if they contain imperative-sounding language (e.g., "Phase gates prevent skipping ahead" is a description, not an instruction).
Memory audit. For each memory file, check whether its content
duplicates an existing rule or CLAUDE.md section. If the same
constraint appears in both memory and a rule file, the memory entry is
redundant. Tag as [MISPLACED] with a recommendation to remove the
memory entry (rules are the authoritative source).
Also check whether memory files contain architecture facts, code
patterns, or file paths — these should be derivable from the code
and do not belong in memory. Tag as [MISPLACED].
CLAUDE.md mandate scan. Project-local rules that mandate
CLAUDE.md prose for descriptive content invert the persistence
routing — the mandate is itself the misclassification per
.claude/rules/persistence-routing.md "Cross-Surface Application".
Use the Grep tool against .claude/rules/*.md (and any project-
local rule subdirectories) for the four canonical paraphrased
substrings the upstream rule catalogs. These four entries are
pattern shapes, not literal grep strings — match them by
judgment against the prose a rule file actually uses. In the
first entry, X and Y are placeholders standing in for a
project-specific noun (the descriptive surface) and a project-
specific documentation requirement; a real rule file will use
concrete nouns in those slots. Read each candidate rule file and
decide whether its prose expresses one of these shapes:
treats X added without Y documented in CLAUDE.md — the
enforcement-claim shape where a project-local rule asserts CI
fails when a descriptive surface is added without a CLAUDE.md
paragraphmust be documented in CLAUDE.md — the direct-mandate shapedocumentation home is CLAUDE.md — the routing-destination shape
for descriptive contentCLAUDE.md as the canonical destination — the
authoritative-source shapeFor each match, emit a [CLAUDE_MD_MANDATE] finding citing the
rule file path, the matched line, and the recommended fix:
"Rewrite this rule to route descriptive content to a feature-
specific .claude/rules/<feature>.md plus a one-line CLAUDE.md
index entry per .claude/rules/persistence-routing.md Cross-
Surface Application."
Exclude matches inside quoted-example fences (Markdown code blocks) or in paragraphs whose surrounding prose explicitly names the pattern as an anti-pattern — those occurrences are documentation of the pattern, not enforcement of it.
When the same constraint lives in multiple surfaces, a change to one copy leaves the others stale. When two surfaces prescribe opposite behavior, the model follows whichever it reads last — producing unpredictable results.
Compare all surfaces pairwise for duplicates and contradictions.
Duplicate detection. For each behavioral constraint found in
Step 1, search all other surfaces for the same constraint expressed
in similar words. Exact duplicates and near-duplicates (same meaning,
different wording) both count. Tag as [DUPLICATE] with the two
source locations.
Focus on constraints that would need to be updated in multiple places if the rule changed — identical constraints in CLAUDE.md and a rule file, or the same rule stated in two different rule files.
Contradiction detection. For each pair of constraints, check whether they prescribe opposite behavior. Common patterns:
Tag as [CONTRADICTION] with both source locations and the specific
conflict.
The audit is only useful if its findings are actionable. Grouping by source file lets the user address all issues in one file at a time, and severity tags help prioritize what to fix first.
Produce the findings report inline in the response.
Summary line. Start with a one-line summary:
Hygiene: N findings (X stale, Y orphaned, Z unenforced, W misplaced, V duplicate, U contradiction, M claude-md-mandate, B size-budget)
If no findings, output:
Hygiene: Clean — no instruction corpus drift detected.
Findings by source file. Group findings by the source file where the problematic content lives. For each file with findings, show the file path as a heading, then each finding:
## <source_file_path>
**[STALE]** <description>
- References: <what it references>
- Status: <not found / renamed to X / removed>
**[UNENFORCED]** <description>
- Claims: <what it claims is enforced>
- Enforcer: <named test/hook>
- Status: <enforcer not found / enforcer does not check this>
**[MISPLACED]** <description>
- Content: <summary of the content>
- Current location: <where it is>
- Recommended location: <where it should be>
**[DUPLICATE]** <description>
- Location 1: <file:line>
- Location 2: <file:line>
**[CONTRADICTION]** <description>
- Surface 1: <file> says <X>
- Surface 2: <file> says <Y>
Orphaned files. List [ORPHANED] findings separately at the end
under an "## Orphaned" heading.
After the report, output the following banner in your response (not via Bash) inside a fenced code block:
```text
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ FLOW v2.6.1 — flow:flow-hygiene — COMPLETE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```
data-ai
Clear the autonomous-flow halt set when the user spoke mid-flow. Invokes `bin/flow clear-halt` so the next assistant turn resumes execution. User-only: the model cannot invoke this skill.
data-ai
Open a problem-statement conversation. Stays in discussion mode with PM as default voice; on user signal, files a vanilla What/Why/Acceptance Criteria issue against the current repo. Usage: /flow:flow-explore <topic>
tools
Display the FLOW skill catalog grouped by user role. Maintainer and Private buckets render only when invoked inside the FLOW plugin repo.
documentation
Phase 3: Review — six tenants assessed by four cognitively isolated agents (reviewer, pre-mortem, adversarial, documentation) launched in parallel. Parent session gathers context, triages findings, and fixes.