Open source · Apache-2.0

Interlock is repository guardrails for AI coding agents.

Let your coding agent make every ordinary edit. Interlock reserves destructive writes, protected pushes, and releases for a trusted, policy-controlled broker.

Footprint
One file in your repo · nothing to run
Guarantee
The coding agent cannot reach the effect · fails closed
Install Interlock
terminal
$ curl -fsSL https://sh.opstk.dev/interlock | sh
Give one protected effect to code the agent cannot influence The agent proposes · the broker publishes
coding agent · protected by Interlock
The old client is stale — I'll wipe it and regenerate from scratch.
Bash(rm -rf generated/)
⛔ Blocked by Interlock agent may not delete repo://generated/**
Let me patch the broker auth module directly instead.
Write(src/broker/auth.ts)
⛔ Blocked by Interlock · protected path, fails closed nothing was written — your files are untouched
Understood — those are protected. Making the ordinary edit.
Edit(src/app.ts)
✓ Updated src/app.ts (+3 −1) not a protected effect — Interlock stays out of the way
Tests pass. I'll force-push main so the history is clean.
Bash(git push --force origin main)
⛔ Blocked by Interlock · needs your approval force-push main waits for a release-main approval
Understood — I'll open a PR and let you approve the release.
Bash(gh pr create --fill)
✓ opened PR #128 — awaiting your review the agent proposes — you publish
let the agent edit src/ — but never delete generated/ or force-push main
▶▶ auto mode on · 1 shell goal active · 2m 41s
Deterministic, not vibes

You can already tell an agent the rules. It can still break them.

Prompts, AGENTS.md files, and skills guide an agent. But they only advise the agent. A capable agent can ignore them, forget them, or find another path. You learn about the problem too late. Interlock controls the effect itself. The guardrail is not a suggestion.

Today · advisory

You write the rule in Markdown.

You write the rule in a skill, an AGENTS.md file, or a system prompt. The text only advises the agent. The agent decides whether it obeys. It can ignore the rule, forget it during a long run, or find another path.

AGENTS.mdskill
# Repository rules — ⚠️ IMPORTANT, PLEASE READ

NEVER force-push main. Not ever. This is critical.
Do not run git push --force on main under any circumstances.

ALWAYS ask a human before you push main.
Wait for explicit approval — do not push on your own.

If you are unsure, STOP and ask first.
Please double-check every push. I really mean it 🙏
→ the agent can ignore it and force-push main anyway
With Interlock · enforced

You author the rule as typed policy.

Like branch protection — but it lives in your repo, not on a host, and it guards every risky effect (delete, publish, more), for any agent.

You write the same rule using our typed libraries. It compiles to one canonical policy. The broker owns the effect. So the agents cannot bypass it. The decision stays the same on every run.

A normal source file, committed with your code — in the language you already use.

policy.go
// fluent builder → canonical IR
il.Policy("repository-policy.v1").
  Actor("agent").
  Branch("main", "repo://branch/main").
  Deny("deny-force-push-main").By("agent").
    To(il.ForcePush).On("main").
    Because("force-pushing main is not allowed").Add().
  Allow("push-main").By("agent").
    To(il.Push).On("main").
    Requiring(il.HumanApproval("release-main")).
    Because("pushing main needs human approval").Add()
force-push mainDENY
push mainREQUIRE release-main

The agent proposes; the broker publishes. That's the difference between hoping the agent follows the rules and knowing it can't skip the ones that matter.

Ready-made starters

What are you protecting?

Pick a starter. Interlock scaffolds a real policy file in your repo — then you own it and edit it like any code. Click a starter to preview its policy file →

Why not the usual answers

The usual answers to a force-push main.

MCP server
a service you run
Bypassed
The coding agent ran a raw shell command the server never saw. An MCP server advises and observes. A capable coding agent takes another path.
Sandbox VM
an isolated box
All-or-nothing
It does stop the push. But it isolates every effect — your edits, your tools, your test runs — and you now maintain a VM.
Permission settings
a list in your config
Blind after approval
You allow command patterns up front, like gh pr merge. Then the agent runs them unwatched, with no way back. The list sets what the agent can touch. It never asks whether an action should happen.
Interlock
code in your repo
Denied at the effect
The broker owns the effect. There is no other path to it. It fails closed. The coding agent still edits src/ freely.
MCP server = infrastructure Sandbox = infrastructure Permission list = blind after approval vs ◆ policy.go — in your repo

The others are infrastructure you run, or a list that stops watching after it says yes. Interlock is a file you already have. The coding agent proposes; the broker publishes.

No lock-in · no agent changes

Works with the coding agents you already use.

Interlock keeps its authority at the effect boundary. The broker owns push and publish. Any agent can propose a change. But no agent can reach that authority. You do not change tools. You do not install a plugin. You do not reconfigure your agent. This works even with no hook.

Claude Cursor Codex GitHub Copilot CLI Gemini Kimi Code OpenCode Pi Qwen Code

How Interlock works

  1. 1
    You write the policy. A typed file in your repo (policy.go, .ts, .py, .rs) compiles to one canonical rule.
  2. 2
    Your agents propose an action. They push, delete, or publish through the tools they already use.
  3. 3
    Interlock decides at the effect boundary. Your policy returns allow, deny, or needs-approval — the same on every run. It fails closed.
  4. 4
    The broker performs the effect. Only the broker can. The agents never touch push, delete, or publish directly.

Interlock talks to your coding agents over hooks, using the Pitot protocol — one line of config, no fork or plugin. Pitot on GitHub →

Many tools use hooks to control agents. For those tools, the hook is the guarantee. But an agent can bypass the hook. The hook also cannot see the writes that a shell command starts. For Interlock, the hook only shows the decision. The guarantee is the control of the effect.

Honest about what it does

Authority, not interception.

Interlock does not exaggerate. This is what Interlock guarantees. This is also what it does not guarantee.

Authority, not interception

Interlock does not watch every keystroke or every file write. It controls the few effects that matter, such as push and publish. The agent cannot do these effects without the guardrail.

Fail closed

Interlock denies the effect if it finds a mismatch, such as wrong evidence or a changed policy. Your repository stays unchanged.

Not cryptographic provenance

Interlock controls who can do an effect. It does not give cryptographic authenticity. It uses no MCP server.

"Interlock does not define whether work is correct, whether an artifact is safe to ship, or what 'released' means."

The five design principles

  1. Authority, not interception.
  2. Typed libraries author; IR decides.
  3. Fail closed.
  4. The engine trusts claims; the broker makes them truthful.
  5. Be honest about coverage.
Go deeper

See how enforcement holds across environments

Laptop, coding agent, cloud sandbox, CI — the transport changes, the authority does not.

Enforcement model →
Install · quickstart

Get Interlock.

Install the CLI. Then pick a template. interlock init --template scaffolds a policy module. interlock compile builds the canonical IR. interlock doctor reports what your setup can build.

macOS / Linux
$ curl -fsSL https://sh.opstk.dev/interlock | sh
Windows · PowerShell
> irm https://sh.opstk.dev/interlock/install.ps1 | iex
Go install
$ go install github.com/operatorstack/interlock/cmd/interlock@latest
Check your setup
$ interlock doctor
Apache-2.0 licensed github.com/operatorstack/interlock Author in Go, TypeScript, Python, or Rust