30-second primer: an LLM (Claude / GPT / ...) only predicts "what text comes next."
To make it really read files, run commands, or browse the web, you wrap it with
tools + a loop: it asks to call a tool → the framework runs it → result is fed back → it continues.
That wrapper is an "agent." This page compares six agent / harness designs. New here? Start with "Concepts" below.
1. 基本概念1. Concepts
1. LLM 本质是"下一个 token 预测器"1. LLM is a next-token predictor
你给它一段文本, 它给你接下来最可能出现的一段文本。没了。
Feed it text, it returns the most-likely next chunk of text. That's all.
An LLM only does one thing: look at the tokens so far, predict the next token;
then append that prediction and predict the next one — step by step, a whole reply appears.
First, text is split into tokens (≈ subwords):
"The cat sat on the"
──tokenize──▶ ["The", " cat", " sat", " on", " the"]
Then one step at a time:
step 1 sees: ["The", " cat", " sat", " on", " the"] → predicts " mat"
step 2 sees: ["The", " cat", " sat", " on", " the", " mat"] → predicts "."
step 3 sees: [..., "."] → predicts <end> (stop)
Each step makes the input one token longer. The total length of "history + new tokens" is
capped by the context window — overflow either gets compacted (covered later in each project's compaction story) or truncated.
它不会执行代码、不会读文件、不会上网。这些全是 agent 在外面套的一层。
It can't execute code, read files, or access the web. All of that is what the agent wraps around it.
2. Function calling: 让 LLM "指点"框架去干活2. Function calling: let the LLM direct the framework
Tell the LLM in the system prompt "you can call read_file(path)". A user asks "read /tmp/foo.py" — the LLM won't invent file contents, it returns structured JSON:
Six steps. All six agent / harness designs follow this skeleton — they differ in how much each step does, what safety layers are added, and how it extends.
4. 为什么 agent 能做到 LLM 做不到的事4. Why agents can do what LLMs can't
Key insight: LLMs have great brains but fake hands. The agent framework installs real hands — and makes sure it doesn't burn the kitchen down. The six designs differ in how they install the hands and how they prevent fires.
术语表 — 忘记某个词时展开查 Glossary — expand when you forget a word
The exact limit depends on model and runtime config; for harness design, the key issue is compaction, truncation, and reloading persistent memory near the limit
API
How programs call programs; here: LLM REST APIs
Send HTTP, get JSON back
Streaming
Return tokens as they are generated
Lower latency, pipeline next step earlier
Function calling / Tool use
LLM returns structured "please call this tool" JSON
Prerequisite for an agent to "do things"
Prompt cache
Server-side cache of long system prompt
Up to 10× cheaper, lower latency
Sandbox
Confined process env (FS/network limited)
Keeps agent from wrecking your machine
Provider
LLM vendor (Anthropic / OpenAI / Google)
Pick one, or write adapters
Turn
One user message + full agent response cycle
"One turn" = the main loop runs a full pass
ReAct
Reasoning + Acting loop: think → act → think
Most systems here are ReAct variants
MCP
Model Context Protocol for external tools
Lets agents plug in any 3rd-party tool
CLAUDE.md / AGENTS.md
Root-level project convention file
Read at startup; a "README for bots"
Plan-and-execute
Ask the model to plan first, then execute step by step
opencode's plan mode, claw-code's EnterPlanMode
Reflection
Agent self-reviews after acting; retries on error
§8 Takeaway · common auxiliary loop
Tools
Typed functions the agent can call (read file, run bash, browse…)
§2 Tools vs Skills table
Skills
Markdown files (SKILL.md) teaching when/how to use tools
codex's default mode uses this stack to bound filesystem and network access
Vercel AI SDK
Provider-agnostic TypeScript SDK from Vercel that abstracts streaming / tool-calling / reasoning across vendors
opencode's provider layer uses it; adding a new vendor is a config one-liner
Self-evolving
Agent that writes new SKILL.md files, updates prompts, or augments memory at runtime — so the next run starts from a higher baseline; a step beyond reflection, where what was learned persists
The Skills layer is the persistence entry point · hermes's skill_manage tool · a natural next step after §8 Reflection
2. 五层概念地图: Prompt → Harness2. The five-layer stack: prompt to harness
In 2023 the craft was prompt engineering. In 2024 it moved to context engineering — retrieval, memory, compaction. In 2025 the frontier climbed two more layers: Skills and Harnesses. The six projects on this page are all different takes on harness engineering.
One-line summary: Prompt Engineering is wording; Context Engineering is what fits in the window; Tools are what the agent can do; Skills are when and how to do it; Harness Engineering is the exoskeleton — without it, the LLM brain has nowhere to attach its hands.
Claude Code is best understood as an agentic harness, not "Claude plus a few shell commands." Its value is the outer state machine: how user input, project context, tool schemas, permission policy, hooks, tool results, and compaction summaries are organized into a durable turn loop. The official docs describe the loop as gather context → take action → verify results; this post expands it into implementation-level state transitions.
Claude Code 状态
它在做什么
为什么重要
Context Assembly
读 system prompt、CLAUDE.md / skills / conversation history / tool schemas, 组装本轮请求。
决定模型"看见什么"; 这比单句 prompt 更接近真实能力上限。
Model Step
流式调用模型, 输出自然语言或结构化 tool_use。
模型不直接执行动作, 只声明"我想调用什么工具"。
PreToolUse
工具执行前先跑 hook, 可以改参、拒绝、要求确认、推迟、补充上下文。
这是 Claude Code 的治理入口: 用户能写程序影响 agent, 但强制权限规则仍会评估。
Load system prompt, CLAUDE.md / skills / conversation history / tool schemas, then assemble the request.
Determines what the model can see; this matters more than any single prompt.
Model Step
Stream the model; receive either natural language or structured tool_use.
The model does not act directly; it declares which tool it wants.
PreToolUse
Run hooks before execution; rewrite input, deny, ask, defer, or add context.
This is the governance surface: users can program the agent, while enforced permission rules still apply.
Permission
Allow / ask / deny based on tool type, path, command risk, and user policy.
Separates "the model wants" from "the system permits."
Execute + Observe
The harness runs shell / file / MCP tools and appends tool_result back into history.
This is where action happens; the model learns the result by observation.
Loop / Terminate
If tool calls remain, go back to the model; if none remain, end the turn.
This is why a coding agent can fix bugs over multiple steps.
Compaction
Summarize old history when context is too long, preserving important state.
Long tasks can continue instead of losing the session.
最关键的 transition: assistant_message has ToolUse → 进工具管线; no ToolUse → 进入 stop/结束检查; hook 或 permission denied → 生成 error tool_result 让模型读到; context too long → compact 后继续。这四个分支就是 Claude Code 状态机的骨架。
The key transitions: assistant_message has ToolUse → enter the tool pipeline; no ToolUse → enter stop/finalization checks; hook or permission denied → append an error tool_result for the model to read; context too long → compact then continue. Those four branches are the backbone of the Claude Code state machine.
Tools 和 Skills 的分工是 Anthropic 2025 年在 Agent Skills 博客 + anthropics/skills 仓库里推的核心抽象。openclaw 把它复述为一句话: "Tools are what the agent calls; Skills teach the agent when and how."
The Tools / Skills split is the core abstraction Anthropic pushed in 2025 (see their Agent Skills blog and the anthropics/skills repo). openclaw restates it as: "Tools are what the agent calls; Skills teach the agent when and how."
Having all five layers in place only means the system is theoretically capable; whether it actually works requires real-task success rates. That's exactly what ClawBench measures: live web tasks that grade each layer end-to-end, not offline DOM snapshots you can game.
github.com/anthropics/skills IS the reference repository for this standard — Anthropic's official collection of Skill examples and the origin of the SKILL.md format. Each skill is a folder containing one required file SKILL.md: YAML frontmatter (name + description) followed by a Markdown body. Claude auto-mounts the skill when the description matches the task, reads the body, and follows it.
# 最小模板(来自 anthropics/skills/template/SKILL.md):
---
name: my-skill-name
description: A clear description of what this skill does and when to use it
---
# My Skill Name
[Add your instructions here that Claude will follow when this skill is active]
## Examples · Guidelines · Reference files · etc.
# Minimum template (from anthropics/skills/template/SKILL.md):
---
name: my-skill-name
description: A clear description of what this skill does and when to use it
---
# My Skill Name
[Add your instructions here that Claude will follow when this skill is active]
## Examples · Guidelines · Reference files · etc.
Real example: anthropics/skills/skills/pdf/SKILL.md has a very precise description — "use this skill whenever the user wants to read PDFs / merge / split / rotate / watermark / OCR" — Claude auto-invokes on those keywords. The body contains Python snippets, CLI guidance, links to REFERENCE.md, etc. The official repo changes over time, so cite counts with a last-checked date.
Tools vs Skills 对照表Tools vs Skills side-by-side
维度
Tools
Skills
是什么
带类型签名的函数
带 YAML frontmatter 的 Markdown 文件夹
谁执行
harness 执行 (调真实 API / shell / FS)
LLM 自己读完照做 (instructions + 参考资料)
回答的问题
"agent 能调什么?"
"什么时候 / 怎么调?"
进入上下文
schema 列在 tools[] 里
description 常驻, 正文按需挂载
跨 harness 复用
每家 harness 都要自己实现
同一 SKILL.md 任何支持的 agent 都能装
例子
bash、read、write、browser、MCP 工具
pdf、mcp-builder、frontend-design
Dimension
Tools
Skills
What
Typed function with a signature
Folder of Markdown with YAML frontmatter
Executor
The harness runs it (hits real APIs / shell / FS)
The LLM reads it and follows (instructions + refs)
How these projects relate: Claude Code (≈ claw-code) ships a first-class Skill tool that mounts SKILL.md; openclaw devotes major docs space to Skills; hermes-agent provides skill_view / skills_list / skill_manage tools that load SKILL.md per the agentskills.io spec; opencode's Markdown-frontmatter agents sit close to this idea; codex has no first-class Skill concept — it uses AGENTS.md like CLAUDE.md for per-project instructions; pi pushes this surface into extensions / packages.
3.5 相关旁支:Flue Framework3.5 Related Aside: Flue Framework
Flue Framework is not one of the six systems compared below; it is an external reference point for the harness layer. It recasts the "five-layer stack" of this page into a four-layer model: Model · Harness · Sandbox · Filesystem. Its slogan "Not another SDK" is a stance — it doesn't add another chat abstraction; it offers a programmable TypeScript control plane at the harness layer. It earns a place here because it echoes §2's framing: the harness is a major engineering axis.
Flue 的四层 ↔ 本页五层Flue's four layers ↔ the five-layer stack
同一段 agent 代码跑五个部署形态。Node.js · Cloudflare Workers · GitHub Actions · GitLab CI · HTTP 服务 — 同一个 harness 实现可以是常驻 server, 也可以是单次 CLI run, 也可以是 CI 任务里的一段。这把 §8 takeaway #4 "agent as a service"再推一步: service vs CLI 不是架构选型, 是部署目标的旋钮。
Secrets never enter the LLM context. Flue keeps tokens like GITHUB_TOKEN at the harness boundary and only injects them into the child-process env at the moment of shell exec — the agent never sees them, and the sandbox only touches them for one syscall. A natural complement to the §3 "PreToolUse / Permission" governance line: governance gates what to do; secret isolation gates what can be read.
One agent codebase, five deployment shapes. Node.js · Cloudflare Workers · GitHub Actions · GitLab CI · HTTP server — the same harness can run as a long-lived service, a one-shot CLI, or a CI step. This pushes §8 takeaway #4 "agent as a service" one step further: service vs CLI is not an architecture choice, it's a deployment knob.
Flue 在六个项目对比中的坐标Where Flue sits relative to the six projects
维度
Flue
最像谁
不一样在哪
语言
TypeScript
opencode (TS+Go) · openclaw (TS)
纯 TS, 不需要 Go runtime
形态
SDK / library, 用户用 TS 写 agent 入口
opencode 的 core library
更彻底——没有自带 TUI, 部署形态完全交给用户
Sandbox
三档可插
hermes (Modal) · openclaw (Docker)
把"挑哪个 sandbox"做成配置而不是源码 fork
定位
"自主代理可编程控制面"
偏 opencode 的服务化思路
更强调"全栈自控": agent 逻辑 + harness + sandbox 都在你这边
Dimension
Flue
Closest sibling
How it differs
Language
TypeScript
opencode (TS+Go) · openclaw (TS)
Pure TS — no Go runtime needed
Shape
SDK / library; users write the agent entry in TS
opencode's core library
More radical — no bundled TUI, deployment shape is fully user-decided
Sandbox
Three pluggable backends
hermes (Modal) · openclaw (Docker)
Backend choice is a config knob, not a source fork
Stance
"Programmable control plane for autonomous agents"
opencode's service-shaped approach
Pushes harder on full-stack ownership: agent logic + harness + sandbox all yours
One-line placement: if §2 names harness engineering as the layer of 2025, Flue is the most literal attempt to ship that layer as a TS package — it doesn't treat "agent" as a product, but as your TS code on top of a standard harness runtime.
4. 六个流程图4. Six diagrams
下面六张图讲的是这些 harness 怎么运作;想量化它们到底 work 得多好, 用我们的 ClawBench 在真实网页任务上跑一跑就知道。The six diagrams below show how these harnesses work; to quantify how well they actually work, run them against our ClawBench on live web tasks.
ReAct 循环 + 共享迭代预算 + 子代理委派。ReAct loop with shared iteration budget and sub-agent delegation.
flowchart TD
U([User message]):::io
A[Apply prompt cache + memory · every 10 turns]:::ctx
M{{Adapter.stream · Anthropic · Bedrock · Gemini}}:::model
P[Parse tool_calls · preserve reasoning_content]:::model
R[ToolRegistry.dispatch · built-in tools]:::tool
S{delegate_task?}:::decision
SA[[Spawn sub-agent · shared IterationBudget]]:::sub
RES[Append tool results]:::tool
C[ContextCompressor · if near context limit]:::ctx
B{budget > 0?}:::decision
Y([Return final message]):::io
U --> A --> M --> P --> R --> S
S -- yes --> SA --> RES
S -- no --> RES
RES --> C --> B
B -- yes --> A
B -- no --> Y
class U step1
class A step2
class M step3
class P step4
class R step5
class SA step6
class RES step7
class C step8
class B step9
click U call jumpTo("hermes", 1)
click A call jumpTo("hermes", 2)
click M call jumpTo("hermes", 3)
click P call jumpTo("hermes", 4)
click R call jumpTo("hermes", 5)
click SA call jumpTo("hermes", 6)
click RES call jumpTo("hermes", 7)
click C call jumpTo("hermes", 8)
click B call jumpTo("hermes", 9)
classDef io fill:#233042,stroke:#7aa2f7,color:#e6e8ef;
classDef model fill:#2b1f3a,stroke:#bb9af7,color:#e6e8ef;
classDef tool fill:#1f3a2b,stroke:#9ece6a,color:#e6e8ef;
classDef sub fill:#3a2b1f,stroke:#e0af68,color:#e6e8ef;
classDef ctx fill:#3a1f2b,stroke:#f7768e,color:#e6e8ef;
classDef decision fill:#2d2d3a,stroke:#8a93a6,color:#e6e8ef;
Hooks before permissions — a PreToolUse hook can deny, ask, defer, or rewrite a call before the policy engine; enforced deny/ask rules remain the safety boundary.
No in-loop sub-agents — task registry is for async background only; multi-agent coord pushed outside.
Auto-compaction with provenance — summaries logged as SessionCompaction events + health probe.
结构化 output[] 流 + 原生推理项 + 沙箱 bash。Structured output[] stream with first-class reasoning items and sandboxed bash.
flowchart TD
U([User message]):::io
K[_build_api_kwargs · instructions · tools · reasoning.effort]:::ctx
ST{{responses.stream · with reasoning.encrypted_content}}:::model
FB[[Fallback — responses.create stream · synthesize from deltas]]:::model
N[_normalize_codex_response · parse output array]:::model
RS[codex_reasoning_items · dedup by ID across turns]:::ctx
PP[PermissionPolicy · ReadOnly · WorkspaceWrite · DangerFull]:::gate
SB[Exec in sandbox · seatbelt · landlock]:::tool
AP[Append tool result]:::tool
CK{incomplete or commentary}:::decision
Y([Return message]):::io
U --> K --> ST
ST -- transport err --> FB --> N
ST --> N --> RS
RS --> CK
CK -- function_call --> PP --> SB --> AP --> K
CK -- commentary --> K
CK -- completed --> Y
class U step1
class K step2
class ST step3
class FB step4
class N step5
class RS step6
class PP step7
class SB step8
class AP step9
class CK step10
click U call jumpTo("codex", 1)
click K call jumpTo("codex", 2)
click ST call jumpTo("codex", 3)
click FB call jumpTo("codex", 4)
click N call jumpTo("codex", 5)
click RS call jumpTo("codex", 6)
click PP call jumpTo("codex", 7)
click SB call jumpTo("codex", 8)
click AP call jumpTo("codex", 9)
click CK call jumpTo("codex", 10)
classDef io fill:#233042,stroke:#7aa2f7,color:#e6e8ef;
classDef model fill:#2b1f3a,stroke:#bb9af7,color:#e6e8ef;
classDef tool fill:#1f3a2b,stroke:#9ece6a,color:#e6e8ef;
classDef gate fill:#3a2b1f,stroke:#e0af68,color:#e6e8ef;
classDef ctx fill:#3a1f2b,stroke:#f7768e,color:#e6e8ef;
classDef decision fill:#2d2d3a,stroke:#8a93a6,color:#e6e8ef;
HTTP as the boundary — TUI / web / IDE all speak to /session/*; OpenAPI 3.1 spec at /doc (server.ts) and mDNS broadcast (server/mdns.ts) let any client discover and generate an SDK.
Build vs plan modes — same tool surface, different permission maps: build (default) allows edit/write/bash; plan lowers write-class tools (edit/write/patch/bash) to ask or deny depending on built-in defaults plus user config. Read-only tools flow through. One loop, two personas.
Provider-agnostic — Vercel AI SDK delegates streaming / tool / reasoning to each adapter.
First-class LSP + MCP — code intelligence and external tools sit beside native ones.
Multi-channel routing — IM traffic from Discord / Slack / Telegram / WhatsApp / iMessage / Signal / Matrix / Teams / Google Chat / Zalo all feeds one Gateway (long-lived daemon); CLI / iOS / IDE act as additional entry points, all landing in shared sessions.
Four default tools — read / write / edit / bash are the only ones the model can call directly; find/grep/ls exist as files but aren't mounted, so the model uses native shell via bash.
Two-key steering — while the agent is running tools, Enter interrupts the remaining tools and lands a new message in reasoning; Alt+Enter queues a follow-up until the current run ends.
"What we didn't build" — sub-agents, plan mode, MCP, permission popups, todos, background bash are all deliberately pushed into extensions / packages; build one or install one.
Session as a tree — /tree jumps back to any old message and forks from there; every branch lives in one file; /share uploads to a GitHub gist and returns a shareable URL.
SDK embedding — the same AgentSession runs in four modes: TUI / print(JSON) / RPC / SDK; openclaw uses the SDK to embed pi as its runner.
packages/coding-agent/src/core/agent-session.ts — AgentSession (3099 lines)packages/coding-agent/src/core/tools/{read,write,edit,bash}.ts — 4 default toolspackages/coding-agent/src/core/extensions/ — TS extension runtimepackages/coding-agent/src/core/compaction/ — replaceable compactionpackages/coding-agent/src/modes/{interactive,print-mode.ts,rpc} — 4 run modespackages/coding-agent/src/core/sdk.ts — embed API (used by openclaw)
5. 一眼看懂5. At a glance
下面表里的术语若有陌生, 后面"深度拆解"会讲透——先扫一眼整体。Unfamiliar terms below will be explained in the deep dives — just skim for now.
Why you should care: it shows how to support multiple LLM providers in one loop, and how to delegate to sub-agents without losing control — the first two engineering problems you'll hit when building your own agent.
Adapter pattern (agent/anthropic_adapter.py, gemini_native_adapter.py, ...) — abstract "stream + receive tool calls" interface; each provider implements it. The main loop never knows who it's talking to.
Shared IterationBudget (run_agent.py:730, parent default 90, child default 50) — the main agent decrements once per API call; sub-agents share the same counter AND each is individually capped at 50. Without this, "a dumb agent spawns 10 sub-agents, each spawns 10 more" explodes exponentially.
delegate_task sub-agents (run_agent.py:8076 + tools/delegate_tool.py:13) — shipped as a tool. Calling it spins up an isolated-context child AIAgent with a restricted toolset. The parent only sees the summary; the 50 child tool-calls don't pollute parent context.
Great for RL training: drop into Modal cloud sandbox, run 100 rollouts in parallel, each with its own FS but a shared reward function. MCP server (mcp_serve.py) exposes internal conversations outward, letting Claude Code / Cursor consume hermes as a tool. ClawBench is a natural RL evaluation target for this setup — its per-evidence scores plug straight in as reward signal.
Complex — single file is 12,000+ lines. Multi-provider means you can't 1:1 map each vendor's latest features (e.g., Claude's extended thinking has no Gemini equivalent).
Why you should care: shows how to make an agent safe enough for production — every dangerous action can be intercepted, rewritten, or audited by scripts. Essential for anyone shipping an agent.
注: claw-code 是 Claude Code 的 Rust 开源复刻。Anthropic 官方文档把 Claude Code 定位为围绕 Claude 的 agentic harness(见 How Claude Code Works)。官方可确认的是 agentic loop、工具、权限、hooks、CLAUDE.md / memory、context compaction 这些机制; 本节的具体源码行、100k 压缩阈值、12 阶段 Bootstrap、health probe 是 claw-code 的实现选择, 不等于官方 Claude Code 内部实现。
Note: claw-code is an open-source Rust reimplementation of Claude Code. Anthropic's docs describe Claude Code as an agentic harness around Claude (see How Claude Code Works). The official surface confirms the agentic loop, tools, permissions, hooks, CLAUDE.md / memory, and context compaction; the source lines, 100k compaction threshold, 12-phase bootstrap, and health probe in this section are claw-code implementation choices, not official Claude Code internals.
目的Purpose
做一个可审计、可干预的 Claude Code 开源实现。每一次工具调用都可以被脚本拦截、改参、查权限、记日志、事后清理。
An auditable, interceptable Claude Code reimplementation. Every tool call can be intercepted, rewritten, permission-checked, logged, or cleaned up afterward.
Pre/Post hooks — claw-code's hooks.rs:23HookEvent enum implements three: PreToolUse, PostToolUse, PostToolUseFailure. Anthropic's official Claude Code docs list more lifecycle hooks, including SessionStart, UserPromptSubmit, PreCompact, Stop, ConfigChange, and others. Pre-hooks can allow / ask / deny / defer / modify input / add context; post-hooks handle cleanup / notify / log.
PermissionPolicy (permissions.rs:175authorize_with_context) — post-hook authorization with static rules + interactive prompter; bash commands also run through bash_validation.rs for syntax + danger checks.
Strict ordering (conversation.rs:414): Pre-hook → Permission → Execute → Post-hook. Note: hook runs before permission — a hook can request allow / ask / deny / defer or rewrite a dangerous command before permission evaluates the final call.
Auto-compact + health probe — threshold is DEFAULT_AUTO_COMPACTION_INPUT_TOKENS_THRESHOLD = 100_000 (conversation.rs:18); compaction runs via compact.rs:96 compact_session; right after, a health probe fires (conversation.rs:297 run_session_health_probe) that probes the session to confirm it still works. The action is logged as an AutoCompactionEvent for audit.
Policy/runtime decoupling — how to run bash is runtime's job; whether to allow it is policy's. One JSON config turns the same loop into "fully autonomous" or "ask for every step."
Hook-before-permission = more expressive — traditional permission is allow/deny. Hook is a programmable middle layer. You can do "in prod, rewrite a destructive command into a dry-run or safer target before permission sees it."
Compaction has provenance — not a black-box history wipe; summary + metadata preserved, issues traceable.
Same runtime, different personas: developers get wide permissions with lint hooks; prod gets strict permissions with forced dry-run hooks; teaching mode asks on every bash. Rust impl means fast startup, low memory, embeddable in other programs.
Main loop has no sub-agents (task registry is async background only). Multi-agent coordination is pushed outside the runtime — a deliberate philosophy: "keep agent context focused on work, not meetings."
为什么你该看懂这家: Responses API 是未来几年其他服务商大概率会跟进的方向。提前看懂 = 别家跟进时你能立刻上手。
Why you should care: Responses API is likely the direction other vendors will follow over the next few years. Learn it now, be ready when others catch up.
目的Purpose
展示 OpenAI 把 agent 能力直接内置到 API 会是什么样——不是让客户端组装工具调用, 而是 API 直接返回"我在想什么 / 要调什么工具 / 要说什么"的结构化流。
What it looks like when OpenAI bakes agent capability into the API itself — not client-side tool-call assembly, but the API streaming structured items: "what I'm thinking / which tool to call / what to say."
Responses API, not Chat Completions (run_agent.py:5183responses.stream) — Chat Completions returns a content string + optional tool_calls array (client assembles). Responses API returns an output[] array of typed items: {type: "message"} / {type: "function_call"} / {type: "function_call_output"} / {type: "reasoning"} — clients route by type.
Encrypted reasoning across turns (run_agent.py:7266 dedup logic) — request with include: ["reasoning.encrypted_content"]; Codex returns encrypted reasoning blobs. Those blobs can be fed back as part of the next turn's input — the model "remembers" how it was thinking, multi-turn reasoning stays coherent.
3-step fallback (run_agent.py:5168 → :5297): responses.stream() → retry → responses.create(stream=True) synthesized from deltas. Even if streaming drops, the turn isn't lost.
Codex has hooks too — config.toml accepts [hooks.pre_tool_use] / [hooks.post_tool_use] scripts for pre/post-tool interception (marked stable in April 2026's codex_hooks release).
OS-level sandbox — macOS seatbelt (sandbox-exec) with .sb configs limits FS / network; Linux uses landlock + bubblewrap + seccomp via the codex-linux-sandbox helper. Codex commonly starts trusted version-controlled repos in workspace-write with on-request approvals; read-only is the safer browsing / CI / untrusted-directory mode. CLI sandbox modes are read-only, workspace-write, and danger-full-access; app-server also has externalSandbox when an outer sandbox already enforces isolation.
为什么 workWhy it works
Typed output——不用正则从 content 里抠 tool_use JSON。
推理保留——长任务不失忆, 省 token 一致性好。
OS 沙箱——比完整容器方案更轻, 比只靠权限提示更硬。
Typed output — no more regex-extracting tool_use JSON from content.
Reasoning preserved — long tasks don't go amnesic; saves tokens, stays consistent.
OS sandbox — lighter than a full container setup and stronger than permissions alone.
First-party optimization — Responses API treats agents as first-class citizens. The client only handles fallback and dedup; the server owns inference, caching, streaming. The whole pipeline is cleaner than "Chat Completions + hand-rolled agent loop." For OpenAI-committed teams, codex is the most natural option in this comparison.
代价Cost
锁定 OpenAI——Responses API 目前只有 OpenAI。推理加密——你拿不到纯文本推理内容, 只能原样传回。
Locked to OpenAI — Responses API is OpenAI-only today. Reasoning is encrypted — you can't inspect it, only pass it back.
6.4 opencode
github.com/sst/opencode
为什么你该看懂这家: 如果你要做 IDE 插件、团队共享 agent、或多端同步, 这是蓝图。
Why you should care: if you want to build an IDE plugin, a team-shared agent, or multi-client sync — this is the blueprint.
One engineering problem: agent logic should not be bound to a TUI. TUI today, VS Code plugin tomorrow, iPhone app the day after — write the agent once.
隐藏系统 agent——compaction(对话过长自动摘要)、summary(生成摘要)、title(自动命名 session)。用户看不到, server 后台在跑。
Client-server split — Server is TypeScript on Bun, holds all sessions + agent loop. Client is Go TUI, but the protocol is open HTTP: POST /session/:id/message, GET /global/event (SSE), POST /session/:id/permissions/:id. OpenAPI 3.1 spec at /doc auto-generates any-language SDKs; mDNS broadcast on startup lets mobile apps discover.
Build vs Plan modes — same tool surface, different permission maps: build (the default) allows edit/write/bash; plan restricts write-class tools (edit / write / patch / bash) to ask or deny (resolved from agent.ts defaults merged with user config), while read-only tools flow through. Two personas, one loop.
Per-tool permissions — each tool independently set to allow | ask | deny, with wildcard support (mymcp_* whitelists a whole MCP bundle). Permission requests flow over HTTP back to the client UI.
Hidden system agents — compaction, summary, title are all marked hidden: true and run server-side on schedule. Users never see them.
Stable protocol → flourishing frontends — HTTP + OpenAPI enables community neovim plugins, mobile apps, web UIs.
Mode switching is free — plan mode is just different permission config, not a separate agent impl.
Vercel AI SDK underneath — swap provider with one config line.
为什么好Why it's good
对团队协作友好——server 跑在共享机器上, 多人接客户端连进来看同一 session。对 IDE 集成友好——任何 IDE 插件都能对接, 不用各自重造 agent。
Team-friendly — run server on a shared machine, multiple clients connect to the same session. IDE-friendly — any IDE plugin can wire up, no need to reinvent the agent.
Why you should care: shows how one agent can handle IM messages, CLI commands, iOS pushes, and IDE sessions in parallel — essential reading if you want an "all-in-one" personal copilot.
目的Purpose
做一个本地优先的多通道 agent。官方把它定位成"单个长驻 Gateway + 所有通道共用一个 agent": 不是又一个聊天框, 而是挂在你设备上的控制面板——Discord / Slack / Telegram / WhatsApp / iMessage / Signal / Matrix / Teams / Zalo 等 10+ IM 通道 + CLI / iOS / IDE 都路由进同一个 Gateway, agent 在共享 session 里工作。
A local-first multi-channel agent. The docs position it as "one long-lived Gateway, many channels, one agent" — not another chat box but a control plane on your device. 10+ IM channels (Discord / Slack / Telegram / WhatsApp / iMessage / Signal / Matrix / Teams / Zalo and more) plus CLI / iOS / IDE all feed the same Gateway and share sessions.
Docs terminology: Tools vs Skills.Tools are the typed functions the agent can call (bash / read / write / browser / canvas and other core tools); Skills are Markdown docs (SKILL.md) injected into the system prompt, teaching when and how to use them. This split is called out in the official docs as the core abstraction.
Gateway + Embedded Runner split (pi-embedded-runner/run.ts) — Gateway is a local WebSocket orchestrator owning channels / cron / auth / sessions; Embedded Runner is the portable agent core (runs in CLI, browser, remote SSH). They meet via session keys.
ToolPolicy pipeline (tool-policy-pipeline.ts) — tools filter by sandbox mode × channel: main session is permissive; sandbox lane only exposes exec · read · write · edit · sessions_*; different messageProvider values (e.g. voice, node) get their own allow/deny mappings. All config-driven, no hardcoding.
Dockerised browser sandbox (sandbox/browser.ts + Dockerfile.sandbox-browser) — every session spins its own container with Chromium + xvfb + noVNC + CDP. Automation, plus you can open port 6080 and literally watch the agent click.
Async compaction (compact.ts) — when context approaches the limit, an async compaction task is queued; the current turn finishes first, then history is summarised. New turns are blocked during compaction so state stays consistent.
ACP bridge (src/acp/session.ts) — openclaw acp exposes the Agent Client Protocol over stdio. Zed, Cursor and other IDEs drive openclaw as a backend without needing native plugins.
Ideal for "personal copilot / on-call bot": the agent watches Slack during a meeting, answers iMessage on the commute, resumes via CLI at home — all the same session. Add ACP and the IDE joins in too. The more CLI-centric systems ask you to context-switch tools yourself. The browser sandbox doubles as a ClawBench runner, so you can use openclaw for both web-agent dev and evaluation in one place.
Higher ops cost: Docker + WebSocket + multi-channel webhooks must all be up. run.ts is 2,100+ lines of dense logic. Not a plug-and-play mini-tool.
6.6 pi
github.com/badlogic/pi-mono · packages/coding-agentpi.dev
为什么你该看懂这家: 当前面的全功能框架比的是"我加了多少特性", pi 反过来比"我能砍掉多少特性还活得下去"。openclaw 的 embedded runner 就是基于 pi 的 SDK——这是 pi 在生产里很有力的存在证明。如果你想把 agent 做成一个能放进自己 app 里的库, 而不是一个吞掉用户工作流的 CLI, 这就是范例。
Why you should care: while the full-featured frameworks compete on "how many features I add," pi competes on "how many features I can strip out and still survive." openclaw's embedded runner is built on pi's SDK — a strong existence proof in production. If you want an agent shaped like a library you embed in your app, not a CLI that eats your workflow, this is the template.
Author Mario Zechner (badlogicgames; pi.dev donated by exe.dev) calls pi "a minimal terminal coding harness." The model gets four atomic tools (read / write / edit / bash); everything else is grown by users via TypeScript Extensions / Skills / Prompt Templates / Themes, which can be shipped as npm or git packages. The pi.dev homepage literally has a "What we didn't build" section: no MCP, no sub-agents, no plan mode, no permission popups, no built-in to-dos, no background bash — each entry tells you the recommended workaround instead.
核心机制Key mechanisms
4 工具默认(packages/coding-agent/src/core/tools/: read.ts · write.ts · edit.ts · bash.ts)——pi README 第一句:"By default, pi gives the model four tools." 也有 find / grep / ls 文件但默认未挂载, 让模型用 bash 走原生工具链。这跟 claw-code 的 40+ 工具是另一极。
Four-tool default (packages/coding-agent/src/core/tools/: read.ts · write.ts · edit.ts · bash.ts) — the pi README opens with "By default, pi gives the model four tools." find / grep / ls exist as files but aren't mounted by default — the model reaches for native shell via bash. Polar opposite of claw-code's 40+ tools.
Four run modes (src/modes/: interactive/ · print-mode.ts · rpc/) — the same AgentSession (3099 lines, src/core/agent-session.ts) runs as: interactive TUI (default), pi -p "query" for scripts (or --mode json for an event stream), JSON-RPC over stdin/stdout (for non-Node integrators), or embedded via the SDK. openclaw takes the SDK path (see §6.5).
Session as a Git-like tree (src/core/session-manager.ts + compaction/) — sessions persist as trees; /tree jumps to any old message, forks a new branch from there, all branches live in the same file; /share uploads to a GitHub gist and returns a shareable URL. Same primitive as opencode's parentID, but promoted to a first-class UX feature.
Two-key steering vs follow-up (shown on pi.dev) — while the agent is running tools, Enter sends a steering message: the current tool finishes, remaining tools are interrupted, and the new message lands in the model's next reasoning step. Alt+Enter sends a follow-up: queued, applied only after the agent finishes the current run. Two-key formalisation of "I can't wait, let me cut in."
Extensions = TypeScript modules (src/core/extensions/) — register new tools, slash commands, keybindings, TUI overlays. Features don't live in core, they live in extensions: want sub-agents? Write an extension that spawns another pi instance. Want plan mode? Flip edit/bash to ask in an extension. Want MCP? Write an extension that bridges MCP calls into bash.
Skills + Prompt Templates + AGENTS.md/SYSTEM.md (src/core/skills.ts · prompt-templates.ts · system-prompt.ts) — Skills load on demand per the SKILL.md spec without busting the prompt cache (progressive disclosure); Prompt Templates are Markdown, expanded via /name; AGENTS.md is loaded at startup from ~/.pi/agent/, parent directories, and cwd — pi's CLAUDE.md equivalent.
Compaction is replaceable (src/core/compaction/) — default behaviour on threshold is summary-rewrite, but extensions can swap in topic-grouping, code-aware compaction, or a different summarisation model. Where claw-code makes compaction a runtime first-class concept (with health probe), pi exposes it as a hook for you to wire.
15+ providers, subscription or API key (src/core/auth-storage.ts · model-registry.ts) — Anthropic Claude Pro/Max, OpenAI ChatGPT Plus/Pro (Codex), GitHub Copilot, Gemini CLI all flow through OAuth subscription. Fourteen API-key providers are listed (Anthropic / OpenAI / Azure / DeepSeek / Bedrock / Mistral / Groq / Cerebras / Cloudflare / xAI / OpenRouter / Vercel AI Gateway etc.). /model or Ctrl+L switches mid-session, Ctrl+P cycles your favourites.
为什么 workWhy it works
Token 效率压榨到极致——4 工具 + 极简 system prompt 意味着每 turn 的 prompt 前缀小, prompt cache 命中率高, 上下文窗口更经得住消耗。pi 主页声称"very token efficient due to its minimal system prompt"。
"Ask pi to build it" 闭环——pi 鼓励你让 pi 自己写一个 extension, /reload 立刻生效。这把"自定义"做成 agent 的自指能力, 不是开发流程外面的事。
Token efficiency squeezed — four tools + a minimal system prompt means small prompt prefixes per turn, higher prompt-cache hit rate, more context budget for actual work. The pi homepage claims it is "very token efficient due to its minimal system prompt."
Small core surface = small bug surface — all variability lives in extensions; core doesn't need to change for new use cases. The opposite bet of claw-code's "every guardrail in the runtime."
"Ask pi to build it" closes the loop — pi encourages you to ask pi itself to write an extension, then /reload makes it live. Customisation is a self-referential capability of the agent, not something outside the dev flow.
For teams who want to embed an agent into their own product, pi is the cleanest option in this set — SDK-first, documented RPC mode, no imposed UX concepts. openclaw embedding pi as a runtime in its Gateway, while only owning channel routing, is a strong advertisement for pi's philosophy. One more thing worth copying: the author publishes his own pi-mono work sessions to Hugging Face via pi-share-hf, donating real OSS workflow data to the RL / agent-training community.
"Deliberately not built" comes with a tax — you grow it yourself. Teams that need permission popups, sub-agents, plan mode, or MCP in production must first write a stack of extensions; reaching for claw-code or opencode is the cheaper path. The two-key steering protocol is elegant but has a learning curve — everyone on a team has to know the Enter vs Alt+Enter distinction or the wrong key will break a long task.
自己造 agent 时可以直接借鉴的设计。顺带一提:把它们造出来后, 用 ClawBench 在真实网页任务上打个分, 就知道到底哪几条 idea 真的 work。
Design patterns you can lift directly for your own agent. And once you've built it, run it against ClawBench on live web tasks to see which of these ideas actually pay off in practice.
No matter how deeply agents nest, total tool calls can't explode. DIY: add a single shared counter decremented by every call — far more robust than "each agent gets its own limit."
Traditional permission is binary allow/deny. Hooks are a programmable middle layer. DIY: expose a "user-injectable function" at every critical decision point, not hard-coded rules.
In multi-turn tasks, the prior turn's reasoning should carry to the next — don't re-think from scratch. DIY: turn on reasoning persistence if the model supports it; if not, inject "last turn's conclusion" via the system prompt manually.
4. 把 agent 做成服务 — opencode4. Agent as a service — opencode
Prompt cache breaks when the prefix changes. Treat dynamic content (memory, hook output) as "only effective for this API call" — don't pollute the history. DIY: history stores only user messages + tool results; all agent-internal metadata lives elsewhere.
6. 预算耗尽时留一次 "grace call" — codex6. Give the model one "grace call" on budget exhaustion — codex
When the tool budget is exhausted, don't hard-error. The codex adapter in hermes grants one more model call (run_agent.py:916 _budget_grace_call) so the model can exit gracefully: summarise what got done, what's left, save partial results. DIY: reserve a single graceful-exit slot in your budget watchdog — the UX upgrade is immediate.
7. Session 分叉作为一等公民 — opencode (源码级)7. Session forking as a first-class primitive — opencode (code-level)
opencode's session.sql.ts uses a parentID field to track session lineage, letting you fork a parallel session from any message. Note: public docs only describe the share feature; forking is present in source but not yet promoted to official docs — this one is from the code. Most agent frameworks treat "undo/retry" as destruction; opencode treats it as a tree. DIY: add a parent_id to persisted messages and you've unlocked "try both approaches at once."
一句话画像One-line mental model
hermes-agent
"ReAct + 预算 + 子代理, 一进程多 provider。""ReAct + budgets + sub-agents, one process, many providers."
Most systems here optimize for running an agent well; hermes-agent additionally optimizes for training one. As evaluation, RL, offline analysis, and cross-model comparison become more important, training-aware harness design is increasingly useful — and hermes is architected for it from the process model up to the data flow.
Modal cloud sandbox, one VM per rollout (environments/hermes_swe_env/hermes_swe_env.py:62) — RL demands hundreds of parallel rollouts, each with isolated FS state that survives until the reward function scores it. Local Docker can't hit that scale; Modal's serverless VMs as "one-shot containers" is what makes hermes feasible as an RL target.
Shared IterationBudget + per-child cap (run_agent.py:730, parent 90, child 50) — exploratory training fears fork-bombs. hermes decrements one shared integer from parent through every descendant; any chain that overflows is cut immediately. Without this, one RL epoch can nuke your cloud bill.
Trajectory compression that preserves head + tail (trajectory_compressor.py:86) — on context overflow, hermes summarises only the middle, keeping the opening (system / human / first tool feedback) and the final four turns. Training signal lives at head ("what to do") and tail ("what happened") — few harnesses treat compaction as a training-data concern; most just truncate.
Deterministic cache IDs (run_agent.py:4209, SHA256(fn:args:index)) — every rollout shares the same prompt prefix instead of random UUIDs, so same-batch rollouts hit the prompt cache. At scale, the savings are not small.
Multi-provider adapters in one process (agent/anthropic_adapter.py / bedrock / gemini_native / auxiliary_client) — same rollout can swap between Claude / Gemini / OpenAI with a config change. Cross-model eval, distillation, ablation all become one-line diffs.
MCP server mode as a signal tap (mcp_serve.py:431) — hermes can expose its internal conversations outward via MCP to Claude Code / Cursor and act as a training-signal collector. An agent's output becomes the next agent's input — research-grade bootstrapping.
Error classifier drives recovery (agent/error_classifier.py:24, FailoverReason enum) — auth / rate-limit / context-overflow each take distinct recovery paths; a single bad rollout can't sink a training run.
Why does this beat "pretty" for elegance? Training is the harshest load an agent harness can face: parallel, idempotent, cost-bounded, failure-recoverable, data-traceable. A harness that withstands all five is usually well positioned for production too, though the reverse is not always true. Hermes bakes "trainable" into every layer; that system-wide coherence is what real elegance looks like.
荣誉提名 (各自最优雅的一处)Honorable mentions (each has one truly elegant choice)
pi 的极简 SDK 核心——默认只给少数核心工具, 把 plan/subagent/MCP/sandbox 等能力推出 core, 更适合被嵌进别人的产品。
claw-code's hooks before permission — one tiny ordering choice unlocks an entire programmable policy surface. Binary "allow/deny" → programmable "intercept then ask" is an order-of-magnitude expressivity jump.
codex's typed output[] protocol — distinguishes "the model is talking / calling a tool / thinking" at the protocol level, instead of making clients regex their way through content.
opencode's client-server split — agent-as-HTTP-service, inheriting decades of Unix-pipe and REST wisdom; additional frontends have low marginal cost.
openclaw's Gateway + Channel abstraction — collapses "where did this message come from" into one layer; the agent doesn't distinguish Slack from CLI. From the multi-channel-agent angle, it has the most unified channel model.
pi's tiny SDK core — keeps the default tool surface small and pushes plan/sub-agent/MCP/sandbox behavior out to extensions, which makes it easier to embed in other products.
This is my taste, not the only right answer. Production audit → claw-code. OpenAI stack → codex. Multi-client work → opencode. Personal multi-channel copilot → openclaw. Embedded SDK → pi. And if you want to actually stress-test any of these systems on real web tasks, that's what ClawBench is for. I vote hermes because training-aware design is likely to matter more over time as agent evaluation, RL, and offline analysis become standard practice.
Four companion notes are folded in below, in full. Section 10 is Harness Engineering (prompts → accountable agent loops, six engineering planes),
Section 11 is Agentic RL (the harness is part of the policy; the PPO/GRPO/SFT+RL rollout ledger),
Section 12 is Core LLM RL Algorithms (PPO / DPO / GRPO quick reference),
and the closing appendix is an orthogonal coding & implementation reference (Classic Hot 100 + from-scratch PyTorch MHA / Conv). The first nine sections compare systems; these add the method and training lens behind them.
10. Harness Engineering:从提示词到可问责的智能体循环10. Harness Engineering: From Prompts to Accountable Agent Loops
并行子 agent 能拓宽检索和独立执行的覆盖面,也会放大 token、协调与合并成本。它只适合可明确拆分、输出契约稳定的子问题;同一代码面或强耦合决策常常需要共享的主控上下文。公开的多 agent 研究系统也报告了更宽探索带来的显著 token 开销,并强调协调方式会影响结果。Multi-agent research system
A long-running agent is not "a model plus a prompt." It is a runtime system: it selects information within a finite context, calls tools, preserves artifacts, enforces authority, manages budget and recovery, and hands results to an evaluator the agent cannot rewrite. Harness engineering is the discipline of designing that layer.
Central claim: a trustworthy agent result belongs to a configuration, not only to a model: model + harness version + environment + tool/permission policy + evaluator + budget. A pass-rate increase alone therefore cannot show that "the model got better," nor that a more elaborate orchestration helped.
10.1 What This Section Does Not Do
This is not a product survey, a declaration that more subagents are always better, or a claim that RSI has arrived. The six deep dives above explain how six concrete systems run. This section asks a different question: how should a harness itself be designed, constrained, and evaluated?
Two meanings must remain separate:
An agent harness is the runtime around a model: context, tools, state, control flow, authority, logs, and recovery.
An evaluation harness provisions a task, executes trials, collects evidence, and scores results. The evaluated agent must not treat it as an editable tool.
When those meanings collapse, "the agent's score improved" becomes dangerously ambiguous. A reader cannot tell whether model, prompt, tools, environment, budget, or scorer changed.
10.2 Draw an Accountable Boundary First
Base model
Agent harness
Environment
Generates candidate text and tool calls
Context, tools, state, budget, recovery
Terminal, browser, computer, service state
An evidence rail outside the agent's write boundary: version manifests, permission decisions, tool events, artifact hashes, usage, terminal state, and evaluator outputs. Humans approve high-risk escalations or interpret uncertain conclusions at explicit handoff points.
This is not a diagram of one released system. It is a design position: the model may propose actions and the harness may schedule them, but authority and acceptance criteria cannot live only in a prompt that says "be careful." MCP provides a protocol boundary for objects such as tools, resources, and prompts. It does not automatically make a tool response trustworthy or replace host-side policy enforcement. MCP Specification
10.3 Six Engineering Planes
3.1 Contract: Tools Are Not Just a List of Function Names
Tools are contracts between a stochastic agent and stateful services. An evaluable tool surface makes its input schema, authority, errors, idempotency, and response scope inspectable. The more overlapping tool paths an agent has, the easier it is to obtain a fragile result through an accidental route. Anthropic's tool-design guidance recommends testing tools on realistic multi-step tasks and using held-out tasks to detect overfitting to development trajectories. Writing tools for agents
The testable question is not "how many tools exist?" It is whether task-shaped narrow tools reduce invalid calls, token waste, or policy violations at equal authority and budget without harming held-out success.
3.2 State: Turn Memory into Artifacts, Not an Ever-Longer Prompt
Context engineering is the selection and maintenance of token state visible at each invocation. It is not merely a larger context window, and it is not dumping every past log into a prompt. Long-running systems need task manifests, progress, tests, candidate artifacts, dependencies, and version history as retrievable external artifacts. A fresh session can then continue from the same evidence instead of guessing what a prior session did.
Three terms deserve a strict distinction:
Term
What it preserves
What it does not guarantee
Context compaction
A summary or selected context for the current conversation
The original environment can be restored
Session handoff
A state manifest, artifact locations, and open questions for a fresh context
Earlier actions can be safely replayed
Checkpoint
Restartable environment state, configuration, and artifact version
A live external service stays unchanged
Public long-running-harness practice emphasizes feature lists, progress files, tests, bootstrap commands, and version history so a new worker reconstructs state from artifacts rather than hidden chat memory. Effective harnesses for long-running agents
Long-running harness lifecycle
Initialize — Freeze task, versions, authority, and budget.
Execute — Use tools and record artifacts and observations in lineage.
Checkpoint — Persist recoverable state; chat history is not a checkpoint.
Evaluate — Measure outcome, cost, and violations in an independent evaluator.
Recover or stop — Retry, hand off, revert, or stop under a fixed policy.
3.3 Authority: Runtime Enforcement, Not Prompt Wording
A prompt can express a preference; it cannot enforce an authority boundary by itself. A serious policy names readable and writable mounts, allowed hosts, credential scope, risky action classes, approval points, resource ceilings, network egress, and audit retention. Sandboxing and network controls are runtime mechanisms, not courtesy instructions. This is why public sandboxing designs discuss both filesystem and network boundaries. Claude Code sandboxing
One simple rule follows: an agent may propose a policy expansion, but it cannot approve that expansion itself, nor rewrite the evaluator and announce that it passed. The rule applies to browser, Computer Use, terminal, and training harnesses alike.
3.4 Control: Parallelism Is a Scheduling Hypothesis
Parallel subagents can widen research and independent execution coverage, but also multiply token, coordination, and merge cost. They fit only materially separable work with stable output contracts; shared code surfaces and tightly coupled decisions often need a common controller. A public multi-agent research system likewise reports substantial token cost for broader exploration and stresses that coordination shapes the outcome. Multi-agent research system
The parent should own global budget, decomposition, cancellation, merge, and publication. Workers should receive narrow objectives, isolated workspaces where possible, explicit deliverables, and durable result records. "Multi-agent is better" becomes an empirical claim only after comparison with a same-model, same-budget, same-task sequential baseline.
3.5 Evidence: Trace, Replay, and Rerun Are Not Synonyms
Every run should at least record harness, model, tool, environment, and policy versions; an initial-state digest; input/output and tool events; approvals and denials; artifact hashes; retries and recovery; evaluator outputs; and token, wall-clock, and resource usage. Secrets, personal data, and third-party content need redaction before retention.
That trace supports three different operations:
Diagnosis: why a run failed, spent unusually, or touched authority.
Observational replay: inspect an event record without repeating external side effects.
Execution rerun: execute from frozen state while declaring nondeterminism and external-dependency controls.
A video or chat transcript generally supports only the first two. It should not be called a reproducible rerun of a changing online service.
3.6 Integrity: The Evaluator Is Part of the System but Not the Optimization Surface
Deterministic tests, model graders, and human review answer different questions. Deterministic verifiers check explicit terminal states; model graders can handle nuanced text but need calibration and error reporting; humans catch unmodeled harm. Agent-evaluation engineering guidance stresses defining tasks, graders, samples, and metrics before interpreting a result as capability. Demystifying evals for AI agents
Harness changes should therefore carry a change manifest: what should improve, what must not regress, the held-out split that accepts it, and the rollback condition. Harness-Bench and VeRO are preprints exploring configuration-level or versioned agent evaluation. They provide useful methodological clues, not proof that elaborate harnesses are stronger on every task or evidence of unbounded self-improvement. Harness-Bench · VeRO
Held-out change, regressions, cross-model or cross-task transfer
Keep final test data out of the optimization loop
This table turns "the harness is good" into claims that can fail. A higher pass rate may come from hidden retries, greater concurrency, or an unequal token budget; omitting those makes the result unhelpful for engineering decisions.
10.5 When a Harness Tries to Improve Itself
Harness optimization can be useful: a system analyzes failed traces, proposes a small context, tool, or control-flow edit, tests it on frozen evaluation, then retains or reverts the version. It is still not automatically RSI. A stronger claim would require the modified harness to make later improvement processes reliably better on tasks that did not select it, while authority and evaluation remain outside the candidate's control.
The minimum acceptable loop is:
A human or external policy freezes editable surface, budget, evaluator, and rollback rule.
The agent proposes a narrow edit from failure lineage and declares expected gain and regression risk.
An independent runner executes capability and regression splits under the same budget and records evidence.
An external acceptance gate merges, rejects, or reverts; the candidate harness has no write access to that gate.
This matches the boundary in the RSI note: improving one workflow is valuable, but one local gain does not establish that the system improved "the improver."
10.6 A Workshop Agenda That Can Be Discussed Publicly
The following is a research agenda, not an announced event, CFP, or sponsorship notice.
Interfaces and environments. Tool protocols, browser and computer actions, sandboxing, portability, and deterministic verification.
Memory and long-horizon execution. Context lifecycles, artifact stores, checkpoints, recovery, durable jobs, and replay.
Optimization and evaluation. Workflow search, multi-agent scheduling, harness evolution, trace analysis, evaluator integrity, cost, and negative results.
A systems paper that claims a harness improvement should at minimum provide a versioned harness/environment manifest, task and evaluator versions, a budget ledger, trace/redaction plan, same-budget baseline, critical ablation, threat model, and failure analysis. These requirements do not guarantee correctness, but they expose a paper's load-bearing dependencies to readers.
10.7 Five Falsifiable Research Questions
Hypothesis
Minimum experiment
Falsifier
Structured external handoffs are more reliable than context compaction alone
Hold model, task, budget, and environment state fixed; compare recovery paths
No held-out completion or recovery gain, or greater cost
Narrow task-shaped tools beat a broad API mirror
Compare success, invalid calls, and tokens under equal authority
Broad tools match results without reliability or cost penalty
Parallelism helps only independent branches
Fix total tokens and worker-time; compare orchestrations
No speed or quality gain, or merge regressions erase it
An external acceptance gate reduces regressions in self-edits
Freeze evaluator/policy; compare versioned and unconstrained edits
Accepted edits regress no less, or the manifest has no predictive value
Process signals improve recovery rather than get gamed
Compare process metrics against independent held-out terminal states
Process score rises without better outcome or safety
These questions join AutoResearch, Agentic RL (Section 11), Agent Research Environments, and Agent Planning: all require separate boundaries for what can change, what feedback is observed, and what finally counts as evidence; the planning guide further separates plan, replanning, refusal, and terminal acceptance.
Section 10 treated the harness as something to design and hold accountable; this section turns to training. Conventional RL often imagines a tidy API: observations arrive, actions leave, and rewards return. Real coding agents do not run that way. They have tool protocols, context compression, subagents, terminals, retries, and stopping rules. For agentic RL, this agent harness is not disposable packaging. It is part of the condition under which the policy actually executes.
Central claim: if training changes the behavior of the test-time harness, it is not training the policy that will run at deployment. Polar is valuable because it moves the rollout integration point to the model API boundary while leaving the native harness as intact as possible.
11.1 Why Forcing an Agent into an Ordinary Environment API Loses Information
A mature harness defines how system prompts are assembled, how tools return observations, when context is compressed, how subagents run concurrently, how files persist, and when execution stops. Rewriting it as an environment owned by a training framework can alter those behaviors or lose tokens, log-probabilities, branches, and tool context.
This is the problem addressed by Polar. It is neither a new PPO / GRPO objective nor a benchmark. It is an asynchronous rollout system: the native harness points model requests to a gateway, the gateway forwards and records the interactions, and training trajectories are reconstructed from the real execution.
The harness stays native. The paper supports several provider-shaped model APIs and captures prompts, sampled tokens, token IDs, and log-probabilities at the proxy.
A trajectory is not a pretty transcript. Strict prefix continuations may be merged. Subagents, parallel branches, and context rewrites should remain separate chains rather than be forced into one linear conversation.
Evaluation stays separate. Tests, session completion, or other evaluators generate outcome or process rewards after rollout; the trainer need not own the harness.
Four layers should be recorded independently: runtime isolation, harness launch configuration, model traffic and trajectory reconstruction, and verification plus reward. Otherwise a score change cannot be attributed to the model, harness, environment, or grader.
11.3 What the Paper Actually Shows
In the paper's specified setup, the authors start from the same Qwen3.5-4B base, use standard GRPO and 293 SWE-Gym training tasks, and report the following absolute pass@1 changes on SWE-Bench Verified across four coding harnesses:
Harness
Reported start → post-training
Absolute change
Codex
3.8% → 26.4%
+22.6
Claude Code
29.8% → 34.6%
+4.8
Qwen Code
34.6% → 35.2%
+0.6
Pi
34.2% → 40.4%
+6.2
The authors also report that prefix_merging reduced trainer-side updates from 1,185 to 218 and shortened wall-clock time in one reconstruction ablation. This is evidence about the paper's design and stated experimental setting, not a law that every harness will receive equal gains.
11.4 Reward Attribution Is the Dangerous Part
The final patch of a long-running agent may pass a verifier, but that does not make every model call equally responsible. Polar explicitly finds that mechanically broadcasting a session outcome reward to every request-level trace creates a substantial reward-hacking risk.
A credible agentic RL environment should therefore disclose:
whether reward is assigned to the final artifact, a submission, a step, or the full session;
how reward maps onto token-level loss masks;
whether tool failures, retries, subagent branches, and context compression remain in the trajectory;
where the verifier runs and whether the agent can contaminate it; and
whether training, validation, and deployment use the same harness version.
A Reward Signal Cannot Substitute for Outcome Fields
Reward Hacking Benchmark (RHB) places shortcuts such as skipped verification, task-adjacent metadata leakage, and evaluation-relevant tampering in multi-step tool tasks, and separates independent from chained regimes. Hack-Verifiable Environments instead embeds detectable vulnerability opportunities directly in an environment. Together they support treating exploitation as a rollout outcome rather than an after-the-fact guess. Both are scoped to their stated tasks and attack surfaces; RHB's model, post-training, and hardening comparisons are not a general ranking of PPO, GRPO, SFT+RL, or a guard.
Field to report separately
Minimum meaning in agentic RL
It cannot substitute for
proxy_reward
The process or terminal signal actually consumed by optimization, group comparison, or credit assignment
User-goal completion or safety
verified_outcome
Final state confirmed by a non-agent-writable independent postcondition or sidecar
Reward, click, tool success, or judge preference
exploit_outcome
A detected shortcut, evaluator/evidence tampering, leakage, or weak-verifier exploit
Safety against unknown attacks
hardening_delta
The change in exploit, legitimate pass, and false-block rates before/after hardening at the same task, policy, action surface, budget, and attack protocol
A claim that reward is safe or loopholes are gone
Hardening Agent Benchmarks with Adversarial Hacker-Fixer Loops adds a necessary check: after patching a verifier, legitimate solutions still need to pass, and unseen exploits should be attacked again. Its terminal-benchmark results are likewise evidence under a stated process, not a safety proof for every agentic-RL environment.
Evidence boundary: "Any harness" means a harness that can be redirected at a model API boundary supported by the proxy. The main evidence covers software engineering, one 4B base model, four coding harnesses, and a specified training set. It does not directly establish training gains for browser or GUI environments.
11.5 Sources Answer Different Questions
Agentic RL can easily compress "it runs RL," "it has trajectories," "it has a verifier," and "training transfers" into one sentence. The following sources matter, but their evidence scopes differ:
Multi-step exploits can be separate outcomes; hardening must also check legitimate passes and false blocks
A lower exploit rate proves an arbitrary reward, verifier, or optimizer safe
The map blocks two common misreadings. First, GUI trajectory data and online RL rollouts are not the same object: the former can support SFT, offline filtering, or training-data research; the latter also needs a behavior policy, reward, attribution, and update rule. Second, possessing a verifier does not mean that it is isolated from the agent. Harbor distinguishes shared from separate verifiers; the task author still has to declare visible artifacts, network, and authority boundaries.
11.6 How This Connects to Environment Design
The benchmark, harness, and sandbox layers in the environment post still apply to agentic RL. A fourth layer must be added: the trajectory and training interface. Evaluation decides what completion means. The harness determines how the policy acts. The sandbox determines visible state and permissions. The training interface determines which behavior receives credit, optimization, and replay.
That is why rerunning the same model with another harness is not an incidental engineering detail. Prompts, tool availability, stopping policy, context policy, and evaluation can all change the rollout distribution. A training result should name those conditions rather than present a final score as an environment-free model property.
11.7 PPO, GRPO, and SFT+RL: Align the Rollout Ledger Before Comparing Update Rules
An algorithm label is not an experimental condition. Even if two runs both say "GRPO," they are not an interpretable comparison when the base checkpoint, harness, reset, tool authority, rollout stopping policy, reward, effective tokens, or evaluation selection differ. For long-running agents, those differences can be larger than the optimizer label.
The recent Single-Rollout Asynchronous Optimization (SAO) makes the issue concrete. It argues that GRPO's group-wise sampling does not naturally fit asynchronous agent rollouts, and reports results for a single-rollout asynchronous update in its coding and reasoning settings. That is a systems hypothesis worth testing, not a universal ranking of PPO, GRPO, or any harness. SAO is a preprint submitted on 2026-07-08; a comparison should disclose how groups are formed, behavior-policy lag, which rollouts actually enter an update, and resource use.
Shared ledger field
Additional PPO disclosure
Additional GRPO disclosure
Additional SFT+RL disclosure
Same tasks, initial states, harness, system prompt, tools and authority, sandbox/verifier version, action surface, and split
Policy/reference/value/reward model versions; KL, advantage, clipping, and value configuration
Group size K; grouping rule for prompt/state; valid-group count; all-equal-reward rate; invalid or discarded-completion rule
SFT data and its provenance/split; SFT token/step budget; how the SFT checkpoint was selected; RL budget used after that checkpoint
behavior_checkpoint, rollout termination/retry/cancel policy, policy lag, effective rollout tokens, tool calls, resets, wall time, and external cost
Rollouts consumed per update and update schedule
Whether a group uses a consistent policy snapshot; how asynchronous arrivals affect groups and updates
Whether SFT and RL share data, validation sets, prompts, or selection signals
proxy_reward, verified_outcome, exploit_outcome, hardening_delta, integrity, recovery, and cost, plus reward-to-loss mapping and verifier hash
Gap between value/reward signals and final independent evaluator
Group reward, normalization/advantage rule, and reward degeneracy
Whether SFT-only, RL-only, and SFT+RL use the exact same independent final suite
Freeze the minimum information in three manifests so a result can be reviewed rather than reduced to a training curve:
This is not ceremonial extra metadata. The current TRL GRPO documentation exposes a stateful environment_factory, reset, environment-owned reward, and a tool loop, and requires a prefix-preserving chat template for that loop. Those are concrete system conditions. Likewise, the TRL PPO interface names a policy, reference, reward, and value model. A framework exposes an interface; it does not automatically make an environment realistic, a reward safe, or transfer held out.
A falsifiable comparison can proceed as follows:
Freeze the RolloutManifest and train/validation/final split, and state which algorithm layer alone may change.
With the same base, harness, action surface, reward/verifier, and total token/rollout/reset/wall-clock budget, construct baseline, SFT-only, PPO, GRPO, or SFT+RL conditions. When resources are tight, compare fewer conditions rather than silently changing budgets.
Beyond mean reward, report the task/workflow distribution, failure branches, effective-rollout rate, GRPO group health, policy lag, verified_outcome, exploit_outcome, hardening's legitimate-pass/false-block behavior, and cost per verified success.
Run DeploymentAcceptance on a final suite that did not select checkpoints, prompts, harnesses, or hyperparameters. Rising training reward or a pass rate in the training environment cannot substitute for it.
Research wording: "PPO may outperform GRPO" or "PPO is better for ClawBench V2" is presently a hypothesis to test. Only results with a shared rollout ledger, independent acceptance, and task-distribution breakdown earn the status of a conditional conclusion.
11.8 A Checklist for Personal Experiments
Fix and record harness, model endpoint, system prompt, tool versions, sandbox image, and verifier hash.
Save replayable token-aligned trajectories, not only natural-language transcripts.
Separate proxy_reward, verified_outcome, exploit_outcome, and hardening_delta; training reward cannot substitute for an independent terminal or exploit report.
Evaluate on at least one task distribution that was not selected or tuned against, so harness adaptation is not reported as general ability.
For PPO, GRPO, and SFT+RL, publish a shared rollout, optimization, and acceptance manifest first; name groups, policy lag, checkpoint selection, and every budget.
Label each piece of evidence as a native rollout, offline trajectory, task/verifier contract, or algorithm objective; do not transfer a conclusion across those categories by default.
Section 11 covered how rollouts are collected from a native harness; this section turns to the objectives that consume them. It focuses on three central algorithms: PPO as the classic online RLHF workhorse, DPO as a common offline preference optimization method, and GRPO as a critic-free RL method often used in reasoning-model training. Many variants deserve their own post; this section sticks to the core ideas.
One sentence: PPO and GRPO are both policy-gradient-style online RL methods: the model samples answers first, then updates generation probabilities using rewards. DPO rewrites the KL-regularized RLHF objective into an offline preference-classification loss. All three use KL, a reference model, or clipping to limit policy drift.
12.0 Memorize This Table First
Algorithm
Short description
Where the data comes from
Online rollout?
Needs a critic?
Best fit
PPO
Classic RLHF
reward model / rule reward / judge
Yes
Usually yes
General alignment when a reward model already exists
DPO
Preference alignment
chosen / rejected pair
No
No
Instruction style, preference data, stable and simple tuning
GRPO
Reasoning RL
reward group from multiple samples for the same prompt
Yes
No
Math, code, and reasoning with verifiable rewards
Mnemonic:
PPO = online sampling + reward model/function + critic baseline + KL/clip
DPO = offline preference pairs + reference model + classification-style loss
GRPO = online multi-sampling per prompt + group-relative reward + no critic
12.1 Shared Foundation: Policy Gradient
An LLM can be viewed as a policy:
pi_theta(y | x)
Given a prompt x, the model generates an answer y. The RL objective is to maximize expected reward:
maximize_theta E_{x ~ D, y ~ pi_theta(. | x)}[R(x, y)]
The simplest update direction is:
grad J(theta) ~= A(x, y) * grad log pi_theta(y | x)
Intuition:
If an answer is better than the baseline, increase its generation probability.
If an answer is worse than the baseline, decrease its generation probability.
Real training must reduce variance, control KL drift, and handle long sequences, which is why more stable objectives such as PPO and GRPO are used.
12.2 PPO: Classic RLHF
The standard PPO-based RLHF pipeline is:
SFT model
-> train reward model from preference data
-> online rollout with current policy
-> PPO update policy under KL constraint
Here pi_old is the old policy that produced the rollout samples. During the PPO update, the importance ratio compares the current policy with the policy used at sampling time. The reason for clip is simple: if the new policy changes too much relative to the old policy, PPO truncates the update to avoid destabilizing training in a single gradient step.
The PPO Workflow
Suppose the prompt is:
Write a Python function that checks whether a bracket string is valid.
The current policy samples this answer:
Scan the string with a stack; push left brackets, and when a right bracket appears, check whether it matches the stack top.
Training then goes through these steps:
Step
What happens
What the quantity is used for
1. rollout
The current policy actually generates an answer
Produces a token trajectory
2. reward
The reward model / unit test / judge scores the answer, for example 0.86
Tells the model whether this answer is good
3. KL penalty
If the new model is too far from the reference, subtract a penalty, for example 0.06
Prevents reward optimization from damaging language ability
4. critic
The value model predicts the expected future score for each prefix
Provides a baseline and reduces variance
5. advantage
actual return - critic prediction
Decides whether this generation was better or worse than expected
This means the generation was better than the critic expected, so PPO increases the probability of the relevant tokens in that answer. But if a token probability changes too aggressively:
ratio = pi_theta(token) / pi_old(token) = 1.35
clip range = [0.8, 1.2]
the surrogate objective for that sample is clipped to 1.2 * advantage, so it no longer encourages the ratio to grow further. The intuition is:
Move toward higher reward, but do not take too large a step at once.
the corresponding token probabilities are pushed down. PPO is not just asking "what is the reward?" It is asking:
Was this generation better than the critic expected?
Did the new policy change too much relative to the old policy?
Is the new policy too far from the reference model?
PPO strengths:
It is online RL and can directly optimize a reward signal.
It is suitable for general RLHF when the reward model is reasonably reliable.
With a critic and clipping, it is more stable than raw REINFORCE.
PPO weaknesses:
It is engineering-heavy: policy / reference / reward / critic models must work together.
Unstable critic training directly corrupts the advantage estimates.
It is sensitive to hyperparameters, KL coefficients, and reward scale.
12.3 DPO: Preference Optimization, Not Traditional Online RL
DPO directly consumes preference pairs:
prompt x
chosen answer y_w > rejected answer y_l
It does not require training an explicit reward model first, and it does not need online rollout. The core idea is to make the model prefer the chosen answer over the rejected answer relative to a reference model:
log pi_theta(y_w | x) - log pi_ref(y_w | x)
should be larger than
log pi_theta(y_l | x) - log pi_ref(y_l | x)
where log_ratio(y)=log pi_theta(y|x)-log pi_ref(y|x), and beta controls preference strength and conservatism relative to the reference. The reference model is still crucial: it is not a critic; it is the behavioral anchor that limits how far the model moves away from the original policy.
Technically, DPO is best described as an offline preference optimization method derived from KL-regularized RLHF. It uses the closed-form relationship between an optimal KL-regularized policy and its implicit reward to avoid training a separate reward model and running online RL.
How DPO Works
DPO does not let the model learn by online trial and error. It trains directly on preference data. For example:
Prompt:
Explain the difference between a reward model and a critic.
Chosen:
A reward model is a judge that scores a complete answer; a critic is a predictor that estimates how much future reward the current state can obtain.
Rejected:
A reward model and a critic both score the model; there is not much difference.
DPO asks whether the current model, relative to the reference model, prefers the chosen answer.
for the same prompt, the chosen answer should improve relative to the reference more than the rejected answer
In practice, implementations usually sum or average token log probabilities across the whole answer. Answer length, truncation, and tokenizer behavior all affect the values, so chosen / rejected samples should be comparable under the same prompt.
DPO's main advantage is engineering simplicity: no rollout, no explicit / separate online reward-model scoring, and no critic. Its limitation comes from the same place: the model learns only from existing preference pairs and does not actively explore new, better answers.
DPO strengths:
Simple and stable; no online RL environment is required.
No separate reward model or critic is needed.
Very convenient when chosen / rejected preference pairs already exist.
DPO weaknesses:
It does not actively explore new answers; it learns from offline preference data.
For math and code tasks with verifiable outcomes, direct online RLVR is often stronger.
If preference coverage is poor, the model may learn style more than capability.
12.4 GRPO: Critic-Free RL Often Used for Reasoning Models
The core idea of GRPO is to sample multiple answers for the same prompt and compare them within the group.
Prompt x
├── answer A -> reward 0.9
├── answer B -> reward 0.7
├── answer C -> reward 0.2
└── answer D -> reward 0.0
Use the group mean as the baseline and the group standard deviation for normalization:
increase the token probabilities for A / C
decrease the token probabilities for B / D
There is no separate value model. The baseline comes from the group mean for the same prompt; the standard deviation only rescales the advantage. In other words:
PPO asks the critic: roughly how much future reward is this prefix worth?
GRPO asks the group: is this answer better or worse than the other answers for the same problem?
GRPO still usually keeps PPO-like ratio / KL control so the model does not over-optimize reward and drift too far from the reference policy. It is especially suitable for math, code, multiple-choice, and format-verifiable tasks because rewards can be computed automatically:
math: whether the final answer is correct
code: whether unit tests pass
tool use: whether the task is completed and the evidence satisfies the requirement
GRPO is especially natural for RLVR, or reinforcement learning with verifiable rewards:
Math: the final answer can be checked.
Code: unit tests can verify behavior.
STEM / reasoning: a rule-based verifier or judge can be used; if using an LLM-as-judge, watch for judge bias and reward hacking.
GRPO strengths:
No critic training, so memory and engineering complexity are lower.
Multiple samples for the same prompt naturally provide relative comparison signals.
DeepSeekMath introduced GRPO; DeepSeek-R1-Zero used GRPO-style large-scale RL; DeepSeek-R1 then added cold-start SFT, rejection sampling / SFT, and additional RL stages, so R1 should not be simplified to "only GRPO."
GRPO weaknesses:
It still requires online rollout, so sampling cost is high.
Rewards should preferably be verifiable; purely subjective preference tasks are not always a good fit.
Group size, reward normalization, and KL control all affect stability.
12.5 Do Not Confuse Reward Model and Critic
Item
Reward model / reward function
Critic / value model
One-liner
Judge
Predictor
Output
How good this answer is
How much future reward this state is expected to get
Direct policy reward signal?
Yes, the policy tries to increase reward
Not directly a reward; the critic fits value / return and is used to compute advantage
You only have chosen/rejected preference pairs and want fast, stable alignment
DPO
You have a reliable reward model and want classic RLHF
PPO
Math / code / reasoning, and rewards can be automatically verified
GRPO
Training resources are limited and you do not want to maintain a critic
DPO or GRPO
You want the model to explore better reasoning through online rollout, and reward can be reliably verified
GRPO
You want to maximize a general reward, and the reward model is mature
PPO
The most practical interview answer:
PPO is the traditional RLHF workhorse: complete but heavy. DPO is the preference-alignment workhorse: offline, simple, and stable. GRPO is a reasoning-RL workhorse: it replaces the critic with group-relative reward and is well suited to verifiable math/code-style tasks.
12.7 Common Questions
Is DPO RL?
In a broad sense, it is derived from an RLHF objective. In the narrower, traditional sense, it is not online RL: there is no rollout, no environment interaction, and no critic. It is more accurate to call it offline preference optimization.
Why Does GRPO Not Need a Critic?
Because it samples multiple answers for the same prompt, uses the group reward mean as the baseline, and uses the group standard deviation to normalize advantage. The critic's role is to provide a baseline; GRPO replaces it with a group baseline.
What Is the Biggest Difference Between PPO and GRPO?
PPO usually trains a value model / critic to estimate advantage. GRPO estimates advantage from relative rewards among multiple samples for the same prompt. PPO is more general; GRPO is cheaper and more direct for verifiable reasoning tasks.
What Do All Three Share?
All three control how much the new model's probabilities change relative to an old policy or reference model. PPO uses ratio clipping and KL, DPO uses a reference-relative preference loss, and GRPO usually keeps KL or ratio clipping as well.
12.8 Final Cheat Sheet
PPO:
online RLHF, reward model/function + critic + KL/clip
strongest general RLHF baseline, but expensive and sensitive
DPO:
offline preference optimization, chosen/rejected pair
no rollout, no explicit reward model, no critic
simple, stable, good for alignment
GRPO:
online critic-free RL, group-relative advantage
no value model, good for verifiable reasoning rewards
common in modern verifiable reasoning RL
An orthogonal implementation reference, kept separate from the harness / RL argument above: a two-hour Classic Hot 100 pattern map plus from-scratch, explainable PyTorch multi-head attention and 1D / 2D convolution templates.
Apr 2026 snapshot · Classic Hot 100 · PyTorch from scratch
本节用于面试前两小时复习,不是完整题解集。这里的 Hot 100 是 Apr 2026 的 classic/interview-prep snapshot,而不是声称同步 LeetCode 当前 live list。目标是快速回忆题型入口、常见模板,以及 multi-head attention、1D convolution、2D convolution 三个高频深度学习手写题。
def backtrack(path, choices):
if is_done(path):
res.append(path.copy())
return
for choice in choices:
if invalid(choice):
continue
path.append(choice)
backtrack(path, next_choices)
path.pop()
import torch
import torch.nn.functional as F
def conv1d_naive(x, weight, bias=None, stride=1, padding=0, dilation=1):
B, Cin, L = x.shape
Cout, Cin_w, K = weight.shape
assert Cin == Cin_w
x = F.pad(x, (padding, padding))
Lpad = x.shape[-1]
Lout = (Lpad - dilation * (K - 1) - 1) // stride + 1
out = x.new_zeros(B, Cout, Lout)
for b in range(B):
for co in range(Cout):
for i in range(Lout):
start = i * stride
total = x.new_tensor(0.0)
for ci in range(Cin):
for k in range(K):
total = total + x[b, ci, start + k * dilation] * weight[co, ci, k]
if bias is not None:
total = total + bias[co]
out[b, co, i] = total
return out
验证:
torch.manual_seed(0)
x = torch.randn(2, 3, 12)
w = torch.randn(4, 3, 5)
b = torch.randn(4)
y = conv1d_naive(x, w, b, stride=2, padding=2)
ref = F.conv1d(x, w, b, stride=2, padding=2)
assert torch.allclose(y, ref, atol=1e-5)
Apr 2026 snapshot · Classic Hot 100 · PyTorch from scratch
This is a two-hour interview-prep notebook, not a full solution manual. The Hot 100 list here is a Classic Hot 100 snapshot for Apr 2026 interview prep, not a claim that it mirrors LeetCode's live list. The goal is to quickly recover each problem's pattern entry point, the template you should reach for, and the shape reasoning behind three common deep-learning implementation prompts: MHA, Conv1D, and Conv2D.
Core rule: Classic Hot 100 practice is not about memorizing problem numbers. It is about recognizing the state, data structure, or transition as soon as you see the prompt. For implementation questions, the bar is not cleverness; it is clear shape accounting, boundary handling, mask semantics, stride, and padding.
A.1 Two-Hour Review Plan
Time
Review
Goal
0-15 min
Arrays, hash maps, prefix sums, two pointers, sliding window
Start with the highest-frequency patterns that usually convert into stable points.
15-35 min
Linked lists, stacks, heaps, binary search
Make the templates feel automatic.
35-60 min
Binary-tree DFS/BFS, BST, LCA
Be explicit about what each recursive call returns.
This table keeps the interview-useful part only: pattern entry point, template, and the one key move. In an interview, state the template first, then handle edge cases.
Problem
Pattern entry point
One-line solution
1 Two Sum
Hash map
As you scan x, check whether target-x was seen; store value to index.
2 Add Two Numbers
Linked-list simulation
Add digit by digit with two pointers and carry; build the result from a dummy node.
3 Longest Substring Without Repeating
Sliding window
Expand right, shrink left when a duplicate appears, update the max length.
4 Median of Two Sorted Arrays
Binary partition
Binary search the cut in the shorter array so both halves have equal size and all left values are <= right values.
5 Longest Palindromic Substring
Center expansion
Try odd and even centers, expand outward, keep the longest interval.
10 Regular Expression Matching
DP
dp[i][j] means s[:i] matches p[:j]; handle * as zero or many copies.
11 Container With Most Water
Two pointers
Squeeze from both ends; move the shorter side because it bounds the area.
15 3Sum
Sort + two pointers
Fix the first value, squeeze the remaining range, and skip duplicates.
17 Letter Combinations
Backtracking
Expand each digit into characters; collect when the path length equals input length.
19 Remove Nth From End
Slow/fast pointers
Start from dummy; move fastn steps first, then walk together to the predecessor.
20 Valid Parentheses
Stack
Push left brackets; each right bracket must match the stack top; finish with an empty stack.
21 Merge Two Sorted Lists
Linked-list merge
Dummy + tail; append the smaller node each time, then append the remainder.
22 Generate Parentheses
Backtracking with pruning
Add ( if left < n; add ) if right < left.
23 Merge k Sorted Lists
Heap / divide and conquer
Pop nodes from a min-heap, or merge lists pairwise.
31 Next Permutation
Suffix handling
Find the rightmost descent, swap with the next larger suffix value, then reverse the suffix.
32 Longest Valid Parentheses
Stack / DP
Store indices and the last invalid position; update length on each match.
33 Search in Rotated Sorted Array
Binary search
Decide which half is sorted, then test whether the target lies in that half.
34 Find First and Last Position
Boundary binary search
Write one lower_bound for the first target and another for the first > target.
39 Combination Sum
Backtracking
Candidates can repeat; pass the current index, collect when the remaining sum is 0.
42 Trapping Rain Water
Two pointers
Maintain left/right maxima; move the smaller side and add trapped water.
46 Permutations
Backtracking
Use a used array so each value is chosen once; collect full-length paths.
48 Rotate Image
In-place matrix
Transpose along the main diagonal, then reverse each row.
49 Group Anagrams
Hash signature
Use sorted string or 26-count vector as the grouping key.
53 Maximum Subarray
Kadane
cur=max(x, cur+x); answer is the max over all cur.
55 Jump Game
Greedy
Track the farthest reachable index; if i > far, return false.
56 Merge Intervals
Sort + merge
Sort by start; if the current interval overlaps the result tail, extend the end.
62 Unique Paths
DP
dp[j] += dp[j-1]; each cell comes from top and left.
64 Minimum Path Sum
DP
In-place or 1D DP; add the smaller of top and left to the current cell.
70 Climbing Stairs
Fibonacci
dp[i]=dp[i-1]+dp[i-2]; roll with two variables.
72 Edit Distance
2D DP
dp[i][j] is prefix distance; take min over insert/delete/replace.
75 Sort Colors
Three pointers
Scan with zero/i/two; swap 0 forward, 2 backward, skip 1.
76 Minimum Window Substring
Sliding window
Expand until requirements are met, shrink while valid, update the shortest window.
78 Subsets
Backtracking / bitmask
Choose or skip each position, or iterate over bitmasks.
79 Word Search
DFS backtracking
Start from matching first-letter cells, search four directions, temporarily mark visited cells.
84 Largest Rectangle in Histogram
Monotonic stack
Keep heights increasing; when a shorter bar arrives, pop and compute area using popped height.
85 Maximal Rectangle
Monotonic stack + row heights
Convert each row into a histogram of consecutive 1s, then reuse problem 84.
94 Binary Tree Inorder Traversal
Stack / DFS
Left-root-right; iterative version pushes all left nodes, pops, then goes right.
96 Unique Binary Search Trees
DP / Catalan
Enumerate root k: dp[n]+=dp[k-1]*dp[n-k].
98 Validate BST
Bounds / inorder
Recurse with (low, high), or require inorder traversal to be strictly increasing.
101 Symmetric Tree
Paired recursion
Compare left.left with right.right, and left.right with right.left.
102 Binary Tree Level Order
BFS
Pop level by level; record current queue length for each layer.
104 Maximum Depth of Binary Tree
DFS
Return 1 + max(left_depth, right_depth).
105 Build Tree from Preorder and Inorder
Recursive build
First preorder value is root; split left/right subtrees by inorder index.
114 Flatten Binary Tree to Linked List
Postorder / preorder rewiring
Flatten left subtree to the right, then attach the original right subtree to the left-chain tail.
121 Best Time to Buy and Sell Stock
One scan
Track historical minimum price; update max profit with current minus min.
124 Binary Tree Maximum Path Sum
DFS
Return one-sided max contribution; update answer with left+root+right.
128 Longest Consecutive Sequence
Hash set
Only start counting from numbers that have no predecessor.
136 Single Number
Bit operation
XOR all numbers; pairs cancel and the singleton remains.
138 Copy List with Random Pointer
Hash / interleaving copy
Map old nodes to new nodes, or insert copied nodes into the original list then split.
139 Word Break
DP + set
dp[i] means prefix can be segmented; enumerate cut j and check s[j:i].
141 Linked List Cycle
Slow/fast pointers
Slow moves one step and fast moves two; meeting means there is a cycle.
142 Linked List Cycle II
Slow/fast pointers
After meeting, move one pointer to head; walk both one step until they meet at cycle entry.
146 LRU Cache
Hash + doubly linked list
Map finds nodes; list maintains recency; evict tail when capacity is full.
148 Sort List
Merge sort
Split by slow/fast pointers, recursively sort, then merge two sorted lists.
152 Maximum Product Subarray
Rolling DP
Track both max and min product because a negative number can swap roles.
155 Min Stack
Helper stack
Main stack stores values; min stack stores current minimum in sync.
160 Intersection of Two Linked Lists
Two pointers switching heads
When A/B reach the end, switch to the other head; equal total path length leads to meeting.
169 Majority Element
Boyer-Moore
Reset candidate when vote is 0; same value increments, different value decrements.
198 House Robber
1D DP
dp=max(skip, rob_prev+x); roll with two variables.
200 Number of Islands
DFS/BFS
Each time land is found, flood-fill the whole island and increment count.
206 Reverse Linked List
Pointer reversal
Iterate with prev, cur; save next before reversing the link.
207 Course Schedule
Toposort / coloring DFS
BFS on indegrees to see if all courses finish, or use three-color DFS cycle detection.
208 Implement Trie
Prefix tree
Each node stores children and is_end; insert/search walks character by character.
215 Kth Largest Element
Heap / quickselect
Keep a size-k min-heap, or partition to find index n-k.
221 Maximal Square
2D DP
If current cell is 1, side length is min(left, up, upper-left) + 1.
226 Invert Binary Tree
DFS
Swap children, then recurse into subtrees.
234 Palindrome Linked List
Slow/fast + reverse
Find middle, reverse second half, compare against the first half.
236 Lowest Common Ancestor
Postorder DFS
If both subtrees hit, current node is LCA; otherwise return the side that hit.
238 Product Except Self
Prefix/suffix products
Scan left products, then scan right products backward; no division needed.
239 Sliding Window Maximum
Monotonic deque
Store indices with decreasing values; drop expired indices as the window moves.
240 Search a 2D Matrix II
Top-right search
Start at top-right; move left if too large, down if too small.
279 Perfect Squares
DP / BFS
dp[i]=min(dp[i-j*j]+1); alternatively BFS over remainders.
283 Move Zeroes
Two pointers
slow points to the next non-zero slot; swap non-zero values forward while scanning.
287 Find the Duplicate Number
Slow/fast pointers
Treat array values as next pointers; Floyd finds the cycle entry.
300 Longest Increasing Subsequence
Greedy + binary search
tails[k] stores the minimum tail for length k+1; binary replace.
301 Remove Invalid Parentheses
BFS / backtracking
BFS by deletion count; the first valid layer is the answer.
309 Best Time to Buy and Sell Stock with Cooldown
State-machine DP
Track hold/sold/rest; after sold, next day can only move to cooldown/rest.
312 Burst Balloons
Interval DP
dp[l][r] is max value for open interval; enumerate the balloon popped last.
322 Coin Change
Complete knapsack
dp[amount]=min(dp[amount], dp[amount-coin]+1).
337 House Robber III
Tree DP
Each node returns two values: rob and not_rob.
338 Counting Bits
Bit DP
bits[i]=bits[i>>1]+(i&1).
347 Top K Frequent Elements
Heap / bucket
Count frequencies, then keep k in a min-heap or bucket by frequency.
394 Decode String
Stack
On [, save current string and repeat count; on ], pop and concatenate.
399 Evaluate Division
Graph DFS / union-find
Variables are nodes, ratios are weighted edges; answer queries by multiplying along a path.
406 Queue Reconstruction by Height
Greedy sort
Sort by height descending and k ascending, then insert each person at index k.
416 Partition Equal Subset Sum
0/1 knapsack
Target is sum/2; update boolean DP in reverse.
437 Path Sum III
Tree prefix sum
DFS maintains prefix counts; add on entry and remove on exit.
438 Find All Anagrams in a String
Sliding window count
Maintain character differences in a fixed-length window; record start when diff is 0.
448 Find All Numbers Disappeared
In-place marking
Use abs(nums[i])-1 as index and negate the corresponding position.
461 Hamming Distance
Bit operation
Count 1s in x ^ y.
494 Target Sum
Knapsack transform
Convert signs into subset sum (sum+target)/2.
538 Convert BST to Greater Tree
Reverse inorder
Traverse right-root-left and accumulate larger values already seen.
543 Diameter of Binary Tree
DFS height
Update diameter with left and right heights at each node; return one-sided height.
560 Subarray Sum Equals K
Prefix sum + hash map
With current prefix cur, add count[cur-k] to the answer.
581 Shortest Unsorted Continuous Subarray
Two scans
Left-to-right max_seen finds the right boundary; right-to-left min_seen finds the left boundary.
617 Merge Two Binary Trees
DFS
If both nodes exist, sum values; otherwise return the non-empty node.
621 Task Scheduler
Greedy formula / heap
Highest frequency decides idle slots: max(len(tasks), (maxFreq-1)*(cool+1)+countMax).
647 Palindromic Substrings
Center expansion
Use every character and gap as a center; expand until unequal.
739 Daily Temperatures
Monotonic stack
Stack stores indices waiting for a warmer day; pop and fill distance when warmer temperature appears.
763 Partition Labels
Greedy
Record each character's last position; cut when scan reaches the current segment's max last.
A.4 Selection Order After Seeing a Prompt
1. Need "contiguous subarray/path sum equals K"? -> prefix sum + hashmap
2. Need "longest/shortest substring"? -> sliding window
3. Sorted / can sort and find pairs or triples? -> two pointers
4. Linked-list delete/merge/reverse? -> dummy + pointer rewrite
5. Tree asks path/height/ancestor? -> DFS return value
6. Matrix connected components? -> BFS/DFS + visited
7. Courses/dependencies/order constraints? -> graph + cycle detection/toposort
8. Optimal value / count / feasibility? -> DP
9. Enumerate all valid answers? -> backtracking
10. Top K / frequency? -> heap / bucket / quickselect
A.5 DP and Backtracking Failure Points
For DP, say these four things before coding:
1. state: what dp[i] / dp[i][j] means
2. transition: which previous states it comes from
3. init: empty string, 0, first row / first column
4. answer: return dp[n] or max(dp)
Backtracking template:
def backtrack(path, choices):
if is_done(path):
res.append(path.copy())
return
for choice in choices:
if invalid(choice):
continue
path.append(choice)
backtrack(path, next_choices)
path.pop()
A.6 From-Scratch MHA
Start with shapes. This is usually more important than the exact syntax:
import torch
import torch.nn.functional as F
def conv1d_naive(x, weight, bias=None, stride=1, padding=0, dilation=1):
B, Cin, L = x.shape
Cout, Cin_w, K = weight.shape
assert Cin == Cin_w
x = F.pad(x, (padding, padding))
Lpad = x.shape[-1]
Lout = (Lpad - dilation * (K - 1) - 1) // stride + 1
out = x.new_zeros(B, Cout, Lout)
for b in range(B):
for co in range(Cout):
for i in range(Lout):
start = i * stride
total = x.new_tensor(0.0)
for ci in range(Cin):
for k in range(K):
total = total + x[b, ci, start + k * dilation] * weight[co, ci, k]
if bias is not None:
total = total + bias[co]
out[b, co, i] = total
return out
Verification:
torch.manual_seed(0)
x = torch.randn(2, 3, 12)
w = torch.randn(4, 3, 5)
b = torch.randn(4)
y = conv1d_naive(x, w, b, stride=2, padding=2)
ref = F.conv1d(x, w, b, stride=2, padding=2)
assert torch.allclose(y, ref, atol=1e-5)
If this post or ClawBench is useful to you, please cite. Click the button for one-click BibTeX copy.
ClawBench
@article{zhang2026clawbench,
title={ClawBench: Can AI Agents Complete Everyday Online Tasks?},
author={Yuxuan Zhang and Yubo Wang and Yipeng Zhu and Penghui Du and Junwen Miao and Xuan Lu and Wendong Xu and Yunzhuo Hao and Songcheng Cai and Xiaochen Wang and Huaisong Zhang and Xian Wu and Yi Lu and Minyi Lei and Kai Zou and Huifeng Yin and Ping Nie and Liang Chen and Dongfu Jiang and Wenhu Chen and Kelsey R. Allen},
year={2026},
eprint={2604.08523},
archivePrefix={arXiv},
primaryClass={cs.CL},
url={https://arxiv.org/abs/2604.08523},
}
This post
@misc{zhang2026harnessblog,
author = {Yuxuan Zhang},
title = {Agent Harness Engineering: A Source-Level Comparison of Coding Agents},
year = {2026},
url = {https://yuxuan.world/blog/harness/}
}
# Agent Harness 工程:六个 Coding Agent 的源码参照对比
作者:Yuxuan Zhang(2026)
URL: https://yuxuan.world/blog/harness/
## 范围
这是一篇双语、交互式的 harness 架构笔记,比较六个开源 coding agent / harness:hermes-agent、claw-code、codex、opencode、openclaw、pi。重点不是“哪个模型更强”,而是这些系统如何组织 loop、tools、skills、sandbox、budget、hooks、session 和 channel。
## 核心框架
文章把 agent 工程拆成五层:Prompt Engineering、Context Engineering、Tools、Skills、Harness Engineering。Harness 是真正的工程主轴:它决定模型如何被调用、工具如何执行、权限如何控制、上下文如何压缩、轨迹如何记录,以及这些轨迹能否用于 RL / agent training。
## 主要结论
1. hermes-agent 最偏 training-first:共享 budget、并行 rollout、Modal VM、压缩与错误分类都服务于可训练轨迹。
2. claw-code 展示 hook-before-permission 的高表达力,但最终执行仍要由权限策略决定。
3. codex 展示 Responses API typed items、跨 turn 加密 reasoning、流式 fallback,以及 OS-level sandbox。
4. opencode 的 client-server 架构、OpenAPI、LSP 和 permission map 适合产品化。
5. openclaw 把多 IM channel、browser sandbox、Tools / Skills 分层组织成 gateway。
6. pi 是 SDK-first 的极简 runtime,适合嵌入产品和扩展。
## 和 ClawBench 的关系
五层都具备只说明理论上可行;实际效果要看真实任务成功率。ClawBench 测的是 live web tasks 的端到端表现,而不是容易取巧的离线 DOM 快照,并用 per-evidence score 给 agent/harness 提供更细的 reward signal。
## 下一步
打开 https://yuxuan.world/blog/harness/ 阅读完整交互文章。它包含六个可逐步播放的流程图,并把关键机制对应到源码文件和部分行号。
# Agent Harness Engineering: A Source-Referenced Comparison of Coding Agents
Author: Yuxuan Zhang (2026)
URL: https://yuxuan.world/blog/harness/
## Scope
A source-referenced comparison of how six open-source coding agents / harnesses actually run:
1. hermes-agent (Python, multi-provider) — ReAct loop with shared IterationBudget (default 90, child 50); delegate_task sub-agents share the parent's budget; Modal cloud VM per RL rollout; trajectory compression preserves head + last 4 turns; deterministic cache IDs; built-in tool registry.
2. claw-code (Rust reimplementation of Claude Code) — strict order PreToolUse hook > Permission > Execute > PostToolUse; hooks fire BEFORE permission so users can allow / ask / deny / defer / rewrite a call; DEFAULT_AUTO_COMPACTION_INPUT_TOKENS_THRESHOLD = 100_000; run_session_health_probe at conversation.rs:297.
3. codex (OpenAI Responses API) — typed output[] array with message / function_call / function_call_output / reasoning items; encrypted reasoning carried across turns via include=reasoning.encrypted_content; streaming fallback cascade (stream -> retry -> create(stream=True) -> synthesize); seatbelt (macOS) / landlock + bubblewrap + seccomp (Linux) OS sandbox; trusted repos commonly use workspace-write with on-request approvals, while read-only is safer for browsing / CI / untrusted directories.
4. opencode (TS server on Bun + Go TUI) — client-server split over HTTP; OpenAPI 3.1 at /doc; mDNS broadcast; build vs plan agents with different permission maps; hidden system agents (compaction / summary / title); LSP as first-class tool; per-tool allow | ask | deny with wildcards.
5. openclaw (TypeScript, multi-channel) — local Gateway daemon routes many IM channels (Slack / Discord / iMessage / Telegram / WhatsApp / Signal / Matrix / Teams / Google Chat / Zalo) plus CLI / iOS / IDE (ACP) into one session; Docker browser sandbox with Chromium + xvfb + noVNC + CDP; core Tools + Skills split = "Tools are what the agent calls; Skills teach when and how".
6. pi (TypeScript library / CLI runtime) — tiny SDK-first agent core; four default tools (read/write/edit/bash); typed provider stream; extension runner for plan/sub-agent/MCP/sandbox behavior; session tree + branch/share workflow; openclaw embeds pi as a runner.
## Conceptual framework (§2 in the post)
Five-layer stack, bottom to top:
- Prompt Engineering — how to phrase input (system prompt, few-shot, CoT)
- Context Engineering — what fits in the window (retrieval, memory, compaction, prompt cache)
- Tools — typed functions the agent can call
- Skills — Markdown (SKILL.md) teaching when/how to use tools — https://github.com/anthropics/skills is the reference repo
- Harness Engineering — loop + sandbox + budget + hook + session + channel (the six systems above are each a harness or harness runtime)
Anthropic officially calls Claude Code an "agentic harness" — which validates this layering.
## Seven design patterns worth adopting (from §8)
1. Shared budget to prevent runaway — hermes's IterationBudget
2. Hook-before-permission for ultimate expressiveness — claw-code
3. Reasoning persisted across turns — codex
4. Agent as a service (client-server split) — opencode
5. Ephemeral injection to preserve prompt cache — hermes
6. Grace call on budget exhaustion — codex-adapter pattern
7. Session forking as first-class primitive — opencode
## hermes-agent and training (§9)
hermes-agent. Rationale: among the compared systems, it is the clearest training-first harness (RL rollouts in parallel, bounded exploration via shared budget, compaction that preserves training signal, cross-provider adapters for ablations, deterministic cache IDs, MCP as signal collector, semantic error classifier for recovery).
## Related benchmark
ClawBench — live browser-task benchmark that grades whether a harness actually works on real everyday online tasks (cookie popups, dynamic JS, multi-step interactions, traceable per-evidence scoring). arXiv:2604.08523, https://claw-bench.com/
## Where to go next
Open https://yuxuan.world/blog/harness/ for the full interactive article with six Mermaid flowcharts you can step through node-by-node, tied to source files and selected line references.