Skip to main content

Put the gate where your agent already runs.

Hook: early guard, advisory · required check: enforcing · guarded tool table / gateway verifier: enforcing at the target

One decision path, several entry points. The recognition, the call and the verdict mapping are the same code everywhere — only the host contract differs.

Pick the row you are actually running. Each one says what it enforces, and what it does not see. A version pin is not a security audit nor an integrity check. The demo repository is changed by pull request; this page does not edit its README.

FAQ

Per-platform pages for the CI routes — GitHub, GitLab CI, Bitbucket Pipelines, the CLI and the REST API: integrations.

What each path asks for — minimum credential, what it does not read, what leaves your machine, how to remove it: per-path credentials on the Trust Center.

1. The GitHub App and the contract-gate Action stop the merge when branch protection requires the two contexts CodeRifts / issuer and CodeRifts / contract-gate.

2. The Claude Code plugin is the mod, and on a contract Write, Edit or MultiEdit it holds the call until preflight answers.

3. The MCP server returns a decision and does not stop the call.

GitHub App

REPORTS BY DEFAULT · PREVENTS WHEN REQUIRED · MERGE · 4-CONDITION CLOSURE VERIFIED

The required check binds to the exact change set and head commit, from a named issuing App.

Install the GitHub App

What "enforced" means here, and when it does not: the check reports its own enforcement status, and it reads not verified when it cannot confirm the branch protection that would make it blocking. We surface that rather than assume it.

Require the check

Two required contexts, and the bypass list is empty. The reader is the required check; the App is the second, issuer-side context. Measured 2026-09-28 on coderifts/demo: ruleset 22074842 and classic main still list contract-gate (required) beside CodeRifts / issuer. The template job name is the context.

  • The reader job name CodeRifts / contract-gate, GitHub Actions, app id 15368. The template job name is the context.
  • The App check CodeRifts / issuer, the CodeRifts App, app id 2860592.

The CodeRifts App no longer posts CodeRifts / contract-gate; it posts CodeRifts / issuer. If your ruleset required CodeRifts / contract-gate bound to the App (2860592), replace it with CodeRifts / issuer (2860592) and add CodeRifts / contract-gate bound to GitHub Actions (15368) — the workflow's if: always() job — otherwise every pull request waits for a check nobody posts.

{
  "bypass_actors": [],
  "rules": [{
    "type": "required_status_checks",
    "parameters": {
      "required_status_checks": [
        { "context": "CodeRifts / contract-gate", "integration_id": 15368 },
        { "context": "CodeRifts / issuer", "integration_id": 2860592 }
      ]
    }
  }]
}

Enforcement status

Measured 2026-09-23 — the App’s full permission set read from GET https://api.github.com/apps/coderifts, and the boundary graded by live-boundary-readback-2026-09-23.

Claude Code

The api-governance plugin at tag v1.2.1 is version 1.2.1, and that plugin carries the mod.

The api-governance plugin at tag v1.2.3 is version 1.2.3.

Claude Code asks for the plugin's api_key option when you install or enable the plugin in /plugin, and you set it with /plugin configure api-governance@coderifts, or from a shell with claude plugin configure api-governance@coderifts --values-stdin and the api_key value on stdin.

The key is stored in your platform's secure credential store, not in settings.json.

The plugin no longer reads the CODERIFTS_API_KEY or CODERIFTS_API_BASE environment variables (before 1.2.2 it did), and the coderifts CLI still reads CODERIFTS_API_KEY.

Since 1.2.2 the plugin asks for the key through its userConfig api_key option, and that option is marked sensitive.

On 2026-10-03 the marketplace file on main lists agent-hooks at version 0.2.2.

The same file at tag v1.2.1 lists agent-hooks at version 0.2.0.

On every Write, Edit and MultiEdit call that touches a contract file, the mod holds the call until preflight answers, and any other decision, an error, an answer it cannot read, or no answer within 8 s is refused.

A CONTINUE or CONTINUE_WITH_MONITORING answer runs the call, and so does no break detected when there is no API key.

Without a key the no-break path is analyze, which is not an authorization.

A Write, Edit or MultiEdit call that does not touch a contract file is not refused.

