Agent Hardness

Reverse Engineering what makes AI agents tick

Three tools. Three agents. One question:
what's actually inside the box?

"You use Claude Code
every day — but what
is it actually doing?"

Every AI coding agent ships as a black box. You type a prompt. It edits your files. Magic?

Not magic. A while loop, a system prompt, and a handful of tools.

What is "Agent Hardness"?

The totality of constraints that define an agent's behavior envelope.

System Promptpersonality, rules, tone
Tool Definitionswhat the agent can do
Permission Modelwhat it's allowed to do
Behavioral Constraintssafety rails, output rules
Context Managementmemory, compaction, sub-agents

Soft agent = few constraints, trusts the model. Hard agent = many constraints, governs the model.

Three Tools We Built

Each one opens up a different agent

claude-code-reverse

HTTP proxy intercepts all Claude Code API calls. Captures system prompts, tool schemas, behavioral rules.

Technique: MITM proxy on localhost:9876

opencode-reverse

Live dashboard connecting to OpenCode's official REST API + SSE event stream. Real-time token tracking.

Technique: SSE on port 4096

pi-mono-reverse

Parses Pi-mono's JSONL session files. Visualizes the minimalist philosophy — just 4 tools, 880 tokens.

Technique: JSONL tree parser

How We Captured This

The MITM proxy technique (claude-code-reverse)

// proxy.js — zero npm dependencies
const server = http.createServer((req, res) => {
  // Intercept HTTPS to api.anthropic.com
  const proxyReq = https.request({
    hostname: 'api.anthropic.com',
    headers: req.headers  // pass auth through
  });

  // Reassemble SSE streaming chunks
  proxyRes.on('data', (chunk) => {
    buffer += chunk;
    res.write(chunk);  // forward to client
    parseSSE(buffer);  // also log it
  });
}).listen(9876);
Claude Code CLI
↓ HTTP
proxy.js :9876
↓ HTTPS
api.anthropic.com

Every request & response logged. SSE streaming reassembled into complete messages.

Finding #1: It's Just a While Loop

Every agent — Claude Code, OpenCode, Pi-mono — runs the exact same core loop.

▶ response = LLM(system_prompt + history + tools)
❓ if response.has_tool_calls:
⚙ results = execute_tools(response.tool_calls)
📥 history.append(results) — continue
⏹ else: break — respond to user

That's it. The "intelligence" is in the model. The code is just a coordinator.

"The model is 80%.
The code is 20%."

What makes Claude Code feel magical isn't clever engineering — it's a really long system prompt telling the model exactly how to behave.

The reverse engineering tools proved this: system prompts and tool definitions account for 85-95% of the agent's personality.

System Prompt Showdown

How much text do you need to make an agent work?

Pi-mono
~880 tok
OpenCode
~7,730 tok
Claude Code
~8,000+ tok

The surprise

Pi-mono uses 10x fewer tokens and still works remarkably well. More constraints ≠ better agent.

What's Actually in the System Prompt?

Claude Code's 8,000+ tokens broken down

SectionTokensPurpose
Identity~50"You are Claude Code"
Workflow Rules~3,200How to use tools, git, PRs
Environment~320OS, cwd, git status, date
Tool Defs~3,500JSON schemas for 17 tools
Reminders~900Start/end context nudges

Key rules we extracted:

  • "Be concise — fewer than 4 lines"
  • "DO NOT ADD ANY COMMENTS unless asked"
  • "Only be proactive when user asks"
  • "Never use --no-verify"
  • "Never commit secrets to repos"

Tool Philosophy: 4 vs 15 vs 17

How many tools does an agent actually need?

Pi-monoOpenCodeClaude Code
Total tools41517
File readreadReadRead
File writewriteWriteWrite
File editeditEditEdit + MultiEdit
ShellbashBashBash
Search files—GlobGlob
Search content—GrepGrep
Sub-agents—TaskTask
Web fetch—WebFetchWebFetch
Plan mode—PlanModePlanMode

Pi-mono's argument

