Tidy · Project Tidiness Convention
Every file in the repository must answer three questions:
- Why does it exist? (Necessity) — What would break if you deleted it?
- Why is it here? (Belonging) — According to this project's directory conventions, which directory does it belong to?
- 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
| Tier | Role | Executor |
|---|---|---|
Directory Convention .claude/tidy.json | Declares what each top-level directory is for, turning 'where does it go' from judgment into table lookup | You 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 turn | Automatic, see 'When receiving a hook prompt' below |
| This Skill | Judgment criteria when writing code, workflow for tidying old projects | You |
Hooks only check new files; existing issues in older projects are handled by 'Mode 2'.
Three Levels of Checking Granularity
| When | What to Do |
|---|---|
| When creating a new file | Run through the 4 questions below (hooks will automatically intercept if available) |
| At milestone/task completion | audit.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-up | Full 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
| Question | What 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 directory | Write 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 task | Put summaries in the reply and commit message; merge long-term knowledge into README or existing docs/ documents |
Committing build/, out/, dist/, rendered videos/audio, logs | Add them to .gitignore; write clearly in README how to generate them |
node_modules/, .venv/ being committed or scattered everywhere | Ignore them; polyglot toolchains each have their own place (see structure.md 'Polyglot Projects') |
Chinese characters, spaces, parentheses in filenames: prompt分享.md, final (1).mp4 | Use English kebab-case for filenames, put Chinese in file titles |
| Boilerplate scaffolding not cleaned up, large chunks of commented-out old code, unused dependencies | Delete 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
allowsection of.claude/tidy.json(e.g.,{"non-portable-name": ["docs/课程/**"]}) and explain in the reply. Keep the exemption as narrow as possible; do not usedisableto 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
keepLocalwith 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
layoutand 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.tomlscripts 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). Forunreferenced, also consider dynamic paths and external calls; see references/file-necessity.md for decision criteria.
Step 3: Propose a Tidying Plan, Wait for Confirmation
| Path | Action | Target Location | Reason |
|---|---|---|---|
prompt分享.md | Move + Rename | docs/prompts.md | Root scattered document; non-ASCII filename |
out/ | Ignore | — | Render artifact, can be regenerated with npm run render |
src/Root_old.tsx | Delete | — | 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
- Ensure the working directory is clean; if not a git repository, suggest
git initand make an initial commit as a snapshot. 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 needgit rm --cached.- Use
git mvfor moves/renames; then run refs.py or grep on old paths to fix all references (imports,staticFile(), configs, scripts, documentation links). - Run the build/tests/lint to confirm nothing is broken.
- 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
.envand 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
| File | Content | When to Read |
|---|---|---|
| references/structure.md | Root directory whitelist, standard directory layouts for various project types (Node/TS, Remotion, Python, Polyglot) | When deciding file placement, designing layout |
| references/file-necessity.md | How to judge whether a file is necessary, common deletable boilerplate | When deciding if a file can be deleted |
| references/naming.md | Naming conventions per language, prohibited naming patterns | When creating or renaming files |
| references/docs.md | Minimum README requirements, docs/ layout, archiving rules | When writing docs or archiving |
| references/config.md | .claude/tidy.json field descriptions and examples | When generating or modifying directory conventions |
| assets/README.template.md | README template | When a project lacks a README |
| assets/gitignore/ | .gitignore snippets: general, Node, Python, media | When completing ignore rules |
| assets/agents-rules.md | Rules pasteable into AGENTS.md (for other AI tools that don't support hooks) | When the project also uses Cursor / Codex, etc. |