Enable AI coding to carry on historical coding styles and keep a consistent coding style.
SaferSkills independently audited inherit-legacy-style (Agent Skill) and scored it 92/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 2 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 2 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
When an AI coding agent is dropped onto a hand-written legacy project, the model's pretraining bias makes it impose its own "mainstream" idioms, causing Style Drift: two competing list-refresh patterns in one codebase, inconsistent naming, duplicated utility functions.
This skill fixes that. It is fully language- and framework-agnostic — it does not judge syntax sugar; it extracts and aligns the project's meta-architecture along four dimensions, then crystallizes the consensus into a root-level .ai-style-rules.md that acts as a binding constraint on subsequent coding.
Core principle: reuse the legacy exemplar over free improvisation. When a legacy pattern can be reused pixel-for-pixel, never inject the model's own preferred style.
The skill's own instructions are in English, but everything this skill produces for the user must mirror the language the user is communicating in:
.ai-style-rules.md content, the CLAUDE.md hook line, grilling questions, the strength-of-enforcement prompt, status reports, and the evolution log — all written in the user's language (e.g. Chinese if the user writes in Chinese, English if in English).On /inherit-legacy-style, the first action must be a silent check for .ai-style-rules.md at the project root:
if .ai-style-rules.md absent → Branch A: [First-time · Full-Scan mode]
if .ai-style-rules.md present → Branch B: [Evolution · Incremental-Sniff mode]Use Glob or ls. Announce the chosen mode in one line, then execute that branch directly — do not ask the user to pick a mode.
Use Glob to locate sources, Grep to search patterns, Read to study exemplars, and extract the four-dimension implicit rules.
Scanning is not one-size-fits-all sampling — sampling starves small projects (too few samples, distorted frequencies); full traversal blows up large repos (token/time overflow). First measure scale:
git ls-files 2>/dev/null | grep -cE '\.(js|ts|jsx|tsx|vue|py|go|rs|java|kt|rb|php|cs|swift|c|cpp|h)$'
# Non-Git fallback: find . -type f \( -name '*.js' -o -name '*.vue' ... \) -not -path '*/node_modules/*' | wc -lPick a tier by source-file count:
| Tier | Source files | Strategy |
|---|---|---|
| Small | ≲ 50 | Full close-read. Read every core source; no sampling. When frequency base is too low (e.g. "3 vs 2") to auto-decide, escalate to grilling — never guess the majority. |
| Medium | 50 – 500 | Layered. Infra layer (apis/utils/store/config) read fully; business layer (views/pages/handlers) sample 2-3 exemplars per dimension by frequency + recency (Git). |
| Large | ≳ 500 | Strict sampling + budget cap. Read only files touched in the last N Git changes + the top 2-3 highest-frequency exemplars per dimension; cap file/read count, locate via --stat summary before Read. |
In every tier, evidence priority is fixed: frequency > recency (Git) > human-written (avoid generated code / vendor). Tell the user the chosen tier in one line (e.g. "833 source files → Large project, strict sampling").
Examples span frontend / backend / CLI to show "cross-stack, meta-architecture only" — map to the project's actual stack; do not force irrelevant examples.
import → types/consts → main → helpers → export; Backend: package/imports → consts → struct/types → constructors → methods → private helpers; CLI: flag defs → config load → main flow → subcommands. Record the actual template.loading/error/data, pagination pageIndex/pageSize/total; Backend: pagination offset/limit vs page/size, transaction boundaries, context propagation; CLI: exit-code conventions, --verbose/--dry-run flag naming. Record naming + combination.Result/error return vs panic/recover) and null-check habits (optional chaining, early return, default fallback, if err != nil).If the scan finds the project self-contradicting (two list-refresh patterns, two naming styles), do not self-arbitrate — go to [Grilling & Alignment] below, one at a time.
.ai-style-rules.md)Once there are no conflicts (or all are resolved), create from scratch the root .ai-style-rules.md with three mandatory sections (write content in the user's language per the Output Language Policy):
Template: reference/rules-template.md.
.ai-style-rules.md is not auto-loaded by future sessions. Right after creating it, install the hook so it becomes a per-turn constraint (see Step 5). Do this before reporting.
Refuse to re-scan in full. Only sniff whether the human's recent changes introduced a new style or new utility that differs from the recorded rules.
Read the existing .ai-style-rules.md into context. If its header records the last-scan commit fingerprint, run git diff <last_hash> HEAD --stat to pinpoint the delta precisely. git status
git log -3 --stat # last 3 commits (read --stat summary first to locate touched files)
git diff HEAD~3 HEAD # only inspect suspect files on demand; do not dump the full diffOversized-diff fallback (e.g. just merged hundreds of files): read only the --stat summary + sample the few largest source changes; do not load the whole diff. Non-Git repo or command failure → fall back to most-recently-modified sources (ls -lt).
Conflict found → go to [Grilling & Alignment], one at a time. No conflict → tell the user "no style drift detected, rules unchanged" and stop.
Never overwrite or erase old rules. Append an evolution log at the end of .ai-style-rules.md (in the user's language):
### [YYYY-MM-DD] Style Evolution Log
- New consensus: … (source: path, user chose option N)
- New exemplar / utility: …Use the real current date (date +%F).
Not every difference deserves a question. On finding two styles, assess signal strength first to avoid spamming the user:
pageIndex(843) vs pageNum(8) → auto-suppress; library choice moment(1) vs dayjs(2) → base too small, non-core, skip entirely.The threshold is heuristic; when unsure, lean toward asking rather than guessing.
Once confirmed a strong signal, enforce the one-soldier grilling protocol:
📄 Evidence in code: atpathAstyleXis used, while atpathB (or in existing rules)styleYis used. ⚠️ Risk: mixing both in new features will fracture the project's style. ❓ Choose: which should subsequent development follow? Reply with a number —1follow X2follow Y3this is the latest evolution, update the rules4I have a new rule: [input]
Prefer presenting the four options via the AskUserQuestion tool.
⚠️ Core insight: the instructions loaded this turn evaporate when the conversation ends or context is compacted. Relying on "I'll remember to load the rules" is unreliable — the constraint dies in a new session. A real constraint must be written where Claude reads it automatically every turn.
Enforcement strength is the user's call — do not default it for them. After creating the rules, first ask via AskUserQuestion (one of three, phrased in the user's language):
❓.ai-style-rules.mdis created. How strongly should subsequent coding obey it? -1Soft hook (recommended · sufficient): write into the projectCLAUDE.md, auto-loaded every session. Easy, but the model can theoretically bypass it. -2Hard hook (mechanical enforcement): soft hook + aPreToolUse[Write|Edit]hook that injects a rule reminder before every file write, unbypassable. Modifiessettings.json. -3No hook for now: just keep the rules file; I'll@-reference it manually.
Options 1 and 2 both do the soft hook first — attach the rules to the project root CLAUDE.md (auto-injected every session):
CLAUDE.md (Glob/ls).Edit to append one reference line in a prominent place, never overwriting: > 📐 Read @.ai-style-rules.md before coding — obey its naming/state/infra rules, avoid the DONTs.(Write this line in the user's language.)
Write a minimal CLAUDE.md containing only that line.Only option 2 adds the hard hook — configure a PreToolUse hook. Key: do NOT `cat` the full file (~1000 extra tokens per write); the content is already loaded once per session via the CLAUDE.md @ reference, so the hook only injects a ~20-token reminder. Prefer invoking the update-config skill to write into settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{ "type": "command",
"command": "echo 'Reminder: obey .ai-style-rules.md before this write (naming/state/infra rules + DONTs).'" }
]
}
]
}
}UsePreToolUse[Write|Edit|MultiEdit]notUserPromptSubmit: the former fires only when actually writing a file (zero cost on reads/chat); the latter burns tokens every turn. After writing, tell the user it's set and a new session / reload fully activates it.
Option 3: skip hooks; just tell the user the rules live in .ai-style-rules.md and to @-reference them when needed.
Without the 5.1 hook (option 1/2), this skill is a one-shot scanner, betraying its "workflow / binding constraint" identity.
Whenever .ai-style-rules.md (loaded via 5.1's CLAUDE.md reference) is in context, any write/edit/refactor task must explicitly load it as the first thought and open the reasoning with a compliance declaration, e.g. (in the user's language):
"Loaded.ai-style-rules.md. This round I will reuse the state-control pattern from exemplarXpixel-for-pixel, keep existing naming, and avoid the DONTs."
Two constraints:
return, empty catch), do not replicate them — flag to the user instead.git ls-files | wc -l first, picks Small/Medium/Large tier (Small=full read, Large=sampling+budget cap), announces the tier.AskUserQuestion for enforcement strength (soft/hard/none); soft → write CLAUDE.md; hard → also call update-config for a PreToolUse hook (inject a one-line reminder, never cat the full file).~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.