\documentclass[a4paper]{article}

% Basic packages
\usepackage[fontset=fandol]{ctex}
\usepackage{amsmath, amssymb}
\usepackage{graphicx}
\usepackage[margin=2.5cm]{geometry}
\usepackage[most]{tcolorbox}
\usepackage{etoolbox}
\usepackage{listings}
\usepackage[hyphens]{url}
\usepackage{hyperref}
\usepackage{booktabs}
\usepackage{subcaption}
\usepackage{float}
\usepackage{enumitem}
\usepackage{longtable}

% Highlight boxes
\newtcolorbox{knowledgebox}[1]{
    enhanced, colback=blue!5!white, colframe=blue!75!black, colbacktitle=blue!75!black,
    coltitle=white, fonttitle=\bfseries, title=#1, attach boxed title to top left={yshift=-2mm, xshift=2mm},
    boxrule=1pt, sharp corners
}

\newtcolorbox{importantbox}[1]{
    enhanced, colback=yellow!10!white, colframe=yellow!80!black, colbacktitle=yellow!80!black,
    coltitle=black, fonttitle=\bfseries, title=#1, sharp corners
}

\newtcolorbox{warningbox}[1]{
    enhanced, colback=red!5!white, colframe=red!75!black, colbacktitle=red!75!black,
    coltitle=white, fonttitle=\bfseries, title=#1, sharp corners
}

% Listings
\lstset{
    language=bash,
    basicstyle=\ttfamily\small,
    keywordstyle=\color{blue},
    stringstyle=\color{red!60!black},
    commentstyle=\color{green!60!black},
    breaklines=true,
    frame=single,
    numbers=left,
    numberstyle=\tiny\color{gray},
    captionpos=b,
    extendedchars=false
}

