An opinionated engineering config for Claude Code. Rules, runtime hooks, and slash-command skills that turn the CLI into a strict pair-programmer.
Quick Start | Contributing | Security | Issues | Releases
49 always-on rules, 143 on-demand standards, 42 skills, 98 hooks, and 18 agents, plus a 905-item review checklist in 71 categories.
The guardrails need no command. Every Bash, Write, and Edit call passes through the hooks before it runs, and a blocked call never runs: Claude reads the refusal and changes course. The same refusal, reproduced from a shell with a fixture from this repository:
$ python3 ~/.claude/hooks/dangerous-command-blocker.py < ~/.claude/tests/fixtures/bash-force-push.json
BLOCKED: Use --force-with-lease instead of --force
Command: git push --force origin main
$ echo $?
2Workflows are skills, typed as slash commands inside a session:
/plan add rate limiting to the login endpoint
/review --local
/ship commit --push
/investigate why the import job times out
Each layer catches what the layer above it missed.
graph LR
A[Session starts] --> B[CLAUDE.md and rules/ load]
B --> C[Claude loads the standards that rules/index.yml matches]
C --> D[Tool call]
D --> E{PreToolUse hooks}
E -->|exit 2| F[Call refused, Claude revises]
E -->|exit 0| G[Tool runs]
G --> H[PostToolUse hooks]
H --> I[Stop hooks format and type-check]
| Layer | What it enforces | When it runs |
|---|---|---|
CLAUDE.md + rules/ |
Always-on engineering rules, tone, anti-hallucination, verification gates | Every conversation |
standards/ + rules/index.yml |
Domain expertise that loads on trigger keywords | When the task needs it |
hooks/ |
Runtime blocks for destructive commands, secrets, banned patterns | Before every tool call |
skills/ |
Documented multi-step workflows: ship, review, plan, audit | When the user invokes /<name> |
agents/ |
Specialized subagents for focused review tasks | When delegated explicitly |
checklists/ |
905-item review checklist for code, infra, and process | On demand during review |
49 rules in rules/ plus 5 in rules/lang/. Every file under rules/ loads into every conversation as a short core, including the language files and the six listed after the table. Each core keeps the obligations that change behavior on an ordinary task and links to its full text in standards/, so the always-loaded set stays at 97,312 characters across 57 files, under the 120,000-character budget CI enforces and the harness limit of 150,000.
| Rule | What it covers |
|---|---|
architecture-defaults |
Six-question architecture gate. Forces DDD, hexagonal, idempotency, dedup, and state-machine standards to load when the task warrants them. Hard rules baseline |
code-style |
DRY/SOLID/KISS, immutability, error classification, branded types, completeness rule, platform-first API selection, no-comments policy, which yields only to a project instruction file that explicitly requires JSDoc or doc comments |
design-philosophy |
Complexity manifestations and root causes, deep modules, strategic vs tactical, design it twice, red flags, design taste |
testing |
Integration-first, strict mock policy, unlabeled Arrange-Act-Assert test structure, expected values from an independent source rather than a recomputation of the code, fake data, deterministic tests. An assertion, test case, or test file is never weakened, skipped, or deleted to make a change pass. Coverage is 100% on every hand-written file with no exclusion directive, and every user-facing entry point and requirement scenario has an end-to-end test |
security |
Secrets, auth, encryption, data privacy, audit logging, supply chain |
git-workflow |
Conventional commits, branches, CI monitoring, PRs whose description carries before and after Evidence and a Merge Danger call: a one-way or two-way door and the blast radius |
verification |
Evidence-based completion gates, response self-check, and a full read of every in-scope file on the first pass of any analysis |
writing-precision |
Precision gate for all text output, plus pronoun discipline, active voice, tone calibration, the requirement that every stated decision carries the measurement behind it, and terms taken from the code or the user rather than coined |
anti-slop |
The structural layer beneath the phrase blocklist. Three deciding tests, the catalogue of rhetorical and grammatical tells drawn from the WikiProject AI Cleanup field guide, the positive signals of human technical writing, and a guard against overcorrection |
normative-keywords |
BCP 14 (RFC 2119 + RFC 8174) keyword glossary. Lowercase primary, uppercase opt-in for critical correctness, security, data integrity, and irreversibility |
repo-analysis |
Clone external repos to a temp directory instead of fetching files via gh/raw URLs. Mandatory shallow-clone workflow, carve-outs for issue/PR/search ops, subagent briefing |
pre-flight |
Duplicate check, market research, architecture fit, interface verification, semantic verification of thresholds copied from existing code, and a test baseline plus a read of the covering tests before the first edit |
surgical-edits |
Every changed line traces to the request |
ai-guardrails |
AI output review, plan before generating, multi-agent validation |
memory-supersede |
Supersede-not-delete for project and feedback memories |
language |
Response language enforcement: all output in English |
smart-questions |
Question format, mandatory recommendation when presenting a choice, status reports, FIXED/RESOLVED/DONE loop closure, Tatham bug-report essentials |
found-fix |
Any verification-surface finding is in scope for the current task. Bans the rationalization phrases that defer fixes to a later session |
user-commands-one-line |
Commands handed to the user to run go in one safe line: a strict-mode subshell, steps joined with &&, gates that fail by exit code, ${VAR:?} on every recursive delete. A result the user must judge before an irreversible step is handed alone, never chained into the change |
same-turn-persistence |
A correction produces a file write before the turn that received it ends. Self-caught mistakes count the same as user-caught ones, the write targets the root behavior rather than the symptom, and an admission bar keeps mandatory persistence from inflating the config |
rule-provenance |
A rule's history lives in the private vault, never in the repository: files state only the current rule. A lesson is logged first and promoted on its third recurrence, unless it is irreversible, silent, or catastrophic |
relay-not-source |
A subagent report, search snippet, or summary is a relay. Relays garble the citation coordinate and not only the content, so a specific claim reads as correct while pointing at the wrong line, timestamp, or record |
agent-operating-limits |
Backstops versus budgets, turn ceilings that carry their measurement, caps whose overflow is reported rather than dropped, the cost of a denied call and of unconditional context injection, and fail-closed on any check that could not run |
deviation-waivers |
Deviating from a rule is allowed, deviating silently is not. A structured waiver with scope, approver, alternatives, and a revisit condition, distinct from a mechanical bypass because it answers a different question. A project's own instruction file may explicitly override a global rule inside that project, never across the security, legal, data-loss, verification, or truthfulness lines |
no-ai-process-leak |
Blocks phase-N markers, plan-path references, spec-folder links, hyperbole tells, and self-criticism from commit messages, PR descriptions, published docs, and messages to colleagues |
no-committed-symlinks |
No repository tracks a symbolic link. Shared source goes through the build, a file needed twice is committed once, and a file from a submodule is committed as its own bytes |
doc-truth |
Documentation that describes code is a claim about the code. A change that falsifies a claim corrects it in the same commit. Four mechanically certain checks at git commit; historical records exempt. A project doc that describes a convention the code consistently no longer follows is stale: the code wins and every mismatch is reported |
markdown-links |
Every file mention in published markdown is a clickable link. Validator and PreToolUse hook enforce |
living-specs |
Non-trivial changes maintain a specs/current/ living behavioral spec: requirements, Given/When/Then scenarios, ADDED/MODIFIED/REMOVED deltas kept in the plan folder inside the local workspace, and a close-out merge that folds a completed change into the spec |
project-workspace |
Every repository keeps the user's working material in a local workspace that is never committed: <repo>/docs/ unless the project owns it, then <repo>/.work/, ignored through .git/info/exclude only. PROMPT.md there stays pasteable into a new session. The README is the single source of truth for the project |
compliance-defaults |
Umbrella for the compliance family. Strictest applicable rule wins, and a published standard counts as binding before its effective date |
accessibility-defaults |
WCAG 2.2 AA floor with AAA where it does not conflict. Keyboard operability, 44x44 targets, reduced motion, no image CAPTCHA |
frontend-render-gate |
A change to rendered output is unverified until something renders it. Names the blind class static review and jsdom cannot reach: cascade outcome, paint order, accessibility tree, focus order, third-party iframes. Ranks evidence tiers, extending the project's own browser or simulator harness first. Every PR, review reply, issue, and tracker comment about a visible change attaches high-resolution Before and After screenshots, for web, mobile, desktop GUI, and TUI |
ai-review-convergence |
Bounds the loop when automated reviewers comment. Zero bot comments is unreachable, so the stop condition is a round with no verified failure. Failure-scenario gate before fixing, minimal diff on response commits |
pr-comment-discipline |
The only comment published on a pull request is a reply inside a thread a person opened. No summary body, no conversation comment, no commit-comment reply, no reply of any length to a bot. Bot threads are read, fixed when real, then resolved in silence. Replies carry a four-sentence ceiling, and anything fixable in the open change is fixed there rather than filed |
functional-index-fidelity |
A database uses an expression index only when the query expression is identical to the indexed one, so an equivalent rewrite silently becomes a sequential scan with no error and no failing test |
privacy-defaults |
GDPR-grade by default in every market. Lawful basis, 30-day DSAR, true erasure, 24-month retention, pseudonymous data treated as personal |
cookie-discipline |
Opt-in for every non-essential cookie, reject-all at click parity with accept-all, no cookie walls, no pre-ticked boxes |
cybersecurity-baseline |
Frontend security defaults: nonce-based CSP, TLS 1.3, NIST password policy, session timeouts, breach-notification windows |
consumer-defaults |
14-day withdrawal, total price up front, click-to-cancel parity, no fake scarcity or fake reviews |
children-privacy-defaults |
18 for profiling and ads, 16 for accounts, verifiable parental consent under 13. Bans engagement-pressure patterns for minors |
ai-compliance-defaults |
EU AI Act risk tiers, visible disclosure on model output, human review for automated decisions, annual bias audits |
anti-spam-defaults |
Opt-in marketing consent, one-click unsubscribe, permanent suppression lists, strict transactional and marketing separation |
Plus 5 language-specific files in rules/lang/: typescript-immutability, typescript-types, typescript-strict, orm-migrations, python.
Six more rules in rules/ load every session like the rest and apply only when their condition holds; each also has an on-demand standard in rules/index.yml that carries its full text: artifact-identity for files a person must supply because the project may not distribute them, emulator-runs for launching an emulator headless or minimised and never full screen, docker-dependencies for keeping every project dependency in the Docker image and none on the host, knowledge-notes, everyday-engineering, and project-glossary.
143 standards in standards/. Each entry in rules/index.yml declares trigger keywords. When a task matches, only those standards load.
Topics: API design, authentication, caching, code review, concurrency and race conditions, container security, contract testing, database, DDD, debugging, distributed systems, idempotency and deduplication, immutability across languages, documentation, frontend, GraphQL, hexagonal architecture, i18n, infrastructure, low-latency engineering, message queues, mobile, monorepo, observability, authoring agent instruction files, OpenTelemetry, performance, postgres, PR comment channels, print design, privacy, redis, resilience, secrets management, SRE, state machines, twelve-factor, TypeScript 5.x, WebSocket, zero-downtime deployments, and more.
42 skills in skills/. Each is a folder with a SKILL.md that documents steps, output format, and rules, in the six-section template that tools/lint-skills.py enforces with --strict in CI: Overview, When to Use, Process, Common Rationalizations, Red Flags, Verification. The linter also parses frontmatter as strict YAML and rejects a description that a # would silently truncate.
Two kinds of skill. A model-invoked skill keeps its description, with trigger phrases, in every session's context, so Claude can reach it on its own. A user-invoked skill sets disable-model-invocation: true: its description leaves the context, it costs nothing until typed, and only the user can start it. The hand-fired ones are user-invoked: /deploy, /cleanup, /hotfix, /guard, /setup, /skill-new, /incident, /readme, /gan, /migrate, /assessment, /module-audit, /benchmark, and /session-log. A skill that another skill must call stays model-invoked, which is why /pr-summary and /fix-issue do: /morning hands work to them.
| Skill | What it does |
|---|---|
/ship |
Delivery pipeline: commit, PR, release, CI checks, worktrees |
/review |
Three-pass code review, QA analysis, visual audit |
/respond |
Handle incoming review comments: classify, verify, draft replies, validate locally, post, resolve, monitor CI |
/assessment |
Architecture completeness audit. Finds missing patterns, planted defects, and standout opportunities. Grades AI slop with tools/slop-scan.py, which runs the ai-slop-blocker detectors over every Markdown file and a commit range, and removes it by deletion. Outputs a machine-readable findings table that /respond can consume. Flags README badges that differ from the standard block |
/plan |
Spec folders with discovery, scope review, ADRs, scaffolding |
/audit |
Security audit, threat modeling, supply chain checks. /audit trust adds untrusted-project safety scanning with IOC catalog at trust-patterns.md |
/test |
Test execution, perf, lint, CI smoke, stub generation |
/deploy |
Post-merge landing and canary monitoring |
/investigate |
Systematic debugging with hypothesis testing, 3-strike limit |
/research |
Multi-source research with entity resolution and citation discipline |
/design |
Design consultation, variants, design-system work |
/refactor |
Guided refactoring with behavior preservation |
/migrate |
Framework or library migration with incremental testing |
/infra |
Container orchestration, IaC, database migrations |
/hotfix |
Emergency production fix with expedited workflow |
/incident |
Incident context gathering, blameless postmortem |
/resolve |
Merge conflict resolution with verification |
/cleanup |
Stale branch, PR, and worktree cleanup |
/checkpoint |
Save and resume state across sessions. Inside a repository it writes the workspace PROMPT.md |
/explain |
Code explanation with Mermaid diagrams |
/fix-issue |
Fix a GitHub issue by number with tests |
/guard |
Directory freeze and scope enforcement |
/benchmark |
Performance regression detection with baselines |
/profile |
N+1 queries, missing indexes, complexity hot spots |
/onboard |
Codebase onboarding: architecture map, "Start Here". Phase 0 prompts before running the trust scan. Flags --trust and --verify pre-decide non-interactively |
/gan |
Generator-Evaluator iteration loop for building features against a scored rubric. Iterates planner, generator, and evaluator subagents until the threshold is met |
/pr-summary |
PR summary with reviewer suggestions |
/readme |
README generation from codebase analysis. Every claim comes from the code, the English file must pass tools/slop-scan.py, and every run also writes Japanese, Simplified Chinese and Hong Kong Traditional Chinese translations with a language switcher; --languages es adds Spanish. The header badges come from tools/readme-badges.py: CI, release, coverage, OpenSSF Scorecard and license, in that order, flat-square |
/retro |
Session retrospective with pattern extraction |
/morning |
Cross-account work triage. Sweeps every authenticated git identity and its organizations, ranks by who is blocked, reports, then works the queue with per-item consent. Merging is blocked mechanically for the run |
/session-log |
Session activity logger for handoff |
/setup |
Interactive project environment setup |
/tdd |
Test-driven development loop. Vertical slices, no horizontal write-tests-then-all-impl |
/zoom-out |
Step back from tactical work to strategic view |
/spike |
Throwaway artifact that answers one design question, two routes (state-branch terminal program, view-branch side-by-side variations) |
/module-audit |
Codebase audit for shallow modules with before-and-after Mermaid recommendations and deletion-test classification |
/concise-mode |
Opt-in terse-reply mode. Drops filler and pleasantries while preserving code blocks, error strings, and destructive-action confirmations |
/cross-model |
Consult a different model for orthogonal reasoning on a consequential decision, especially when confident. Discovers whichever model CLI is installed rather than assuming a vendor, and treats the answer as a relay to re-verify |
/brain |
Read from and write to the second-brain vault. Capture, ingest, ask, link, health, refresh, falsify, wrong, compile, eval. falsify hunts facts that are wrong rather than merely old; wrong logs a miss with its cause so the dominant failure mode becomes visible |
/interview-me |
One-question-at-a-time intent clarification for an underspecified ask, driven to high confidence before any implementation |
/aside |
Freeze the active task, answer a side question with no state mutation, then resume exactly where it stopped |
/skill-new |
Scaffold a new skill with the enforced frontmatter and section template, then validate with the skill linter |
98 hooks in hooks/ wired through settings.json. Each runs before, after, or around a tool call.
Bypass channels. Every hook supports two. Either grants a pass; both coexist.
- Parent-shell env var
<NAME>_DISABLE=1(set before launching Claude Code). - In-session file registry
~/.claude/.bypass-state.json. Engage from a live session viapython scripts/bypass.py set <hook> --ttl 600 --reason "<why>"; clear withpython scripts/bypass.py clear [<hook>]; inspect withlist. TTL clamps to [60, 3600] seconds; the 60-minute ceiling is intentional so a forgotten bypass cannot stick. Wildcard entries (set "*") short-circuit every hook until expiry, with a default TTL of 5 minutes and a ceiling of 20. The reader enforces the same ceilings, so a hand-written entry with a far expiry is ignored, and config protection blocks Write and Edit on the registry file. File mode is 0600. Seehooks/_lib/bypass.py.
Block-message schema. New hooks render their stderr through hooks/_lib/output.py block(...). Five sections in fixed order (What was detected, Why this rule exists, How to fix, If the rule does not apply here, Decision guidance for Claude), one of four decision verbs (STOP-AND-ASK, FIX-AND-RETRY, BYPASS-ONCE, BYPASS-WITH-REASON), both bypass channels named in every message. Validator at output.validate_block_message(...). See hooks/large-file-blocker.py for a worked example.
Adding a hook. Five steps, in order. Skipping step 2 is the quiet failure: the hook runs, exits 0 on every payload, and looks like it is passing.
- Write the test suite first under
tests/hooks/<hook-name>/.hooks/tdd-gate.pyblocks the source file until a matching test exists. The fixturestool_use,assert_blocks,assert_allows, andrun_hookcome fromtests/conftest.py; a hand-rolled subprocess call must propagateCOVERAGE_PROCESS_STARTandPYTHONPATHor its lines are never measured. - Register the hook ID in
STANDARD_HOOKSinhooks/_lib/hook_profile.py.should_runreturns False for any ID the active profile does not list, so an unregistered hook silently no-ops. - Wire the matchers into
settings.json, one entry per tool:Write,Edit,MultiEdit. - Import shared infrastructure from
_lib:_lib.hook_inputforread_hook_payload, which blocks on a payload the guard cannot read,_lib.suppressionfor third-party directives,_lib.bypassfor the file registry,_lib.audit_logfor the trail,_lib.outputforblock(...)andwarn(...),_lib.git_invocationto strip git global options such as-Cand-cbefore matching a subcommand. The module is_lib.suppression, never a baresuppression; the bare form does not resolve and the fallback silently disables directive support. - Ship detection-heavy hooks in warn mode first, blocking behind a
<NAME>_ENFORCE=1env var, and promote once the false-positive rate is known against real code.
| Hook | Trigger | What it does |
|---|---|---|
accessibility-mechanical-checks.py |
PreToolUse Write/Edit/MultiEdit | Catches the WCAG failures that are decidable from source: an image with no alt, an icon-only button with no accessible name, an input with no label, a click handler on a div with no role or key handler, tabindex above zero, a missing lang. Reads JSX tags with arrow functions and nested expressions intact, ignores capitalised components such as <Input>, and honours an eslint-disable-next-line naming the matching jsx-a11y rule. Bypass ACCESSIBILITY_CHECKS_DISABLE=1 |
ai-attribution-blocker.py |
PreToolUse Bash/Write/Edit | Blocks AI co-author trailers, Claude-Session trailers, and claude.ai session links in commits and PRs, and any git push whose outgoing commits carry one |
ai-disclosure-checks.py |
PreToolUse Write/Edit/MultiEdit | Blocks rendering model output with no visible AI disclosure, and chatbot UI with no label saying what it is. EU AI Act Art. 52, California SB 942. Bypass AI_DISCLOSURE_DISABLE=1 |
ai-process-leak-blocker.py |
PreToolUse Bash/Write/Edit | Blocks AI-process language in commits, PRs, release notes, and code comments. Catches phase-N markers, plan-path references, links into a spec folder or the local workspace, and hyperbole tells. In a source file only comments are scanned, so a product string such as a step label passes. Writes into the workspace or the session scratchpad are exempt, and a Bash command counts as publishing only when the publishing command sits outside quotes |
ai-review-request.py |
PostToolUse Bash | After gh pr create, gh pr ready or git push on an open PR the acting account authored, requests every AI review the repository supports: @claude review always once where the Claude App runs in manual mode, the claude-review label where a workflow is gated on it. CodeRabbit and Codex already review each push and get nothing. Never blocks; reports one ai-review: line. Also a CLI: --repo owner/name --pr N --account login [--dry-run]. Records each pull request it sees created in a per-session ledger that pr-comment-discipline.py reads. Bypass AI_REVIEW_REQUEST_DISABLE=1 |
ai-slop-blocker.py |
PreToolUse Bash/Write/Edit/MultiEdit | Blocks the structural slop tells that survive a phrase blocklist: negative parallelism, significance inflation, participial evaluation tails, unnamed authorities, hedged speculation, marketing verbs replacing is and has, throat-clearing, trailing recaps, chat residue, unfilled placeholders, curly quotes, search narration such as sites that refused or the date a check ran. Bold-label bullets and headings are blocked only inside a published PR comment. Codes SLOP001 to SLOP015. Search narration is allowed in the vault, the project workspace and PROMPT.md. Code spans are masked before matching, and every detector was calibrated against the 333 Markdown files under the rules, standards, checklists, skills, agents and docs directories plus the root documents. Bypass AI_SLOP_DISABLE=1 |
as-any-blocker.py |
PreToolUse Write/Edit | Blocks TypeScript as any and generic any. No allow marker; only third-party tool directives are honored. |
aws-profile-guard.py |
PreToolUse Bash | Blocks aws configure set without --profile |
banned-phrases-blocker.py |
PreToolUse Bash/Write/Edit | Blocks conversational fluff and tactical hyperbole in PRs and docs |
banned-prose-chars.py |
PreToolUse Write/Edit/Bash | Blocks em dashes, en dashes, parens in prose, emojis, ASCII art, and in Markdown prose a spaced hyphen standing in for a dash |
bulk-resolve-blocker.py |
PreToolUse Bash | Blocks multi-thread resolveReviewThread loops on GitHub or GitLab |
comment-blocker.py |
PreToolUse Write/Edit/MultiEdit/Bash | Blocks any comment added to source code, in every language it recognizes: C-family, Python, shell, YAML, Make, Docker, Terraform, SQL, Lua, Clojure, TeX, Vim script, HTML and its template dialects, CSS, assembly by dialect, Jupyter code cells, and more, resolved by extension, basename, shebang, or content. Docstrings and doc-comment blocks count as comments. An edit is resolved against the file on disk, so only newly added comments are reported. On a Bash git commit it scans every staged file against HEAD, which catches content written outside the Write and Edit tools. During a merge, a file the merge took unchanged from the other parent is skipped, since the merge authored nothing in it. Paths listed in the machine-local comment-waivers.txt, copied from comment-waivers.example.txt, are not checked. Exempt: tool directives such as eslint-disable, @ts-expect-error, noqa and action version pins, the bare Arrange, Act, Assert markers in test files, and .env.example files. Operator bypass COMMENT_BLOCKER_DISABLE=1 |
test-aaa-markers.py |
PreToolUse Write/Edit/MultiEdit/Bash | Requires every added or changed test in Python, JS/TS, Go, and bats to carry the bare Arrange, Act, Assert markers once each, in order, as three blocks separated by one blank line. Untouched legacy tests are not checked. On a Bash git commit it checks the staged files, skipping a file a merge took unchanged from the other parent. Bypass TEST_AAA_MARKERS_DISABLE=1 |
compact-context-saver.py |
SessionStart / PreCompact / PostCompact | Preserves git status across compaction, scoped per project |
config-protection.py |
PreToolUse Write/Edit/MultiEdit | Blocks edits to linter, formatter, and typechecker configs like tsconfig, eslint, ruff, mypy. Forces fixing code instead of weakening config |
console-log-blocker.py |
PreToolUse Write/Edit | Blocks console.* in non-test code. No allow marker; only third-party tool directives are honored. |
conventional-commits.py |
PreToolUse Bash | Validates conventional commit format |
commit-test-weakening.py |
PreToolUse Bash | Blocks a commit whose test files, summed across every changed and untracked test file that defines a test case and compared with the last commit, lose test cases or assertions or gain skip markers. It reads the working tree, so a test removed by a shell script is caught as well as one removed with Edit, and a test moved to another file nets to zero. Bypass COMMIT_TEST_WEAKENING_DISABLE=1 |
coverage-exclusion-guard.py |
PreToolUse Write/Edit/MultiEdit | Blocks an edit that adds a coverage exclusion directive to source, such as istanbul ignore, c8 ignore, pragma: no cover, #[coverage(off)], or LCOV_EXCL_LINE, and an edit to a coverage config that writes a threshold under 100. A new omit or exclude entry asks for confirmation, since only generated and vendored paths may be excluded. Prose files are exempt. Bypass COVERAGE_EXCLUSION_GUARD_DISABLE=1. |
dangerous-command-blocker.py |
PreToolUse Bash | 190 patterns: destructive shell commands, reverse shells, cloud deletions, IaC destroy. A heredoc body fed to cat, tee, git, gh or glab is data and is not matched; a body fed to a shell still is. A Docker or Podman flag such as -f, -a or -v counts only as its own token inside the same call, a protected path such as .git, .env or .claude counts only as an argument of the rm call itself, .git counts only as a whole path component, so a bare mirror named like name.git is an ordinary path, and deleting a .env file under a literal /tmp or /private/tmp path is allowed unless the path climbs out with ... Git global options such as -C and -c are stripped before matching, so git -C <dir> push --force blocks like the plain form, and -f or a cluster such as -fu counts as a force push. A build-directory cleanup skips the remaining checks only when every segment of the command is that cleanup. Input that is not valid JSON blocks. Protected-branch pushes are allowed when the repository the push targets, following cd and -C, is listed in a machine-local solo-repos.txt, seeded from solo-repos.example.txt; a push whose target cannot be determined never qualifies. Deleting a test file and searching / or the home directory with find, grep -r, rg, or fd raise a confirmation prompt, except a test file that is untracked and in no commit |
doc-sync-guard.py |
PreToolUse Bash | Blocks a git commit whose staged diff makes existing documentation false. Four certain checks: a variable the code reads that .env.example does not name, and an export, CLI flag, or package script removed while tracked markdown still names it. Checks the repository a leading cd or git -C names, and includes unstaged changes for commit -a. Changelogs, ADRs, and specs are exempt as historical records. Bypass DOC_SYNC_DISABLE=1 |
frontend-render-gate.py |
PreToolUse Bash, Linear save_issue and save_comment |
Blocks a git commit that changes rendered output (.tsx, .html, .dart, styles, theme tokens, native views such as *View.swift or *Screen.kt, desktop layouts such as .qml or .xaml, and sources importing a terminal UI library) without touching any render-level check: an e2e or browser suite, XCUITest, androidTest, or a terminal snapshot. A *.spec.tsx unit test does not count. Cascade outcome, paint order, the accessibility tree, focus order, and third-party iframes are invisible in source and absent from jsdom. At publish time it reads the branch diff against its base: gh pr create or edit, gh issue create, edit, or comment, a review-thread reply, glab mr create or update, and a Linear issue or comment on a branch with a visible change are blocked until they carry an After: image, plus Before: when an existing surface changed, each at least 1600 px on its longer side. Interface wording with no image and no visible change asks for confirmation. Images in one set must share one pixel width, and once one label names a device, every label names device and viewport; an image exactly one viewport tall asks for a full-page capture. Every attached After: image must show the #FACC15 change marker: sips downscales it to 360 px wide and at least 20 pixels must sit near that color. Before: images are exempt, an image sips cannot read blocks, and CHANGE_MARKER_SIPS replaces the sips command, split like a shell line. Attachment paths follow $VAR and cd, a path built from a command substitution is named as one the check cannot expand, and a tracker item is judged by its own text. Bypass FRONTEND_RENDER_GATE_DISABLE=1, or a TTL-bound entry in the shared bypass registry. |
docker-context-guard.py |
PreToolUse Bash | Forces --context or DOCKER_CONTEXT per call |
dockerfile-compose-quality.py |
PreToolUse Write/Edit/MultiEdit | Blocks .env and key/cert copies, secret-named ENV/ARG with literal values, Compose privileged: true, and host-namespace toggles. Warns on floating tags, USER root, deprecated top-level version:, and literal secrets in environment:. Bypass DOCKERFILE_QUALITY_DISABLE=1 |
drizzle-raw-sql-blocker.py |
PreToolUse Write/Edit | Blocks Drizzle raw query escape hatches, including on tx and trx receivers and in test files |
drizzle-schema-sync.py |
PreToolUse Write/Edit | Enforces Drizzle schema vs migration parity |
english-only-reminder.py |
UserPromptSubmit | Injects system-reminder forcing English assistant output |
env-file-guard.py |
PreToolUse Write/Edit | Blocks edits to .env, private keys, cloud creds, tfstate |
force-push-during-review.py |
PreToolUse Bash | Blocks history-rewriting pushes when a reviewer's latest review on the pull request is CHANGES_REQUESTED, in the repository the command targets; blocks when the review state cannot be read, and allows a branch with no pull request. Shares its force-flag patterns with the dangerous-command blocker, so -fu and global options are caught the same way |
foreign-session-guard.py |
PreToolUse Write/Edit/MultiEdit/NotebookEdit | Denies a write that lands inside another live Claude Code session's working directory, read from ~/.claude/sessions/, because that session reports the file as its own change, and tells the agent to give the user a prompt to paste into that session instead. A session whose directory contains this one is ignored, and in a directory two sessions share, the one that started first owns it. A write inside the knowledge vault named by SECOND_BRAIN_VAULT always passes, since every session shares it. Bypass FOREIGN_SESSION_GUARD_DISABLE=1 |
found-fix-rationalization-blocker.py |
PreToolUse Bash/Write/Edit | Blocks rationalization phrases that defer verification-surface findings to a later session. Targets commit messages, PR bodies, release notes, and code comments; in a source file only comments are scanned, and the session scratchpad is exempt. A publishing command inside a quoted string or heredoc body is data, not a commit |
gateguard-fact-force.py |
PreToolUse Write/Edit/MultiEdit | Forces reading a file before the first edit per session unless the user named the path. Operationalizes the pre-flight "Confidence" rule |
gcloud-config-guard.py |
PreToolUse Bash | Forces --configuration per call |
gh-run-watch-blocker.py |
PreToolUse Bash | Blocks gh run watch and equivalents that poll every 3s and burn the API rate budget, including glab ci view --live and glab ci status --wait or --live. Text in single quotes or a quoted heredoc body is not read as a command. Bypass GH_RUN_WATCH_DISABLE=1 |
gh-short-sha-guard.py |
PreToolUse Bash | Blocks gh run list --commit with a SHA shorter than 40 characters, which matches no runs and exits 0, so a CI wait built on it reports done or not started |
gh-token-guard.py |
PreToolUse Bash | Requires inline GH_TOKEN, blocks gh auth switch. Exempts gh auth plus invocations that reach no API (--version, --help or -h anywhere in the call, config, alias, completion). Reads commands on every line, and ignores gh text inside single quotes or a quoted heredoc body |
knowledge-note-guard.py |
PreToolUse Write/Edit/MultiEdit/Bash | Enforces the knowledge-note specification inside the second brain: missing frontmatter, missing ## For future agent preamble, an undated volatile claim, a wikilink to a note that does not exist, a pointer with no resolvable target (FRESH-3), a write into the immutable raw folder, a removal outside trash. Skips specs/, eval/ and tests/, which hold plan artifacts rather than notes, and the vault's local workspace folder when .git/info/exclude registers it. Bypass KNOWLEDGE_NOTE_DISABLE=1 |
memory-write-guard.py |
PreToolUse Write/Edit/MultiEdit | Keeps the session memory directory a generated artifact while a second brain vault is configured: every Write or Edit into the memory directory is blocked, since /brain compile writes it as a script, and an edit to MEMORY.md passes only when it leaves the compiled block unchanged. Completely inert when SECOND_BRAIN_VAULT is unset or does not resolve, so a clone without a vault keeps the harness default. Bypass MEMORY_WRITE_GUARD_DISABLE=1 |
privacy-leakage-checks.py |
PreToolUse Write/Edit/MultiEdit | Catches personal data in console.log, identifiers in localStorage, a cookie set with no consent check, and hardcoded analytics or marketing tracker IDs with no consent guard around them. Bypass PRIVACY_CHECKS_DISABLE=1 |
repo-fetch-blocker.py |
PreToolUse Bash | Blocks per-file source fetching via gh api .../contents, gh repo view <o>/<r> <path>, glab api .../repository/files, and raw.githubusercontent.com curl/wget. Forces a shallow clone instead, and its private-repo advice passes the token through a credential helper, never the URL. Text in single quotes or a quoted heredoc body is not read as a command. Bypass REPO_FETCH_DISABLE=1 |
git-author-guard.py |
PreToolUse Bash | Blocks commits with unresolved identity or placeholder authors, and a git config write to user.email or user.name outside --global; a bare key with no value is a read and passes |
glab-token-guard.py |
PreToolUse Bash | Requires inline GITLAB_TOKEN, blocks GitLab auth login. Exempts auth, config, version, and a --help or -h anywhere in the call |
interactive-cmd-blocker.py |
PreToolUse Bash | Blocks cp/mv/rm without -f. macOS aliases these to -i, which hangs the agent on confirmation prompts. A call prefixed with command skips the alias and passes, and quoted text and heredoc bodies are never read as commands. On macOS it also blocks kcov and a make coverage whose Makefile calls kcov, which trace through stderr there, have held 44 GB, and report a wrong number; it names the Linux-container recipe instead. It also blocks a mame launch that would open a window: no -window, a headless run missing SDL_VIDEODRIVER=dummy, -video none or -sound none, or a run marked MAME_WATCHED=1 without -nomaximize; informational commands such as -listxml pass. Bypass INTERACTIVE_CMD_DISABLE=1 |
zsh-special-name-guard.py |
PreToolUse Bash | Under zsh only, blocks the two traps a rule alone did not prevent: a zsh special name used as a variable, such as path, status, or argv, which replaces shell state so path= breaks every later command; and an unquoted word with a leading =, which zsh expands to a command path and aborts the rest of the command. Quoted text, heredoc bodies, and [[ ]] or (( )) comparisons are ignored. Unreadable input blocks. Bypass ZSH_SPECIAL_NAME_GUARD_DISABLE=1 |
internal-config-leakage.py |
PreToolUse Bash/Write/Edit | Prevents internal config references in external output. A gh or glab call that only reads, such as view, list, --help, or an api GET, is not publishing. A git commit, git tag or git notes that takes its message from -F <file> or --file checks that file and leaves the other words of the command, such as git add paths, alone |
kubectl-context-guard.py |
PreToolUse Bash | Forces --context or KUBECONFIG per call |
large-file-blocker.py |
PreToolUse Bash | Blocks commits with files over 5MB: the staged blob, plus files that commit -a or a same-command git add will include, in the repository a leading cd or git -C names |
markdown-link-discipline.py |
PreToolUse Write/Edit/MultiEdit | Blocks new bare file mentions in markdown when the path resolves to a real repo file |
mcp-health-check.py |
PreToolUse/PostToolUse mcp__* |
Tracks MCP server health in cache/mcp-health.json. Short-circuits calls to servers past the unhealthy-failure threshold |
migration-idempotency.py |
PreToolUse Write/Edit | Forces idempotent DDL: IF NOT EXISTS where PostgreSQL supports it, OR REPLACE for functions, views, triggers and procedures, a guarded DO block for types, policies, roles and users, and IF EXISTS on every DROP |
mise-global-guard.py |
PreToolUse Bash | Blocks mise use --global, forces project-local config |
mock-internal-blocker.py |
PreToolUse Write/Edit | Blocks mocking own services, DB, Redis, queues in tests, including Python dotted patch targets and root-level test_*.py files |
mutation-method-blocker.py |
PreToolUse Write/Edit/MultiEdit | Blocks 105 in-place mutation patterns in JS/TS. No allow marker; only third-party tool directives are honored. |
normative-keyword-discipline.py |
PreToolUse Write/Edit/MultiEdit | Blocks bullet items starting with Should or should in rules, standards, checklists, and CLAUDE.md. Enforces the BCP 14 weasel-words rule. Bypass NORMATIVE_KEYWORD_DISABLE=1 |
notify-webhook.py |
Stop | POST to CLAUDE_NOTIFY_WEBHOOK on response completion |
package-manager-guard.py |
PreToolUse Bash | Blocks npm, npx, yarn and pip installs and names the pnpm or uv command to run instead. Version probes such as npm --version, uv pip, and quoted text pass. Bypass PACKAGE_MANAGER_GUARD_DISABLE=1 |
pr-comment-discipline.py |
PreToolUse Bash | Blocks every command that publishes a pull-request comment outside a thread: the gh pr comment subcommand, gh pr review with a body, a reviews POST carrying a non-empty summary, a pulls/<n>/comments POST with no in_reply_to, an issues/<n>/comments POST, a commit-comment POST, a GitLab MR note or new discussion, and a parentless Bitbucket comment. Reads --input and --body-file payloads. A comment command inside a heredoc body is data. Leaves thread replies, empty-body review submissions, and description edits alone. Asks before a second gh pr create in a repository where the same session already opened one. Bypass PR_COMMENT_DISCIPLINE_DISABLE=1 |
pr-merge-blocker.py |
PreToolUse Bash | Refuses every pull request merge form while a /morning sweep holds the session lock. Covers gh pr merge, glab mr merge, REST merge endpoints, and GraphQL merge mutations. Silent outside a sweep, so /deploy land keeps working. Leaves git merge and gh pr update-branch alone. Bypass PR_MERGE_BLOCKER_DISABLE=1 |
prisma-raw-sql-blocker.py |
PreToolUse Write/Edit | Blocks Prisma raw query escape hatches, in test files too |
prisma-schema-sync.py |
PreToolUse Write/Edit | Enforces schema.prisma vs migration parity, including every column of a multi-column ALTER TABLE and field-level @unique(map:) names |
private-terms-guard.py |
PreToolUse Write/Edit/MultiEdit/Bash | Blocks a write, or a git commit of staged files, that puts a term from the private denylist into a published file of this repository. The denylist lives in the vault at .private-terms.txt, so the list itself is never published; with no vault or no list the hook allows everything. Git-ignored and out-of-repository paths are not checked. Undecodable input and an unreadable index block. Bypass PRIVATE_TERMS_GUARD_DISABLE=1 |
read-injection-scanner.py |
PostToolUse Read/WebFetch/WebSearch | Scans fetched content for prompt-injection patterns (instruction override, tool redirection, authority claims, base64 runs, unicode confusables) and emits a warning. Bypass READ_INJECTION_DISABLE=1 |
redis-atomicity.py |
PreToolUse Write/Edit | Forces atomic Redis sequences via Lua/MULTI, and flags locks taken without a TTL. A read and a write count as a race only on the same receiver, and never on a Map. No allow marker; only third-party tool directives are honored. |
check-then-act-blocker.py |
PreToolUse Write/Edit/MultiEdit | Flags a read that decides a write followed by that write. Warns by default through additionalContext, which the model reads; blocks under CHECK_THEN_ACT_ENFORCE=1 |
transaction-scope-guard.py |
PreToolUse Write/Edit/MultiEdit | Flags network I/O and timers inside a transaction, and array-mode transactions carrying dependent writes |
dedup-store-guard.py |
PreToolUse Write/Edit/MultiEdit | Blocks in-memory deduplication ledgers that empty on restart, in TypeScript, JavaScript, Python, Go, Java, Kotlin, C#, Ruby, Dart, Rust, Elixir and Clojure |
concurrent-fanout-guard.py |
PreToolUse Write/Edit/MultiEdit | Flags unbounded Promise.all over caller-supplied input |
python-mutation-guard.py |
PreToolUse Write/Edit/MultiEdit | AST-based Python immutability: blocks mutable defaults, collection mutation through parameters, global, module and class level containers, and object.__setattr__ escapes; warns on parameter attribute writes and non-frozen dataclasses |
polyglot-immutability-guard.py |
PreToolUse Write/Edit/MultiEdit | Shared mutable state in Go, Rust, C, C++, Swift, Java, Kotlin, C#, Dart, Ruby and Lua |
idempotency-guard.py |
PreToolUse Write/Edit/MultiEdit | Operations unsafe to repeat: bare mkdir and ln -s, unguarded rc-file appends, Terraform timestamp() and uuid(), a disabled Kafka idempotent producer |
immutability-analyzers.py |
PostToolUse Write/Edit/MultiEdit, Stop | Runs clang-tidy, golangci-lint, ruff, pyright, rubocop, luacheck, detekt, PMD, swiftlint and the Dart analyzer on files edited in the turn with the configs in analyzers/; findings on changed lines block, a missing analyzer blocks, and a finding on an untouched line goes to the model as an advisory to investigate |
retro-pointer.py |
Stop | One-line summary at session end when blocks accumulated, shown to the user as a systemMessage |
review-state-guard.py |
PreToolUse Bash | Blocks accidental REQUEST_CHANGES, DISMISS, or DELETE on reviews not authored by the user |
rtk-rewrite.py |
PreToolUse Bash | Rewrites CLI commands through RTK for token savings |
scope-guard.py |
PreToolUse Write/Edit/MultiEdit | Reads the most recent active plan.md under the workspace plans/ or specs/ (modified within 60min). A plan whose header carries an Archived: or Superseded: stamp is closed and governs nothing. Blocks the edit when its target is not in the plan's declared file list, which accepts paths and extensionless names such as Makefile. Files outside the repository that holds the spec, such as the vault, are never checked. Bypass SCOPE_GUARD_DISABLE=1 |
secret-scanner.py |
PreToolUse Bash | 38 secret patterns before git commit |
sequelize-raw-sql-blocker.py |
PreToolUse Write/Edit | Blocks Sequelize raw query escape hatches, in test files too |
sequelize-schema-sync.py |
PreToolUse Write/Edit | Enforces Sequelize model vs migration parity |
session-resume-context.py |
SessionStart | Names the local workspace and surfaces its PROMPT.md in full, then the most recent checkpoint or active plan (within 7 days), as additionalContext on startup, clear, or compact so the session resumes with a pointer to in-progress work |
project-workspace.py |
SessionStart / Stop / PreToolUse Bash | Claims the local workspace in .git/info/exclude, blocks the end of a turn once while PROMPT.md is older than the newest change, refuses a forced git add over the workspace, and refuses any add or commit that would version a PROMPT.md anywhere. Bypass PROJECT_WORKSPACE_DISABLE=1 |
settings-hygiene.py |
PreToolUse Write/Edit/MultiEdit | Blocks credentials and absolute home paths in settings |
smart-formatter.py |
PostToolUse Edit/Write | Records each edited file in a per-session batch for the Stop hook, which does the formatting |
stop-format-typecheck.py |
Stop | Claims the session's batch from smart-formatter.py by rename, formats each file once with the formatter the project configures, ruff before black, prettier, shfmt and rubocop only where their config file exists, then runs tsc once per touched workspace and reports any failure back to the model |
subagent-brief-quality.py |
PreToolUse Task | Enforces subagent prompt quality with shape, file references, and length cap. Two or more failed checks block; a single failed check goes to the model as an advisory to investigate |
symlink-commit-blocker.py |
PreToolUse Bash | Blocks commits that would record a symbolic link: a staged mode 120000 entry, plus paths that commit -a or a same-command git add will include. Removing a tracked link is allowed |
tdd-gate.py |
PreToolUse Write/Edit/MultiEdit | Blocks creation of a new production source file when no companion test file can be located. Exempts config files, __init__.py, conftest.py, setup.py, type-only modules, re-export-only index barrels, and throwaway scripts under a scratchpad/ directory or the shared /tmp root. The per-user TMPDIR stays gated, since pytest's tmp_path lives there. Bypass TDD_GATE_DISABLE=1. Also blocks an edit to a test file that lowers its assertion or test-case count or adds a skip marker, through assertion_weakening.py. An edit that leaves the file no weaker than its last committed version passes, so removing tests that no commit holds is allowed. Its own bypass is TEST_WEAKENING_DISABLE=1 |
terraform-workspace-guard.py |
PreToolUse Bash | Forces TF_WORKSPACE per call, including after global options such as -chdir |
todo-marker-blocker.py |
PreToolUse Write/Edit/MultiEdit | Blocks TODO/FIXME/HACK/XXX/WIP markers in source code, including a marker that carries an issue number or any other parenthesized note. No allow marker; only third-party tool directives are honored. |
typeorm-raw-sql-blocker.py |
PreToolUse Write/Edit | Blocks TypeORM raw query escape hatches, in test files too |
typeorm-schema-sync.py |
PreToolUse Write/Edit | Enforces TypeORM entity vs migration parity |
user-commands-one-line.py |
Stop | Reads the reply that ends the turn and blocks it when two or more lines begin with ! , when a ! line joins steps with ; outside strict mode, silences a failure with || true, or deletes recursively from a variable path without ${VAR:?}. Reads last_assistant_message, or the transcript tail since the last user prompt. Skips a turn a Stop hook already continued. Bypass USER_COMMANDS_ONE_LINE_DISABLE=1 |
user-supplied-artifact-guard.py |
PreToolUse Bash | Keeps files the user must supply themselves out of git history. Blocks git commit, and git add with an explicit path, when a file matches a digest declared in artifacts.manifest.json or carries an unambiguous ROM, disc-image, firmware, or model-weight extension. Size pre-filters the digest check. Bypass USER_SUPPLIED_ARTIFACT_DISABLE=1 |
vault-compile.py |
SessionStart | Recompiles this project's memory directory from the vault before the catalog is injected, so memory is never one forgotten command behind. Silent unless the compile changed something, and every failure path exits zero, because a memory directory one compile behind beats a session that cannot start. The compile is cut off after VAULT_COMPILE_TIMEOUT_SECONDS, 20 by default, and the timeout is logged. Bypass VAULT_COMPILE_DISABLE=1 |
vault-context-loader.py |
SessionStart | Injects the second brain's catalog once per session, so what the vault holds is known before the first question rather than searched for after it. Also reports when vault maintenance is overdue, since a loop that stops running is otherwise as silent as one with nothing to do, and surfaces any captures a previous session queued |
vault-recall.py |
UserPromptSubmit | Injects the second-brain notes closest to the prompt, title and preamble only. Ranks with the same function /brain eval scores, so a recall regression is measurable. Read-only, and silent unless the vault resolves and a note clears the score floor. Bypass VAULT_RECALL_DISABLE=1 |
vault-session-capture.py |
PreCompact | Appends what the session worked on to today's vault note before the transcript is compacted away, which is the last moment the detail still exists. Appends under a lock, so parallel sessions never overwrite each other |
vault-capture-queue.py |
Stop | Decides whether a turn corrected a belief or uncovered a cause and, when it did, queues it for the next session to file, which works the queue alongside the user's task without asking. Writes one append-only line and starts nothing, because a process cannot tell a durable lesson from an aside and an unattended writer holding that judgement files inference as fact. Bypass VAULT_CAPTURE_QUEUE_DISABLE=1 |
workflow-guard.py |
PreToolUse Write/Edit/MultiEdit | Blocks a GitHub Actions workflow on a -latest label, a third-party action not pinned to a full commit SHA, an npm, npx, yarn or pip step, a push or pull_request workflow with no top-level cancelling concurrency group, a release workflow that cancels in progress, and one workflow that both checks pushes and releases. Warns on a macOS runner in a workflow that uses no macOS-only tool and is not a homebrew-* tap, on an Ubuntu LTS older than ubuntu-26.04, and on a job without step-security/harden-runner. Bypass WORKFLOW_GUARD_DISABLE=1 |
18 specialized subagents in agents/. Each follows the agent template at TEMPLATE.md and inherits shared discipline from _shared-principles.md.
Agent spawning is off to cut token use. settings.json denies Agent, Workflow, CronCreate, RemoteTrigger, and SendMessage, and sets disableWorkflows, enableWorkflows: false, workflowKeywordTriggerEnabled: false, and disableAgentView. The agents above stay on disk but cannot be launched, and skills that delegate to a subagent run their steps inline. To re-enable, remove those deny entries and keys.
| Agent | Purpose |
|---|---|
accessibility-auditor |
WCAG 2.1 AA accessibility review |
concurrency-auditor |
Actor timelines per write path, race conditions, idempotency and dedup durability |
api-reviewer |
API backward compatibility and design review |
blast-radius |
Trace all consumers of changed interfaces |
conversation-analyzer |
Read a session transcript and surface patterns worth capturing as instincts, hooks, or rule revisions |
documentation-checker |
Documentation accuracy vs codebase |
gan-planner |
First step of the /gan loop. Expands a brief into acceptance criteria, a file list, and a five-row scoring rubric |
gan-generator |
Second step of the /gan loop. Implements the plan against the named files. Returns proposed diffs, never writes |
gan-evaluator |
Third step of the /gan loop. Scores the implementation against the planner's rubric. Returns per-row scores and concrete feedback |
i18n-validator |
Translation file validation |
migration-planner |
Database migration safety and ordering |
opensource-sanitizer |
Pre-public-push safety net. Scans diffs for leaked secrets, PII, internal references, and other artifacts that should not appear in a public repository |
red-team |
Adversarial analysis: attack happy paths |
critic |
Final hostile pass on a near-complete change, focused on what is missing rather than what is wrong |
privacy-auditor |
Personal data flows, missing consent gates, retention violations, automated-decision transparency |
scope-drift-detector |
Compare diff against plan for scope drift |
test-scenario-generator |
Test scenarios with priority and traceability |
type-design-analyzer |
Review TypeScript type design for encapsulation, invariant expression, and runtime safety |
Pick the skill by what you are trying to do, not by what the skill is called. Scenarios are grouped by intent. When two skills could apply, the final subsection shows how to pick.
| Scenario | Start with |
|---|---|
| "I need to build X" | /plan --discover then implement |
| "Think through this before coding" | /plan |
| "Record an architecture decision" | /plan adr new <title> |
| "Generate boilerplate matching project patterns" | /plan scaffold <type> <name> |
| "Set up this project for the first time" | /setup |
| "Spin up Docker or database for local dev" | /infra docker or /infra db |
| "First-time codebase walkthrough" | /onboard |
| "Write the test first, then code" | /tdd |
| "Explain how this code works" | /explain |
| "I am lost in unfamiliar code" | /zoom-out |
| Scenario | Start with |
|---|---|
| "Review this PR" | /review <PR> |
| "Review my local branch before pushing" | /review --local |
| "Test coverage gaps and QA scenarios" | /review qa |
| "Accessibility, performance, SEO audit on the UI" | /review design |
| "Run tests, coverage, lint, build" | /test |
| "Load test or HTTP perf benchmark" | /test perf |
| "Design consultation before implementing UI" | /design |
| "Generate UI design variants for comparison" | /design variants |
| "Reviewer left comments on my PR" | /respond |
| "Pre-submission audit or take-home check" | /assessment |
| "Find what is missing the way an interviewer would" | /assessment --focus <area> |
| "Remove AI slop from a project" | /assessment --focus slop |
| "Summarize this PR for reviewers" | /pr-summary |
| "Are we secure" | /audit |
| "Threat model or STRIDE analysis" | /audit threat |
| "Dependency vulnerability scan" | /audit deps |
| Scenario | Start with |
|---|---|
| "Commit and push" | /ship commit --push |
| "Open a PR" | /ship pr |
| "Create a tagged release" | /ship release |
| "Is my code ready to ship" | /review --local then /ship |
| "CI is failing" | /ship checks |
| "Watch CI to green and address AI bot threads" | /ship commit --pipeline |
| "Land the PR after approval" | /deploy land |
| "Canary deploy and monitor" | /deploy canary |
| "Parallel work across branches" | /ship worktree init |
| Scenario | Start with |
|---|---|
| "Something is broken" | /investigate |
| "Why is this slow" | /profile |
| "Performance regression vs baseline" | /benchmark |
| "Prod is broken, fix NOW" | /hotfix |
| "Write a postmortem" | /incident |
| "Fix a GitHub issue by number" | /fix-issue <number> |
| Scenario | Start with |
|---|---|
| "This code needs restructuring" | /refactor |
| "Upgrade framework or library version" | /migrate |
| "Replace library A with library B" | /migrate |
| "Resolve merge conflicts" | /resolve |
| Scenario | Start with |
|---|---|
| "Write or update a README" | /readme |
| "Translate the README" | /readme, which always writes ja, zh-Hans and zh-HK; --languages <tags> adds more |
| "Generate an assessment-style README" | /readme --variant assessment |
| "What does the community say about X" | /research X |
| "X vs Y, which is better" | /research X vs Y |
| "Find prior art for an idea" | /research <topic> |
| Scenario | Start with |
|---|---|
| "Clean up stale branches, PRs, and worktrees" | /cleanup |
| "Save session state to resume later" | /checkpoint save |
| "Resume where I left off" | /checkpoint resume |
| "Lock down before a risky operation" | /guard |
| "Standup or handoff notes" | /session-log |
| "Session retrospective" | /retro |
| "Discover codebase patterns and extract rules" | /retro discover |
| Scenario | Start with |
|---|---|
| "Poll something every N minutes" | /loop <interval> /<command> |
| "Self-paced repeat of a task" | /loop /<command> |
| "Cron-style scheduled remote agent" | /schedule |
| Ambiguity | Choose | Because |
|---|---|---|
/review vs /assessment |
/review for diff-level findings; /assessment for whole-system audit |
/review catches bugs in what was written; /assessment finds patterns that should be present but are not |
/review vs /audit |
/audit for security focus; /review for general quality |
/audit runs STRIDE, dependency scans, and secret detection; /review runs the 71-category checklist |
/respond vs /ship --pipeline |
/respond for an attended pass over human and AI-bot threads, bots included by default, --humans-only to skip them; /ship --pipeline for unattended AI-bot threads |
Set RESPOND_DRIVES_PIPELINE=1 to delegate the bot loop to /respond and unify the vocabulary across both flows |
/investigate vs /profile |
/investigate for correctness; /profile for performance |
/investigate debugs why something fails; /profile finds bottlenecks in working code |
/refactor vs /migrate |
/refactor for internal restructure; /migrate for framework or version change |
/refactor preserves behavior in your own code; /migrate follows the upstream's official upgrade docs |
/explain vs /onboard |
/explain for a single file or function; /onboard for a whole project |
/explain traces data flow with Mermaid; /onboard produces a "start here" guide with architecture map |
/explain vs /zoom-out |
/explain for "what does this do"; /zoom-out for "where does this fit" |
/explain goes deep into one piece; /zoom-out traces callers and surfaces the architectural role |
/loop vs /schedule |
/loop for one terminal session; /schedule for a remote cron-style agent |
/loop self-paces or polls inside the current session; /schedule runs an agent on a server on a recurring schedule |
/cleanup vs /refactor |
/cleanup for git artifacts; /refactor for code quality |
/cleanup deletes stale branches, PRs, worktrees; /refactor improves code structure without changing behavior |
/test vs /review qa |
/test to execute; /review qa to analyze |
/test runs the test suite, coverage, lint, perf; /review qa finds coverage gaps and writes scenarios |
| Tool | Version | Install |
|---|---|---|
| Claude Code | Latest | docs.anthropic.com |
| Git | >= 2.0 | Pre-installed on macOS |
| Python | 3.14, pinned in .mise.toml and the only version CI tests |
mise install |
| jq | >= 1.6 | brew install jq |
| RTK | >= 0.23.0 | cargo install rtk |
Clone the repository, then symlink its contents into the Claude config directory so the config stays in sync with git:
git clone git@github.com:gufranco/claude-engineering-rules.git
cd claude-engineering-rules
ln -sf "$(pwd)/"* "$HOME/.claude/"Feed a hook the force-push fixture. It refuses and exits 2, the code Claude Code reads as a block:
python3 ~/.claude/hooks/dangerous-command-blocker.py < ~/.claude/tests/fixtures/bash-force-push.json; echo "exit $?"Expected output:
BLOCKED: Use --force-with-lease instead of --force
Command: git push --force origin main
exit 2
The rules and skills load in the next Claude Code session you open.
42 MCP servers wired in settings.json across three transports:
- Stdio, no env: AWS, Docker, Filesystem, Kubernetes, Lighthouse, Memory, Ollama, Playwright, PostgreSQL, Puppeteer, Railway, Redis, Semgrep, Sequential Thinking
- Stdio with env: Brave Search, Browserbase, Cloudflare, Discord, Exa Web Search, fal.ai, Firecrawl, GitHub, GitLab, Google Maps, LangSmith, Obsidian, Perplexity, Qdrant, Resend, Slack, Todoist
- Remote HTTP, zero startup: Asana, Atlassian, Browser Use, ClickHouse, Figma, Linear, Mermaid Chart, Notion, Sentry, Supabase, Vercel
- 51 deny rules block Read and Edit on sensitive files:
.envvariants,secrets/, SSH keys, AWS creds, GnuPG, kube and Docker config,.npmrc,.pypirc,.netrc,*.pem,*.key,*.tfstate,*.tfvars, plus Read onnode_modules - 19 allow rules skip the permission prompt. They include the unscoped
Read,Write,Edit,Bash,WebFetch,WebSearch,Skill, andNotebookEdittools, so the allow list is broad rather than read-only, plus scoped entries such asgit diff,git log,git status,pnpm run, andpnpm exec. Deny rules still win over these allows, and the hooks are the layer that blocks destructive commands
The env-file-guard.py hook adds a runtime block on Write and Edit to the same file classes at any path, plus credentials/ directories, .pgpass, and service-account*.json. It does not cover Read or Bash, so a secret file outside the deny globs is still readable.
Project structure
$HOME/.claude/
CLAUDE.md Core engineering rules, always loaded
RTK.md RTK token-optimized CLI proxy reference
settings.json Permissions, hooks, MCP servers
checklists/ Unified 905-item review checklist across 71 categories
rules/ 49 short rule cores, each linking to its full text
index.yml Rule and standard catalog with trigger keywords
lang/ 5 language-specific cores: TypeScript, Python, ORM migrations
standards/ 143 on-demand standards, including the full text of every rule
agents/ 18 specialized subagents
skills/ 42 slash-command skills
audit/trust-patterns.md IOC catalog for the /audit trust scan
hooks/ 98 runtime hooks
.github/scripts/ Validation and maintenance scripts (CI helpers)
hooks/_lib/ Shared hook libraries (mutation detectors, audit log, suppression, git command normaliser)
analyzers/ Immutability configs for the end-of-turn analyzers, and their local proof suite
tests/ pytest suites, Node script tests, smoke cases, and fixtures
pyproject.toml Python dev toolchain, locked in uv.lock
package.json Release toolchain, locked in pnpm-lock.yaml
.github/workflows/ Lint, validation, hook tests
How do I customize or disable a rule?
Rules in rules/ load into context automatically. To disable one, delete or rename the file. To customize, edit the markdown. Changes take effect on the next conversation.
How do I add a new skill?
Run /skill-new <name>. It asks whether the skill is model-invoked or user-invoked, scaffolds the frontmatter and the six sections, and blocks until python3 tools/lint-skills.py --strict skills/<name> passes. Pick model-invocation only when Claude, or another skill, must reach the skill on its own; anything only ever typed by hand is user-invoked and costs no context.
Why integration tests over unit tests?
The testing rule treats unit tests as a fallback for pure functions. A test that mocks the database may pass while the actual query is broken. The mock proves the mock works, not the code. See rules/testing.md.
How does two-tier rule loading save context?
The 143 standards total 27,356 lines. Loading all of them into every conversation would burn the context window. rules/index.yml maps each standard to trigger keywords. When a task matches, e.g. "add a database migration" pulls database.md, only the relevant standards load.
What does the dangerous command blocker cover?
190 patterns: filesystem destruction, privilege escalation, reverse shells, git destructive operations, AWS/GCP/Azure CLI deletions, Vercel/Netlify/Firebase, Docker and Kubernetes destructive commands, database CLI drops, IaC destroy, SQL statements without WHERE, credential exfiltration.
Releases are automatic. Merging to main runs CI; a green CI run triggers
release.yml, which derives the next version
from the Conventional Commits since the last tag, tags it, syncs that version
into .claude-plugin/marketplace.json and
both plugin manifests, and publishes GitHub release notes.
| Commit type | Effect |
|---|---|
feat |
minor release |
fix, perf, refactor, revert |
patch release |
docs, test, style, build, ci, chore |
no release |
! or a BREAKING CHANGE: footer |
major release |
CHANGELOG.md is written by hand and is not generated. It
carries the reasoning behind a change, which generated notes cannot.
CONTRIBUTING.md covers the setup, the local gate, and the
conventions. The short version:
make install
make test-allmake test-all runs the suite, the linters, the type checker, and make validate, which is the drift gate: it walks every registry against what is
actually on disk and fails when the two disagree. That covers a rule or
standard missing from rules/index.yml, a skill or agent
missing from this README, a test-shaped file left in hooks/ where
the bypass smoke test would execute it, and a count check whose pattern stopped
matching. That last one matters most: a check that matches nothing cannot fail,
so it reports success while verifying nothing, which is how a stale number
survives a green run.
Every pull request runs eight CI jobs on ubuntu-26.04: lint, workflow lint,
typecheck, hook tests, the Python suite at 100% branch coverage with nothing
excluded, a release-config dry run that also holds the Node scripts at 100%
and verifies registry signatures, CodeQL, and dependency review. Each job
records its network egress with harden-runner. GitHub's own actions are pinned
to a release tag and third-party actions to a commit SHA. Dependabot keeps
the actions and the Node packages current; renovate.json
covers the Python pins, the pre-commit hooks, the actionlint version, and the
runner image label. Releases are cut by semantic-release from Conventional
Commits.
| Need | Where |
|---|---|
| Bug report or feature request | GitHub Issues |
| Security report | Private security advisory |
| Contributing | Contribution guide |
| Conduct | Code of conduct |
Report vulnerabilities privately through
a security advisory,
never a public issue. SECURITY.md carries the threat model,
the supported versions, and the supply-chain controls.
Hooks are advisory. They stop an accidental destructive command; they are not a sandbox and do not contain untrusted code.