Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Configure CC Safety Net rulebooks for user, project, or shareable GitHub scope.
.claude/skills/kenryu42-cc-safety-net/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 295% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 281% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 133% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 298% | 0% |
| case-22 | ✓→✓ | = Same ✓ | 255% | 0% |
CC Safety Net hooks into coding agent CLIs (Claude Code, Codex, Cursor, Gemini CLI, and others) and blocks destructive commands and secret access before they run. The cc-safety-net CLI inspects and controls that protection. Run it as npx -y cc-safety-net.
The installed CLI is the authority for command syntax. Do not guess flags.
bashnpx -y cc-safety-net --help npx -y cc-safety-net help <command>
Run npx -y cc-safety-net rule doc and treat that output as the complete source of truth for rulebook schema, paths, GitHub sources, matching behavior, and validation.
These commands are read-only and safe to run for discovery: --help, --version, status, doctor, logs (without --prune-legacy), explain, rule list, rule verify, rule doc, policy check, help. Every other command mutates configuration or installed integrations; run those only as part of a workflow below.
bypass built-in CC Safety Net protections.
rule.json) list rulebook sources. Rule definitions live in rulebook.json,not directly in rule.json.
rulebooks at .cc-safety-net/rules/<rulebook-name>/rulebook.json in a repository.
rulebook.json on every tool call, so a savededit applies to the next command with no sync step.
policy.json sets the safety level, per-feature toggles, per-rule overrides, and path lists. Ithas two scopes: the project file .cc-safety-net/policy.json, committed and shared with the team, layered on the user file that applies to every project.
standard, strict, or paranoid, set per session with theCC_SAFETY_NET_LEVEL environment variable.
BLOCKED by CC Safety Net message:explain a decision.
the policy.
explain andrule doc show: answer from the source.
npx -y cc-safety-net logs (narrow with --project ., --agent <name>, or --since <days>).
npx -y cc-safety-net explain as one literal argument. Prefer anargv-capable tool; when invoking through a shell, shell-escape the whole command as one argument. Never interpolate raw command text into double quotes: $(), backticks, and variables would expand before explain receives it. Add --cwd <path> when the decision depends on the working directory. Once received, explain analyzes the string and never executes it.
reason. explain exits 0 for both allowed and blocked verdicts; read the verdict from the output, not the exit status.
reason names, such as git stash before git reset --hard.
npx -y cc-safety-net logs --suspect --since 7, or fetchone entry with npx -y cc-safety-net logs --id <id>.
explain and read which rule fired.rule (see configure rules), then re-run explain to confirm the new verdict.
hatch, such as CC_SAFETY_NET_WORKTREE=1 for local git discards in linked worktrees (git discards in a temp-root repository outside the workspace are already allowed), or rule wrapper add when a trusted transparent wrapper hid the real command from the analyzer. Pass the wrapper name as a separate argv value, or shell-escape it as one argument. If the user explicitly wants that built-in rule off, read its id from the ruleId field of explain --json and propose a per-rule policy override (see configure the policy). Otherwise explain the risk the rule guards against and suggest reporting the case at https://github.com/kenryu42/cc-safety-net/issues.
Use information already provided in the user's prompt. Ask only when the scope, action, rule intent, merge behavior, or target command is unclear.
transparent wrapper, migrate legacy rules, or explain custom rules from the prompt when possible.
npx -y cc-safety-net rule verifynpx -y cc-safety-net rule listrule depends on project context. Look at manifests, scripts, task runners, CI, infrastructure, database, migration, and deployment files that explain risky commands.
rule doc.rule.json and<rulebook-name>/rulebook.json.
.cc-safety-net/rules/<rulebook-name>/rulebook.json in thecurrent repository.
owner/repo; installing rules from a GitHubsource is outside this workflow.
use npx -y cc-safety-net rule add owner/repo --only <rulebook...>; omit --only only when they want every rulebook, and add --ref <ref> only when they name a non-default ref. rule add --only <rulebook...> with no source selects from the official cc-safety-net/rulebooks repository, whose curated rulebooks block destructive Terraform, AWS, gcloud, and Azure CLI operations; prefer installing one of those over authoring when it already covers the request.
npx -y cc-safety-net rule wrapper add with the trustedwrapper name passed as a separate argv value, or shell-escaped as one argument, over editing rule.json by hand.
before writing when creating a new rulebook, merging with existing config, or resolving ambiguity.
.cc-safety-net/rules/<rulebook-name>/rulebook.json, and ensure the source name, directory name, and rulebook name match exactly.
npx -y cc-safety-net rule verify and npx -y cc-safety-net rulelist. Both commands cover every scope, so neither takes --global.
npx -y cc-safety-net rule verify. Run list onlyif the rulebook is also installed in local rule.json.
Rule invariants:
.safety-net.json or ~/.cc-safety-net/config.json rules. Convertexisting legacy files with npx -y cc-safety-net rule migrate.
allowed_commands. The tests fixtures are optional;rule verify evaluates rulebook_version 2 fixtures against the rulebook's own rules, and fixture commands are analyzer input that CC Safety Net never executes.
rule, and that rule must exist inthe rulebook.
project-rules; do not put filesystem paths inrules.
edit rather than activating it.
rule.json makes every source in its scope inactive: those rules stop applying while other custom rules and built-in protections stay active. Fix the file named in the diagnostic.
the later rulebook.
npx -y cc-safety-net rule add owner/repo fetches remote rulebooks, validates them, and vendorseach one into <rulebook-name>/rulebook.json; npx -y cc-safety-net rule update [source] re-fetches and overwrites those copies and prints what changed. The runtime never fetches, and a remote source with no vendored file reports that rule update has to vendor it first.
rule sync is deprecated: it only migrates lock and cache leftovers from an earlier version.Never run it as a validation or activation step.
Both policy.json files are protected: you propose the change, the user applies it. Reading them is allowed, writing them is not.
policy.json fields, all optional except version: 1 (policy check reports every schema error, so validate against it rather than guessing further fields):
safety.level: standard, strict, or paranoid. safety.overrides: booleans forfail_closed, paranoid_rm, and paranoid_interpreters that pin one capability apart from the level.
workflow.worktree_mode: boolean, allows local git discards in linked worktrees; discards in atemp-root repository outside the workspace need no toggle.
destructive_command_protection and secret_protection: an enabled boolean, and per-ruleoverrides mapping a built-in rule id (git.reset-hard, secret.basename.env) to "on" or "off". Get the id for a blocked command from the ruleId field of explain --json.
destructive_command_protection.allow_paths: absolute or ~/ paths where recursive deletetargets are permitted. secret_protection.allow_paths: exact user-managed paths exempted from secret protection, globs rejected. secret_protection.deny_paths: extra paths protected like built-in secrets.
audit.retention_days: days of audit history to keep, user scope only.npx -y cc-safety-net status for the effective policy and the filepaths it loaded, npx -y cc-safety-net rule list for custom rules, plus whatever project context the request depends on. Read an existing policy.json before proposing changes to it.
policy-proposal.json. Forproject scope, set only the fields the team intends to control; an unset field inherits from the user policy, and apply writes only the fields the proposal sets. Applying replaces the target file, so the proposal is the complete policy, not a patch. Audit settings are user scope only; a project proposal cannot set them.
npx -y cc-safety-net policy check policy-proposal.json and show the user the printeddiff. Add --global to target the user policy instead of the project one. Fix every reported error and re-check until it passes.
npx -y cc-safety-net policy apply policy-proposal.json (with --global when that is the scope). It confirms interactively, there is no --yes flag, and agent invocations of policy apply are blocked by design, so never run it, wrap it, or write the file yourself.
npx -y cc-safety-net status and report theeffective policy, including any project scope deltas it prints.
npx -y cc-safety-net doctor first. It reports each supported platform as detected,configured, and verified, and names outdated installs with the exact repair command.
npx -y cc-safety-net install --claude-code.Run npx -y cc-safety-net help install for the full target list. Bare install opens an interactive picker; leave that for the user's own terminal.
npx -y cc-safety-net@latest update to update every installed integration at once.flag.
doctor again and confirm the affected platformrows read as verified.
npx -y cc-safety-net status shows what the runtime enforces right now, including a degradedpolicy.json that rule list does not report.
npx -y cc-safety-net doctor verifies the installation: platform detection and hook config,a synthetic guard self-test, and configuration scopes. Use --json when parsing the result.
rule verify, rule list, then re-test thecommand with explain.
For questions the CLI output cannot settle, such as why the analyzer treats a construct a certain way or whether a gap is a known limitation, read the source code of the installed version.
<version> from npx -y cc-safety-net --version.at <repo>/skills/cc-safety-net/SKILL.md inside it, so the repository root is two directories above the skill file. Use the candidate only if its package.json has "name": "cc-safety-net" and version <version>, and a src/ directory exists next to it. If the package version differs, run doctor to report the outdated integration, then treat the candidate as unavailable and continue to the next step.
without a file path), resolve the immutable commit recorded with the published package using npm view "cc-safety-net@<version>" gitHead. Require a 40-character lowercase hexadecimal commit and fetch that exact commit into a fresh owner-only temporary directory:
bash set -euo pipefail git_head=$(npm view "cc-safety-net@<version>" gitHead) [[ $git_head =~ ^[0-9a-f]{40}$ ]] || { echo "Invalid published gitHead" >&2; exit 1; } source_dir=$(mktemp -d "${TMPDIR:-/tmp}/cc-safety-net-v<version>-XXXXXXXX") trap 'rm -rf -- "$source_dir"' EXIT chmod 700 "$source_dir" git -c init.templateDir= init "$source_dir" git -c core.hooksPath=/dev/null -C "$source_dir" fetch --depth 1 https://github.com/kenryu42/cc-safety-net "$git_head" git -c core.hooksPath=/dev/null -C "$source_dir" checkout --detach "$git_head" [[ $(git -C "$source_dir" rev-parse HEAD) == "$git_head" ]] || { echo "Source checkout mismatch" >&2; exit 1; } printf 'Source checkout: %s\n' "$source_dir" trap - EXIT
Never answer from main; it can contain unreleased behavior the installed version does not have.
docs/ first; residual-risk.md and secret-protection-known-limitations.md exist toanswer whether something is a known gap. For behavior questions, continue into src/analyzer, src/guards, and src/rules.
read-only reference; do not edit, build, or run it.
rm -rf -- "<source_dir>".config, or propose a policy that weakens protection to get a blocked command through unless the user explicitly asks for that outcome and understands what the block guards against.
hook; it is the integration entry point that reads hook JSON from stdin, not auser-facing command.
logs --prune-legacy permanently deletes legacy logs. Run it only on an explicit request, andrun it with --dry-run first.
rule remove --delete-source deletes the local source directory. Ask before using it.gui --no-open and give the user the URL instead of opening a browser from a session.UPDATE_AVAILABLE: line, ask the user once whether to runnpx -y cc-safety-net@latest update, continue the workflow without waiting either way, and do not raise it again.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 13,627 | 7,808 | -43% | 1 | 1 | 0% | 2,110 | 4,781 | +127% | 0 | 0 | — |
case-02 | fail→fail | 18,663 | 9,806 | -47% | 1 | 1 | 0% | 3,387 | 4,869 | +44% | 0 | 0 | — |
case-03 | fail→fail | 5,202 | 40,318 | +675% | 1 | 1 | 0% | 238 | 4,921 | +1968% | 0 | 0 | — |
case-04 | fail→fail | 22,270 | 13,071 | -41% | 1 | 1 | 0% | 3,120 | 5,278 | +69% | 0 | 0 | — |
case-05 | fail→fail | 13,220 | 7,938 | -40% | 1 | 1 | 0% | 2,184 | 4,809 | +120% | 0 | 0 | — |
case-06 | fail→fail | 13,612 | 9,862 | -28% | 1 | 1 | 0% | 1,933 | 4,880 | +152% | 0 | 0 | — |
case-07 | fail→pass | 8,887 | 8,745 | -2% | 1 | 1 | 0% | 1,281 | 5,055 | +295% | 0 | 0 | — |
case-08 | fail→fail | 9,188 | 10,297 | +12% | 1 | 1 | 0% | 1,449 | 4,942 | +241% | 0 | 0 | — |
case-09 | fail→fail | 20,426 | 8,495 | -58% | 1 | 1 | 0% | 3,291 | 4,697 | +43% | 0 | 0 | — |
case-10 | fail→fail | 15,616 | 8,450 | -46% | 1 | 1 | 0% | 2,378 | 4,930 | +107% | 0 | 0 | — |
case-11 | fail→fail | 14,871 | 20,374 | +37% | 1 | 1 | 0% | 2,091 | 4,913 | +135% | 0 | 0 | — |
case-12 | fail→fail | 14,557 | 8,576 | -41% | 1 | 1 | 0% | 1,249 | 4,958 | +297% | 0 | 0 | — |
case-13 | fail→fail | 12,859 | 16,246 | +26% | 1 | 1 | 0% | 2,065 | 6,048 | +193% | 0 | 0 | — |
case-14 | fail→pass | 21,369 | 12,842 | -40% | 1 | 1 | 0% | 1,477 | 5,632 | +281% | 0 | 0 | — |
case-15 | fail→fail | 13,332 | 9,200 | -31% | 1 | 1 | 0% | 1,656 | 4,842 | +192% | 0 | 0 | — |
case-16 | fail→pass | 18,023 | 14,915 | -17% | 1 | 1 | 0% | 2,884 | 6,715 | +133% | 0 | 0 | — |
case-17 | fail→fail | 11,781 | 9,213 | -22% | 1 | 1 | 0% | 1,680 | 4,731 | +182% | 0 | 0 | — |
case-18 | fail→fail | 13,874 | 7,671 | -45% | 1 | 1 | 0% | 2,232 | 4,773 | +114% | 0 | 0 | — |
case-19 | fail→fail | 8,796 | 5,586 | -36% | 1 | 1 | 0% | 1,180 | 5,110 | +333% | 0 | 0 | — |
case-20 | fail→pass | 10,819 | 4,759 | -56% | 1 | 1 | 0% | 1,292 | 5,143 | +298% | 0 | 0 | — |
case-21 | fail→fail | 19,340 | 3,516 | -82% | 1 | 1 | 0% | 2,674 | 4,822 | +80% | 0 | 0 | — |
case-22 | pass→pass | 11,393 | 17,852 | +57% | 1 | 1 | 0% | 1,634 | 5,806 | +255% | 0 | 0 | — |
case-23 | pass→pass | 10,416 | 13,162 | +26% | 1 | 1 | 0% | 1,711 | 5,474 | +220% | 0 | 0 | — |
case-24 | pass→pass | 6,679 | 14,749 | +121% | 1 | 1 | 0% | 1,023 | 5,596 | +447% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted, and 10 counted toward the lift figure. The other 14 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +17 percentage points is the difference between those two pass rates over the 10 comparable cases. 6 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 9/20/2026 | +18% |
| gemini-3.6-flash | verified | 9/2/2026 | — |
| gemini-3.6-flash | verified | 8/13/2026 | — |
Other measured skills in the registry, with their headline benchmark lift.