Skip to main content
policy.json is CC Safety Net’s settings file. It selects your safety preset, turns built-in rules on or off, allows or blocks specific paths, and sets how long audit records are kept. Your user file applies everywhere, and an optional project file committed to a repository layers on top of it. Your own blocking rules live in rule.json and rulebooks instead. See Custom rules.

Policy file location

The runtime reads both files on every tool call, so an edit applies to the next command. Where configuration lives lists every file CC Safety Net reads and what CC_SAFETY_NET_HOME moves.

What the config working directory is

The config working directory is the directory your agent session runs in. CC Safety Net reads the project .cc-safety-net/ folder from there, and resolves relative deny_paths and allow_paths entries against it. A cd inside a command, or a tool call that names its own working directory, does not change it.

Project policy

A team ships a safety policy by committing .cc-safety-net/policy.json to the repository. Members run nothing, and the runtime reads the file on the next tool call. The project file holds only the fields it sets. Every absent field inherits from the user policy. The effective policy is the user policy with the project policy layered on top: CC Safety Net ignores an audit section in a project file and reports project policy audit settings are ignored; audit is user scope only.

The user config directory is not a project

The directory that holds your user .cc-safety-net/, your home directory by default, is never also a project. Run from there and .cc-safety-net/policy.json is your user file, so no project file layers on top. Commands that write the project file refuse to run there. See Which file policy writes.

Reported weakenings

CC Safety Net applies a project policy as written. It reports each field the project relaxes relative to the user policy on its own line:
  • project policy lowers level: <user> -> <project>
  • project policy disables fail_closed, project policy disables paranoid_rm, project policy disables paranoid_interpreters
  • project policy enables worktree mode relaxations
  • project policy disables destructive command protection
  • project policy disables secret protection
  • project policy disables rule <id>
  • project policy adds destructive allow path: <path>
  • project policy adds secret allow path: <path>
status lists these lines under Project policy, doctor prints them under Project policy deltas:, and the status line shows 🔻 while any weakening is in force.
A lowered level is measured against safety.level in the user policy. A disabled capability is measured against the user policy with its level raised by CC_SAFETY_NET_LEVEL. So under CC_SAFETY_NET_LEVEL=paranoid, a project safety.overrides.paranoid_rm: false turns paranoid_rm off and appears as a weakening. The switch below keeps paranoid_rm on.

Ignore project weakenings

Set CC_SAFETY_NET_PROJECT_TIGHTEN_ONLY=1 to refuse every weakening a project policy makes. The merge drops each field listed above, and the project file’s tightenings still apply. See Environment. status still reports the dropped fields under Project policy (ignored), and doctor under Project policy deltas (ignored):. The status line shows no 🔻. policy check, policy apply, and the dashboard’s project draft preview the merge without the switch, so they show what a member without it gets.

Edit the policy file

Your agent cannot change policy.json in either scope. Protected policy.json files describes the block. Make the change yourself in one of these ways:
  • Use the dashboard. Run cc-safety-net gui. It can also repair a file that does not validate. See Dashboard.
  • Edit the JSON directly. The runtime reads the change on the next tool call. You do not need to restart anything.
  • Apply an agent’s proposal. The agent writes a proposal file and runs cc-safety-net policy check <file> to show you the diff. You run cc-safety-net policy apply <file> in a terminal and confirm. See policy.
After a hand edit, confirm the result:
A degraded verdict means CC Safety Net rejected part of your file, and npx cc-safety-net doctor names the fields. See Invalid policy behavior.

Complete policy example

Every field, with its default value:
Only version is required, and an omitted field takes the default shown above. An unrecognized key, at the top level or inside any section, is an error.

Schema reference

integer
required
The schema version, which must be 1. It is the only required field. A missing or wrong value reports version must be 1.
string
default:"standard"
The safety preset, one of "standard", "strict", or "paranoid". strict enables fail_closed, and paranoid enables fail_closed, paranoid_rm, and paranoid_interpreters. See Modes for what each capability changes.
boolean
Set the fail-closed capability explicitly, up or down, regardless of the preset. Omit the key to inherit from the preset.
boolean
Set the paranoid rm capability explicitly, up or down. Omit the key to inherit from the preset.
boolean
Set the paranoid interpreter capability explicitly, up or down. Omit the key to inherit from the preset.
boolean
default:"false"
Relax local-discard git rules inside a confirmed linked worktree. See Modes for what worktree mode relaxes and what it never relaxes.
boolean
default:"true"
Master switch for the registered destructive-command rules. Setting it to false skips every registered rule except the catastrophic rules, which always apply.
object
default:"{}"
Per-rule state, keyed by destructive-command rule id, with the value "on" or "off". It applies on top of your preset, so "on" can enable a rule the preset leaves off and "off" can disable one it turns on.
string[]
default:"[]"
Paths exempted from destructive-command rules. Entries must be absolute or start with ~/.
boolean
default:"true"
Master switch for secret protection. Setting it to false skips the entire secret stage, including your deny_paths.
object
default:"{}"
Per-rule state, keyed by secret-protection rule id, with the value "on" or "off". Most secret rules are on by default, so "off" is the usual direction. "on" opts into a rule from the Coding CLI config tier, which is off by default.
string[]
default:"[]"
Extra paths to protect as secrets, in addition to the built-in sensitive paths. See Deny paths for the validation rules.
string[]
default:"[]"
Exact files or directory trees exempted from built-in secret-pattern rules. Configured deny paths and Coding CLI protections still apply. See Secret allow paths for the accepted forms and precedence.
integer
default:"30"
Days of audit history to keep before the sweep deletes it. Must be an integer between 1 and 365.

