autodev-init
Every other skill in this plugin ships someone else's conventions. This one reads
yours out of the code and writes them down, so review, audit, and auto
enforce what your project actually does.
Output goes to .claude/project-rules.md in the project — not into the
plugin. It is project-local, git-committed, and human-editable. The generic
standards and rule-* skills stay as the fallback for anything you have not
decided.
Rule one: observe, never assume
Every line you write must be backed by a count from this codebase. If you cannot
produce evidence, the convention does not go in the file — write it in the
"Undecided" section instead. A generated rules file that guesses is worse than
none, because review will enforce the guess.
If .claude/project-rules.md already exists, this is a refresh: re-measure,
show a diff of what changed, and preserve every hand-edited line. Never silently
overwrite a human's edit.
Step 1: Establish the stack
cat package.json 2>/dev/null | head -60
ls -d src app pages components lib server 2>/dev/null
cat tsconfig.json 2>/dev/null | head -30
Record: framework and major version, router style, package manager (from the lockfile), TypeScript strictness, test runner, linter/formatter.
Step 2: Measure the conventions
Run these and keep the counts — they are the evidence.
# Component style: function declarations vs arrow consts
grep -rEc "^export (default )?function [A-Z]" --include='*.tsx' src app 2>/dev/null | awk -F: '{n+=$2} END {print "fn components:", n+0}'
grep -rEc "^export const [A-Z][A-Za-z]* = \(" --include='*.tsx' src app 2>/dev/null | awk -F: '{n+=$2} END {print "arrow components:", n+0}'
# Data fetching
grep -rl "useQuery\|useSuspenseQuery" --include='*.tsx' --include='*.ts' src app 2>/dev/null | wc -l
grep -rl "useSWR" --include='*.tsx' --include='*.ts' src app 2>/dev/null | wc -l
grep -rl "await fetch(" --include='*.tsx' --include='*.ts' src app 2>/dev/null | wc -l
# Validation at boundaries
grep -rl "from ['\"]zod['\"]" --include='*.ts' --include='*.tsx' src app 2>/dev/null | wc -l
# Styling: tokens vs raw colors
grep -rEo "\b(bg|text|border)-(background|foreground|primary|secondary|muted|accent|destructive)\b" --include='*.tsx' src app 2>/dev/null | wc -l
grep -rEo "\b(bg|text|border)-(gray|slate|zinc|white|black|red|blue|green)-?[0-9]*\b" --include='*.tsx' src app 2>/dev/null | wc -l
# Error and state handling
grep -rc "catch" --include='*.ts' --include='*.tsx' src app 2>/dev/null | awk -F: '{n+=$2} END {print "catch blocks:", n+0}'
grep -rl "isLoading\|isPending" --include='*.tsx' src app 2>/dev/null | wc -l
# Test layout
ls **/*.test.* **/*.spec.* __tests__ 2>/dev/null | head -5
Read 3–5 of the most recently changed non-trivial components in full. Counts tell you what is common; reading tells you what is intended.
git log --format= --name-only -50 -- '*.tsx' | grep -v '^$' | sort | uniq -c | sort -rn | head -10
Step 3: Find the boundaries
These matter more than style, because getting them wrong is a security bug:
- Where does auth get enforced? Middleware, per-route, or per-component?
- Where does external data enter, and is it validated there?
- Which directories are server-only? What stops a secret reaching the client?
- If there is a database: where do RLS policies live, and is deny-by-default the pattern?
Step 4: Resolve contradictions with the user
Where the codebase is split — say 60/40 between two patterns — do not pick the majority silently. Ask, using AskUserQuestion, with the counts in the options:
Components are 34 arrow-const and 22 function-declaration. Which is the convention going forward?
Ask about at most the four most consequential splits. Everything else goes to "Undecided".
Step 5: Write .claude/project-rules.md
# Project Rules
Generated by autodev-init on <date> from <N> files. Hand edits are preserved on
refresh — edit freely.
## Stack
<framework, router, package manager, TS strictness, test runner>
## Conventions
- <rule> — observed in <N>/<M> files
- <rule> — decided by <user>, <date>
## Boundaries
- Auth enforced at: <where>
- External data validated at: <where> using <what>
- Server-only: <paths>
## Anti-patterns for this codebase
- <specific pattern>, because <project-specific reason>
## Undecided
- <split convention with counts> — no rule; do not flag either form in review.
Then tell the user, in one line each: what you measured, what you asked, and what remains undecided.
Step 6: Wire it in
.claude/ is ephemeral tooling state and should be ignored — but this one file
is worth committing. A bare !.claude/project-rules.md negation only works if
.claude/ is ignored as a directory, so add both, and check the result rather
than assuming:
grep -q "^\.claude/$" .gitignore || printf '\n# autodev tooling state\n.claude/\n' >> .gitignore
grep -q "project-rules" .gitignore || printf '# ...except the project rules, which are committed\n!.claude/project-rules.md\n' >> .gitignore
git check-ignore -v .claude/project-rules.md && echo "STILL IGNORED — fix the negation before continuing"
If the repo already ignores only specific paths inside .claude/ rather than
the whole directory, leave that alone and just confirm project-rules.md is
committable. Do not restructure someone's .gitignore.
Tell the user that review, audit, and auto should read
.claude/project-rules.md and that it outranks the plugin's generic
standards skill wherever the two disagree — the project's own observed
convention wins over a shipped default.
What not to do
- Do not write a rule you did not measure.
- Do not restate general best practice. "Handle errors" is not a project rule;
"errors surface through
<ErrorState>, never a toast" is. - Do not reformat or refactor anything. This skill only reads and writes one file.
- Do not run on a repo with fewer than ~10 source files — there is no convention to observe yet. Say so and stop.
Proving the run
Observable: every rule written to .claude/project-rules.md cites the file
it was measured from, and re-reading that file still supports the rule.
The failure mode of this skill is a confident convention nobody follows — a rule inferred from two files and applied to two hundred. A citation makes that checkable by someone who was not here. Before finishing, re-read three cited files at random and confirm each still says what the rule claims. State how many files the conventions were measured across; a rule derived from one file is a guess and should say so.