Skip to main content

draft

Turn a correction or rule the user stated in this conversation into a cc-enforcer rule file (hookify.<name>.local.md), show the complete draft, and save it only after the user approves and picks the project or personal folder. Use when the user runs /cc-enforcer:draft or asks to make a correction into a rule.

Source facts

Repository
rsmdt/cc-enforcer
Last source activity
October 9, 2026 at 13:30
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
draft
description
Turn a correction or rule the user stated in this conversation into a cc-enforcer rule file (hookify.<name>.local.md), show the complete draft, and save it only after the user approves and picks the project or personal folder. Use when the user runs /cc-enforcer:draft or asks to make a correction into a rule.
# Draft a rule from the conversation You turn something the user corrected or stated in this conversation into one rule file that cc-enforcer enforces from the next tool call on. You write nothing until the user approves the draft. ## 1. Find the correction Look back through the conversation for the most recent correction or stated rule: the user stopping or undoing something Claude did ("don't edit applied migrations, add a new one"), a convention they spelled out ("components live in `src/components/<Name>/`"), or a check they want every time ("never push to main"). If the user passed text with the command, that text is the rule. If there is no correction and no stated rule, say so plainly — "I found no correction or stated rule in this conversation" — and ask what the rule should be. Do not invent one. Stop there and wait for the answer. ## 2. Draft the complete rule file Write one rule per file, named `hookify.<name>.local.md`. Fill in every part: - **name** — short kebab-case, saying what the rule guards (`no-applied-migration-edits`). - **event** — when it is checked: `bash` (a Bash command), `file` (Edit, Write, MultiEdit), `stop` (Claude ending its turn), `prompt` (a prompt the user submits) or `all` (every tool call, stop and prompt). Pick the narrowest event that catches the mistake. - **action** — `block` stops the action and tells Claude why; `ask` pauses a tool call for the user's approval (only on `bash`, `file` or `all`); `warn` lets it run and hands Claude the message. Use `block` for what must never happen, `ask` when it is sometimes right, `warn` for a reminder. - **tool_matcher** — optional: exact tool names separated by `|`, or `*`. - **conditions** — all must hold. Each has a `field`, an `operator` and a `pattern`. For one regular expression on the event's main text, the simple form `pattern:` replaces `conditions`. - **message** — the body after the frontmatter. Claude reads it when the rule applies, so say what is wrong and what to do instead; a message that names no allowed alternative leaves Claude guessing. **Fields by event:** | Event | Fields | |-------|--------| | `bash` | `command` | | `file` | `file_path`; `new_text` (the new text of an Edit, the content of a Write, MultiEdit new strings); `old_text` (the replaced text); `content` (the Write content, else `new_text`) | | any tool call | any key of the tool's input | | `prompt` | `user_prompt` | | `stop` | `transcript` (its last 32 KB) | The simple `pattern` checks `command` on `bash`, `new_text` on `file`, `user_prompt` on `prompt` and `transcript` on `stop`. **Operators:** `regex_match` (case-insensitive, matches anywhere); `contains`, `equals`, `not_contains`, `starts_with`, `ends_with` (literal, case-sensitive); `llm_evaluate`, whose pattern is a plain-language yes/no question the user's model answers about the field ("Does this change an existing migration rather than add a new one?"). Use `llm_evaluate` only when no pattern can say it, and pair it with a `regex_match` that narrows where it is asked. `llm_evaluate` is not allowed on `stop`, and `ask` is not allowed on `stop` or `prompt`. **Regular expressions** are JavaScript regular expressions, always case-insensitive. Python forms `(?P<name>…)`, `(?P=name)`, `\A`, `\Z` and a leading `(?i)`, `(?s)` or `(?m)` are accepted; other Python-only syntax (atomic groups, possessive quantifiers, conditionals) makes the file invalid. Write patterns unquoted in YAML; quote one only when it starts with a character YAML treats specially (`*`, `&`, `!`, `[`, `{`, `>`, `|`, `@`, `` ` ``, `%`, `'`, `"`) or contains `: ` or ` #`. ## 3. Show the draft and ask Show the whole file in one fenced block with its file name, then ask two things in one message: 1. Approve it as it is, or say what to change. 2. Save it to the **project** folder (the `.claude/` folder that holds this project's rules, shared with everyone on the project) or the **personal** folder (`~/.claude/`, every project on this machine). Do not create, write or edit any file before the user approves. If they ask for changes, show the revised complete file and ask again. If the draft uses `ask` or `llm_evaluate`, add this warning under it: > Hookify does not understand `ask` or `llm_evaluate`. If Hookify is also installed, it treats `ask` as `warn` (it shows the message and lets the action run), and a rule with an `llm_evaluate` condition never fires there. ## 4. Save on approval After the user approves and names a folder: 1. Project: the nearest `.claude/` folder that already holds `hookify.*.local.md` files, searching from the working directory up to and including the git root (outside a repository, only the working directory's `.claude/`); cc-enforcer reads project rules from that one folder only. When no such folder exists, use `.claude/` at the git root, or in the working directory outside a repository. Never create a rule folder nearer than an existing one: the nearer folder would take over and the existing project rules would stop applying. Personal: `~/.claude/`. Create the folder if it does not exist. 2. If `hookify.<name>.local.md` already exists there, show the existing file and ask before replacing it. 3. Write the approved text exactly as shown, as `hookify.<name>.local.md`. 4. Tell the user where it was saved and that it applies from the next tool call — no restart needed. To switch it off later: `/cc-enforcer-toggle <name> off`; to list rules: `/cc-enforcer-rules`. ## Examples A correction about migrations — never edit one that was applied: ```markdown hookify.no-applied-migration-edits.local.md --- name: no-applied-migration-edits event: file action: block tool_matcher: Edit|MultiEdit conditions: - field: file_path operator: regex_match pattern: db/migrations/.*\.sql$ --- Applied migrations must not change. Add a new migration file in db/migrations/ that makes the change instead. ``` A command the user wants to approve each time: ```markdown hookify.confirm-force-push.local.md --- name: confirm-force-push event: bash action: ask pattern: git\s+push\s+.*(--force|-f\b) --- Force-pushing rewrites shared history. Prefer `git push --force-with-lease`, or push a new commit instead. ``` A convention no pattern can state: ```markdown hookify.components-in-own-folder.local.md --- name: components-in-own-folder event: file action: block tool_matcher: Write conditions: - field: file_path operator: regex_match pattern: \.tsx$ - field: content operator: llm_evaluate pattern: Does this file define a React component outside a src/components/<Name>/ folder of its own? --- Each component lives in src/components/<Name>/<Name>.tsx. Create the folder and put the component there instead. ``` A reminder at the end of a turn: ```markdown hookify.run-tests-before-done.local.md --- name: run-tests-before-done event: stop action: warn pattern: \b(done|finished|complete)\b --- Run the test suite and report its result before saying the work is done. ```
View on GitHub