A scanner tells you a line is wrong.
It cannot tell you who wrote it.
RepoOps does not rebuild a static analyzer. It runs the one you already trust over the diff the agent just produced, checks the packages it reached for, catches a secret the moment it is written, and reads the screenshots too. Then it does the part that was missing: it joins each finding to the session behind it and to what that session cost.
Local scans on your machine · the diff rather than the whole repository · a scan that could not run says so instead of reporting a clean tree
What it does
The parts, and the module behind each one.
Four scans over what an agent produces, and one join that turns a finding into something you can act on.
Semgrep over the agent's own diff
Scanning the whole repository buries what changed under everything that was already there. RepoOps scopes the scan to the agent working-tree diff against your main branch and shells out to Semgrep OSS, so you get the upstream rule set and its maintenance. With Semgrep absent, a built-in pass runs a handful of high-signal rules over the same diff and the surface names which engine produced the result.
lib/agent-diff-scan.mjsA package name the model invented
Every dependency an agent adds is checked against the registry before anyone installs it, so a hallucinated or squatted name is named as one. A registry RepoOps cannot reach degrades the row to unverified. It never degrades to safe.
lib/dependency-provenance.mjsA secret caught at write time
The gate runs the content of a generated file through the same pattern table the redactor uses, so there is no second list to drift out of step. A blocked event keeps the match types, the counts, a fingerprint and a redacted preview, and hands back the secret-free view of the write.
lib/secret-gate.mjslib/redact.mjsThe screenshot is a text channel
An agent that pastes a terminal or a dashboard screenshot moves a secret into a channel no text detector watches. The image is read with the bundled OCR and the extracted text goes through the detectors that already ship, rather than a second set written for images.
lib/multimodal-secret-scan.mjsThe session and the dollars beside the finding
Each finding carries the session that produced the diff and what that run cost. The uncommitted diff is one change, so the match is on recency across the whole scan and the surface says so rather than implying a per-line trace. An unpriced model reports as unpriced instead of borrowing another model's rate.
lib/security-cost-fusion.mjsA rollup a team lead can read
The three local scans over what agents write publish a redacted snapshot, so someone who is not sitting at the machine can see the shape of what is being found without the code that was found in. The scanning still happens locally; only the summary moves.
lib/agent-code-findings-snapshot-publisher.mjsWhere it lands
What the platform gets, and what you get.
How it helps the platform
Finding is where the security layer stops being about sessions and starts being about code.
- It gives the causal chain a code anchorA finding names a file and a line, which is what the security attribution leg needs to walk back to a commit and a developer. A signal with no code anchor can be triaged. It cannot be traced.
- It supplies the input the fix loop builds againstA finding at or above your build floor is what the remediation loop scopes a brief from. The quality of the brief comes straight from the specificity of the finding, which is why the diff scope matters more than the rule count.
- It keeps one pattern table across the productThe write-time gate, the redactor, the key inventory and the screenshot pass all read the same secret-shape corpus. One list means a new pattern lands everywhere at once and no surface quietly falls behind the others.
How it helps you
You review the work of the run that just finished, while you still remember what you asked for.
- Findings you can act on todayA repository-wide scan hands you a backlog. A diff-scoped scan hands you the set of problems the agent created in the last hour, which is the only set anyone actually fixes.
- A price tag on the bad runSeeing that a session produced four high-severity findings and cost real money is a different conversation from seeing either fact alone. It answers whether this was a run you would have paid for if you had known.
- No false comfort from a scan that never ranAn empty result from a scanner that failed to start looks exactly like a clean codebase. RepoOps separates the two: did not run reads as did not run, with the reason and the install command.
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 package that does not exist
- The situation
- An agent confidently adds an import for a helper library it invented, and the name is close enough to a real one that nobody reading the diff blinks.
- What RepoOps does
- Dependency provenance checks the name against the registry as part of the scan and flags it before an install command is ever run.
- What you get
- You catch a hallucinated dependency at review time rather than discovering that someone else registered the name and shipped code inside it.
- 02
A credential written into a config file
- The situation
- An agent scaffolds a deployment config and helpfully fills the auth field with the real key it found in the environment.
- What RepoOps does
- The write-time gate matches the secret shape as the file is generated, blocks the write, and records the match types, counts and a fingerprint without keeping the value.
- What you get
- The key never reaches the working tree, so there is no commit to rewrite and no history to purge. The record of the catch is safe to share.
- 03
An expensive run that also wrote bad code
- The situation
- A long agent session burns through a noticeable amount of budget and lands a diff nobody has read closely.
- What RepoOps does
- The scan runs over that diff, and every finding arrives carrying the session and the metered cost of the run that produced it.
- What you get
- One row that answers both questions your manager will ask: what did it get wrong, and what did it cost to get it wrong.
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.
The session join is a correlation
The uncommitted diff is one change, so every finding in a scan carries the same session, the most recent one in the window, with that session's whole cost. It is not a per-line trace, and each finding says so on its face.
Semgrep is an external tool
RepoOps shells out to Semgrep OSS rather than bundling a scanner. Without it installed you get the built-in high-signal pass over the same diff, clearly labelled, and the install command for the full rule set.
It finds. It does not block
These scans report. Stopping a tool call before it happens is the enforcement gate on the Contain page, and that gate ships all-advisory with its hook unregistered.
A clean scan is not a proof of safety
A rule set catches the classes it describes. RepoOps reports what the scanner found over the diff it read, and nothing on this page claims that a repository with no findings has no vulnerabilities.
Read further
Where this is documented in full.
- Agent code scanthe diff scoping, the engine fallback, and the session join
- Dependencieswhich packages you would lose sleep over, before they are compromised
- Agent code securitythe team rollup of all three local scans over what agents write
- Security cost fusionone row per flagged session, ranked by severity then cost
- Security guardrailsthe classic working-tree footguns, each with the exact fix
Scan the diff your agent just wrote.
One developer, no account, nothing leaving the machine. Arm a control when you want one.