The catch refuses the call when the check fails before the tool runs.

When the tool has already run, the catch still returns a deny and says the change is unchecked.

The band is for the turn.

It leads with that turn's refusal, and when the turn has both a refusal and an allowance it appends a count of how many were refused and how many were allowed this turn.

A new turn clears the band.

With one refusal and one allowance in the turn, the count text is · 1 refused, 1 allowed this turn.

The refusal mark is ✗ CodeRifts.

Installed as a mod, it is one of the mods the user installed: a mod that runs before it can answer or rewrite the call, or what this mod reads, so it never sees the change; disableAllHooks in any settings file (the .claude/settings.json of the project included), --safe-mode or --bare turns it off.

Only an organization mod (installed in place from a marketplace directory the administrator owns, and enabled in managed settings) runs before the mods users install and keeps its refusal for the calls it sees; installed from its GitHub marketplace this plugin never counts as one, and --safe-mode or three crashes of the hooks worker unload even that.

This mod (api-governance 1.2.3) does not inspect shell commands: a shell write to a contract file passes it; the required check is the guarantee.

The install lines at tag v1.2.1 are /plugin marketplace add coderifts/api-governance and /plugin install api-governance@coderifts.

/plugin marketplace add coderifts/api-governance
/plugin install api-governance@coderifts

The project-scope option is labeled Install for all collaborators on this repository (project scope).

That option enables the plugin for everyone who works in this repository.

Committing that entry turns the plugin on for your collaborators but does not download it to their machines, so each collaborator also runs claude plugin install api-governance@coderifts --scope project once.

Read on 2026-10-03, claude --version printed 2.1.288 (Claude Code) and claude plugin list printed api-governance@coderifts version 1.2.1, enabled, scope user, and agent-hooks@coderifts version 0.2.2, enabled, scope user.

The mods overview documents a dim line such as 1 mod active · first-mod. This round did not open /plugin, so that line is not measured for api-governance.

The module comment at tag v1.2.1 says that on 1.2.0 the mod refused the breaking edit and allowed a second edit in the same turn, and that the 1.2.0 band showed only the last one.

This round did not repeat that edit.

ADVISORY · TOOL CALL · TIMEOUT AND UNMATCHED TOOLS PASS THROUGH

This host passes a stalled hook through. Its documentation says so plainly: do not count on a stalled hook to act as a gate. Our adapter therefore returns a hard refusal on every internal failure, rather than trusting the host to stop.

Two routes. The catalogue is the short one.

claude plugin marketplace add coderifts/api-governance
claude plugin install agent-hooks@coderifts

✔ Successfully installed plugin: agent-hooks@coderifts (scope: user)

The block below is the 2026-09-26 plugin list, which printed 0.2.0.

agent-hooks@coderifts
Version: 0.2.0
Scope: user
Status: enabled

Or wire it yourself, if you would rather pin the path. A version pin is not a security audit nor an integrity check.

npm i @coderifts/agent-hooks

Then one entry in your project's .claude/settings.json — the package ships it at claude-code/settings.snippet.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit|Bash",
        "hooks": [
          {
            "type": "command",
            "timeout": 8,
            "command": "node",
            "args": [
              "${CLAUDE_PROJECT_DIR}/node_modules/@coderifts/agent-hooks/claude-code/hook.mjs"
            ]
          }
        ]
      }
    ]
  }
}

timeout is in seconds — the host's unit, and deliberately low: our own budget is 5000 ms, so a slow answer becomes a readable approval request rather than a host-level pass-through.

Optional environment: CODERIFTS_API_KEY, CODERIFTS_ENDPOINT, CODERIFTS_TIMEOUT_MS. Without a key the gate runs in analyse mode and every gated call ends at a human — there is no setting that makes an unanswered call pass.

That optional environment is the npm hook path, not the api-governance plugin, which does not read CODERIFTS_API_KEY.

@coderifts/agent-hooks 0.3.1. A write to a named contract file is denied. A write that can reach a contract file without naming it asks, and it asks only when a contract file is under that directory. Published 2026-10-04. When CodeRifts could not decide, the refusal says GOVERNANCE_UNAVAILABLE: CodeRifts could not decide (why); this is not a finding about your change. This is that package. It is not the api-governance 1.2.3 mod, and it is not the coderifts CLI.

