# content-instruction-drift Detect near-duplicate sections that have drifted apart across instruction files | | | |---|---| | **Severity** | info (auto) | | **Autofix** | - | | **Since** | v0.17.0 | | **Category** | [Content Intelligence](content-intelligence.md) | ## Why Teams often copy a section between instruction files — CLAUDE.md, AGENTS.md, GEMINI.md, QWEN.md, `.github/copilot-instructions.md`, `.cursor/rules/**/*.mdc`, `.clinerules/**/*.md` (not `workflows/`, which load on demand rather than every turn), `.claude/rules/*.md` — so every assistant gets the same guidance. Then someone edits one copy and forgets the others. The copies silently disagree, and different agents follow different rules for the same task. Exactly identical sections are fine: that is intentional sync. Near-identical sections (similar but not equal after normalization) are the bug this rule catches — one copy drifted. This differs from neighboring rules: `content-contradiction` matches known contradictory phrase pairs, `content-inconsistent-terminology` flags mixed term variants, and `content-redundant-with-tooling` flags instructions better enforced by tool config. This rule compares whole sections across files for structural near-duplication. ## Examples **Bad (drifted copies):** ```markdown ## Testing Run the full suite with `make test` before every push. Integration tests require Docker; start it with `make docker-up` first. Never skip failing tests — fix them or file an issue with the failure output. ## Testing Run the full suite with `make test` before every push. Integration tests require Docker; start it with `make docker-up` first. ``` One copy gained a sentence about failing tests; the other never got it. **Good (identical copies, intentionally synced):** ```markdown ## Testing Run the full suite with `make test` before every push. Integration tests require Docker; start it with `make docker-up` first. Never skip failing tests — fix them or file an issue with the failure output. ``` ## How to fix Compare the two sections named in the violation and reconcile them: 1. Decide which copy is current (usually the most recently edited one). 2. Update the stale copy to match exactly, or rewrite both if neither is fully right. 3. Better: keep one source of truth. Generate the copies with a compiler (files with generated-file markers are skipped when `ignore-generated: true`, the default), or replace the duplicated section with a short pointer to a single shared file. **Intentional harness-specific divergence.** Sometimes two copies are *supposed* to differ — e.g. CLAUDE.md says "Claude Code style tool names" where AGENTS.md says "Codex style tool names". Suppress that section with a standard inline directive in the file the violation is reported on (the later file in path order — or both files, to be safe): ```markdown ## Tool naming ...harness-specific content... ``` The directive comment itself never affects the comparison: HTML comments and whitespace are stripped before sections are compared, so adding a suppression to one file cannot create (or hide) drift distance in another pair. Tune the rule in `.skillsaw.yaml`: ```yaml rules: content-instruction-drift: severity: warning similarity-threshold: 0.85 # 0-1 exclusive; higher = only very close copies fire min-section-words: 60 # ignore sections shorter than this ignore-generated: true # skip files with a generated-file marker similarity-max-sections: 400 # cap on sections entering pairwise comparison ``` `similarity-max-sections` caps the number of qualifying sections compared across files (default 400). Raise this setting if you maintain an unusually large monorepo. ## Configuration ```yaml rules: content-instruction-drift: enabled: auto # true | false | auto severity: info ``` | Parameter | Description | Default | |-----------|-------------|---------| | `similarity-threshold` | Similarity ratio (0-1, exclusive) above which two sections in different instruction files are considered drifted copies; identical sections never fire | `0.8` | | `min-section-words` | Minimum number of words a section must contain to participate in drift comparison | `40` | | `ignore-generated` | Skip files carrying a generated-file marker (e.g. 'generated by ... do not edit', APM's 'Generated by APM CLI' header) — compiled instruction files are near-copies by design | `true` | | `similarity-max-sections` | Maximum number of qualifying sections compared pairwise; sections beyond the cap (in file-path order) are skipped, bounding the quadratic comparison on degenerate inputs | `400` | *Run `skillsaw explain content-instruction-drift` to see this documentation and the rule's effective configuration in your terminal.*