When an API your agent depends on changes (a renamed field, a removed endpoint, a dropped auth scope), your agent breaks silently. The tests stay green; the break shows up at runtime, mid-task. CodeRifts catches it before the call and returns a machine-readable verdict your agent can act on.
Three steps: guard your tool calls, adopt the policy, read the verdict.
Install the runtime guard: @coderifts/agent-guard (withCodeRifts / the guarded registry). It runs an authorize preflight (operation-bound) for contract changes. On authorize responses, execution_action is a closed set of four: CONTINUE, CONTINUE_WITH_MONITORING, REQUEST_APPROVAL, STOP — anything unrecognised fails closed. This quickstart runs the tool only on CONTINUE (see Step 3 for monitoring). Fail-closed also on an unverifiable receipt or a degraded server. Analyze-mode responses omit execution vocabulary entirely — see Decision Spec v2. The runtime sees only calls through the returned tool table. Closes eager-execution ordering: mutating work is built inside the factory after the verdict — snapshot-to-commit correspondence requires a host conditional write (compare-and-swap on a version token). PR comments and MCP tools alone do not prevent a call — what each path does.
npm install @coderifts/agent-guard @coderifts/sdk
The canonical call — supply the change as artifacts[] with before/after content; the factory runs only if the verdict permits:
import { guardToolCall } from '@coderifts/agent-guard';
import { CodeRifts } from '@coderifts/sdk';
const client = new CodeRifts({ apiKey: process.env.CODERIFTS_API_KEY });
const outcome = await guardToolCall(
{
toolName: 'Edit',
arguments: { path: 'openapi.yaml' },
// The change CodeRifts preflights: id, type, before, after are all required.
artifacts: [{ id: 'public-api', type: 'openapi', before: baseSpec, after: proposedSpec }],
},
// The mutating work is created ONLY here, after the verdict — this closes eager-execution
// ordering. Snapshot-to-commit correspondence still requires a host conditional write
// (compare-and-swap on a version token).
async (envelope, redactedCall) => applyEdit(redactedCall),
{ client, operation: 'merge', environment: 'production' },
);
if (!outcome.executed) {
// Fail-closed: the tool never ran. Closed set when present:
// CONTINUE | CONTINUE_WITH_MONITORING | REQUEST_APPROVAL | STOP
// (unknown is not permission; this example proceeds only on CONTINUE).
console.error('CodeRifts blocked the call:', outcome.verdict);
}
If the guard detects a contract change but you did not supply artifacts[] with content, it fails closed locally with outcome.verdict.cause === 'MISSING_ARTIFACT_CONTENT' — an actionable error (pass the change), never a silent bypass. resolveArtifacts can fill before/after in from git automatically — see Make CodeRifts the only path below.
Prefer a framework drop-in? CodeRifts also ships ready-made snippets (LangGraph, AutoGen, and more) — each has a keyless quick check (one document; not a guard) plus an enforcement block that posts a change set and needs an API key — and a keyless /api/v1/public/preflight endpoint for trying it out without a key:
curl https://app.coderifts.com/api/v1/snippets/langgraph
# full framework list: https://app.coderifts.com/api/v1/snippets
CodeRifts publishes a default agent policy: when a contract artifact changes, call preflight_change_set with preflight_mode: "authorize" and context.operation, then branch on execution_action (not on ad-hoc on_block / on_warn strings, and not on analyze bodies). Fetch the policy and enforce it as-is, or customize:
curl https://app.coderifts.com/api/v1/policy/default
{
"policy": {
"name": "CodeRifts Default Agent Policy",
"rules": [
{
"trigger": "before_tool_call",
"condition": "contract_artifact_change",
"action": "preflight_change_set"
}
]
}
}
Acting paths use authorize (Decision Spec v2). Full field contract: /decision-spec/. Example authorize body (not analyze — analyze omits execution vocabulary):
{
"preflight_mode": "authorize",
"decision_spec_version": "2.0",
"receipt_kind": "operation_authorization",
"decision": "BLOCK",
"execution_action": "STOP",
"safe_for_agent": false,
"risk_score": 60,
"breaking_changes": 4,
"requires_migration": true,
"patterns": ["AUTH_SCHEME_REMOVAL", "ENDPOINT_REMOVAL", "TYPE_NARROWING"],
"chain_receipt": "…"
}
On authorize, branch on execution_action (CONTINUE | CONTINUE_WITH_MONITORING | REQUEST_APPROVAL | STOP). Unrecognised values fail closed. Use decision as explanation only; do not branch on safe_for_agent alone. This quickstart proceeds only on CONTINUE (CONTINUE_WITH_MONITORING needs monitoringSinkWired). Mode-less preflight returns 400. Analyze responses use analysis_outcome / may_execute:false and never grant permission. Schema:
curl https://coderifts.com/schemas/preflight-response.v2.consumer.json
# Prose + examples: https://coderifts.com/decision-spec/
Guarding one call is good; guarding the whole tool surface so the model can't route around it is inescapable. The registry hands the agent only guarded tools, and the resolver supplies before/after from git — both fail-closed, both honest about scope.
withCodeRifts / guardToolRegistry takes your raw tool list and returns the only table the agent may see — every mutating tool wrapped so it cannot execute without going through CodeRifts. The runtime sees only calls through that returned table; host-side direct invokes are invisible. Unknown tools default to mutating (guarded, never assumed safe). Construction throws (fail-closed) if any mutator would remain raw:
import { guardToolRegistry } from '@coderifts/agent-guard';
// withCodeRifts is the composition entry that returns this same guarded table.
const { tools, coverage, report } = guardToolRegistry(rawTools, {
guard: { client }, // your CodeRifts client
// unknownToolPolicy: 'mutating' (default) — unknown tools are guarded, not trusted
});
// coverage: 'COMPLETE' (every mutator guarded) | 'PARTIAL' | 'BYPASSED' (break-glass)
// Register ONLY the guarded table with your agent runtime — never the raw tools.
agent.registerTools(tools);
Scope honesty. The registry secures the agent-runtime tool boundary only — report.claim.inescapable_runtime is true only when coverage is COMPLETE. It never claims inescapable_merge or inescapable_deploy (both always false): a human or a second process merging on the GitHub UI is a separate, repo-side layer. Making the PR check block a merge requires branch protection and related setup — see Make the Check Block a Merge.
resolveArtifacts turns a git diff plus blob reads into artifacts[] ready for the guard — the companion to MISSING_ARTIFACT_CONTENT. It produces content, never decides: report.claim.produces_verdict is always false, and the verdict fingerprint is untouched. A missing $ref, unreadable blob, or ambiguous source becomes an unresolved[] entry with a reason — never fabricated content.
import { resolveArtifacts, guardToolCall } from '@coderifts/agent-guard';
// The host provides a PURE git snapshot: base/head refs + blob reads.
const r = resolveArtifacts(
{ baseRef: 'main', headRef: prHeadSha, changedFiles, blobs },
{ openApiAssembly: 'bundle_inline' },
);
if (r.coverage === 'COMPLETE') {
// Resolved cleanly — hand the artifacts straight to the guard.
await guardToolCall(
{ toolName: 'merge', arguments: {}, artifacts: r.artifacts },
factory,
{ client, operation: 'merge' },
);
} else {
// PARTIAL / UNRESOLVED — fail closed; inspect r.unresolved (never invent content).
throw new Error('artifacts not resolvable: ' + JSON.stringify(r.unresolved));
}
Together: the guard demands content (MISSING_ARTIFACT_CONTENT if absent), and the resolver supplies it honestly (COMPLETE or fail-closed). Runtime coverage (registry) plus repo-side merge enforcement together give full coverage — each layer states its own residual.
CodeRifts is an MCP server. Point your agent at it and its three MCP tools appear automatically, with no integration code.
MCP endpoint: https://app.coderifts.com/mcp (transport: streamable-http)
Manifest: https://coderifts.com/mcp.json
Registry: io.github.coderifts/api-governance
See the three MCP tools and the REST API endpoints on the MCP Integration page.
| Endpoint | Purpose | Auth |
|---|---|---|
POST /api/v1/preflight |
Change-set preflight — requires preflight_mode (analyze | authorize); authorize may return a signed receipt (Decision Spec v2) |
key |
GET /api/v1/public/preflight |
Keyless preflight verdict | none |
POST /api/v1/agent-readiness-score |
0-100 agent-readiness score for a spec | key |
GET /api/v1/decision-spec/schema |
Redirect to Decision Spec docs; preflight union schema: https://coderifts.com/schemas/preflight-response.v2.consumer.json | none |
GET /api/v1/policy/default |
Recommended agent policy | none |
GET /api/v1/snippets/{framework} |
Framework integration snippets | none |
Coding agents read AGENTS.md as procedural memory, and more than 60,000 repositories already ship one. Paste this section so any agent working in your repo runs an API-safety check before it merges.
## API safety
Before merging changes to API schemas, OpenAPI specs, or
.github/workflows files, get a CodeRifts verdict:
- Runtime: wrap mutating tools with @coderifts/agent-guard (withCodeRifts /
the guarded registry). Authorize preflight with context.operation; branch on
execution_action: CONTINUE → proceed; REQUEST_APPROVAL or STOP → do not call;
unrecognised → fail closed. Analyze mode is risk-only (not permission).
Decision Spec v2: https://coderifts.com/decision-spec/
- PR report: the CodeRifts GitHub App comments on the PR. A red report alone
does not block merge — require the check under branch protection when you
want a merge gate (docs: Make the Check Block a Merge).
- MCP: preflight_change_set at https://app.coderifts.com/mcp — always pass
preflight_mode (authorize when acting; analyze for risk only).
Treat REQUEST_APPROVAL and STOP as non-proceed; do not auto-merge on WARN.