Skip to main content
Use this guide to fix common CC Safety Net installation and behavior problems. Run 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

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:
  1. Run npx cc-safety-net doctor. It checks hook integration for every supported agent and reports misconfiguration with the exact configuration path.
  2. 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.
  3. Amp Code: run amp plugins list and confirm a cc-safety-net (User Plugins) row with status active. Any other status requires plugins: reload in Amp or a reinstall with install --amp. A local file at ~/.config/amp/plugins/cc-safety-net.ts masks the personal plugin. install --amp removes a managed copy and fails with an actionable error on an unmanaged one. Amp reads plugins at startup, so restart Amp or run plugins: reload after a change.
  4. Antigravity CLI: check ~/.gemini/config/hooks.json for a managed PreToolUse entry running npx -y cc-safety-net hook --agy-cli.
  5. Claude Code: run /plugin inside Claude Code and confirm that cc-safety-net appears 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.
  6. Codex: run codex plugin list and confirm the cc-safety-net@cc-marketplace line reads installed, enabled. Then run /hooks in the TUI, select the cc-safety-net PreToolUse hook, and press t to mark it as trusted. The hook will not fire until you trust it.
  7. Cursor: check ~/.cursor/hooks.json for a managed preToolUse entry running npx -y cc-safety-net hook --cursor. The config is global, so one entry covers Cursor IDE and Cursor CLI across all projects.
  8. Gemini CLI: run gemini extensions list and confirm the https://github.com/kenryu42/gemini-safety-net source is installed and enabled (check both User and Workspace scope, Workspace wins if set). Reinstall with gemini extensions install https://github.com/kenryu42/gemini-safety-net and start a new Gemini session.
  9. GitHub Copilot CLI: confirm the cc-safety-net@cc-marketplace plugin is installed (/plugin) and enabled in enabledPlugins in ~/.copilot/settings.json. For Copilot CLI 1.0.8+, check inline hook config and disableAllHooks in 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 defines disableAllHooks decides the result: true disables all hooks, while false stops lower-priority values from applying. A hook in .claude must run cc-safety-net hook --copilot-cli or cc-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+.
  10. Grok Build: check ~/.grok/hooks/cc-safety-net.json (or $GROK_HOME/hooks/cc-safety-net.json) for a managed PreToolUse entry running npx -y cc-safety-net hook --grok-build. Re-run npx -y cc-safety-net@latest install --grok-build if it’s missing.
  11. Hermes Agent: confirm the managed plugin files exist in $HERMES_HOME/plugins/cc-safety-net (~/.hermes/plugins/cc-safety-net when HERMES_HOME is unset) and enable the plugin with hermes plugins enable cc-safety-net --no-allow-tool-override. Hermes loads a user plugin only when its config.yaml lists it. Restart Hermes so the plugin loads. doctor reads 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.
  12. Kimi Code: check ~/.kimi-code/config.toml (or $KIMI_CODE_HOME/config.toml) for a [[hooks]] block running npx -y cc-safety-net hook --kimi-code on PreToolUse Bash. Re-run npx -y cc-safety-net@latest install --kimi-code if it’s missing.
  13. OpenClaw: the plugin is installed and enabled through OpenClaw’s own CLI. Re-running npx -y cc-safety-net@latest install --openclaw runs openclaw plugins install <plugin dir> --force and openclaw plugins enable cc-safety-net, then confirms the plugin loaded (openclaw plugins inspect cc-safety-net --runtime shows the details). Restart the OpenClaw Gateway afterwards, and if plugins.allow is set in openclaw.json, it must also list cc-safety-net. doctor reads the plugin directory and openclaw.json only; it never asks a running Gateway whether the plugin loaded, so a stopped Gateway is not reported as a failure.
  14. OpenCode: check $XDG_CONFIG_HOME/opencode/opencode.json (or .jsonc) when XDG_CONFIG_HOME is set; otherwise check ~/.config/opencode/opencode.json (or .jsonc). Confirm that the plugin[] array contains cc-safety-net. OpenCode can cache a stale version. See the Installation cache-clearance steps.
  15. Pi: confirm pi install npm:cc-safety-net completed and you restarted Pi so the extension loads. Pi runs CC Safety Net as an in-process extension; run npx cc-safety-net doctor, which probes Pi directly.
  16. After making any changes, reload or restart your agent session.
If you are unsure which mechanism your agent uses, see Integration architecture.
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:
  1. 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-net on every command, which adds a few hundred milliseconds even with a healthy npm cache.
  2. 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.
  3. Rule out registry latency:
    If the --prefer-offline run 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.
  4. Repair the npm cache:
    A bloated or corrupted cache slows every npx resolution, warm runs included. npm cache verify garbage-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.