With bash, you don't need Glob, Grep, WebFetch, or Git tools. The model composes them from find, rg, curl.

Claude Code's argument

Dedicated tools are safer and produce smaller tool results (fewer tokens). Explicit > implicit.

Context Window: The Real Constraint

What fills up the 200K token budget?

Pi-mono
0.4%
OpenCode
3.9%
Claude Code
4.0%
System Prompt
Tool Definitions
Skills / Reminders
Context / MCP / Env
Available for conversation

Pi-mono starts with 99.6% of context free. Claude Code starts with 96%. Sounds similar — but over a long session, that 4% fixed cost compounds.

Permission Models: Trust vs. Control

How much should an agent be allowed to do unsupervised?

YOLO

Pi-mono

  • No confirmation dialogs
  • No permission gates
  • Trust the model entirely
  • User opts in by running it

GATED

OpenCode

  • User-selected permission mode
  • Tool calls can be approved/denied
  • Explicit tool preference rules
  • Security-focused constraints

TIERED

Claude Code

  • Must Read before Write
  • No --force-push by default
  • No --no-verify ever
  • Atomic MultiEdit (all-or-nothing)
  • Hook system for custom gates

The Hardness Spectrum

Where each agent lands on the trust-vs-control axis.

P
O
C
Soft (trust model) Hard (govern model)
Pi-mono
OpenCode
Claude Code
DimensionPi-mono (Soft)OpenCode (Mid)Claude Code (Hard)
System prompt880 tokens7,730 tokens8,000+ tokens
Tool count41517
Permission gatesNoneUser-selectableTiered + hooks
Output verbosityModel decides"Concise""< 4 lines"
Git safetyNoneSomeExtensive (no force, no amend)

When Memory Fills Up: Compaction

How agents handle long conversations

All three agents implement some form of context compaction:

1. Detect context approaching limit
↓
2. Prune old tool outputs (cheap)
↓
3. Call LLM to summarize conversation
↓
4. Replace old messages with summary

Claude Code's trick

Uses Haiku (cheap, fast model) for compaction — not Sonnet. Different models for different jobs. The quota check, topic detection, and compaction all use Haiku.

Pi-mono's advantage

Starting at 0.4% context, compaction kicks in much later. The minimal system prompt buys more conversation room.

Sub-Agents: Divide and Conquer

How Claude Code and OpenCode handle complex tasks

// The Task tool creates isolated contexts
Task({
  description: "Research auth patterns",
  prompt: "Find all auth middleware...",
  subagent_type: "Explore"
})

// Sub-agent gets:
// - Fresh context window
// - Own tool access
// - Single response back
// Parent context stays clean
  • Isolated context — sub-agent's tool results don't pollute parent
  • Stateless — one request, one response, no follow-up
  • Parallelizable — launch multiple agents at once
  • Model-flexible — can use cheaper models for simpler sub-tasks

Pi-mono?

No built-in sub-agents. Instead: bash can spawn another Pi-mono process. Unix philosophy.

The Hidden Token Killer: Tool Results

System prompts get all the attention. But tool results are what actually blow up your context.

System prompt
~3,200
Tool defs
~3,500
User message
~42
Read large file
~12,000+

One Read of a big file can cost 3-4x more tokens than the entire system prompt. This is why agents tell you: "prefer Grep over cat, prefer Edit over Write."

What This Means for You

Practical takeaways from the reverse engineering

Try It Yourself

All three tools are in the weekend_projects folder

claude-code-reverse

node proxy.js
# Point Claude Code at localhost:9876
# Open visualize.html to explore

opencode-reverse

npm run dev
# Connects to OpenCode on :4096
# Live dashboard at localhost:3000

pi-mono-reverse

npm run dev
# Load any .jsonl session file
# Dashboard at localhost:3000

Run an agent session. Read the captured data. See for yourself what's inside the box.

Agent Hardness

The model is the intelligence.
The prompt is the personality.
The tools are the hands.
The constraints are the guardrails.

agent37.club