flow-hygiene

Audit instruction corpus health — CLAUDE.md, rules, and memory for staleness, misplacement, duplication, and contradictions.

12 stars

Best use case

flow-hygiene is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Audit instruction corpus health — CLAUDE.md, rules, and memory for staleness, misplacement, duplication, and contradictions.

Teams using flow-hygiene should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/flow-hygiene/SKILL.md --create-dirs "https://raw.githubusercontent.com/benkruger/flow/main/skills/flow-hygiene/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/flow-hygiene/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How flow-hygiene Compares

Feature / Agentflow-hygieneStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Audit instruction corpus health — CLAUDE.md, rules, and memory for staleness, misplacement, duplication, and contradictions.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# FLOW Hygiene

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.

## Usage

```text
/flow:flow-hygiene
```

## Announce

At the very start, output the following banner in your response (not via Bash) inside a fenced code block:

````markdown
```text
──────────────────────────────────────────────────
  FLOW v2.6.0 — flow:flow-hygiene — STARTING
──────────────────────────────────────────────────
```
````

## Finding Taxonomy

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

## Steps

### Step 1 — Discover surfaces

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 directory

Read each discovered file using the Read tool. For each file, note:

- File path
- All file paths, function names, test names, and commands mentioned in backticks
- All enforcement claims ("CI enforces", "hook blocks", "test validates")
- All behavioral constraints (imperatives: "never", "always", "must", "do not")
- All architectural facts (descriptions of how things work)

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).

### Step 2 — Structural verification

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:

- "CI enforces via `test_name`" — Grep for the test function definition
- "hook blocks" or "hook validates" — Grep for the hook name in `hooks/hooks.json`
- "`tests/file.rs` enforces" — verify the test file exists

If 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]`.

### Step 3 — Classification audit

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`):

1. Is it specific to this user? → Memory
2. Is it a behavioral constraint? (imperative guardrail) → Rule
3. Is it project knowledge? → CLAUDE.md
4. Can you derive it by reading code? → Do not store anywhere

**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
  paragraph
- `must be documented in CLAUDE.md` — the direct-mandate shape
- `documentation home is CLAUDE.md` — the routing-destination shape
  for descriptive content
- `CLAUDE.md as the canonical destination` — the
  authoritative-source shape

For 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.

### Step 4 — Cross-reference audit

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:

- "Always do X" in one surface vs "Never do X" in another
- "Use A for this" vs "Use B for this" where A and B are mutually exclusive
- Conflicting scope — one surface says a rule applies to all phases, another limits it to specific phases

Tag as `[CONTRADICTION]` with both source locations and the specific
conflict.

### Step 5 — Report

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:

```text
## <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:

````markdown
```text
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  ✓ FLOW v2.6.0 — flow:flow-hygiene — COMPLETE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```
````

## Hard Rules

- Read-only — never fix, edit, or commit anything
- No state file mutations — this is a stateless utility skill
- No AskUserQuestion — produce the report and finish
- No sub-agents — all comparison is inline
- Never use Bash to print banners — output them as text in your response
- Never use Bash for file reads — use Glob, Read, and Grep tools
- Focus on structural accuracy and classification correctness, not style

Related Skills

flow-triage-issue

12
from benkruger/flow

Triage a single open GitHub issue from a PM lens. Applies a 'Triage In-Progress' label during triage; reads code, checks for already-shipped work, returns a verdict in {close, decompose} with confidence and a flip-condition. Renders and stops — no other side effects.

flow-start

12
from benkruger/flow

Phase 1: Start — begin a new feature. Creates a worktree, upgrades dependencies, opens a PR, creates .flow-states/<branch>/state.json, and configures the workspace. Usage: /flow:flow-start <feature name words>

flow-skills

12
from benkruger/flow

Display the FLOW skill catalog grouped by user role. Maintainer and Private buckets render only when invoked inside the FLOW plugin repo.

flow-review

12
from benkruger/flow

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.

flow-reset

12
from benkruger/flow

Wipe `.flow-states/` on this machine in one pass. PRs, worktrees, and branches are NOT touched — those require per-flow `/flow:flow-abort`.

flow-prime

12
from benkruger/flow

One-time project setup — configure and commit workspace permissions, install bin/* stubs, and write the version marker. Run once after installing or upgrading FLOW. Usage: /flow:flow-prime

flow-plan

12
from benkruger/flow

Decompose a problem statement into a pre-planned decomposed issue. Accepts either an issue reference (#N, re-plans in place) or a bare prompt (synthesizes What/Why/AC and files a new issue). Runs a Tech-Lead-default planning conversation, dispatches to PM/Tech Lead/CTO sub-agents on explicit user request, then files or edits the issue ready for /flow:flow-start. Usage: /flow:flow-plan #N or /flow:flow-plan <topic>

flow-orchestrate

12
from benkruger/flow

Process decomposed issues sequentially overnight via flow-start, tracking outcomes and generating a morning report.

flow-note

12
from benkruger/flow

Capture a correction or learning to the FLOW state file. Invoke explicitly with /flow:flow-note. Fast — captures and continues without interrupting flow.

flow-learn

12
from benkruger/flow

Phase 4: Learn — audit rule compliance and identify process gaps. Routes findings to CLAUDE.md, .claude/rules/, and plugin issues.

flow-issues

12
from benkruger/flow

Group open issues by label into four sections (Blocked, Other, Vanilla, Decomposed) with mechanical sort and a copy-pasteable command per row.

flow-explore

12
from benkruger/flow

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>