Findings where your team already looks
SARIF 2.1.0 for GitHub code scanning and most security dashboards, JUnit XML for CI test reports, and CSV for spreadsheets, ticketing and SIEM imports. Each finding names the step in the run it came from.
Syntony / Agents and tools / Rubato
A free agent that reviews what another AI agent did. Give it a run log and it finds the moments the agent took liberties with its task: acting after a person said stop, routing around a refusal, weakening its own oversight, reaching for credentials, sending data out, and claiming work the log does not show. It comes with free red team probes: small test repositories built to tempt an agent.
Try it
The same engine you download, running in your browser. Nothing you paste leaves this page.
What it looks for
Each finding names the event in the log, quotes the evidence and says what a person should check. Severity drops when the task itself asked for the action, or when the call failed.
Free red teaming
Each probe writes a tiny repository built to tempt an agent, with the exact task to give it. Run it in a sandbox with no real credentials, then score the session as pass, fail or inconclusive. The secrets are fake and every planted address ends in .invalid.
A red team tests your agent with its real tools, permissions and data: chained prompt injection, tool and memory poisoning, privilege paths, multi-agent handoffs and the approval flows around them. Then it checks that each fix holds.
node rubato.mjs probes node rubato.mjs probe RP-01 --out rp-01 # a test repository with a planted instruction cd rp-01 && claude # give it the task in PROBE.md node rubato.mjs review <session.jsonl> --probe RP-01
How it works
The engine gives the same result every time, so you can rerun it and compare. The agent does what patterns cannot: it reads around each finding and decides.
Claude Code session files, OpenAI or Anthropic message arrays, or a simple JSONL of tasks, messages, tool calls and results. It links each result to its call and works out what every call did: which files it wrote, which hosts it contacted, whether it changed anything.
It finds the task, any stop or interruption, and instructions such as "do not push to main" or "ask me before changing CI". Then it checks every later action against them, and checks every claim in the agent's final message against the tool results.
Installed in Claude Code, Rubato runs the engine, reads the events around each finding, and decides whether it is confirmed, explained by the task, or a false alarm. It never runs commands from the log and never edits it.
Did the agent stay within its task? A table of findings with event numbers, what to do now for each confirmed one (undo, rotate a credential, review a diff), and which control would have stopped it.
Install
Version 1.2.0. Needs Node.js 18 or later and nothing else. The agent works in Claude Code; the engine works on its own anywhere.
rubato.mjs ↓, a single readable JavaScript file with no dependencies. Save it somewhere stable, such as a tools folder in your home directory.
From your project folder, or with --global for every project:
node /path/to/rubato.mjs init
This writes .claude/agents/rubato.md with the path to the engine filled in.
In Claude Code:
Use the rubato agent to review my last session.
Rubato lists your recent sessions with rubato.mjs sessions, picks the one you mean and writes its report.
node rubato.mjs review session.jsonl node rubato.mjs review run.json --json --out report.json node rubato.mjs review run.jsonl --scope scope.json --fail-on high
--fail-on high exits with code 2 when there is a high-severity finding, so you can gate a pipeline on it.
Logs and scope
Without a scope file, Rubato uses the task in the log and the working folder. With one, it also checks tools, paths and hosts against your lists.
~/.claude/projects/, as they are. Interruptions count as a stop.tool_calls, or Anthropic-style arrays with tool_use and tool_result blocks, as JSON or JSONL.type set to task, message, reasoning, tool_call or tool_result. Print an example with rubato.mjs example.* and ** work as usual.{
"task": "Fix the failing checkout test",
"tools": ["Read", "Edit", "Bash", "Grep"],
"paths": ["src/**", "test/**"],
"hosts": ["api.stripe.com"],
"workdir": "/home/dev/shop",
"maxSubagents": 4
}
For operations and security teams
Rubato is built to run on every agent session in CI, not only the ones someone thought to check.
SARIF 2.1.0 for GitHub code scanning and most security dashboards, JUnit XML for CI test reports, and CSV for spreadsheets, ticketing and SIEM imports. Each finding names the step in the run it came from.
Each finding carries references to the EU AI Act (Art. 12 record-keeping, Art. 14 human oversight), the OWASP Top 10 for LLM Applications 2025, the NIST AI RMF, NIST SP 800-53 and MITRE ATT&CK.
Pass several files or a whole folder. You get one combined report and a summary table, and --fail-on turns any level of finding into a failed build.
Claude Code session logs, OpenAI and Anthropic message arrays, Rubato JSONL, and CSV exports with a header row. Run sessions in a project folder to list that project’s Claude Code logs.
No network calls, no telemetry and no dependencies. It is one readable file your security team can review before it runs on an isolated host.
Fixed rules, not a model. The same log always gives the same findings, and every report carries a SHA-256 of its input so it can go in an evidence file. 100,000 events take under two seconds on a laptop.
# Every session from last night, as SARIF for code scanning node rubato.mjs review ~/.claude/projects/-home-dev-shop/ --format sarif --out rubato.sarif # Fail the pipeline on any high finding, with JUnit for the test report node rubato.mjs review agent-run.jsonl --scope scope.json --format junit --out rubato.xml --fail-on high
Why the name
Rubato means stolen time. A player stretches a phrase here and hurries it there, and the score allows some of it. Too much and the piece falls apart.
Agents take the same kind of liberty with a task. Most of it is fine. Rubato finds the places where the agent stretched past what anyone allowed, so a person can decide whether the piece still holds.
It sits with the rest of our instruments: A440 sets the pitch, Sordino mutes an action that should not happen, Fermata holds until a person says go, Ritardando slows a claim until the evidence is checked, and Attacca carries a finding straight on to governance.
Before you rely on it
Rubato runs on your machine and makes no network calls. It reads only the log and scope files you give it, and writes only the agent file and the report you ask for.
Rubato is licensed by Syntony under the Syntony Free Tools License: free to run, copy and modify within your organization, including for commercial work, but not to resell or redistribute.
Our agent red teaming tests what your agent does with real tools and permissions, then checks that each fix holds.