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_interpretersproject policy enables worktree mode relaxationsproject policy disables destructive command protectionproject policy disables secret protectionproject 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.
How CC Safety Net measures a weakening
How CC Safety Net measures a weakening
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
SetCC_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 changepolicy.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 runcc-safety-net policy apply <file>in a terminal and confirm. Seepolicy.
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: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.
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:
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:
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:
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:
- A configured deny path always wins. If the same target is in both lists, the result is
secret.deny-path. - Coding CLI credential and config rules (
secret.cli.*) always win. - An allow-path match suppresses any other built-in secret rule for that target.
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.
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 invalidpolicy.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.
Configuration recovery lists what each invalid field falls back to and how to get back to ready.
Related pages
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.