Safety level and capability overrides

safety.level picks a preset. safety.overrides then sets individual capabilities explicitly. This is the only place that can turn a capability down. Environment variables can only raise the level or force capabilities on. See Environment for the full precedence.
That example takes the paranoid preset but leaves interpreter one-liners alone. A combination of capabilities that matches no preset reports as the effective level custom.

Which allow list do I use

Pick the setting by what blocked the command. The block message names the rule id. To let an agent work freely in a scratch folder, put the folder under a temp directory such as /tmp, where recursive deletes and Git discards already pass. The two allow_paths lists are separate, and neither relaxes the other’s rules.

Destructive-command protection

To allow a blocked command, turn off the rule that blocks it. Allow a blocked command walks through finding the rule id and testing the change. destructive_command_protection.overrides addresses built-in rules by id, for example:
An unregistered id fails with unknown destructive command rule id "<id>". That includes the fixed denial ids, such as guard.policy-config, which are not rules. Any value other than "on" or "off" fails with destructive_command_protection.overrides.<id> must be "on" or "off". You cannot turn off catastrophic rules. They ignore enabled: false and an "off" override.

Allow paths

destructive_command_protection.allow_paths treats each listed directory like a temp directory for recursive deletes. See Recursive deletes under allow_paths for what it covers. Validation is stricter than for deny paths:

Secret protection

Secret protection blocks reads and writes of files that can hold credentials. The Secret protection reference lists every built-in rule id and the paths each one protects. To allow a protected file, see Allow a blocked file. secret_protection.overrides addresses individual built-in rules by id, with the value "on" or "off". "off" disables a rule that is on by default, and "on" opts into a rule from the default-off tier:
CC Safety Net rejects an unregistered id with unknown secret protection rule id "<id>", and any other value with secret_protection.overrides.<id> must be "on" or "off".

Rules that are off by default

The Coding CLI config rules, which cover coding agents’ settings and MCP files, ship off because agents edit those files as routine work. Turn one on with an explicit "on" override. The Secret protection reference lists their ids and paths.

Block any file or folder with deny paths

secret_protection.deny_paths blocks every agent access to a file or folder you name, whether or not it holds secrets. For example, to stop the agent from touching your shell profile:
A deny path blocks reads and writes at every safety level. With the entry above, cat ~/.zshrc and echo x >> ~/.zshrc both block as secret.deny-path. A folder entry covers everything inside it. No allow path or override relaxes a deny path. Validation: Deny paths belong to secret protection, so secret_protection.enabled: false turns them off too. secret.deny-path is not a registered rule id, so an override cannot disable it.

Secret allow paths

secret_protection.allow_paths exempts an exact file, or a directory and everything in it, from the built-in secret-pattern rules. Use it for files you keep on purpose, such as a repository’s .env.test or a fixture directory of non-secret credential-shaped files. An entry can also be a folder, then **/, then an exact file name. ~/code/**/.env.local exempts every .env.local at any depth below ~/code, and nothing else. No other glob form is accepted. The precedence is fixed:
  1. A configured deny path always wins. If the same target is in both lists, the result is secret.deny-path.
  2. Coding CLI credential and config rules (secret.cli.*) always win.
  3. An allow-path match suppresses any other built-in secret rule for that target.
Validation: A **/ entry never exempts the folder itself. An allow path also covers a target reached through a symlink.

Audit retention

audit.retention_days sets how many days of audit records to keep. The default is 30, and the accepted range is 1 to 365.
A value outside the range puts the runtime in degraded, and retention uses the nearest bound, or 30 when the value is not a whole number. See Retention for when the sweep deletes records.

Invalid policy behavior

An invalid policy.json never blocks ordinary work. CC Safety Net keeps each valid field, replaces each invalid one with a protective default, and reports the runtime as degraded. A missing file is not an error. CC Safety Net uses the built-in defaults, and the runtime stays ready.
CC Safety Net discards invalid entries instead of repairing them. A mistyped deny path silently stops protecting that location, and an invalid safety.level silently lowers you to standard. Run npx cc-safety-net status after every hand edit.
Configuration recovery lists what each invalid field falls back to and how to get back to ready.

Modes

What each safety capability changes, and what worktree mode relaxes.

Environment

Every variable, and where each configuration file lives.

Custom rules

The separate rule.json and rulebook schemas for your own blocking rules.

Configuration recovery

Ready versus degraded, the fallback for each field, and the repair steps.
Last modified on October 27, 2026