Every control on this page
is off until you arm it.
These are the parts of RepoOps that act on a live run: a gate that can refuse a tool call, a switch that stops a run in flight, a broker that keeps your real key out of the agent, and an allowlist that pins where a sandboxed run may reach. They ship dormant, on purpose, so RepoOps never blocks or kills anything behind your back. A policy fault degrades to no enforcement rather than to a blocked call.
All-advisory on install · the pre-tool hook is not registered until you register it · a partial kill is reported as partial
What it does
The parts, and the module behind each one.
Five controls, each with its own arming switch and its own honest failure mode.
A gate on the pending tool call
One pure decision on a single call: allow, block or flag. It rides the agent's own synchronous pre-tool hook for Claude Code, the Codex CLI and the GitHub Copilot CLI, plus the MCP tool-call seam, rather than the capture path. Only a high or critical firing is block-eligible; medium and low warn even when the detector is armed to enforcing.
lib/enforcement-gate.mjsscripts/cc-pretooluse-enforce.mjslib/mcp-enforce.mjsA kill switch with three legs
Revoke the run's scoped token, signal the agent process, block the run's branch so a git hook refuses further commits. Each leg reports whether it completed and whether anything was verified, and the run is marked contained only when all three did both. Dormant, it still computes the full plan so you can see what arming would actually do.
lib/run-kill-switch.mjsA broker between the agent and your key
Instead of a long-lived key sitting in the agent's environment and context, a local broker holds the one real key and mints a short-lived, task-scoped token from it. The raw key never leaves the module, is never logged or stored, and the broker fails closed when no key is set. It listens on loopback only.
lib/broker/credential-broker.mjsA per-repo egress allowlist
Pin the domains and addresses a sandboxed run may reach. The list maps straight onto the shipped sandbox's per-host network capability, so a pinned host becomes exactly one granted capability and nothing else leaves. A policy that cannot be loaded is treated as the empty list, never as allow-all.
lib/egress-policy.mjslib/sandbox/capabilities.mjsForensics for the run you just stopped
Over the redacted session record already on the machine, RepoOps builds a timeline, a blast-radius report and a step-by-step replay. An incident is reconstructed from local evidence without shipping the raw session anywhere.
lib/run-forensics.mjsA subagent that attests back to its parent
When work fans out to subagents, which agent in the tree did this has no answer. A signed record carries the parent run, the subagent, the tool and data scope the parent declared, and whether the subagent exceeded it. Verification recomputes the digest from the record's own fields rather than trusting a stored one. Dormant unless attestation is switched on.
lib/a2a-attestation.mjsWhere it lands
What the platform gets, and what you get.
How it helps the platform
Containment is what turns the watching layer into a control plane rather than a dashboard.
- One gate, several agentsThree coding-agent hooks and the MCP seam all call the same pure decision function. A new detector or a changed policy lands once and every entry point behaves the same way, which is the only version of this that stays honest as agents multiply.
- The same detectors, used a second timeThe gate runs the risky-command and exfiltration-pairing rules the watching layer already ships. There is no second rule set to keep in step, so a rule you tuned on findings behaves identically when you arm it.
- Fail-safe in a chosen directionA broken policy bundle yields allow, and an unloadable egress policy yields the empty allowlist. The two directions are deliberate: a fault must never silently wedge a developer's agent, and it must never silently open the network.
How it helps you
You decide what RepoOps is allowed to stop, one detector at a time, and you can always see what a control would have done.
- Nothing turns itself onThe bundle ships all-advisory and the pre-tool hook is not registered at install. Watch the detectors fire for a week, then arm the ones you trust. There is no default posture to discover the hard way.
- A partial kill is reported as partialIf the broker was never armed, the pid is unknown, or a signal was denied, you see which leg failed and why. The alternative, a green banner that means two out of three, is worse than no switch at all.
- A key the agent never holdsWith the broker armed, a leaked context or a poisoned tool call gets a short-lived scoped token instead of your production credential. The blast radius of a bad run drops to what that token could do before it expired.
In practice
Three days this changes.
Each one runs on the modules above. The situation, what RepoOps does with it, and what you are left holding.
- 01
The command that reads a secret and sends it
- The situation
- An agent composes a single shell command that reads a dotenv file and pipes the contents to an external host, and it looks unremarkable inside a long tool call.
- What RepoOps does
- The gate matches the read verb, the secret path and the outbound call as one pairing on the pending call, before the tool runs. Armed, it blocks. Advisory, it flags and records.
- What you get
- Either the call does not happen, or you get a specific record of the exact call that would have exfiltrated a credential, with the reason attached.
- 02
A run going wrong while you watch it
- The situation
- A long agent run starts making changes nobody asked for, and every minute it keeps working the cleanup gets bigger.
- What RepoOps does
- The kill switch runs its three legs in order and reports each: token revoked, process signalled, branch blocked so a hook refuses further commits.
- What you get
- The blast radius stops growing while you read the timeline. If a leg could not complete you know which one, so you can finish the job by hand.
- 03
A sandboxed job that should only talk to two hosts
- The situation
- A scheduled agent run needs your package registry and your own API, and nothing else, but the sandbox it runs in can reach the whole internet.
- What RepoOps does
- Pin those two hosts in the repository's egress allowlist. They become exactly two granted network capabilities on the shipped sandbox, and the daemon hook fires when a run reaches for anything else.
- What you get
- An unlisted host is an alert rather than a quiet outbound request, and a policy you cannot load closes the sandbox instead of opening it.
The limits
What this does not do.
Stated here rather than found out later. The long version, with the module behind each boundary, is on the proof page.
A default install enforces nothing
The gate ships all-advisory and its hook is not registered. No page here may describe RepoOps as protecting a machine it has not been armed on, and this one will not.
It sees agents that expose a hook
Enforcement runs on the Claude Code, Codex CLI and GitHub Copilot CLI pre-tool hooks and the MCP seam. There is no network interception here and no plan for one, because inspecting your agent's traffic would contradict the rest of this.
The approval hold is inert today
Two detectors can raise a hold when armed to enforcing, and the human approver that would release one is not wired yet. With no approver a hold degrades to a flag with its reason rather than hanging a call nobody can release.
It is not tamper-proof
The armed state is a config file, and anything running with your privileges can change it. Prompt injection is also unsolved at the model layer: these controls bound the blast radius of an agent that has been talked into something. They do not claim to stop every attack.
Read further
Where this is documented in full.
- Controlsarm or disarm each advisory control, per repository
- Control matrixthe posture across every inventoried repository, read-only
- Egress policythe per-repo allowlist and what happens to an unlisted host
- Run forensicswhat one run did, in order, and the human-gated kill switch
- Security as proofthe boundaries in full, with the module behind each one
Watch first. Arm what you trust.
One developer, no account, nothing leaving the machine. Arm a control when you want one.