Pattern packs
Most categories are one pack file. A pack whose category is a string joins that category, as closing-offer.json and backtick-branches.mjs join claude-tells. The built-in packs live under hooks/lib/patterns/: ai/ for writing patterns, git/ for commit, PR, and review checks, prose/ for punctuation. A project adds its own packs the same way.
A .mjs pack executes code from the checkout. The hook imports it, so its top-level code and its detect function run in the hook process with your permissions on every tool call. Read a .mjs pack before you add it. A .json pack holds data only.
- Where packs load from, in order
Each source is walked recursively, sorted by name, and only
.jsonand.mjsfiles are read. - Pack fields
Pattern entry fields:
- The three pattern kinds
Every
'inside aphraseor anopeningcompiles to['’], so the straight and the curly apostrophe both match. - scope values and the hook that feeds each
check-edit.mjsalso reads a file thatcatorteewrites from a heredoc, and a notebook cell: a markdown cell as a prose file, a code cell as a code file. - presets semantics
A built-in pack lists the presets it belongs to.
- excludePacks and options
features.aiWriting.excludePacksdrops a pack by id, built-in or not: - A JSON pack
Save this as
.claude/concise/patterns/team-words.json: - An .mjs pack
Save this as
.claude/concise/patterns/long-sentences.mjs: - Manage packs from the console
The
concise-webconsole from the npm package can also switch, add, update, and remove packs. - Validate and render
The validator checks the built-in packs plus any paths you pass, prints
ok: <N> packs, <M> patterns, and exits 1 on a problem.