If you run Claude Code, Codex, or Cursor on a real codebase, those agents can read your .env file and propose an outbound curl call in the same session. To ordinary endpoint security, that looks identical to a developer doing the same thing. numbat is an open source tool in Perplexity’s GitHub organization that ties agent actions to the specific session that proposed them.
What numbat does
numbat hooks into AI coding agents, normalizes their activity into a single event model, and runs detection rules against it locally. It reads agent activity from three sources: hooks and plugins installed into the agent, OpenTelemetry logs the agent exports, and session files the agent leaves on disk.
Its coverage matrix lists 27 agents and agent hosts, including Claude Code, Codex, Cursor, Gemini CLI, and GitHub Copilot CLI. A rule engine built on CEL evaluates each event, and 51 rules ship built in. Those rules are grouped by behavior: secrets, exfiltration, persistence, privilege, lateral movement, tampering, and more, with MITRE ATT&CK technique IDs attached.

The finding that matters: chained sequences
The most useful built-in rule fires on a secret file read followed by a data-bearing upload in the same session. In a staged test on the v0.2.0 Windows release, the reviewer wrote a five-line Claude Code session where the user asks the agent to send a config to a support endpoint, the agent reads .env, and then proposes curl --data-binary @.env to an address on the reserved .invalid domain.
numbat scan raised three findings: the .env read (medium severity), the proposed curl upload (high severity), and the chain finding chain.secret_read_then_egress linking the two, tagged with ATT&CK techniques T1048, T1552, and T1567. The reviewer notes that in this case the user asked for the upload, so the rule fires on a pattern, not proof of a rogue agent. And numbat only knows the upload was proposed, not whether anything actually left the machine.
Forensic reconstruction from disk
For sessions already completed, numbat timeline lays out a stored session in chronological order, and numbat case build packages the evidence with SHA-256 manifests. Stored-session parsers cover 11 of the 27 agents in the matrix: Claude Code, Codex, Copilot CLI, Claude Cowork, Cursor, Gemini CLI, Kimi Code, OpenClaw, OpenCode, Pi, and Windsurf. For most others the format is marked deferred.
A case bundle’s manifest shows internal consistency, but the README is explicit that an unsigned bundle does not prove source authenticity or completeness. Reconstruction also only works from what an agent wrote to disk.
Blocking: opt-in and narrow
All 51 shipped rules are monitor-only by default. To make a rule block, you copy its YAML into your own rules directory, keep its ID, add enforce: true, bump its version, and reinstall the hook with --enforce. Even then, numbat does not stop anything directly: it returns the agent’s native deny response, and the agent host decides what to do with it.
Shell command blocking is limited to a static subset: one simple command or one pipeline of simple commands in a POSIX shell, and one simple command in PowerShell or cmd.exe. Multiple statements, conditionals, loops, command substitution, eval, and Invoke-Expression are detection-only. It also fails open: a malformed payload, a rule evaluation error, a crash, or a lost output sink all suppress numbat’s deny.
Getting started
numbat is a single binary under the Apache 2.0 license. The latest tagged release is v0.2.0, from 17 August 2026, with macOS, Linux, and Windows builds on amd64 and arm64. Install it with Go 1.26.6 or newer:
go install github.com/perplexityai/numbat/cmd/numbat@latestThe recommended path is to run read-only commands first, install a monitoring hook in monitor mode, and read what it reports before deciding whether any rule should block. The reviewer’s conclusion: treat numbat as visibility and forensics for your coding agents, with blocking as a best-effort extra on top, not a policy boundary.
numbat is on GitHub, with its coverage matrix and enforcement guide in the repository.

