status for the quick verdict. Then run doctor for the full report.
Run diagnostics first
status prints the runtime verdict (ready or degraded), the active protections and safety level, your policy path, and one bullet per outstanding issue. A disabled Claude Code plugin appears as the first Not active item, not as a separate verdict. status is informational and always exits 0.
doctor checks each supported agent’s hook integration, confirms that blocking works, validates custom rules, reports active mode flags and recent activity, lists system versions, and checks for updates. It is the one command that reports both rule configuration and policy.json. See the doctor command reference for each check.
Review the output before you work through the individual issues below. Most problems are visible here.
A
degraded verdict means a configuration source was rejected and something safe is enforced in its place. It does not mean your commands are blocked. Invalid configuration never denies ordinary work. See Configuration recovery.Fix common issues
Hook not firing: commands execute without being checked
Hook not firing: commands execute without being checked
If you run a command that should be blocked and it executes without any intervention, the hook is not registered correctly for your agent.Steps to resolve:
- Run
npx cc-safety-net doctor. It checks hook integration for every supported agent and reports misconfiguration with the exact configuration path. - Re-run the install command for your agent. For a valid managed installation, this is idempotent and repairs a missing or disabled managed entry. If the installer reports an unrecognized, symlinked, or foreign config or file, follow its manual recovery message instead of overwriting it. The full per-agent command table is in Installation.
- Amp Code: run
amp plugins listand confirm acc-safety-net (User Plugins)row with statusactive. Any other status requiresplugins: reloadin Amp or a reinstall withinstall --amp. A local file at~/.config/amp/plugins/cc-safety-net.tsmasks the personal plugin.install --ampremoves a managed copy and fails with an actionable error on an unmanaged one. Amp reads plugins at startup, so restart Amp or runplugins: reloadafter a change. - Antigravity CLI: check
~/.gemini/config/hooks.jsonfor a managedPreToolUseentry runningnpx -y cc-safety-net hook --agy-cli. - Claude Code: run
/plugininside Claude Code and confirm thatcc-safety-netappears in the installed plugins list and is enabled. If it doesn’t appear, reinstall with/plugin install cc-safety-net@cc-marketplace, then/reload-plugins. - Codex: run
codex plugin listand confirm thecc-safety-net@cc-marketplaceline readsinstalled, enabled. Then run/hooksin the TUI, select the cc-safety-net PreToolUse hook, and presstto mark it as trusted. The hook will not fire until you trust it. - Cursor: check
~/.cursor/hooks.jsonfor a managedpreToolUseentry runningnpx -y cc-safety-net hook --cursor. The config is global, so one entry covers Cursor IDE and Cursor CLI across all projects. - Gemini CLI: run
gemini extensions listand confirm thehttps://github.com/kenryu42/gemini-safety-netsource is installed and enabled (check both User and Workspace scope, Workspace wins if set). Reinstall withgemini extensions install https://github.com/kenryu42/gemini-safety-netand start a new Gemini session. - GitHub Copilot CLI: confirm the
cc-safety-net@cc-marketplaceplugin is installed (/plugin) and enabled inenabledPluginsin~/.copilot/settings.json. For Copilot CLI 1.0.8+, check inline hook config anddisableAllHooksin this precedence order:.github/copilot/settings.local.json,.github/copilot/settings.json,.claude/settings.local.json,.claude/settings.json,~/.copilot/settings.json, then~/.copilot/config.json. The first file that definesdisableAllHooksdecides the result:truedisables all hooks, whilefalsestops lower-priority values from applying. A hook in.claudemust runcc-safety-net hook --copilot-cliorcc-safety-net hook -cp; a plain Claude Code hook does not register for Copilot. User hook files under~/.copilot/hooks/require Copilot CLI 0.0.422+. - Grok Build: check
~/.grok/hooks/cc-safety-net.json(or$GROK_HOME/hooks/cc-safety-net.json) for a managedPreToolUseentry runningnpx -y cc-safety-net hook --grok-build. Re-runnpx -y cc-safety-net@latest install --grok-buildif it’s missing. - Hermes Agent: confirm the managed plugin files exist in
$HERMES_HOME/plugins/cc-safety-net(~/.hermes/plugins/cc-safety-netwhenHERMES_HOMEis unset) and enable the plugin withhermes plugins enable cc-safety-net --no-allow-tool-override. Hermes loads a user plugin only when itsconfig.yamllists it. Restart Hermes so the plugin loads.doctorreads only the plugin files and Hermes configuration; it does not ask a running Hermes whether the plugin loaded. Restart and test again after a change. - Kimi Code: check
~/.kimi-code/config.toml(or$KIMI_CODE_HOME/config.toml) for a[[hooks]]block runningnpx -y cc-safety-net hook --kimi-codeonPreToolUseBash. Re-runnpx -y cc-safety-net@latest install --kimi-codeif it’s missing. - OpenClaw: the plugin is installed and enabled through OpenClaw’s own CLI. Re-running
npx -y cc-safety-net@latest install --openclawrunsopenclaw plugins install <plugin dir> --forceandopenclaw plugins enable cc-safety-net, then confirms the plugin loaded (openclaw plugins inspect cc-safety-net --runtimeshows the details). Restart the OpenClaw Gateway afterwards, and ifplugins.allowis set inopenclaw.json, it must also listcc-safety-net.doctorreads the plugin directory andopenclaw.jsononly; it never asks a running Gateway whether the plugin loaded, so a stopped Gateway is not reported as a failure. - OpenCode: check
$XDG_CONFIG_HOME/opencode/opencode.json(or.jsonc) whenXDG_CONFIG_HOMEis set; otherwise check~/.config/opencode/opencode.json(or.jsonc). Confirm that theplugin[]array containscc-safety-net. OpenCode can cache a stale version. See the Installation cache-clearance steps. - Pi: confirm
pi install npm:cc-safety-netcompleted and you restarted Pi so the extension loads. Pi runs CC Safety Net as an in-process extension; runnpx cc-safety-net doctor, which probes Pi directly. - After making any changes, reload or restart your agent session.
Hooks are slow: every command waits before it runs
Hooks are slow: every command waits before it runs
A healthy check finishes in well under a second. If every command waits for seconds, the delay is in resolving the
cc-safety-net package, not in the analysis itself.Steps to resolve:-
Check how your agent runs the hook. The Claude Code plugin runs its bundled copy directly, so package resolution cannot be the cause there. The Antigravity CLI, Cursor, Grok Build, Hermes Agent, and Kimi Code hooks run
npx -y cc-safety-neton every command, which adds a few hundred milliseconds even with a healthy npm cache. -
Measure the resolution cost outside the agent:
Run it two or three times. The first run after a release downloads the package and is slow once; warm runs should settle in the low hundreds of milliseconds.
-
Rule out registry latency:
If the
--prefer-offlinerun is fast while the plain run stays slow, npx is waiting on the npm registry. That is a network or proxy problem, not a CC Safety Net one. -
Repair the npm cache:
A bloated or corrupted cache slows every npx resolution, warm runs included.
npm cache verifygarbage-collects and repairs it. In the report that led to this section (issue #16), it reclaimed over 5 GB and brought hooks back under a second.
A destructive command slipped through
A destructive command slipped through
If a command you expected to be blocked was allowed, work through this list. Most cases are a documented allowance or a lower safety level than you assumed, not a gap.Steps to resolve:
-
Run
npx cc-safety-net explain "<the command>"to see the full step-by-step analysis of how CC Safety Net evaluated that specific command. The output names the rules that were checked, the effective safety level, and, when a rule exists but is off at your level, the rule activation line that says so. -
Check the effective level in that output. Standard mode is best-effort: it deliberately allows dynamic executables, command structure assembled through substitution, unverifiable recursive-delete targets such as
rm -rf "$target", and metadata-only checks of built-in sensitive paths. If your commands can come from prompt injection or another adversarial context, raise the level to strict or paranoid, which fail closed on all of those forms. -
The command may fall into an explicitly allowed category. For example,
rm -rfwithin the current working directory is allowed by default because it’s scoped to your project. See the Allowed commands reference for the full list. -
Run
npx cc-safety-net status. Adegradedverdict means a rule source was dropped, so the denials that source contributed are not being enforced. See Configuration recovery. -
Look for a
Project policyblock in that samestatusoutput. It appears when a project.cc-safety-net/policy.jsonrelaxed the user policy, and each line names one relaxed field, for exampleproject policy lowers level: strict -> standard,project policy disables rule <id>, orproject policy adds destructive allow path: <path>. Any of those can explain a rule that stopped firing in this project but still fires elsewhere. The status line shows the same condition as🔻, anddoctorprints the same lines underProject policy deltas:. -
If the command runs through a proxy that CC Safety Net does not analyze, register it with
npx -y cc-safety-net rule wrapper add <command>so analysis looks through it to the real child command. -
If you need the command blocked in your context, create a custom rulebook with
npx -y cc-safety-net rule initand add a rule to.cc-safety-net/rules/project-rules/rulebook.json. See Custom rules for the schema. -
If none of the above explains it, the command shape may be a coverage gap, which is a public bug under the project policy. Open a GitHub issue that describes the command shape, not a ready-to-paste payload. Secret leakage, a write outside the intended directory, and supply-chain or package-integrity problems use the private disclosure path. The security policy defines both procedures.
Attach a reviewed
explaintrace from step 1. Never attach a raw trace or real credentials. If the boundary is documented, Known limitations identifies it and names the layer that covers it.
CC Safety Net is blocking a command I need
CC Safety Net is blocking a command I need
Built-in rules are conservative by design. If a command you need is being blocked, you have several options.Steps to resolve:
-
Run
npx cc-safety-net explain "<the command>"to understand exactly why it’s being blocked and which rule matched. -
If the deny reason is “Command analysis exceeds CC Safety Net’s derived-command work limit. Reduce nested or embedded command complexity and retry.”, no rule matched. The command exhausted the fixed work budget for derived commands, such as shell one-liners inside
find -exec,xargs, orparallel, commands embedded behind wrappers, and similar nested forms. The budget is a compile-time constant, so no configuration raises it. Split the command into simpler commands and retry. - If the deny reason is “CC Safety Net could not analyze the command because it exceeds safe analysis limits. Simplify or split the command and retry.”, no rule matched either. The command crossed a fixed path-canonicalization or shell-structure budget. Commands that do this carry enough path-like tokens to exhaust the path-canonicalization budget, inline shell functions past the projection’s cap of 256 call sites, or nest heredoc bodies deeper than the parser allows. The budget is a compile-time constant, so no configuration raises it. Simplify or split the command and retry.
- If the deny reason is “CC Safety Net failed closed because command analysis failed unexpectedly. This is not caused by your command. Report it to the user.”, the analysis hit an internal fault rather than a budget. Reworking the command is not the fix. Report it, as the reason says.
-
If the deny reason is “CC Safety Net could not use the requested working directory because it does not exist, is inaccessible, is not a directory, or uses an unsupported path form. Use an existing accessible working directory. If the requested directory is missing, create it from an accessible location before retrying the command.”, the command was never analyzed. This is an Amp Code shell call whose
dircould not be resolved. Point the call at a directory that already exists, or create the missing one from an accessible location, and retry. -
If the deny reason is the one below, the agent tried to run
cc-safety-net policy apply:This block is deliberate and has no override, because applying a proposal rewrites the policy the guards enforce. Runnpx cc-safety-net policy apply <file>yourself in a terminal.policy checkstays allowed, so the agent can still show you what the proposal would change. The recognizer over-matches on purpose, so it also fires onnpx,bunx,pnpm dlx,npm exec, andbun/nodeforms of the same command. -
Consider these alternatives depending on your situation:
- Working in a linked git worktree? Turn on worktree mode with
workflow.worktree_modeinpolicy.jsonorCC_SAFETY_NET_WORKTREE=1. This relaxes local-discard rules when the command is proven to run inside a linked worktree, which is designed to be a disposable, isolated workspace. - Need a safer variant? For example,
git push --force-with-leaseis allowed and provides the same outcome as--forcewith an added safety check.git clean -n(dry-run) is allowed and lets you preview what would be removed. - Command is genuinely needed? Run it manually outside the agent. This is always an option, and CC Safety Net will tell the agent to ask you to do exactly this when a block fires.
- Working in a linked git worktree? Turn on worktree mode with
Custom rules are not being enforced
Custom rules are not being enforced
A rule source that cannot be verified is dropped. Your commands keep running, but the rules from that source stop applying. The runtime reports
degraded. This failure can be quiet during a clean session, so check it after each rule configuration change and upgrade.Every other verified scope and every built-in protection keeps enforcing. A full breakdown of each failure and the fallback it produces is in Configuration recovery.Steps to resolve:- Run
npx cc-safety-net statusfor the verdict, thennpx cc-safety-net doctorfor the full reason. It names the rejected source and condition. - Run
npx -y cc-safety-net rule listto see which sources and rules are actually active, plus any issues and warnings. Thennpx -y cc-safety-net rule verifyto validate rulebook structure. - Check that you’re using the correct file locations:
- User scope:
~/.cc-safety-net/rules/rule.json(created withrule init --global) - Project scope:
.cc-safety-net/rules/rule.jsonin your project root
- User scope:
- Ensure both
rule.jsonand your rulebook JSON files are valid JSON. Common mistakes include trailing commas and unquoted keys. An unreadablerule.jsondrops that whole scope, including itstransparent_wrappers. - Confirm that
"version": 1is present inrule.jsonand"rulebook_version": 1is present in eachrulebook.json. Both fields are required. - If you edited a rulebook and the old behavior persists, you edited a file the scope does not load. Every source loads from
<rules dir>/<rulebook name>/rulebook.json, where the name comes from the source entry inrule.json, and a saved edit there applies on the next tool call with no publishing step. Runnpx -y cc-safety-net rule listto see the source and rulebook name each scope actually loaded, then check that the file you edited sits under that name. Check also that nooverridesentry inrule.jsonturns the rule off. A rulebook name another source already claimed is ignored with a warning, so its rules never load at all. - If you previously used the legacy inline config (
.safety-net.jsonor~/.cc-safety-net/config.json), runnpx -y cc-safety-net rule migrateto convert it to the new layout. An unmigrated legacy file’s rules are inert until you do. - After changing a rulebook source, run
npx -y cc-safety-net rule verifyto revalidate it. There is no rebuild step.rule verifyreloads each scope the way the guard does and fails with the exact remaining diagnostic rather than reporting a false success. For a remote source,npx -y cc-safety-net rule updaterefetches it and overwrites the vendoredrulebook.json, so local edits to that file are lost.
degraded. Nothing is blocked only because it is unconfigurable.status or the status line reports degraded
status or the status line reports degraded
degraded means a configuration candidate was rejected and something safe is enforced in its place. Causes include a dropped rule source, a duplicate rulebook name, or an invalid policy.json that falls back to salvaged values or protective defaults. Ordinary work is never denied for this reason.Steps to resolve:-
Run
npx cc-safety-net doctor. Theconfig.runtime-degradedfinding carries the full reason, naming the rejected file and condition. -
For a rule source, apply the repair the reason names. The
config.runtime-degradedfix hint states it as:An invalid or misnamed rulebook ends its reason withfix that file. A missing local rulebook ends withcreate that file or remove that source from the rules config. A missing remote rulebook ends with an instruction to runcc-safety-net rule updateto vendor that source. Then runnpx -y cc-safety-net rule verifyto confirm. -
Fix
policy.jsonby hand because the runtime never rewrites it. Rejected sections fall back to protective defaults, so the usual symptom is more denials than you configured. The exception is an invalidsafety.level, which falls back tostandardand therefore lowers your protection. -
Re-run
npx cc-safety-net statusand confirm the verdict isready.
doctor reports rulebook lock and cache leftovers
doctor reports rulebook lock and cache leftovers
doctor reports the info finding config.v2-leftovers, titled Rulebook lock and cache leftovers detected, when a rule.lock file or a cache directory from an earlier version is still on disk in either scope. Its detail lists the paths it found.Nothing reads those files. The runtime loads each rulebook.json directly, so the finding is informational. The verdict stays ready and every configured rule keeps enforcing. The fix hint is exactly:rule sync is deprecated and does nothing else. It runs offline, copies any cached rulebook that still matches its recorded digest into the live path its source loads from, then deletes the lock and the cache. See rule sync for the rest of its output and the case where it refuses to run.Status line not showing in Claude Code
Status line not showing in Claude Code
The status line requires an entry in
~/.claude/settings.json. If it’s not appearing, the entry is likely missing, malformed, or pointing to the wrong runtime.Steps to resolve:- Open
~/.claude/settings.jsonand verify thestatusLineentry is present. It should look like one of the following: - Changes to this file take effect immediately. You do not need to restart Claude Code.
- If you’re using the
claude xvariant, it is only compatible with the native version of Claude Code. If you installed Claude Code via npm, usenpxorbunxinstead. - Test the status line command directly in your terminal to confirm it produces output:
If this command fails, the status line will be blank inside Claude Code.
- The status line reflects the
enabledPlugins["cc-safety-net@cc-marketplace"]entry in~/.claude/settings.json. If you run CC Safety Net as a manual hook or for another agent, it may show❌even though protection is active. See Status line for what each indicator means.
Getting an update
Getting an update
Keep CC Safety Net up to date to get the latest blocking rules and bug fixes.Update every installed integration:
update detects installed integrations, including disabled ones, and refreshes each one in place. It reports an integration as skipped when it cannot find the agent CLI. The @latest tag matters because a bare cc-safety-net spec can run an older cached copy instead of the current release. Pressing u in the interactive installer runs the same update.Claude Code (plugin marketplace):To update automatically instead, go to /plugin → select Marketplaces → choose cc-marketplace → enable auto-update.If you have a local install, update it with your package manager.Check your current version:Collect diagnostics and report the issue
If you’re unable to resolve an issue with the steps above, collect the full diagnostic output before filing a report:--json flag produces structured output that captures your environment, installed versions, hook configuration, and self-test results in a single snapshot.
Report bugs, coverage gaps, false positives, installation problems, and documentation issues in a public GitHub issue. Use the private path in the security policy for secret leakage, a write outside the intended directory, and supply-chain or package-integrity problems.