% Front-page metadata
\newcommand{\notetitle}{文章笔记：Harness Engineering for Coding Agents}
\newcommand{\noteauthors}{基于 HumanLayer 技术博客整理}
\newcommand{\notedate}{2025}
\newcommand{\videochannel}{HumanLayer}
\newcommand{\videopublishdate}{2025}
\newcommand{\videoduration}{约 25 分钟}
\newcommand{\videourl}{https://www.humanlayer.dev/blog/skill-issue-harness-engineering-for-coding-agents}
\newcommand{\videocoverpath}{}
\newcommand{\repourl}{https://github.com/hqhq1025/ai-course-notes}

% Footer with repo info
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhf{}
\fancyfoot[C]{\thepage}
\fancyfoot[R]{\footnotesize\color{gray}\href{\repourl}{AI Course Notes}}
\renewcommand{\headrulewidth}{0pt}
\renewcommand{\footrulewidth}{0pt}

\begin{document}

\begin{titlepage}
\centering
{\Large 文章笔记\par}
\vspace{1.2cm}
{\huge\bfseries \notetitle\par}
\vspace{0.8cm}
{\large \noteauthors\par}
\vspace{0.3cm}
{\large \notedate\par}
\vspace{1.2cm}

\ifdefempty{\videocoverpath}{
\vspace{4cm}
{\large\itshape ``The model is probably fine. It's just a skill issue.''\par}
\vspace{0.5cm}
{\normalsize --- HumanLayer\par}
\vspace{3cm}
}{
\includegraphics[width=0.82\textwidth,height=0.45\textheight,keepaspectratio]{\videocoverpath}\par
}

\vfill
\begin{tcolorbox}[width=0.9\textwidth, colback=black!2!white, colframe=black!60, sharp corners]
\textbf{文章作者}：\videochannel\par
\textbf{发布日期}：\videopublishdate\par
\textbf{预计阅读时长}：\videoduration\par
\textbf{文章链接}：
\ifdefempty{\videourl}{
未填写
}{
\url{\videourl}
}\par
\textbf{项目主页}：\href{\repourl}{\nolinkurl{\repourl}}\par
\end{tcolorbox}
\end{titlepage}

\tableofcontents
\newpage

%% --- 正文内容开始 --- %%

\section{引言：不是模型的问题，是配置的问题}

HumanLayer 团队在过去一年中目睹了 coding agent 以各种方式失败：忽视指令、未经提示执行危险命令、在最简单的任务上反复打转。每次失败后，本能的反应总是一样的：``我们只需要更好的模型''、``GPT-6 会修好一切''、``等训练数据里有了我用的那个库就好了''。

然而，经过数十个项目、数百次 agent 会话的实践，HumanLayer 反复得出同一个结论：\textbf{这不是模型问题（model problem），而是配置问题（configuration problem）}。

\begin{importantbox}{核心论点}
Coding agent 的质量公式：
$$\text{Coding Agent} = \text{AI Model(s)} + \text{Harness}$$
模型只是其中一半。Harness（运行时环境与配置）决定了模型能力能否被充分发挥。与其祈祷下一代模型拯救一切，不如专注于``如何从当前模型中榨取最大价值''。
\end{importantbox}

是的，模型会越来越聪明，某些现有的失败模式会消失。但正因为模型更聪明了，我们会给它们更大、更难的新问题，而它们将以意想不到的方式继续失败。\textbf{意外的失败模式是非确定性系统的根本问题}。

\begin{knowledgebox}{什么是 Harness？}
Harness 是 coding agent 的``运行时''或``外围设备''：它是模型与环境交互的所有配置点的总和。包括但不限于：skills、MCP servers、sub-agents、memory、AGENTS.md 文件等。你可以把它理解为模型的``装备系统''---模型本身是角色属性，harness 是武器、护甲和工具。
\end{knowledgebox}

\subsection{本章小结}

Coding agent 的表现不仅取决于底层模型的能力，更取决于 harness 的质量。HumanLayer 的核心主张是：当 agent 失败时，先检查 harness，再怀疑模型。


\section{Harness Engineering 与 Context Engineering}

\subsection{Harness Engineering 的定义}

Harness engineering 这个术语由 Viv 提出，其核心思想是：\textbf{每当你发现 agent 犯了一个错误，就花时间工程化一个解决方案，使得 agent 永远不会再犯同样的错误。}（Mitchell Hashimoto 的总结）

\begin{importantbox}{Harness Engineering 的六个核心问题}
\begin{enumerate}[leftmargin=1.5em]
    \item 如何赋予 coding agent 新的能力？
    \item 如何教会它训练数据中没有的代码库知识？
    \item 如何在 system message 中的 ``CRITICAL: always do XYZ'' 之外增加确定性？
    \item 如何让 agent 的行为适配特定代码库？
    \item 如何在``魔法 prompt''之外提高任务成功率？
    \item 如何防止 context window 过快膨胀或被低质量上下文填满？
\end{enumerate}
\end{importantbox}

\subsection{Context Engineering 的超集关系}

HumanLayer 的联合创始人 Dex 在 12-factor agents 中提出了 context engineering 的概念。Context engineering 是 prompt engineering 的超集，涵盖了系统性提高 AI agent 可靠性的各种技术。

Harness engineering 则是 context engineering 的子集，\textbf{主要通过 harness 配置点来精心管理 coding agent 的 context window}。

\begin{knowledgebox}{Viv 的四个定制杠杆}
Viv 关于 harness engineering 的文章将定制杠杆分为四类：
\begin{enumerate}[leftmargin=1.5em]
    \item \textbf{System prompt}：系统级指令
    \item \textbf{Tools / MCPs}：工具与能力扩展
    \item \textbf{Context}：上下文管理
    \item \textbf{Sub-agents}：子代理分工
\end{enumerate}
HumanLayer 额外强调了两个 Viv 未重点讨论的杠杆：\textbf{hooks}（自动化集成与确定性控制流）和 \textbf{skills}（渐进式知识披露）。
\end{knowledgebox}

\subsection{Post-Training 与 Harness 的耦合}

前沿 coding 模型会在其对应 harness 上进行 post-training（例如 Claude 在 Claude Code 上训练，GPT-5 Codex 在 Codex harness 上训练）。这导致了有趣的现象：

\begin{warningbox}{Post-Training 的双刃剑}
模型对其训练 harness 的过度拟合可能适得其反。Terminal Bench 2.0 的数据显示：Opus 4.6 在 Claude Code 中排名第 33，但放到一个 post-training 时未见过的 harness 中，排名升至第 5（上下浮动约 4 名）。这说明 \textbf{默认 harness 不一定是最优 harness}，定制化配置可能释放模型被默认 harness 压制的潜力。
\end{warningbox}

一个典型案例是 OpenCode 项目。Codex 模型与 Codex harness 的 \texttt{apply\_patch} 工具紧密耦合，以至于 OpenCode（一个开源的 Claude Code 替代方案）不得不专门为 GPT/Codex 模型添加 \texttt{apply\_patch} 工具来模拟 Codex harness，而 Claude 和其他模型则继续使用常规的 edit 和 write 工具。

\subsection{本章小结}

Harness engineering 是 context engineering 的子集，通过配置 harness 的各个组件来管理 agent 的 context window。核心理念是：遇到错误就工程化一个永久性修复。即使模型经过了 post-training，默认 harness 也并非不可改进。


\section{CLAUDE.md 与 AGENTS.md：Agent 配置文件}

\subsection{基本概念}

在触碰任何其他 harness 配置点之前，通常值得先定制你的 \texttt{CLAUDE.md} / \texttt{AGENTS.md} 文件。这些是放在仓库根目录的 markdown 文件，harness 会确定性地将其注入 agent 的 system prompt。

\subsection{ETH Zurich 研究的启示}

ETH Zurich 发表了一项研究，测试了 138 个 agentfile 在多个仓库中的效果，结论是大多数 agentfile ``无用甚至有害''。研究的主要发现：

\begin{table}[H]
\centering
\caption{ETH Zurich Agentfile 研究关键发现}
\begin{tabular}{@{}p{5cm}p{8cm}@{}}
\toprule
\textbf{发现} & \textbf{具体数据} \\
\midrule
LLM 生成的文件 & 实际损害表现，且成本增加 20\%+ \\
人工编写的文件 & 仅帮助约 4\% \\
推理 token 消耗 & Agent 多花 14--22\% 的推理 token 处理指令 \\
步骤与工具调用 & 更多步骤、更多工具调用，但分辨率未提升 \\
代码库概览 & 目录列表完全无帮助，agent 自己就能发现仓库结构 \\
\bottomrule
\end{tabular}
\end{table}

\subsection{编写高质量 Agentfile 的原则}

HumanLayer 认为该研究恰好验证了他们之前的建议：

\begin{importantbox}{Agentfile 最佳实践}
\begin{enumerate}[leftmargin=1.5em]
    \item \textbf{避免自动生成}：LLM 生成的 agentfile 效果更差
    \item \textbf{指令越少越好}：不省略必要指令的前提下，尽量精简
    \item \textbf{使用渐进式披露}（Progressive Disclosure）：不要把所有信息都塞进去
    \item \textbf{保持简洁和普适}：内容应普遍适用，避免过多条件规则
    \item \textbf{不要过度引导工具使用}：过度指定``用什么工具''反而导致更差的结果
\end{enumerate}
HumanLayer 自己的 CLAUDE.md 不到 60 行。
\end{importantbox}

\begin{warningbox}{常见误区}
\begin{itemize}[leftmargin=1.5em]
    \item 把代码库概览和目录结构放进 agentfile --- agent 自己会探索
    \item 用 LLM 自动生成 agentfile --- 实际效果为负
    \item 塞入大量条件规则（``如果 X 则 Y，否则 Z''）--- 增加推理负担却不提高成功率
    \item 详细指定每个任务应该使用什么工具 --- 过度约束模型的灵活性
\end{itemize}
\end{warningbox}

\subsection{本章小结}

CLAUDE.md / AGENTS.md 是最基础的 harness 配置点。但``有配置''不等于``好配置''：自动生成的、信息过载的、过度引导的文件反而有害。核心原则是精简、普适、渐进式披露。


\section{MCP Servers：工具扩展}

\subsection{MCP 的角色}

MCP（Model Context Protocol）servers 主要用于将工具（tools）接入 coding agent，扩展其文件 I/O 和 bash 命令之外的能力。MCP 规范还包括 resources、prompts、elicitations 等特性，但这些在 MCP 客户端和 coding agent harness 中通常支持不佳。

当你将 MCP server 接入 coding agent 时，可用工具列表、工具描述和调用参数会被注入 agent 的 system prompt。因此，MCP server 可以通过工具描述来定制 agent 的行为。

\begin{warningbox}{MCP 安全警告}
因为 MCP server 的工具描述会被添加到 coding agent 的 system prompt 中，\textbf{永远不要连接你不信任的 MCP server}。这可能成为 prompt injection 的危险载体。STDIO servers 和其他通过 \texttt{npx} 或 \texttt{uvx} 在客户端运行的 server 也可以在没有 prompt injection 的情况下在你的主机上执行代码。
\end{warningbox}

\subsection{工具过多的危害}

HumanLayer 的亲身经验：接入过多 MCP 工具后，context window 被工具描述填满，agent 更快地进入``笨区''（dumb zone）。

\begin{knowledgebox}{Instruction Budget 概念}
每个 agent 的 context window 有一个隐式的 ``instruction budget''（指令预算）。每一条无关的工具描述都是 agent 必须处理但没有收益的指令。这些无用指令会挤占真正重要的上下文空间。Anthropic 甚至为此发布了实验性的 MCP tool search 功能，在用户连接了过多 MCP 工具时渐进式地向 Claude 披露工具。
\end{knowledgebox}

\textbf{关键建议}：如果你不在主动使用某个提供大量工具的 MCP server，就关掉它。

\subsection{CLI 优于 MCP 的场景}

HumanLayer 发现，当 MCP server 复制了训练数据中已有 CLI 的功能时，直接提示 agent 使用 CLI 效果更好。对于 GitHub、Docker 或大多数数据库，coding agent 可以直接使用对应的 CLI 和 shell 命令。模型在训练时已经见过这些工具，且 CLI 可以与 \texttt{grep}、\texttt{jq} 等工具组合使用，提供额外的上下文效率。

\subsection{实战案例：Linear CLI 替代 MCP}

HumanLayer 曾使用 Linear MCP server，后来发现实际只用到其中一小部分功能。于是他们编写了一个轻量 CLI 来封装 Linear API，提供非常精简的响应，并在 CLAUDE.md 中给出 6 条用法示例。

\begin{lstlisting}[caption={CLAUDE.md 中的 Linear CLI 示例配置},language={}]
## Linear
Use the Linear CLI for:
- fetching issues:    linear get-issue ENG-XXXX
- listing issues:     linear list-issues or linear my-issues
- adding comments:    linear add-comment -i ENG-XXXX "comment"
- adding links:       linear add-link ENG-XXXX "url" -t "title"
- updating status:    linear update-status ENG-XXXX "status name"
- get branch name:    linear get-issue-v2 ENG-XXXX --fields branch
- get ticket images:  linear fetch-images ENG-XXXX
\end{lstlisting}

这种方式节省了数千个 token（原本来自 MCP server 的工具定义），以及更多来自冗长 MCP 响应的 token。

\subsection{本章小结}

MCP servers 是扩展 agent 能力的强大工具，但需要克制使用。工具过多会挤占 context window、增加无效指令负担。当 CLI 已经在训练数据中被充分覆盖时，CLI 是更好的选择。始终以 context efficiency 为优化目标。


\section{Skills：可复用知识的渐进式披露}

\subsection{Skills 的概念}

Skills 最初由 Anthropic 为 Claude Code 引入，现已成为多个 harness（如 Codex、OpenCode）支持的开放标准。每个 skill 是一个目录，包含一个 \texttt{SKILL.md} 文件和可能的附属资源。

\begin{warningbox}{Skills 安全风险}
Skill 注册中心已经被发现分发过数百个恶意 skill。像对待 \texttt{npm install random-package} 一样对待 skill ---阅读你正在安装的内容。ClawHub、skills.sh 等注册中心的 skill 可以在你的机器上执行任意代码。
\end{warningbox}

\subsection{渐进式披露的核心思想}

HumanLayer 早期犯过的错误：把所有指令和工具都塞进 system prompt，结果 agent 越来越差。在 agent 开始工作之前，instruction budget 就已经被消耗殆尽。

\textbf{Skills 通过渐进式披露解决这个问题}：agent 只在决定需要时（或你替它决定时）才获得特定的指令、知识或工具。

\subsection{Skill 的激活机制}

当 skill 被激活时，其目录中的 \texttt{SKILL.md} 文件作为 user message 加载到 agent 的 context window 中。\texttt{SKILL.md} 文件可以告知 agent 该 skill 还捆绑了什么其他资源。

\begin{table}[H]
\centering
\caption{Skill 目录结构示例}
\begin{tabular}{@{}ll@{}}
\toprule
\textbf{文件/目录} & \textbf{用途} \\
\midrule
\texttt{SKILL.md} & 主指令文件，描述 skill 的功能和使用方式 \\
\texttt{response\_template.md} & 响应模板，规范 agent 的输出格式 \\
\texttt{CLIs/linear-cli} & 捆绑的命令行工具 \\
\texttt{CLIs/tunnel-cli} & 捆绑的命令行工具 \\
\bottomrule
\end{tabular}
\end{table}

更高级的渐进式披露：你可以在 skill 中捆绑多个 markdown 文件，每个文件包含不同功能或用途的信息，主 \texttt{SKILL.md} 文件告诉 agent 其他文件是什么以及何时应该读取它们。

\subsection{Skills 与工具分发}

目前无法直接在 skill 中捆绑 MCP server 或自定义 agent 工具。替代方案是将工具编写为可执行文件、CLI、NPM 包或其他可以与 skill 一起分发或在 skill 文件中指示 agent 安装的形式。

例如，与其配置一个 Playwright MCP server，不如提供一个基于 BrowserBase 的 agent browser skill 或 Vercel 的 agent browser CLI 的 web 浏览 skill。

\subsection{本章小结}

Skills 是实现渐进式披露的关键机制---只在需要时加载知识和工具，避免 system prompt 过载。使用时需注意安全风险，避免盲目安装未审核的第三方 skill。


\section{Sub-Agents：上下文隔离的利器}

\subsection{Sub-Agents 的正确用法}

Sub-agents 是一个流行但常被误解的 harness 配置点。HumanLayer 尝试过``前端工程师''sub-agent、``后端工程师''sub-agent、``数据分析师''sub-agent 的模式。\textbf{这不管用。}

\begin{importantbox}{Sub-Agents 的核心价值：Context 隔离}
Sub-agents 真正有效的用法是 \textbf{context control}（上下文控制）。它们提供了一种封装整个 coding agent 会话工作的方式：调度 agent 只看到它写给 sub-agent 的 prompt 和 sub-agent 的最终结果。所有中间的工具调用、工具返回结果或其他消息都不会进入父 agent 的 context window。

将工作拆解为离散任务并委派给 sub-agents，是保持主 agent 线程处于``聪明区''的关键方法。
\end{importantbox}

\subsection{Context Rot：经验证据}

Chroma 的 context rot 研究为 HumanLayer 的实践经验提供了实证支持：\textbf{模型在更长的 context length 下表现更差}。

关键研究发现：
\begin{itemize}[leftmargin=1.5em]
    \item 测试了 18 个模型的 needle-in-a-haystack 任务
    \item 随着 context 长度增加，性能下降---即使在简单任务上
    \item 当问题与上下文中相关信息的语义相似度低时，性能下降更陡峭
    \item 干扰效应在更长的 context window 中会复合叠加
\end{itemize}

在实践中，HumanLayer 观察到：父会话中每一个不相关的中间工具调用、每一个 grep 结果、每一次文件读取，都是潜在的干扰源。

\subsection{为什么``更大的 Context Window''不是答案}

\begin{warningbox}{对``扩大 Context Window''方案的质疑}
当一个实验室提供某模型的 extended-context 版本时，你通常得到的不是一个具有更大``instruction budget''的更大模型，而是\textbf{同一个模型加上一些巧妙的数学技巧}（如 YaRN）来延长模型能处理的序列长度。

回到 needle-in-a-haystack 问题：更大的 context window 并不能让模型更擅长找针---\textbf{它只是让干草堆更大了}。如果你认为需要更长的 context，你可能只是需要\textbf{更好的 context window 隔离}。
\end{warningbox}

Sub-agents 从结构上解决这个问题：每个 sub-agent 获得一个全新的、小型的、高相关性的 context window 和全新的 instruction budget，只有压缩后的结果流回父 agent。这让你可以将多个 context window 串联起来解决一个大问题。

\subsection{Sub-Agent 的典型用例}

\begin{table}[H]
\centering
\caption{Sub-Agent 适用场景}
\begin{tabular}{@{}p{4.5cm}p{8.5cm}@{}}
\toprule
\textbf{用例} & \textbf{说明} \\
\midrule
定位代码定义/实现 & 问题简单但需要大量中间工具调用来搜索 \\
分析代码库模式 & 识别特定类型工作的代码模式 \\
跟踪信息流 & 例如跨服务边界追踪一个请求的流转 \\
代码/文档/Web 研究 & 通用研究任务，结果简洁但过程繁重 \\
\bottomrule
\end{tabular}
\end{table}

Sub-agents 应返回高度压缩的响应，同样遵循渐进式披露原则。例如，HumanLayer 的 sub-agents 在回答问题的同时引用源（文件路径:行号 或 URL），这样父 agent 不会暴露于 sub-agent 使用的所有源，但如果需要更多细节，它有足够的信息去找到相关上下文。

\subsection{Sub-Agents 与成本控制}

Sub-agents 还能帮助控制成本。HumanLayer 对父会话使用昂贵模型（Opus），因为计划和编排等任务需要深度思考；对每个 sub-agent 使用更便宜、更快的模型（如 Sonnet 或 Haiku）。Sub-agents 接收的是更小、更离散的任务，低阶模型即可胜任---不需要在一次代码搜索上消耗 Opus 的 token。

\subsection{自制 Sub-Agent 方案}

\begin{knowledgebox}{当 Harness 不原生支持 Sub-Agents 时}
有些 harness 完全不支持 sub-agents（甚至 Codex 直到最近才添加，且支持仍是实验性的）。

替代方案：编写一个 MCP server，提供一个工具来启动新的 agent 会话。该工具接收父 agent 的 prompt，启动一个新的 coding agent 会话，然后返回 sub-agent 的最终响应给父 agent。

需要注意的陷阱：
\begin{itemize}[leftmargin=1.5em]
    \item 如果 harness 原生支持 sub-agents，这种模式会允许 sub-agents 通过 MCP 再分派 sub-agents，可能导致不可预测的``电话游戏''
    \item 必须非常仔细地编写 sub-agent 的 system prompt，明确指定其角色范围：做什么、不做什么、返回什么信息、如何返回、有哪些工具
    \item 许多 harness 有 MCP 工具调用超时限制，可能需要调高
\end{itemize}
\end{knowledgebox}

\subsection{本章小结}

Sub-agents 的核心价值不是角色分工，而是 context 隔离。它们通过为每个离散任务创建独立的 context window，防止中间噪声在父线程中累积。同时，sub-agents 还提供了成本控制的手段，对不同复杂度的任务使用不同级别的模型。


\section{Hooks：确定性控制流}

\subsection{Hooks 的概念}

Claude Code 有 hooks 的概念：用户定义的命令或脚本，在特定事件发生时和 agent 生命周期的各个阶段自动执行。类似地，OpenCode 有 plugins。其他 coding agent 可能有类似的配置点（遗憾的是，Codex 没有等效功能）。

Hooks 在概念上类似于 git hooks，但更灵活。它们可以用来添加新功能、集成外部服务、自动化常规操作、修改权限和配置默认行为。

\subsection{Hooks 的典型用例}

\begin{table}[H]
\centering
\caption{Hooks 常见用例}
\begin{tabular}{@{}p{3cm}p{10cm}@{}}
\toprule
\textbf{用例类别} & \textbf{具体实现} \\
\midrule
\textbf{通知} & Agent 完成时播放声音；审批待处理过久时提醒 \\
\textbf{审批} & 基于输入值和更灵活的规则自动批准或拒绝工具调用。例如：自动拒绝所有试图运行数据库迁移的 \texttt{Bash()} 调用，并指示 agent 让用户手动执行 \\
\textbf{集成} & Agent 完成时发送 Slack 消息、创建 GitHub PR、设置预览环境 \\
\textbf{验证} & 每次 agent 停止时运行类型检查或构建，将错误反馈给 agent \\
\bottomrule
\end{tabular}
\end{table}

\subsection{实战 Hook 示例}

以下是 HumanLayer 仓库中使用的一个 Stop hook。当 Claude 停止时，它运行 Biome 格式化器和 TypeScript 类型检查。有错误则反馈给 Claude；无错误则静默退出。

\begin{lstlisting}[caption={HumanLayer 的验证 Hook（Stop Hook）},language=bash]
#!/bin/bash
cd "$CLAUDE_PROJECT_DIR"

# prebuild: generate types and build internal SDK
PREBUILD_OUTPUT=$(bun run generate-cache-key \
  && turbo run build --filter=@humanlayer/hld-sdk \
  && bun install 2>&1)
if [ $? -ne 0 ]; then
    echo "prebuild failed:" >&2
    echo "$PREBUILD_OUTPUT" >&2
    exit 2
fi

# biome and typecheck run in parallel
# biome --write exits code 1 if it made changes,
# so run twice: second pass exits 0 if all fixed
OUTPUT=$(bun run --parallel \
  "biome check . --write --unsafe \
   || biome check . --write --unsafe" \
  "turbo run typecheck" 2>&1)
if [ $? -ne 0 ]; then
    echo "$OUTPUT" >&2
    exit 2
fi
\end{lstlisting}

\begin{importantbox}{Hook 设计原则：成功静默，失败详报}
这个 hook 体现了一个关键设计原则：
\begin{itemize}[leftmargin=1.5em]
    \item \textbf{成功时完全静默}---没有任何内容进入 agent 的 context
    \item \textbf{失败时只输出错误}---仅将必要信息反馈给 agent
    \item \texttt{exit 2} 告诉 harness 重新启动 agent，让它在完成之前修复错误
\end{itemize}
这与 back-pressure 的理念一脉相承：让 agent 能够验证自己的工作，而不是把验证留给人类。
\end{importantbox}

\subsection{本章小结}

Hooks 提供了在 agent 生命周期的特定节点注入确定性控制流的能力。最有价值的模式是验证 hook：成功静默、失败时才向 agent 反馈错误信息，迫使 agent 在标记完成之前解决问题。


\section{Back-Pressure：自动验证机制}

\subsection{核心洞察}

HumanLayer 的核心洞察：\textbf{使用 coding agent 成功解决问题的概率，与 agent 验证自身工作的能力强相关。}

他们在构建测试和其他 back-pressure 机制上投入了大量时间，这仍然是投资回报率最高的工作之一。

\subsection{验证机制的类型}

HumanLayer 代码库中的验证机制包括：

\begin{table}[H]
\centering
\caption{Back-Pressure 验证机制}
\begin{tabular}{@{}p{4cm}p{9cm}@{}}
\toprule
\textbf{机制} & \textbf{说明} \\
\midrule
类型检查和构建步骤 & 最好使用强类型语言 \\
单元测试/集成测试 & 验证功能正确性 \\
代码覆盖率报告 & 有一个 Stop hook 在覆盖率下降时提示 agent 增加覆盖率 \\
UI 交互和测试集成 & Playwright、agent-browser 等 \\
\bottomrule
\end{tabular}
\end{table}

\subsection{验证机制的 Context Efficiency}

\begin{warningbox}{验证输出必须精简---血泪教训}
HumanLayer 早期让 agent 在每次改动后运行完整的测试套件，结果 4000 行通过的测试输出淹没了 context window。Agent 随后失去了对实际任务的跟踪，开始对它刚刚读取的测试文件产生幻觉。

现在的做法：\textbf{吞掉成功输出，只呈现错误}。构建也是一样---\textbf{成功是静默的，只有失败才产生详细输出}。

验证机制必须是 context-efficient 的，否则验证本身就成了干扰源。
\end{warningbox}

HumanLayer 在 CLAUDE.md 文件中给 Claude 提供了关于如何使用所有这些验证机制的简洁指令，有些甚至被打包进 skills 中以实现渐进式披露。

\subsection{本章小结}

Back-pressure 是提高 agent 任务成功率的最高杠杆点之一。关键是让 agent 能自我验证，但验证输出必须精简：成功静默，失败详报。否则验证本身会污染 context window，反而降低 agent 的表现。


\section{实践经验：什么有效，什么无效}

\subsection{不要过度优化}

HumanLayer 坦诚承认：完全有可能花在优化 coding agent 配置上的时间比实际用 agent 写代码的时间还多---他们经历过。他们的做法是：\textbf{偏向交付}（bias towards shipping）。只在 harness 配置确实能帮助更快交付更高质量代码的程度上投入时间。

当 agent 失败时，花时间工程化一个解决方案使其不再以同样方式失败---但不会预防性地去寻找问题来解决。

\subsection{无效的做法}

\begin{table}[H]
\centering
\caption{HumanLayer 实践中无效的做法}
\begin{tabular}{@{}p{5cm}p{8cm}@{}}
\toprule
\textbf{做法} & \textbf{问题} \\
\midrule
提前设计理想 harness & 在遇到真实失败之前做的配置往往是错误的 \\
安装大量 skills 和 MCP servers ``以防万一'' & 增加无效指令负担，挤占 context \\
每次会话后运行完整测试套件（5+ 分钟） & 输出淹没 context window \\
微观优化 sub-agents 的工具访问权限 & 导致大量工具来回切换，效果更差 \\
\bottomrule
\end{tabular}
\end{table}

\subsection{有效的做法}

\begin{importantbox}{经过验证的最佳实践}
\begin{enumerate}[leftmargin=1.5em]
    \item \textbf{从简单开始}：只在 agent 实际失败时才添加配置
    \item \textbf{设计-测试-迭代-丢弃}：HumanLayer 丢弃的 hooks 远多于实际使用的
    \item \textbf{仓库级配置分发}：将经过实战检验的配置通过仓库级别的配置文件分发给整个团队
    \item \textbf{优化迭代速度}：不要追求``第一次就对''，而是让每次迭代更快
    \item \textbf{先扩展再收缩}：先给 agent 一整套能力（如 Linear），然后在了解实际需求后精简暴露给模型的内容
\end{enumerate}
\end{importantbox}

\subsection{本章小结}

Harness engineering 的最佳策略是反应式而非预防式：从简单开始，在失败中学习，逐步添加配置。同时要有勇气丢弃不管用的东西。优化迭代速度比追求一步到位更重要。


\section{总结与延伸}

\subsection{核心要点回顾}

这篇 HumanLayer 的文章系统性地论述了 coding agent 性能优化的方法论。核心论点可以浓缩为一句话：\textbf{``The model is probably fine. It's just a skill issue.''}---当你的 coding agent 表现不佳时，问题大概率出在 harness（配置与运行环境），而非模型本身。

文章介绍的六大 harness 配置杠杆可以总结如下：

\begin{table}[H]
\centering
\caption{六大 Harness 配置杠杆总览}
\begin{tabular}{@{}p{3.5cm}p{4cm}p{5.5cm}@{}}
\toprule
\textbf{配置杠杆} & \textbf{核心作用} & \textbf{关键原则} \\
\midrule
CLAUDE.md / AGENTS.md & 基础行为配置 & 精简、普适、避免自动生成 \\
MCP Servers & 能力扩展 & 按需启用、CLI 优先 \\
Skills & 渐进式知识披露 & 按需加载、注意安全 \\
Sub-Agents & Context 隔离 & 用于隔离而非角色分工 \\
Hooks & 确定性控制流 & 成功静默、失败详报 \\
Back-Pressure & 自动验证 & 验证输出必须精简 \\
\bottomrule
\end{tabular}
\end{table}

\subsection{贯穿全文的设计理念}

文章反复强调的几个设计理念值得深思：

\begin{enumerate}[leftmargin=1.5em]
    \item \textbf{Context Efficiency}：所有配置决策的终极评判标准是``这是否让 context window 中的信息更高效？''
    \item \textbf{Progressive Disclosure}：信息按需加载，避免预加载所有可能需要的内容
    \item \textbf{Silent Success, Verbose Failure}：成功不产生输出，失败才详细报告---这是验证机制的设计金律
    \item \textbf{Reactive, Not Proactive}：不要预防性优化，在真实失败中学习和改进
    \item \textbf{Instruction Budget}：将 context window 视为有限预算，每条指令都有机会成本
\end{enumerate}

\subsection{拓展阅读}

\begin{itemize}[leftmargin=1.5em]
    \item HumanLayer 关于 CLAUDE.md 最佳实践的博文
    \item Dex 的 12-factor agents 框架
    \item Viv 关于 harness engineering 的系列文章
    \item ETH Zurich 的 agentfile 有效性研究（138 个 agentfile 的实证分析）
    \item Chroma 的 context rot 研究
    \item Terminal Bench 2.0 benchmark
    \item Matt Pocock 关于 AGENTS.md 的文章
    \item OpenAI 关于 harness engineering 的博文
\end{itemize}

%% --- 正文内容结束 --- %%

\end{document}
