agent-hygiene@v1
Hygiene rules for the AI-coding era — patterns that show up disproportionately in commits authored or co-authored by Claude Code, Cursor, Copilot agent, Aider, Codex, and other coding agents. Each rule targets a failure mode that happens more often with agents than with humans, but the rules themselves are agent-agnostic — they catch any commit matching the pattern, no special-casing on author identity.
Composes with the existing hygiene rulesets — reach for all three on agent-heavy projects:
extends: - alint://bundled/hygiene/no-tracked-artifacts@v1 - alint://bundled/hygiene/lockfiles@v1 - alint://bundled/agent-hygiene@v1no-tracked-artifacts@v1 already covers OS / editor / build
junk (.DS_Store, *.bak, *.swp, node_modules/, .env,
10 MiB+ files); this ruleset focuses on the patterns that are
distinctly agent-shaped — versioned-duplicate filenames,
scratch / planning docs, AI-affirmation prose, debug residue,
and model-attributed TODO markers.
Defaults are non-blocking on the heuristic checks (info /
warning) and error only on unambiguous bugs (debugger;
in non-test source). Override severity per-rule in your own
config once you’re ready to enforce.
agent-no-versioned-duplicates
Section titled “agent-no-versioned-duplicates”- kind:
file_absent - level:
warning
Filename looks like a versioned duplicate (e.g. app_old.js, api_FINAL.py, utils_copy.ts). Replace the original instead of keeping a parallel copy.
agent-no-scratch-docs-at-root
Section titled “agent-no-scratch-docs-at-root”- kind:
file_absent - level:
warning
Scratch / planning documents should not be committed at the repo root. Move the content into a real doc (CHANGELOG, ADR, design doc, README) or delete it once the work is done.
agent-no-affirmation-prose
Section titled “agent-no-affirmation-prose”- kind:
file_content_forbidden - level:
info
AI-style affirmation phrasing in committed content. These are characteristic of agent-authored prose; trim before merge.
agent-no-console-log
Section titled “agent-no-console-log”- kind:
file_content_forbidden - level:
warning
console.log/.debug/.traceleft in non-test source. Route through the project logger or remove before merge.
agent-no-debugger-statements
Section titled “agent-no-debugger-statements”- kind:
file_content_forbidden - level:
error
debugger;/breakpoint()must not be committed. These halt execution at runtime. Remove before merge.
agent-no-model-todos
Section titled “agent-no-model-todos”- kind:
file_content_forbidden - level:
warning
Agent-attributed TODO marker. Resolve, convert to a tracked issue, or remove the model attribution. These outlive the session that wrote them.
Source
Section titled “Source”The full ruleset definition is committed at crates/alint-dsl/rulesets/v1/agent-hygiene.yml in the alint repo (the snapshot below is generated verbatim from that file).
# alint://bundled/agent-hygiene@v1## Hygiene rules for the AI-coding era — patterns that show up# disproportionately in commits authored or co-authored by# Claude Code, Cursor, Copilot agent, Aider, Codex, and other# coding agents. Each rule targets a failure mode that happens# *more often* with agents than with humans, but the rules# themselves are agent-agnostic — they catch any commit# matching the pattern, no special-casing on author identity.## Composes with the existing hygiene rulesets — reach for# all three on agent-heavy projects:## extends:# - alint://bundled/hygiene/no-tracked-artifacts@v1# - alint://bundled/hygiene/lockfiles@v1# - alint://bundled/agent-hygiene@v1## `no-tracked-artifacts@v1` already covers OS / editor / build# junk (`.DS_Store`, `*.bak`, `*.swp`, `node_modules/`, `.env`,# 10 MiB+ files); this ruleset focuses on the patterns that are# *distinctly* agent-shaped — versioned-duplicate filenames,# scratch / planning docs, AI-affirmation prose, debug residue,# and model-attributed TODO markers.## Defaults are non-blocking on the heuristic checks (`info` /# `warning`) and `error` only on unambiguous bugs (`debugger;`# in non-test source). Override severity per-rule in your own# config once you're ready to enforce.
version: 1
rules: # --- Versioned-duplicate filenames ------------------------------- # Agents tend to write `app_old.js` / `api_FINAL.py` / # `utils_copy.ts` instead of replacing the original. # Combined with `hygiene-no-editor-backups` from # `no-tracked-artifacts@v1` (which catches `*.bak` / `*~` / # `*.swp`), this gives broad coverage of the # leftover-artefact filename surface. # # Important non-coverage: we deliberately do NOT match # `*_v[0-9]*` / `*-v[0-9]*`. Real codebases use those for # legitimate versioning — API versions # (`gitlab_v1_callback.py`), schema migrations # (`076_add_v1_tables.py`), release notes # (`release-notes-v1.md`), and versioned tests # (`test_v1_api.py`). The other suffixes below are # unambiguous — `_old`, `_new`, `_FINAL`, `_copy`, `_backup`, # `.copy.` are almost never legitimate part of a real # filename's identity. - id: agent-no-versioned-duplicates kind: file_absent paths: - "**/*_old.*" - "**/*_old" - "**/*_new.*" - "**/*_final.*" - "**/*_FINAL.*" - "**/*_copy.*" - "**/*_backup.*" - "**/*.copy.*" level: warning message: >- Filename looks like a versioned duplicate (e.g. app_old.js, api_FINAL.py, utils_copy.ts). Replace the original instead of keeping a parallel copy.
# --- Planning / scratch docs at repo root ------------------------ # Agents spawn planning files (PLAN.md, NOTES.md, ANALYSIS.md, # …) as part of their workflow and frequently forget to delete # them before committing. Best-practice AGENTS.md templates # explicitly tell agents to remove these post-merge — this rule # enforces the discipline. # # `root_only: true` so a legitimate `notes.md` deeper in the # tree (e.g. `docs/notes.md` for a feature, or a per-package # `packages/foo/NOTES.md`) does not trigger. - id: agent-no-scratch-docs-at-root kind: file_absent paths: - PLAN.md - NOTES.md - ANALYSIS.md - SUMMARY.md - FIX.md - DECISION.md - TODO.md - SCRATCH.md - DEBUG.md - TEMP.md - WIP.md root_only: true level: warning message: >- Scratch / planning documents should not be committed at the repo root. Move the content into a real doc (CHANGELOG, ADR, design doc, README) or delete it once the work is done.
# --- AI-affirmation prose in source ------------------------------ # Reviewers consistently flag these stock phrases as "AI smell." # The pattern is narrow enough that legitimate code shouldn't # match — info-level so it's a soft nudge, not a hard gate. # # The exclude list covers content that legitimately QUOTES # AI-style text from upstream sources (CHANGELOG entries, # roadmap rationale, cookbook examples) or captures it as # test fixture output (snapshot tests, fixtures dirs). - id: agent-no-affirmation-prose kind: file_content_forbidden paths: include: ["**/*.{rs,ts,tsx,js,jsx,py,go,java,kt,rb,md}"] exclude: - "**/*test*/**" - "**/__tests__/**" - "**/fixtures/**" - "**/CHANGELOG*" - "**/ROADMAP*" - "**/*.snap" pattern: "(?i)(you'?re absolutely right|excellent question|happy to help|great (point|question)|let me know if you need)" level: info message: >- AI-style affirmation phrasing in committed content. These are characteristic of agent-authored prose; trim before merge.
# --- Debug residue ------------------------------------------------ # `console.log` / `.debug` / `.trace` left in non-test JS / TS # sources. The exclude list balances catching real production # leftovers vs. legitimate logging in build tooling, browser # demos, and vendored content. # # The leading `(?:^|[\s;{(])` ensures we don't match # `myconsole.log(...)` or other false positives where `console` # is part of a longer identifier. - id: agent-no-console-log kind: file_content_forbidden paths: include: ["**/*.{ts,tsx,js,jsx,mjs,cjs}"] exclude: # Test files and directories — `**/*test*/**` matches # any segment containing "test" (`tests/`, `e2e-tests/`, # `cross-sdk-tests/`, `test_helpers/`, …) — broader than # `**/test*/**` which only matches segments STARTING # with "test". - "**/*.{test,spec}.*" - "**/*test*/**" - "**/__tests__/**" - "**/fixtures/**" # Build / dev tooling config files (vite.config.ts, # rollup.config.mjs, etc.) often log intentionally. - "**/*.config.*" # Build / utility scripts — agent harnesses and CI # glue legitimately log; src/ is where this rule earns # its keep. - "**/scripts/**" # Browser-facing demos and websites — `console.log` is a # legitimate browser-debugging tool, and the codebase # may keep example logs intentionally. - "**/website/**" - "**/public/**" - "**/demo/**" - "**/demos/**" - "**/examples/**" # Vendored / third-party code we don't own. - "**/vendor/**" - "**/vendored/**" - "**/third_party/**" - "**/3rdparty/**" # Agent worktrees and harness scratch space — these are # ephemeral copies of the working tree (e.g. Claude # Code's `/parallel` worktrees), not real source. - "**/.claude/**" pattern: '(?:^|[\s;{(])console\.(log|debug|trace)\s*\(' level: warning message: >- `console.log` / `.debug` / `.trace` left in non-test source. Route through the project logger or remove before merge.
- id: agent-no-debugger-statements kind: file_content_forbidden paths: include: ["**/*.{ts,tsx,js,jsx,mjs,cjs,py}"] exclude: - "**/*.{test,spec}.*" - "**/*test*/**" - "**/__tests__/**" - "**/fixtures/**" - "**/scripts/**" - "**/website/**" - "**/public/**" - "**/demo/**" - "**/demos/**" - "**/examples/**" - "**/vendor/**" - "**/vendored/**" - "**/third_party/**" - "**/3rdparty/**" - "**/.claude/**" # Require `;` after `debugger` so the rule doesn't trip # on the WORD "debugger" appearing in prose comments # (`* called by the vscode debugger`). Same idea for # `breakpoint()` — must include the parens, not just the # word. pattern: '(?:^|[\s;{(])(debugger\s*;|breakpoint\s*\(\s*\))' level: error message: >- `debugger;` / `breakpoint()` must not be committed. These halt execution at runtime. Remove before merge.
# --- Model-attributed TODOs -------------------------------------- # `TODO(claude:)`, `FIXME(cursor:)`, `XXX(gpt:)` etc. — TODO # markers that name a coding agent. They outlive the session # that wrote them and are typically actionable items the agent # intended to come back to but never did. # # Excludes documentation and changelogs — projects that # *describe* these patterns (alint's own ROADMAP / CHANGELOG / # cookbook are the canonical case) trip the rule on their own # examples otherwise. - id: agent-no-model-todos kind: file_content_forbidden paths: include: ["**/*.{rs,ts,tsx,js,jsx,py,go,java,kt,rb,scala,c,cc,cpp,h,hpp,md}"] exclude: - "**/CHANGELOG*" - "**/ROADMAP*" - "**/cookbook/**" - "**/*test*/**" - "**/__tests__/**" - "**/fixtures/**" pattern: '(?i)\b(TODO|FIXME|XXX|HACK)\s*\(\s*(claude|gpt|copilot|cursor|gemini|codex|aider|chatgpt)\b' level: warning message: >- Agent-attributed TODO marker. Resolve, convert to a tracked issue, or remove the model attribution. These outlive the session that wrote them.