A PreToolUse hook installed outside managed settings does not prove the call was refused: since Claude Code 2.1.287 a user-installed mod runs before it, can answer the call so the hook never runs, and can approve a call the hook blocked; only a hook in managed settings is final.

Source, read 2026-10-03: code.claude.com/docs/en/plugins/mods/events and code.claude.com/docs/en/plugins/mods/overview.

Measured 2026-09-26 (external run). Plugin marketplace add, plugin list, and agent-hooks. This page did not re-run the host.

One file for a fleet is a different step. One file puts the hook on every machine; the required check makes it a gate.

Indexed from r/ClaudeAI, 2026-06-22 (the thread URL returned no body on this run): “CLAUDE.md says what you would like to happen. A hook decides what is allowed to happen.” The wording looked for on that forum, “Use hooks — if a restriction matters, don’t rely on Claude remembering prose in CLAUDE.md once the context gets crowded”, was not found. The carrier informs, the hook stops, and the required check forces. audit what happened under the allow list. The same split is on what each path does.

Measured 2026-09-26 (external run) — plugin marketplace add, plugin list, and agent-hooks. This page did not re-run the host.

MCP server

ADVISORY · TOOL CALL · DOES NOT EXECUTE

Three tools over streamable HTTP. No key needed to connect, initialize or list tools; a key is needed for metered governance.

During the public beta every organization gets Team features at $0 with a self-serve key, public and private repositories alike, no separate Team key to request, and each key allows 1,000 requests a month: after that authorize returns BETA_LIMIT_REACHED, analysis keeps working, and one email to hello@coderifts.com raises the limit.

Get a self-serve key.

Advisory on its own: it returns a decision and cannot stop the call — a guard client is what turns that decision into a refusal. The poison gate does run on this path and can raise a verdict, never lower a BLOCK. It sees only what you send in the call.

curl -sS -X POST https://app.coderifts.com/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

MCP details   Registry entry →

Measured 2026-09-18. JSON-RPC result with three tools; digest sha256:497eb029…d700.

Measured 2026-09-18 — live tools/list against the hosted server. Re-measured every day by the proof run.

Other ways in

One path per goal

The rows in this table are a menu, not advice. Pick your goal on the left and install the ONE path in the middle — the rest are things you can also run, not things we are recommending you run as well.

PREVENTS means the default configuration stops the thing. REPORTS means it tells you and stops nothing until you wire the condition named beside it. The GitHub App row is the check-run read on 2026-10-04, not the generated table’s neutral clamp. When a spec names a route before a server answers it, list that route under ignore.paths in the base branch's .coderifts.yml: the gate judges that spec, and since 2026-10-04 a pull request cannot add the exclusion because the decision keys come from the base.

Your goal The one path Default Also possible — not the offer
Stop a contract change from merging GitHub App REPORTS until branch protection requires CodeRifts / issuer and CodeRifts / contract-gate. On coderifts/demo pull request 4 both concluded failure: issuer check_run 111270526393 and contract-gate check_run 111270560848. This page does not call that conclusion neutral. CI step posts the same verdict, and is also not a merge gate until the check is required.
Governed tool use in Claude Code, Cursor or OpenCode MCP server, plus the Claude Code PreToolUse hook where the host is Claude Code. The fleet file is one file on every machine. Cursor files from init --agents: .cursor/rules/coderifts.mdc and .cursor/hooks.json (the default command writes 13 files across the hosts). MCP server: REPORTS — it issues receipts and executes nothing. PreToolUse hook: PREVENTS (exit 2, fail-closed when governance cannot run). OpenClaw takes the same tool call; whether the host honours a refusal is the host’s declaration, not ours. Windsurf and Devin are not on this page until a host run exists.
An agent framework — LangGraph, AutoGen, a plain function SDK / @coderifts/agent-guard ADVISORY — a client. It returns a verdict; your code is what halts. It gates nothing by itself. REST API directly, if you would rather not take the dependency.
CI only — no GitHub App GitHub Action / GitLab CI / Bitbucket, or the CLI in the job The CI step REPORTS: it posts a real check conclusion, and a merge is not blocked until that check is required. The CLI gates — deploy-gate, publish-gate, the pre-push hook — are PREVENTS by default (exit 1), with a published opt-out. The App as well, if you later want the PR comment.
An execution boundary — refuse the call or the apply coderifts/k8s-admission or coderifts/gateway-verifier ENFORCING, and customer-hosted: both run in your cluster or in front of your service, against a keyring you pin. No CodeRifts-operated service is called at admit time — which is the point and also the limit: nothing we run can observe, delay or rescue that decision. Nothing here. Every other row on this page decides about a change; only these two are at the point of execution.

