Plugins

Extend ocra with VCS adapters, runtimes, reviewers, rules, tools and listeners.

ocra's own adapters, runtimes, reviewers and session log are built-in plugins; yours use the same contract.

Writing a plugin

A plugin is a module that exports an object as default (or plugin):

// tools/ocra-team-rules.mjs
export default {
  name: "team-rules",
  configure(ctx) {
    ctx.registerRules([
      {
        path: "services/**",
        rule: `Owned by ${ctx.settings.team}: check idempotency keys on every write.`,
      },
    ]);
  },
};

Register it in .ocra/config.json:

{
  "plugins": ["./tools/ocra-team-rules.mjs"],
  "pluginSettings": { "team-rules": { "team": "payments" } }
}

Plugins resolve from the repository's dependencies (package names) or from paths relative to the repository root (which may point outside it). They run code, so they load only in local reviews, never for pull or merge requests or with --no-repo-config.

Plugins from your ocra Cloud account

When you are signed in, your ocra Cloud settings may name plugins by npm package name, with pluginSettings. The account only names them: a plugin loads on a machine only after you allow it there with ocra plugins allow.

ocra plugins allow ocra-plugin-team-rules@1.4.0   # shows the package and its publisher, then installs it
ocra plugins list
ocra plugins deny ocra-plugin-team-rules

allow takes an exact version, never a range or tag. It shows the registry's name, version, publisher, maintainers and integrity, installs with install scripts off (details in ocra plugins), and records name, version and integrity in plugins.json (readable only by you). npm runs in that directory, so your project's npm configuration does not apply; a package without a listed integrity is refused. The integrity covers the package tarball, not its dependencies, which npm resolves at install time. Allowing a plugin is a supply-chain decision, like adding a dependency.

A review loads a plugin your account names only:

  • if this machine allowed it, from that directory alone, never from the reviewed checkout's node_modules, and only while the installed package still has the version and integrity recorded when you allowed it;
  • where a repository's plugins could load: local reviews, never --pr or --mr, never with --no-repo-config.

An account plugin this machine has not allowed is skipped with one warning giving ocra plugins allow <name>@<version>. One the repository already lists loads as the repository's; one whose plugin name is taken is skipped; one that fails to load is skipped with a warning, never failing the review.

The account's pluginSettings are keyed by npm package name (@acme/ocra-team-rules, not the team-rules plugin it exports) and reach only the account's loaded plugins, under their plugin name. The configuration's pluginSettings win, and a repository plugin's settings come from the repository alone.

Lifecycle

HookRunsOn failure
bootstrap(ctx)All plugins concurrentlyWarning; the review continues
configure(ctx)In load orderThe review stops, naming the plugin
postConfigure(ctx)Concurrently, after all registrationsThe review stops

Use bootstrap for work that may fail harmlessly, such as fetching remote settings.

What a plugin can register

MethodContributes
registerVcs(name, factory)A code host adapter
registerRuntime(name, factory)An agent runtime
registerReviewer(definition)A reviewer with its own prompt and model tier
registerRules(rules)Path-scoped review rules
registerTool(tool)A tool reviewers can call, with a Zod input schema
onEvent(listener)A listener for every review event (telemetry, notifications). A listener that throws is disabled with one warning; the review continues

Plugins receive only their own settings (ctx.settings), validated by an optional settingsSchema. Registering a name twice, using a reserved tool name, or registering after configure fails with an error naming the plugin.

Writing a runtime

  • Factory input: the model chains, the environment, the declared providers, sampling (temperature, seed) when configured, and agentModels: every agent's own chain by agent id, for a runtime that prepares providers before the first call. Such an agent also sends its chain as models on its task specs and completion requests; a runtime that ignores both uses the tier's chain.
  • Sampling: the runtime's sampling property says what it sends, with notApplied for what it cannot pass on; without it, the runtime is reported as applying none.
  • Effort: a task spec carries its reviewer's effort; a completion request names its agent (the plan call's reviewer, or verifier, judge, helper) and effort; both are absent when none is configured. A runtime that sends effort implements appliedTo(agent): whether every call of that agent sent it, in unsupported the models that do not take the level (the run warns once per agent), and in notApplied the sampling settings left out. Without it, the runtime is reported as sending no effort, with one warning. effortCapability(model) from @open-cr-agent/core gives ocra's table of a model's parameter style and levels.
  • Failover: ChainRunner from @open-cr-agent/core can serve runTask and complete, as in both built-in runtimes. It picks each call's chain (the agent's, else its tier's), refuses a tier without a model with CONFIG_INVALID, tracks each model's health for the run (short rate limits waited out, out-of-quota models dropped, a circuit breaker) and moves to the next model when an attempt fails. You give it ModelAttempts: task and complete run one attempt on one model and return an AttemptOutcome (findings, steps, tool calls, text, usage, and an error saying whether another model may succeed and, with a QuotaError, how long to wait; an attempt the abort signal cut short returns one, since an outcome without an error counts as finished); optional refuse says before any request why a chain cannot be served, optional ready starts what attempts need. Create one runner per runtime instance, so health spans the run.
  • Helpers in @open-cr-agent/core, so your runtime reviews as the built-in ones do: reviewTools, the read-only review tools to offer the agent next to RuntimeOptions.tools, and REVIEW_TOOLS, their names (an attempt's findings are what the agent passes to report_finding; task_done ends it); MAX_AGENT_STEPS, the cap on model requests per review attempt; RESUME_MESSAGE, sent once to an agent that stops with steps left, no answer and no task_done; parseModel(model), which splits provider/model and throws CONFIG_INVALID for anything else; parseQuotaError(message, status?), which reads a provider's rate-limit or quota error into a QuotaError; withoutSecrets(text, secrets), to redact keys from a provider's error before it is quoted; emptyUsage() and addUsage(); EFFORT_LEVELS and thinkingBudget(capability, level, outputLimit?), the thinking budget ocra derives for a level; and proxiedFetch(env), a fetch that honors HTTP_PROXY, HTTPS_PROXY and NO_PROXY from the given environment.

Security

A plugin runs code. Load plugins only from repositories you trust, and allow a plugin your account names only after checking who publishes it; to review someone else's branch, run ocra review --no-repo-config, which ignores the repository's config and plugins. In CI, read configuration from the protected base branch, never from the pull request under review.

Edit on GitHub

On this page