TL;DR Create
.claude/claude-security-guidance.mdand write your repo's security rules in plain language: "never logcustomer_id", "every/adminroute must callrequire_role". Thesecurity-guidanceplugin loads it as context in its model-backed reviews (end-of-turn and commit), and starts flagging violations the generic checklist had no way to know about. Heads up: it's additive guidance, not a wall. It blocks nothing.
The security-guidance plugin reviews Claude's code in three layers. Two of them use the model (one at the end of each turn, one on each commit) and check your diff against a built-in vulnerability checklist: injection, unsafe deserialization, SSRF, weak cryptography. That checklist is generic. It knows nothing about your repo: not that you never log customer_id here, not that every admin route goes through a guard. You hand it that yourself, in .claude/claude-security-guidance.md.
The file: your threat model in plain language
It isn't schema-based config. It's plain text, the rules you'd hand a human reviewer joining the team:
# Security guidance for this repo (.claude/claude-security-guidance.md)
- Do not log `customer_id` or `account_number` at INFO level or above.
- All routes under `/admin` must call `require_role("admin")` before any database read.
- Use `crypto.timingSafeEqual` for token comparison, never `===`.
The model-backed reviews load this alongside the built-in checklist. From then on, if Claude writes a log.info(customer_id), the end-of-turn review flags it as a finding and Claude fixes it in the same session, even though "don't log customer_id" is nothing any generic checklist could have guessed.
Which layer reads it (and which doesn't)
The plugin has three layers. This guidance is read by only the two that use the model:
| Layer | When | Reads your guidance |
|---|---|---|
| Per-edit patterns | On each edit (deterministic, free) | No |
| End-of-turn review | When each turn ends | Yes |
| Commit review | On each commit or push Claude makes | Yes |
The per-edit layer is a text match with no model, and you extend it with a different file, .claude/security-patterns.yaml (its own tip). This Markdown guidance is the judgment layer: the model reads it, not a regex.
Where you put it
It's looked up in three places, and every one that exists is loaded and concatenated (user, then project, then local), with a combined 8 KB cap:
| Scope | Path | For |
|---|---|---|
| User | ~/.claude/claude-security-guidance.md |
All your projects |
| Project | .claude/claude-security-guidance.md |
Checked in with the repo |
| Project local | .claude/claude-security-guidance.local.md |
Gitignored, your overrides |
The project one is the important one: commit it and the whole team inherits the same threat model. Everyone's reviewer now knows the house rules without anyone repeating them.
Heads up: it's guidance, not a wall
This is what the docs make clear, and it's worth remembering:
- It's additive and doesn't block. It adds context to the checklist, it doesn't replace it. No layer stops an edit or a commit: the finding reaches Claude as an instruction to fix, and the model can miss things.
- It can't be used to silence. A rule that says "ignore SSRF" does not suppress those findings. The guidance only adds, never subtracts.
- If you need hard enforcement, this isn't the place: use a hook that blocks the edit, or a CI check.
- The model-backed reviews spend tokens (Opus 4.7 by default). The per-edit layer, the
security-patterns.yamlone, is the free one.
Reference
| Extension | File | Read by | Cost |
|---|---|---|---|
| Threat model in plain language | .claude/claude-security-guidance.md |
Model-backed reviews (turn and commit) | Tokens |
| Deterministic patterns | .claude/security-patterns.yaml |
Per-edit match | Zero |
Official docs: Add guidance for the model-backed reviews
Requirements
- The
security-guidanceplugin installed (CLI v2.1.144+). - A git repository (the turn and commit reviews diff against git).
- Active Anthropic authentication: without it, the model-backed layers skip and only the per-edit match runs.