CommunityCoding & Developmentgithub.com

GaoFei2025-0314/tidy

Standardizes file tidiness and maintainability in AI-generated projects — judges whether each file is necessary, where it should be placed, and whether it should be deleted or archived. Keeps the root directory clean, naming consistent, and directory conventions clear.

What is tidy?

Tidy is a comprehensive AI agent skill designed to enforce project structure hygiene and maintainability in any software project, particularly those generated or modified by AI coding assistants. It operates through a three-tier mechanism: a directory convention configuration (`.claude/tidy.json`), automatic hooks that intercept non-compliant new files, and a manual skill mode for auditing and fixing existing projects. The skill provides detailed guidance on common AI bad habits (e.g., creating temporary scripts in the root, naming files with non-ASCII characters, committing build outputs) and offers a five-step workflow for cleaning up existing repositories: scanning with `audit.py`, checking file references with `refs.py`, presenting an action plan (keep/move/rename/delete/archive/ignore/keep local), executing changes safely with git, and finally solidifying directory conventions. It supports all major AI coding tools (Claude Code, Cursor, Codex) and requires only Python 3.9+ standard library for its scripts. The skill emphasizes safety by never deleting irreproducible files without confirmation, offering a clear decision tree for archiving vs. deleting, and providing allowed/ignore lists to override checks when necessary.

Works with✓Claude Code✓Codex CLI✓Cursor
npx skills add https://github.com/GaoFei2025-0314/tidy/tree/HEAD/skills/tidy

Installed? Explore more Coding & Development skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Tidy · Project Tidiness Convention

Every file in the repository must answer three questions:

  1. Why does it exist? (Necessity) — What would break if you deleted it?
  2. Why is it here? (Belonging) — According to this project's directory conventions, which directory does it belong to?
  3. Can others understand it? (Readability) — Just from the file name and README, can a newcomer guess what it's for?

When the user inputs /tidy, directly execute the 'Mode 2: Tidy an Existing Project' below.

Three-Tier Mechanism

TierRoleExecutor
Directory Convention .claude/tidy.jsonDeclares what each top-level directory is for, turning 'where does it go' from judgment into table lookupYou generate it while tidying the project, then maintain it long-term
Hooks (installed with the plugin)Inject rules and directory conventions at session start; intercept non-compliant new files; check for new files at end of each turnAutomatic, see 'When receiving a hook prompt' below
This SkillJudgment criteria when writing code, workflow for tidying old projectsYou

Hooks only check new files; existing issues in older projects are handled by 'Mode 2'.

Three Levels of Checking Granularity

WhenWhat to Do
When creating a new fileRun through the 4 questions below (hooks will automatically intercept if available)
At milestone/task completionaudit.py <root> --changed (for git projects, only checks changes relative to HEAD) or --since 2h (by modification time, works for non-git projects). For tools without hooks (Codex, Cursor), run this before every delivery.
When user requests a project tidy-upFull audit.py <root>, follow 'Mode 2'

For warnings that are confirmed as intentional (e.g., deliberate delivery copies, third-party filenames), use audit.py <root> --review <rule> <path> --reason <conclusion> to record them; they will not be reported again. If the file content changes, the warning will reappear to remind you to re-check.


Mode 1: While Writing Code (Applies Every Time)

The 4 Questions Before Creating a New File

QuestionWhat to Do If It Fails
Is it necessary? Can it be written into an existing file? Is it only temporary?Merge into an existing file; put temporary content in the reply, don't save it to disk
Where does it go? Does it conform to the layout in .claude/tidy.json?Put it in an already declared directory; if a new top-level directory is truly needed, register it in both the layout and the README's 'Directory Structure'
What is it called? Does the name describe its purpose and match the style of the same directory?Follow the naming conventions in references/naming.md
Should it be committed? Is it a build artifact, dependency, secret, or large file?Add it to .gitignore, do not version it

AI's Most Common Bad Habits (Prohibited)

