ocra

Configuration

The .ocra/config.json file and environment variables.

ocra reads .ocra/config.json from the root of the repository being reviewed. Every key is optional; unknown keys are rejected so typos fail loudly.

ocra review --config <file> reads a file of your own instead, wherever it is: a CI checkout, your home directory. It is yours to trust, so it applies with --no-repo-config too, which is how reviews of code you do not trust (the evaluation harness, for example) get declared model endpoints and limits. Plugins it names are resolved from its own directory. With --pr and --mr it replaces the base branch's file; plugins are still not loaded there.

{
  "$schema": "https://raw.githubusercontent.com/jma49/Open-CR-Agent/main/docs/schema/config.v1.json",
  "models": {
    "top": "google/gemini-3.1-pro-preview",
    "standard": ["google/gemini-3.5-flash", "google/gemini-flash-lite-latest"],
    "light": "google/gemini-flash-lite-latest"
  },
  "concurrency": 4,
  "taskTimeoutMinutes": 10,
  "runTimeoutMinutes": 25,
  "verify": true,
  "judge": true,
  "maxCostUsd": 1,
  "include": [],
  "exclude": ["legacy/**"],
  "runtime": "opencode",
  "plugins": [],
  "reviewers": {},
  "pluginSettings": {}
}

The optional $schema key points editors at the file's JSON Schema (draft 2020-12, generated from the code and tested against it), so they complete keys and flag unknown ones and bad values as you type; ocra itself ignores the key.

Models

Models are written as provider/model, using OpenCode's provider IDs (for example google, anthropic, openai). Each tier takes one model or a failback chain:

TierUsed for
standardReviewer agents
lightHelper calls such as grouping changed files
topThe judge

When a model is overloaded or rejects a request, the task retries on the next model in the chain. A rate limit with a short stated wait (up to 90 seconds) pauses that model for every task and retries it; a limit marked as daily, a longer or missing wait, or a fourth limit in a row takes the model out of the chain for the rest of the run. Each model has a circuit breaker: after two failures in a row it is skipped for a minute, then one request probes it; success brings it back, another failure skips it for twice as long (up to ten minutes). Credential errors stop immediately, because another model of the same provider would fail too.

Environment variables override the file, comma-separated for chains:

export OCRA_MODEL_STANDARD="google/gemini-3.5-flash,google/gemini-flash-lite-latest"
export OCRA_MODEL_LIGHT="google/gemini-flash-lite-latest"
export OCRA_MODEL_TOP="google/gemini-3.1-pro-preview"

Effort

Most current models can be told how much to reason before they answer. effort sets it per tier, reviewers.<id>.effort for one reviewer (its review tasks and its plan call), and roles.<role>.effort for the verifier, the judge or the helper calls (grouping files, relocating quotes). Levels are none, minimal, low, medium and high. An agent takes its own effort, else its tier's (reviewers by their tier, the verifier standard, the judge top, helpers light); the verifier and the judge never take a reviewer's. Unset sends nothing, so the provider's default applies.

{
  "effort": { "standard": "medium", "top": "high" },
  "reviewers": { "security": { "effort": "high" } },
  "roles": { "helper": { "effort": "minimal" } }
}

OCRA_EFFORT_TOP, OCRA_EFFORT_STANDARD and OCRA_EFFORT_LIGHT override a tier's effort.

  • The direct runtime sends the level as reasoning_effort, or as reasoning: { effort } for a provider declared with "effort": "openrouter" (Model providers). none is sent as none. A call that sends any other level sends no temperature or seed: reasoning models refuse or override them. If the endpoint answers HTTP 400 naming the parameter, the call is sent again without it, once, without counting as the model's failure; that model's later calls go without it, and the run warns.
  • The opencode runtime does not send an effort yet; the run warns and records it as not applied.
  • The JSON report's provenance.agents lists each agent's tier, its effort and whether it was applied, and notApplied for the sampling settings its calls left out. --plan shows each task's effort. The configuration hash covers effort.

Provider keys

Keys are read from the environment only. Use the variable your provider expects in OpenCode, for example ANTHROPIC_API_KEY or OPENAI_API_KEY. For Google, GEMINI_API_KEY, GOOGLE_API_KEY and GOOGLE_GENERATIVE_AI_API_KEY all work.

