paranoid_
Core

Team policy file

.paranoid.toml at the repo root is the only other file paranoid reads besides command-line flags. It is optional, and it has a small, fixed set of keys.

paranoid has no general configuration system. An unknown key, an unknown table, or a key with the wrong type is an execution error (exit 3) that names the offending key.

The keys

fail-under = 80
strict = true

[[disable]]
rule = "TI012"
reason = "flaky under load, tracked in issue #142"
expires = "2026-12-01"

[sandbox]
image-go = "golang:1.26"
image-python = "python:3.12-slim"
image-node = "node:22-slim"

[formal]
allowed_axioms = ["Classical.choice"]

[formal.llm]
provider = "anthropic"
model = "claude-opus-5-5"

[formal.llm.proof]
provider = "openai"
model = "my-local-prover"
base_url = "http://localhost:11434/v1"
api_key_env = "LOCAL_LLM_KEY"
KeyTypeMeaning
fail-underintegerThis repo's own --fail-under default
strictbooleanThis repo's own --strict default
[[disable]].rulestring, requiredA rule ID to suppress everywhere it would fire
[[disable]].reasonstring, required, non-emptyWhy the rule is disabled
[[disable]].expiresstring, optionalRFC 3339 or a bare date; once passed, the rule fires again
[sandbox].image-gostringContainer image pin for a detected Go suite
[sandbox].image-pythonstringContainer image pin for a detected Python suite (pytest or unittest)
[sandbox].image-nodestringContainer image pin for a detected npm/pnpm/yarn suite
[formal].allowed_axiomslist of strings, on one lineAxioms FV010 accepts in addition to the defaults (Lean: propext, Classical.choice, Quot.sound; Rocq: none). Each entry must be a non-empty string. sorryAx, Lean.ofReduceBool, and Lean.trustCompiler are rejected with an error, because allowing them would hide a hole. Only read with verify --formal-check
[formal.llm].provider
[formal.llm.proof].provider
[formal.llm.spec].provider
stringanthropic, openai, or gemini. Default anthropic
[formal.llm*].modelstringModel name. Default claude-opus-5-5 for anthropic. The other providers have no default, so a model is required
[formal.llm*].base_urlstringAn http or https URL, without a user name or password. For openai this is how you point at a local or compatible server
[formal.llm*].api_key_envstringThe NAME of the environment variable that holds the key. Default ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY

[[disable]] is an array of tables: repeat the block to disable more than one rule. [sandbox] and [formal] may each appear at most once. Both are optional; a file with only fail-under and strict is valid, and so is an empty file.

LLM settings: [formal.llm]

These tables set the provider for the online paranoid formal subcommands. They are never read by verify, which does not call an LLM. See Online features and providers.

Run paranoid formal providers to see what the file resolves to.

Precedence

For both fail-under and strict, the flag has the highest precedence, then the file, then the default:

  1. The command-line flag wins whenever it is given on the command line, even if the value matches the built-in default.
  2. Otherwise, .paranoid.toml's value wins, when the file sets that key.
  3. Otherwise, paranoid's own default applies: fail-under 50, strict off.

--sandbox-image always wins over a [sandbox] pin, the same rule. A pin only applies to the language DetectSuite already chose (a Python pin does nothing on a Go repository); it never changes which suite is detected.

Every command that runs the verify pipeline (verify, baseline, fix-prompt) honors an auto-detected policy file the same way. Only verify exposes --no-policy today; the other two commands cannot opt out of it individually yet.

How a disabled rule appears in the report

A [[disable]] match is reported the same way as a baseline match (see Baseline & suppressions): the finding leaves findings and the score, and appears in the report's suppressed section with the entry's reason. The one difference is the source field on each suppression entry, "policy" instead of "baseline"; text and markdown output label it suppressed-by-policy rather than suppressed-by-baseline. An entry whose expires date has passed stops suppressing: its finding comes back into the report and the score, and the report still lists the expired match.

Matching is by rule ID alone, not by file or evidence text the way a baseline entry matches: a [[disable]] entry disables that rule everywhere in the diff, not one specific finding of it. Disabling a rule this way is broader than baselining one finding; use the baseline file instead when you want to carry forward one specific, already-reviewed finding.

See Report & schema for the exact JSON shape.

Loading

FlagMeaning
--no-policyIgnore .paranoid.toml, even when present at the repo root

.paranoid.toml loads from the repo root only, the same rule the baseline file follows: no path-override flag, no walking up parent directories, no global file outside the repo. A missing file is not an error, there is nothing to load. A file that exists but fails to parse is always a hard error (exit 3), naming the key or table that broke it.

Using this in CI

Commit .paranoid.toml at the repo root; the GitHub Action needs no new input for it, since the file is read from the checked-out repository itself, the same way .paranoid-baseline.json already is. [[disable]] and [sandbox] apply exactly as they do outside CI. fail-under does not: the action always passes --fail-under explicitly (that input's own default is 50), so a repo's fail-under key never takes effect through the action; strict is unaffected, since the action only adds --strict when its own strict input is true. See Exit codes & CI.

.paranoid.toml is not watched by SF006, the rule that flags a change to .paranoid-baseline.json or a hook configuration file. An agent under audit could add a [[disable]] entry for a rule that would otherwise flag its own work, and this would not be surfaced the way editing the baseline file is.