❌ Bad Habit✅ Correct Practice
Writing temporary scripts like test.py, debug.js, check_xxx.py in the root directoryWrite them to .scratch/ (ensure it's ignored) or the system temp directory, delete after the task
Copying out foo_v2.ts, foo_new.ts, foo.backup.ts, foo_old/Edit the original file directly, leave history to git
Generating IMPLEMENTATION_SUMMARY.md, FIX_REPORT.md after every taskPut summaries in the reply and commit message; merge long-term knowledge into README or existing docs/ documents
Committing build/, out/, dist/, rendered videos/audio, logsAdd them to .gitignore; write clearly in README how to generate them
node_modules/, .venv/ being committed or scattered everywhereIgnore them; polyglot toolchains each have their own place (see structure.md 'Polyglot Projects')
Chinese characters, spaces, parentheses in filenames: prompt分享.md, final (1).mp4Use English kebab-case for filenames, put Chinese in file titles
Boilerplate scaffolding not cleaned up, large chunks of commented-out old code, unused dependenciesDelete after confirming no references
Same configuration written in two places (.prettierrc + package.json#prettier)Keep only one
Pre-creating empty directories or files 'just in case'Create them only when needed

When Receiving a Hook Prompt

  • New file creation blocked: Follow the prompt to change your approach — merge into an existing file, change directory, change name, or simply don't save it to disk. Do not try to bypass the block by writing files with Bash (Stop checks will still catch it).
  • Pre-completion check lists issues: Handle each one (delete temp files, merge copies, move, add to .gitignore) before finishing.
  • User explicitly asks for it (e.g., wants a Chinese filename): Add the path to the allow section of .claude/tidy.json (e.g., {"non-portable-name": ["docs/课程/**"]}) and explain in the reply. Keep the exemption as narrow as possible; do not use disable to turn off the entire rule, and do not add exemptions on your own.
  • Files that should be kept locally but not in git (finished videos, approved voiceovers, model weights, etc.): Register them in keepLocal with a reason, then add to .gitignore. Do not delete.
  • Need a new top-level directory: First confirm no suitable existing directory, then register it in layout and README's 'Directory Structure'.

Mode 2: Tidying an Existing Project

All scripts are in this skill's scripts/ directory and depend only on Python 3.9+ standard library.

Step 1: Scan

python3 <skill>/scripts/audit.py <project root>            # Text report
python3 <skill>/scripts/audit.py <project root> --format json

Step 2: Understand the Project, Check References

The script is heuristic; verify each warning before acting. Text reports will fold large numbers of similar issues; use --all to view them one by one. Before concluding:

  • Read the README, package.json / pyproject.toml scripts and entry points;

  • Check references for each file you want to delete or move:

    python3 <skill>/scripts/refs.py <project root> <file> [<file> ...]
    

    Results are one of four types: in-use (explicit reference), convention (loaded by convention by the framework), maybe (only weak match), unreferenced (none found). For unreferenced, also consider dynamic paths and external calls; see references/file-necessity.md for decision criteria.

Step 3: Propose a Tidying Plan, Wait for Confirmation

PathActionTarget LocationReason
prompt分享.mdMove + Renamedocs/prompts.mdRoot scattered document; non-ASCII filename
out/Ignore—Render artifact, can be regenerated with npm run render
src/Root_old.tsxDelete—refs.py: unreferenced; content identical to Root.tsx

Only seven actions: Keep / Move / Rename / Delete / Archive / Ignore / Keep Local (ignore but don't delete, register in keepLocal). Mark uncertain items as 'pending confirmation'. When a warning is an expected situation (delivery copy, burst of frames), the action is to add an allow rule, not delete the file.

Deletion and batch moves require user confirmation first. Do not move files before the plan is confirmed.

Step 4: Execute

  1. Ensure the working directory is clean; if not a git repository, suggest git init and make an initial commit as a snapshot.
  2. python3 <skill>/scripts/audit.py <root> --fix-gitignore: Automatically add unignored dependencies, artifacts, junk files, and secrets to .gitignore (appends only, does not delete). Files already tracked by git will be listed and may need git rm --cached.
  3. Use git mv for moves/renames; then run refs.py or grep on old paths to fix all references (imports, staticFile(), configs, scripts, documentation links).
  4. Run the build/tests/lint to confirm nothing is broken.
  5. Commit structural changes and code modifications separately.

Step 5: Solidify Directory Conventions (Don't Skip)

After tidying, generate directory conventions so every future session automatically follows them:

python3 <skill>/scripts/audit.py <root> --init     # Generate a draft .claude/tidy.json from existing top-level directories

Then fill in descriptions for each directory (replace TODO). The descriptions should be detailed enough to guide placement decisions, e.g., "public/": "Static material read by staticFile(): images, fonts, voiceovers", not just 'static assets'. Also update the README 'Directory Structure'. See references/config.md for configuration format.

Safety Bottom Lines

  • Non-reproducible files (user materials, recordings, handwritten prompts, data) must never be deleted without confirmation — move them to an appropriate directory or archive.
  • Do not read or output secrets from .env and similar files; if a secret is found to be tracked by git, remind the user to rotate the secret and clean the history, not just delete the file.
  • If unsure whether a file is in use, mark it 'pending confirmation'; do not guess.

Delete or Archive?

'Whether it's in git' and 'whether to delete' are judged separately.

This file...
├─ Can it be regenerated at low cost? (build artifacts, cache, logs, dependencies, temporary frames)
│    └─ Yes → Delete + add to .gitignore
├─ Can it be regenerated, but at high cost? (finished videos, approved voiceovers, rendered course packs, trained models — cost time, money, or re-approval)
│    └─ Yes → Keep locally + add to .gitignore + register in tidy.json's keepLocal (with reason), state generation method in README
├─ Is it obsolete code already tracked by git?
│    └─ Yes → Delete directly (git history is the archive)
├─ Non-reproducible and still valuable? (research notes, old prompts, design drafts, decision records)
│    └─ Yes → Move to docs/archive/, prefix filename with date, add a line of reason in docs/archive/README.md
├─ Is it a large-volume asset? (audio/video, datasets, models)
│    └─ Yes → Do not commit to git (or use Git LFS), state retrieval method in README
└─ Non-reproducible and no value → List them, delete after user confirmation

See references/docs.md for detailed archiving rules.

Reference Files

FileContentWhen to Read
references/structure.mdRoot directory whitelist, standard directory layouts for various project types (Node/TS, Remotion, Python, Polyglot)When deciding file placement, designing layout
references/file-necessity.mdHow to judge whether a file is necessary, common deletable boilerplateWhen deciding if a file can be deleted
references/naming.mdNaming conventions per language, prohibited naming patternsWhen creating or renaming files
references/docs.mdMinimum README requirements, docs/ layout, archiving rulesWhen writing docs or archiving
references/config.md.claude/tidy.json field descriptions and examplesWhen generating or modifying directory conventions
assets/README.template.mdREADME templateWhen a project lacks a README
assets/gitignore/.gitignore snippets: general, Node, Python, mediaWhen completing ignore rules
assets/agents-rules.mdRules pasteable into AGENTS.md (for other AI tools that don't support hooks)When the project also uses Cursor / Codex, etc.

Related Skills