The agent runtime receives only what it needs from your environment: PATH, HOME, locale, proxy and CA settings, and the credentials of the providers named in your model chains (for a provider ocra does not know, every variable starting with its uppercased id, such as GROQ_ for groq). Anything else, like cloud credentials or GITHUB_TOKEN, stays out. If a provider needs another variable, list its name in OCRA_RUNTIME_ENV, comma-separated.

For providers that always need a key (Google, Anthropic, OpenAI, OpenRouter, Groq, Mistral, DeepSeek, xAI, Azure), ocra checks before starting that one is set and names the variable if it is missing.

To reach your own server or a company gateway that speaks the OpenAI API, declare it under providers; which providers work and what each needs is on Model providers.

Execution

KeyDefaultMeaning
concurrency4Review tasks running at once (1–32)
taskTimeoutMinutes10Limit for one review task
runTimeoutMinutes25Limit for the whole run
maxCostUsdnoneSpend limit for the run: review tasks use up to 80% of it, verification and judging the rest (see --max-cost-usd)
maxTasks60Most review tasks one run starts. Past it, --ultra's second passes go first, then later reviewers, so every file keeps its first reviewer as long as possible; skipped files are reported as not reviewed (exit code 3)
judgetrueMerge, filter and recalibrate findings across reviewers (one top-tier call per run with findings)
verifytrueFact-check findings before reporting them (one standard-tier call per file with findings)
samplingnone{ "temperature": 0–2, "seed": n } for every model call; either may be left out, and unset means each provider's default. --temperature and --seed override it. The direct runtime sends both. The opencode runtime sets the temperature on its agents, and OpenCode passes it on only for models its catalog says accept one (it marks your declared models so); it has no seed setting, so a seed is reported as not applied. The JSON report's provenance.sampling says what was applied. A seed makes runs repeatable only where the provider honors it

A task that fails or times out never fails the run; its files are reported as failed.

File selection

ocra skips binary files, likely secrets (.env, keys, certificates, cloud and registry credentials, Terraform variables and state), deleted files, media and archives, lock files, vendored and generated code, and very large diffs. Files over 1 MB are diffed as binary and skipped. Database migrations are never skipped as generated code (the other rules still apply).

  • exclude: globs to skip in addition.
  • include: globs to review even if they would be skipped as generated or by extension. Secrets can never be included.

Reviewers

reviewers.<id> turns a reviewer off, sets the risk tier it starts at (higher or lower than its default), or sets its effort. Risk tiers, from lowest: trivial (≤10 changed lines), lite (≤100), full (larger changes, more than 20 files, or a sensitive path: CI workflows, or a directory or file name with a word such as auth, oauth, jwt, password, credential, secret, login, permission, acl, identity, crypto or security).

{ "reviewers": { "correctness": { "minTier": "lite" }, "security": { "enabled": false } } }

Pairs the matrix skips are listed under skipped in the JSON report; a file no reviewer covers shows up as unreviewed in coverage.

Shared configuration

An organization can keep common settings in one place and let repositories extend it:

{ "extends": "https://config.example.com/ocra.json#sha256=<hex>" }

The shared file may set models, concurrency, the timeouts, verify, judge, maxCostUsd, maxTasks, include, exclude, effort, reviewers, roles, github, providers (only when pinned, see below) and rules (the same shape as .ocra/rules.json entries). It cannot list plugins or choose a runtime: it comes from outside the repository and must not run code. The repository's own values win; include, exclude and rules are combined and models, effort, reviewers, roles, github and providers are merged key by key.

Only https URLs are accepted, without redirects, up to 256 KB. The optional #sha256= fragment pins the exact content; a file that declares providers must be pinned, since a provider decides where your code goes (Model providers). If the file cannot be loaded or is invalid, ocra warns and continues with the repository's own settings; limits set only in the shared file, such as maxCostUsd, then do not apply, so set them in the repository too if they must always hold.

Plugins

runtime names the registered runtime to use: opencode (the default) runs the reviewers through OpenCode and reaches every provider in its catalog; direct calls the endpoints declared under providers itself and reaches nothing else (Model providers). plugins lists extra plugins by package name or path, and pluginSettings.<plugin-name> holds each plugin's settings. See Plugins.

Edit on GitHub

On this page