npx skills add moveju112/rule-architect -gAn agent skill that generates a production-grade, runtime-neutral rule set for a
project: one slim AI_RULES.md index, runtime entry files that resolve to it, and
on-demand docs/*.md rule files — all verified by a script and a quiz test before
it calls itself done.
Works in English and Korean. Triggers are registered in both languages, and the generated rules follow the project's existing docs language (or yours, if the project has none).
This skill runs on judgment. A weak model produces a broken rule set.
--updatein particular must honor "diff-edit only the changed sections". A weak model regenerates whole files instead and destroys hand-written rules.
| Tool | Minimum | Recommended | Do not use |
|---|---|---|---|
| Claude Code | Sonnet 5 (fresh generation only) | Opus 5 / Fable 5 + effort high |
Haiku tier |
| Codex CLI / GPT | GPT-5 flagship tier | GPT-5 Codex + reasoning high |
mini · nano tiers |
Never run --update at the minimum tier. Use Opus 5 / Fable 5 on Claude, or a
flagship tier on GPT. And commit your existing rule files first — that way a bad
run is one git checkout away from undone.
Model-independent: scripts/verify_rules.py. Line budgets, link integrity, and
citation-freshness checks are deterministic, so the model tier does not affect them.
- AI_RULES.md (≤60 lines) — the runtime-neutral slim index: Core Rules + run commands + a Routing table.
- The Routing table maps "situation/task → file to read", not "topic → file". Rows without a concrete trigger are rejected.
- CLAUDE.md + AGENTS.md — relative symlinks to
AI_RULES.mdon Linux/WSL/POSIX projects.- Repositories that must work without symlink support receive two short regular-file pointers instead.
- Both entries use the same mode; neither contains rule bodies or points at the other.
- docs/*.md (≤150 lines each) — topic rule docs, loaded only when the topic comes up.
- Always:
ARCHITECTURE.md,CODING_RULES.md,PITFALLS.md - Conditional:
CONTROLLER_RULES.md,ENUM_CODES.md,RESPONSE_KEYS.md,DB_RULES.md,DEPLOY.md
- Always:
- docs/tasks/*.md (≤80 lines each) — playbooks for recurring tasks: numbered steps, each citing
file:lineevidence.- Generated only for tasks where
git logshows the same file set changed together ≥3 times (e.g.ADD_API.md,ADD_MODEL.md). - Cross-file couplings are recorded as playbook steps, not as standalone rules.
- Generated only for tasks where
Every rule carries a grade, a reason, and a contrasting pair of examples.
- **[MUST|NEVER|PREFER]** <rule, one line>
- why: <one line>
- ❌ <a real violation from THIS project — file:line or snippet>
- ✅ <the correct form — real project code>Conflict priority: NEVER > MUST > PREFER.
PITFALLS.md uses symptom → cause → fix, with the symptom quoting the error
message verbatim so it stays greppable.
Record only what the code cannot tell you.
Anything one ls, one file read, or one grep would reveal is not a rule.
Cross-file couplings, required ordering, forbidden actions, in-flight migrations —
those are rules.
The rule set is written in one language per run, chosen in this order:
- The project's existing
AI_RULES.md/ legacy rule index /docs/*.md/READMElanguage. - The language you are writing in.
- English.
Structural tokens never change: MUST / NEVER / PREFER, why:, the ❌/✅
markers, UPPERCASE file names, and the <!-- generated by rule-architect -->
marker stay as-is in every language.
npx skills add moveju112/rule-architect -gWorks with Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, and the other
agents the Skills CLI supports. Drop -g to install into the
current project instead of user-level.
As a Claude Code plugin instead:
claude plugin marketplace add moveju112/rule-architect
claude plugin install rule-architect@rule-architectOr from inside a Claude Code session:
/plugin marketplace add moveju112/rule-architect
/plugin install rule-architect@rule-architect
By hand:
git clone https://github.com/moveju112/rule-architect.git ~/.claude/skills/rule-architect
# optional — register the slash command
ln -s ~/.claude/skills/rule-architect/commands/rule-architect.md ~/.claude/commands/Without the symlink the /rule-architect slash command is not registered, but the
skill still fires on natural-language triggers.
/rule-architect [project-path]
/rule-architect [project-path] --update # diff-update an existing rule set
Natural language, either language:
| English | Korean |
|---|---|
| "make rules for this project" | "이 프로젝트 룰 만들어줘" |
| "generate AI rules" | "AI 룰 만들어" |
| "upgrade the project rules" | "프로젝트 룰 고도화해줘" |
Two gates, and the rule set is not done until both pass.
scripts/verify_rules.py <project-root> — the form gate. Strict by default:
exceeding a target budget fails rather than warns. --lenient demotes target
overruns to warnings; hard limits fail either way. It checks:
- bidirectional link integrity, and that
ARCHITECTURE.md,CODING_RULES.md, andPITFALLS.mdexist and are linked - line budgets: AI_RULES.md ≤60 (hard 80), docs ≤150 (hard 190), playbooks ≤80 (hard 100)
- both runtime entries are valid relative symlinks to
AI_RULES.md, or both are portable pointers - Core Rules ≤10 bullets, and routing rows whose trigger is neither empty nor a restatement of the file name
- every graded rule carries a
why:line and a ✅ example - placeholder scan, UPPERCASE naming
- citation freshness — a cited
src/db.py:42fails both when the file is gone and when the file is shorter than 42 lines, which is how a rule that quietly survived a refactor gets caught.Dockerfile,Makefile, and dotfiles count as citations; bare naming patterns likeUPPERCASE.mddo not.
Quiz test — the content gate. A fresh subagent answers 5 questions given ONLY
AI_RULES.md once and the generated docs, with no source access:
- 3 recall — "Where does a new model have to be registered?"
- 1 judgment — "I want to do X; is approach Y allowed?" (measures application, not recall)
- 1 negative — something the rules do not cover. It passes only if the agent says "not in the rules, check the source" instead of inventing an answer.
- Pass = ≥4 correct AND the negative question passed.
scripts/quiz.py builds the isolation prompt and grades the run, archiving it to
.rule-architect/quiz/<run-id>.json. It deliberately does not execute a model —
the skill dispatches the isolated subagent, and a quiz "pass" with no archived run
does not count.
scripts/manifest.py records a SHA-256 for each generated regular file and records
the type and target for each runtime symlink. It merges into the existing manifest
(--replace records a complete set instead). Before an update run,
manifest.py check compares the working tree against those records:
| Exit | Meaning | Policy |
|---|---|---|
| 0 | generated files unchanged | safe to regenerate |
| 1 | a file was hand-edited, or is missing | conflict — never overwrite, report and ask |
| 2 | no manifest (legacy project) | treat every rule file as hand-written; add only |
This is what replaces "commit your rule index first and hope". The old single marker at the bottom of a rule index could not tell a hand-written rule from a stale generated one; a per-file hash can, and the policy on ambiguity is to stop rather than guess.
scripts/scan.py <root> prints a JSON manifest of the measured signals — stack,
layer directories, enum-defining files, deploy artifacts, git co-change groups —
the conditional-doc decisions derived from them, each with its evidence. It also
reports brokenRuleLinks, which blocks an update before a damaged entry is mistaken
for a new project.
Same commit in, same manifest out. Git history is scoped to the project directory,
so a project nested inside a larger repository does not inherit that repository's
commits.
Every traversal is bounded (--max-files, --max-bytes, --max-commits), vendor
and build directories are skipped, and hitting a cap sets a truncated flag, so a
partial scan can never be mistaken for a complete one.
A repo scan knows what the project contains. It cannot know what the agent kept
getting wrong in it. scripts/harvest.py <root> reads this project's past session
transcripts and prints your own corrections — recency-ordered, credential-redacted,
with a table of the terms that recur across different corrections. Corrections are
the highest-yield rule source there is: someone already paid for each one.
The script only measures. A candidate is promoted to a rule only when it repeats
(≥2 corrections), is recent, belongs to this project, and still agrees with the
current code — then it cites file:line evidence like any other rule. Nothing from
the harvest lands in a rule file verbatim.
python3 scripts/harvest.py <root> --days 180 --limit 60Rules a machine can enforce — forbidden calls, forbidden imports, banned paths — are not written into the docs. Prose depends on the agent having loaded and honoured it; a hook does not. They are listed in the final report as hook promotion candidates, and emitted only when you explicitly ask:
python3 scripts/hookgen.py emit <root> --rules spec.json # spec + guard, prints the settings entry
python3 scripts/hookgen.py emit <root> --rules spec.json --write # also merges it into .claude/settings.json
python3 scripts/hookgen.py check <root> # what is already installedTwo rule shapes: forbid matches a regex against the text a call would write; deny blocks a path
outright for the tools it lists (["Read", "Grep", "Glob"] keeps an off-limits directory unread — a
repo-wide grep with no path is the one case it cannot attribute).
emit installs .rule-architect/hooks.json (the rules) and .claude/hooks/rule_guard.py
(a generic PreToolUse guard that reads them). The guard blocks the call and tells the
agent which rule it broke; it fails open on any internal error, so a guard bug can never
wedge a session. --write edits your harness config, so it is never passed on its own.
Only rules whose violation a regex can name get promoted. Anything needing type information, call graphs, or judgement stays prose.
If the md-en-kr skill is installed, the run offers English compression at the end. It is an offer, never automatic.
python3 tests/test_rules.py # clones the fixture per case, breaks one contract, asserts the failureLayout:
scripts/ scan.py, harvest.py, manifest.py, verify_rules.py, quiz.py,
hookgen.py, rule_guard.py (copied into projects, not run here)
tests/ test_rules.py + fixtures/good/ (a rule set that passes strict)
docs/adr/ decisions and their consequences
archive/ dated records from earlier builds — not the current contract
archive/ holds dated internal records from the original build, kept in Korean as
written. They are not the current contract and are known to have drifted from it;
archive/README.md names the drift.
MIT — see LICENSE.