Cursor one-click, link shape measured 2026-09-26 against docs/mcp-one-click.md in the app repo (the href, not a click): Add to Cursor. VS Code one-click, same source: Add to VS Code. Claude Desktop: no official one-click.

Measured 2026-09-23 against the truth table and, for the two customer-hosted paths, against what each path does (read 2026-09-20 from those repositories’ own READMEs). If a default in that table moves, this table is wrong until it follows — scripts/check-enforcement-vocabulary.mjs derives its verdicts from the same page and will say so.

OpenClaw

ADVISORY · TOOL CALL · FAIL-CLOSED IS A HOST DECLARATION

The host declares this hook fail-closed itself. Its own source says an authorization hook should fail closed when a required field is absent — we did not have to impose it.

openclaw plugins install @coderifts/agent-hooks

Then confirm it loaded:

openclaw plugins inspect coderifts-contract-gate

CodeRifts contract gate
id: coderifts-contract-gate
Status: loaded
Version: 0.2.0

Two things worth knowing. The host fetches the package itself — no npm i first. And the runtime id is coderifts-contract-gate, not the package name, so inspect @coderifts/agent-hooks returns Plugin not found.

Measured on host 2026.6.35, which is the compatibility floor the package declares. The current release is not measured.

LIVE_ROUTE — unverified on current host. The card names host 2026.6.35, which is the compatibility FLOOR the package declares — not a run on a host, and not a date. The current release is not measured.

Docker MCP Gateway

NOT_SHIPPED · INTERCEPTOR SEAM MEASURED

Not built. The interceptor seam is real and we measured it on 2026-09-13: an empty stdout passes the call through, and a non-empty CallToolResult stops it before the container starts.

In the Docker MCP Gateway (v0.44.1, read 2026-10-04), an HTTP interceptor denies a call only by returning a non-empty JSON tool result; the HTTP status alone is not read as a deny, so an interceptor that answers an empty 403 lets the call through. Docker documents this as operator-controlled interceptor behaviour.

Not built. Measured 2026-09-13.

Measured 2026-09-13 — interceptor seam located, route NOT_SHIPPED. Host version at that run: not recorded.

GitHub Actions · GitLab CI · Bitbucket Pipelines

ADVISORY · CI STEP · CLOSURE REQUIRES IMMUTABLE-SHA WORKFLOW PIN

Contract gates in the pipeline, with a signed preflight receipt rather than a threshold on a count.

GitHub Actions   GitLab CI   Bitbucket Pipelines

LIVE_ROUTE — unverified on current host. The workflow snippets are documented; no dated run on a GitLab or Bitbucket runner is recorded here.

OpenCode

ADVISORY · TOOL CALL · DOES NOT EXECUTE

A remote MCP server entry. The key travels in a header, never in the URL.

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "coderifts": {
      "type": "remote",
      "url": "https://app.coderifts.com/mcp",
      "enabled": true,
      "oauth": false,
      "headers": {
        "Authorization": "Bearer {env:CODERIFTS_API_KEY}"
      }
    }
  }
}

Writes to opencode.json. Served byte-identical at app.coderifts.com/snippets/opencode_json; an app-side contract test fails if this block and that route disagree.

LIVE_ROUTE — unverified on current host. The config block is byte-checked against app.coderifts.com/snippets/opencode_json by an app-side contract test, so the two cannot drift — but nothing here has been run on OpenCode, and no date says otherwise.

CLI

