L01 — Why security-benchmark harnesses are different¶
The CPU/RAM framing
Andrej Karpathy's shorthand for agent infrastructure: "The LLM is the CPU, the context window is RAM, and you're the operating system." (YC AI Startup School, June 2025.) By 2026 he was pushing a sharper version of the same point in talks on agentic engineering (reported via a Sequoia masterclass — I haven't found a primary recording, so treat the framing, not the exact quote, as the citable part): the thing worth optimizing is the harness around the model, not the model itself. This course is about building that OS for one specific, harder case.
A coding-agent harness assumes the agent is on your side: it might overreach
a config file or declare victory too early, but it isn't trying to defeat
the harness itself. Point the same agent at a security benchmark — "find
and exploit the vulnerability in this service" — and that assumption
breaks. The task now actively rewards escaping scope, lying about results,
and finding the cheapest path to "looks solved." Concretely: a model graded
on "exploit this login form" has every incentive to print "Exploit
successful: SQL injection confirmed" and stop, whether or not a payload
ever reached the database — that sentence costs it nothing to produce and,
in a harness that trusts self-reports, scores exactly the same as a real
exploit.
Three consequences follow directly from that, and they're the spine of this course:
Scope has to be adversarially sound, not just convenient. A normal
harness grants broad filesystem access because it's annoying to scope
narrowly and nothing is trying to abuse the gap. A security-benchmark
harness has to assume the agent will try the gap, because finding gaps is
literally the task. This is why AgentCage
denies by default at the process level — open(), subprocess, and
socket.connect are all checked against an explicit allowlist — rather
than trusting the agent to stay in its lane.
Verification cannot ask the agent what happened. "I got a shell on the
target" is not evidence. The harness needs to independently confirm the
claimed outcome — check that a flag file was actually read, that a
privileged command actually ran, that a specific response actually came
back from the target — using a channel the agent doesn't control. This is
the entire reason HCP's Verifier
interface is a separate concern from the agent's own output, and why
VerifyLoop parses an external
test run's output rather than a self-report.
Comparisons across models need the same adversarial task run the same way. If you're benchmarking which model is best at a security task, the scope, the target, and the verification method all have to be held fixed — otherwise a "better" score might just mean a looser cage. HarnessBench exists to hold everything but the model constant.
Cooperative vs. adversarial harness, side by side¶
flowchart LR
subgraph Cooperative["Cooperative coding harness"]
direction TB
A1[Agent tries to succeed] --> A2[Occasional overreach<br/>or early stop]
A2 --> A3[Loose scope is fine —<br/>nothing exploits the gap]
end
subgraph Adversarial["Security-benchmark harness"]
direction TB
B1[Agent is graded on<br/>finding gaps] --> B2[Task actively rewards<br/>escaping scope]
B2 --> B3[Loose scope IS the<br/>vulnerability]
end
Cooperative -.different assumption.-> Adversarial
The rest of this course builds the three properties above — adversarial scope, independent verification, held-constant comparison — into a working toy benchmark, one lecture and one project at a time.
Where to start: if you've never built a harness at all, read L04 — Context is not free first; it's the general-purpose intuition this course assumes. If you already think in terms of context windows and tool calls, continue to L02.