After a fix, re-run the timing command from step 2. Warm runs in the low hundreds of milliseconds are as fast as the npx-based integrations get.
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:
  1. 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.
    A real trace is not automatically safe to share. Redaction covers recognized credential shapes only; the command text, its parsed tokens, absolute paths including your home directory, and your policy file path are carried through. Reproduce the case with placeholder credentials and review the output before pasting it anywhere.
  2. 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.
  3. The command may fall into an explicitly allowed category. For example, rm -rf within the current working directory is allowed by default because it’s scoped to your project. See the Allowed commands reference for the full list.
  4. Run npx cc-safety-net status. A degraded verdict means a rule source was dropped, so the denials that source contributed are not being enforced. See Configuration recovery.
  5. Look for a Project policy block in that same status output. It appears when a project .cc-safety-net/policy.json relaxed the user policy, and each line names one relaxed field, for example project policy lowers level: strict -> standard, project policy disables rule <id>, or project 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 🔻, and doctor prints the same lines under Project policy deltas:.
  6. 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.
  7. If you need the command blocked in your context, create a custom rulebook with npx -y cc-safety-net rule init and add a rule to .cc-safety-net/rules/project-rules/rulebook.json. See Custom rules for the schema.
  8. 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 explain trace 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.
Built-in rules are conservative by design. If a command you need is being blocked, you have several options.Steps to resolve:
  1. Run npx cc-safety-net explain "<the command>" to understand exactly why it’s being blocked and which rule matched.
  2. 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, or parallel, 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.
  3. 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.
  4. 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.
  5. 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 dir could not be resolved. Point the call at a directory that already exists, or create the missing one from an accessible location, and retry.
  6. 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. Run npx cc-safety-net policy apply <file> yourself in a terminal. policy check stays allowed, so the agent can still show you what the proposal would change. The recognizer over-matches on purpose, so it also fires on npx, bunx, pnpm dlx, npm exec, and bun/node forms of the same command.
  7. Consider these alternatives depending on your situation:
    • Working in a linked git worktree? Turn on worktree mode with workflow.worktree_mode in policy.json or CC_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-lease is allowed and provides the same outcome as --force with 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.
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:
  1. Run npx cc-safety-net status for the verdict, then npx cc-safety-net doctor for the full reason. It names the rejected source and condition.
  2. Run npx -y cc-safety-net rule list to see which sources and rules are actually active, plus any issues and warnings. Then npx -y cc-safety-net rule verify to validate rulebook structure.
  3. Check that you’re using the correct file locations:
    • User scope: ~/.cc-safety-net/rules/rule.json (created with rule init --global)
    • Project scope: .cc-safety-net/rules/rule.json in your project root
  4. Ensure both rule.json and your rulebook JSON files are valid JSON. Common mistakes include trailing commas and unquoted keys. An unreadable rule.json drops that whole scope, including its transparent_wrappers.
  5. Confirm that "version": 1 is present in rule.json and "rulebook_version": 1 is present in each rulebook.json. Both fields are required.
  6. 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 in rule.json, and a saved edit there applies on the next tool call with no publishing step. Run npx -y cc-safety-net rule list to see the source and rulebook name each scope actually loaded, then check that the file you edited sits under that name. Check also that no overrides entry in rule.json turns the rule off. A rulebook name another source already claimed is ignored with a warning, so its rules never load at all.
  7. If you previously used the legacy inline config (.safety-net.json or ~/.cc-safety-net/config.json), run npx -y cc-safety-net rule migrate to convert it to the new layout. An unmigrated legacy file’s rules are inert until you do.
  8. After changing a rulebook source, run npx -y cc-safety-net rule verify to revalidate it. There is no rebuild step. rule verify reloads 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 update refetches it and overwrites the vendored rulebook.json, so local edits to that file are lost.
You can run all of these while the runtime is degraded. Nothing is blocked only because it is unconfigurable.
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:
  1. Run npx cc-safety-net doctor. The config.runtime-degraded finding carries the full reason, naming the rejected file and condition.
  2. For a rule source, apply the repair the reason names. The config.runtime-degraded fix hint states it as:
    An invalid or misnamed rulebook ends its reason with fix that file. A missing local rulebook ends with create that file or remove that source from the rules config. A missing remote rulebook ends with an instruction to run cc-safety-net rule update to vendor that source. Then run npx -y cc-safety-net rule verify to confirm.
  3. Fix policy.json by 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 invalid safety.level, which falls back to standard and therefore lowers your protection.
  4. Re-run npx cc-safety-net status and confirm the verdict is ready.
See Configuration recovery for every failure row and its fallback.
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.
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:
  1. Open ~/.claude/settings.json and verify the statusLine entry is present. It should look like one of the following:
  2. Changes to this file take effect immediately. You do not need to restart Claude Code.
  3. If you’re using the claude x variant, it is only compatible with the native version of Claude Code. If you installed Claude Code via npm, use npx or bunx instead.
  4. 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.
  5. 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.
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:
The --json flag produces structured output that captures your environment, installed versions, hook configuration, and self-test results in a single snapshot.
Review diagnostic and explain output before sharing it. It contains absolute filesystem paths including your home directory, project and directory names, and your configuration paths. Redaction covers recognized credential shapes only, so reproduce the problem with placeholder credentials rather than real ones and read the output before you paste it.
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.
Last modified on September 1, 2026