ADVISORY · DEPLOY / PUSH · TWO IN-HOOK FAIL-OPEN PATHS

npx coderifts --help

Use CLI 8.6.8 or later: 8.6.7 setup-required-check bound CodeRifts / contract-gate to the App (2860592), so a ruleset it wrote waited for a check nobody posts.

The gates: deploy-gate (a deploy on a signed preflight receipt, fail-closed by default), publish-gate (npm publish against the working tree), registry-gate (a directory of specs, locally validated).

Why this line reads ADVISORY and not “prevents”: each of these gates is fail-closed by default, and each default has a documented environment variable that turns it advisory — CODERIFTS_DEPLOY_ADVISORY=1 is the one we publish in full. A default is a statement about how something is configured, not about what happened on a run. A reader who takes a default named “prevents” as an outcome is reading a declared setting as a measured result, the same way an annotation is not a verified property. The two fail-open paths named in the class line above are the other half of that gap, and they are why this page reports the weaker of the two.

CLI reference

Measured 2026-09-26 (external run). init --agents writes 13 files, including .cursor/rules/coderifts.mdc and .cursor/hooks.json; status --paths; conformance 16/16; tools/list. This page did not re-run those commands. The 13-file count is the default host list in packages/cli/src/agent-host-files.embedded.js (9) plus three MCP configs plus the workflow.

Measured 2026-09-26 (external run) — init --agents 13 files, status --paths, conformance 16/16, tools/list. This page did not re-run those commands.

SDK — Node and Python

ADVISORY · CLIENT · ENFORCES NOTHING

Advisory. The SDKs call the same endpoints you could call yourself and hand you the decision; they enforce nothing on their own. Node and Python have no dedicated pages yet — the install lines live on the MCP page.

Node SDK →   Python SDK →   Decision spec

LIVE_ROUTE — unverified on current host. No dated run on either runtime is recorded here.

REST API

ADVISORY · HTTP · NO GRANT, NO RECEIPT

Advisory. The REST endpoint returns an analysis, issues no grant and no receipt, and prevents nothing. It is also the raw-spec path: the description-level checks that read what a change added do not run there.

API reference

LIVE_ROUTE — unverified on current host — for the documented examples. The endpoints themselves are probed daily by scripts/check-internal-links.mjs --live, which reports their status without asserting support.

Editor and catalogue

ADVISORY · EDITOR / CATALOGUE · GATES NOTHING

Advisory, both. The VS Code extension marks the editor and cannot stop a commit; the Backstage card displays decisions already made and gates nothing.

VS Code   Backstage

LIVE_ROUTE — unverified on current host. Neither the VS Code extension nor the Backstage card has a measured run behind it on this page.

ChatGPT dots, the plugin URL, and the required check on a pull request are written at dots and the gate. That page is not an install route on this list.

The four clicks that connected a personal ChatGPT app are written at the ChatGPT app page. That page is not an install route on this list.

MCP servers: start here. That page is not an install route on this list.

or start from the template repository: coderifts/template.

What to expect after installing

Without a key      Analysis runs. Every gated call ends at a human.
                   No decision, no receipt — authorization_effect: NONE.

With a key         The gate issues a grant bound to that exact change,
                   consumed once, with a receipt anyone can verify offline.

What the gate reads, and what it does not

A change set is judged on what it adds. A sentence already sitting in a tool you did not touch does not decide your change: adding a tool to a set that contains a browser tool whose description says it can go forward/back in browser history is allowed, and so is editing that browser tool. Measured 2026-09-14, on the day that narrowing landed — before it, that standing sentence refused the whole set, and the quoted wording is how it read on that date.

A tool that arrives new is different. It has no previous text, so every sentence of it is new and all of it is read. If the description of a tool you are adding carries an instruction, the change goes to a human — and that is the case the gate is for. So if your first run stops there, read the tool you just added before you look at the ones that were already installed.

A set-level report asks the other question — is this whole set safe — and still reads every tool in full. The two are not the same question, and the gate does not merge them.

The free half is not a trial. Analysis and verification stay free because a format spreads when anyone can check it. What is paid is the authority.

How verification works   Pricing

Works with