问题背景:盲目堆叠 Markdown 🍅
每个 Coding Agent 系统都会攒下一堆 markdown:项目规范、架构笔记、部署手册、任务清单。最省事的接法只要把所有内容拼进 prompt让模型自己看着办就可以。但工程实践里,指令遵循恰恰是从这里开始悄悄劣化的。因为胡乱的拼接影响Agent能力其实是一件很可惜的事情,没有发挥出模型能力最大的价值。
第一种失效是指令竞争。上下文窗口是一块共享且大小固定的资源,每一份注入的文档都在竞价同一份注意力。过时的笔记和当前的指令并排躺在一起,格式一样、抬头类似,模型收不到任何通道层面的信号来判断优先级孰高孰低。当一份半年前的手册写着用 sqlite,而本轮任务的要求正好是milvus时,这个冲突怎么解决,可能要凭几分运气。
第二种失效是位置挤压。长文档不只跟别的指令抢位置,还会挤掉最新的工具执行结果,而那恰恰是 Agent 此刻推理最需要的部分。在有压缩或截断参与的长会话里,一份 2000 行的风格指南足以把上一次测试报错推出有效注意力区域。这带来了一个荒谬的效果:Agent拿到的文本更多了,能落地的指令反而更少了。
所以结论不是少写 markdown,而是一个文件说了什么,远不如它在什么时机、经什么通道进入上下文重要。管好这件事正是 harness 的意义之一。
两种契约:AGENTS.md 与 SKILL.md 🍅
目前 Coding Agent 们的系统殊途同归,都沉淀出同一个模式:把 markdown 空间拆成两份文件。
| 文件 | 用途 | 加载时机 | 作用域 |
AGENTS.md | 工作区规则:Agent 在这个项目里应当如何行事 | 每个 turn 开始前注入 | 跨任务持久生效 |
SKILL.md | 任务工作流:某一类任务的具体步骤与工具预期 | 该类任务被触发时加载 | 仅服务于当前工作流 |
AGENTS.md 装的是无论 Agent 在干什么都必须成立的东西:构建命令、评审规范、绝不可越的边界。这些约束必须在任意长的会话里活下来,所以 harness 每一轮都重新注入,刷新它的位置,而不是任它沉入漫长历史的中段慢慢失效。SKILL.md 装的则是只在特定任务运行时才成立的流程:发布清单在执行发布时毫无疑问是很重要的,但在修 bug 时就是纯粹的噪音。触发时才加载,让它恰好在适用的时刻占住 recency 优势。这样在不适用时,上下文成本为零。
抛开文件名,从架构上看,这样的拆分定义了两层功能:
AGENTS.md → 不变指令层。 项目级约束,配上轮级刷新;这是 harness 用纯文本能立起来的类似底层规则的东西。
SKILL.md → 任务执行层。 按需加载的流程逻辑,生命周期严格绑定在召唤它的那个工作流上。
注入通道决定约束强度 🍅
双文件拆分只是更大设计空间里的一个点。harness 手上有好几种把指令送进模型上下文的机制,同一句话走不同的通道,约束力差很多。把它们摆在一起比较会更明显。
| 注入方式 | 进入上下文的时机 | 持久性 | 约束强度 | 典型失效模式 |
| 固化进系统提示词 | 会话开始,固定不动 | 整个会话 | 最强 | 无法按项目适配;每加一条规则,所有任务永久买单 |
每轮重新注入(AGENTS.md) | 每轮开始前刷新 | 整个会话,无位置衰减 | 强 | 膨胀:每一行每轮都要付费,文件必须压在 ~100 行 |
触发时加载(SKILL.md) | 任务激活时 | 工作流存续期间 | 局部强 | 触发漏判:任务没被识别,流程就根本不会加载 |
| 首条用户消息里一次性倾倒 | 会话开始,仅一次 | 随历史增长而衰减 | 中等,持续退化 | 约束在任务中途悄悄滑出有效注意力,甚至滑出窗口 |
| 会话中途检索注入(RAG 式) | 语义命中时 | 一轮 | 弱 | 被当成可供查阅的参考资料,而非必须服从的指令 |
| 工具结果与文件读取里的内容 | 工具返回时 | 一轮 | 最弱(有意为之) | 模型被训练成不信任数据通道里的文本——这正是防御 prompt 注入的边界 |
从这张表里能看出两条规律。
第一,约束强度跟着信任层级走,不跟措辞走。 模型在训练时就内化了一套权威排序:系统指令 > harness 注入的上下文 > 用户消息 > 工具返回的数据。这套排序本是用来防御对抗性 prompt 注入的——挡住藏在被抓取网页、被读取文件里的私货指令——但它同样会削弱放错了通道的正当指令。同一条规范,写在 Agent 任务中途恰好 Read 到的文件里,就是从数据通道进来的,被打折看待是模型的正确行为;写进 AGENTS.md,就是从指令通道进来的,才谈得上约束力。一个不加区分地倾倒 markdown 的 harness,等于亲手把自家规则降级到爬来的数据那一档。
第二,约束强度与同通道注入的体积成反比。 在任何单一通道内部,权威是被共享这条通道的全部 token 摊薄的。一份每行都承重的 100 行 AGENTS.md,约束力远胜一份把约束埋在背景叙述里的 2000 行文件——注意力先在整个载荷上摊开,然后才轮得到指令遵循。这也是渐进式披露(Progressive Disclosure)不只是省 token 的原因:先亮出高层元数据(skill 的名字加一行描述),确有必要时才加载全文,让每条通道的载荷都足够小,真正注入的内容才留得住它应有的分量。
把指令放进刷新节奏与它的变化速率相匹配的、权威最高的那条通道。 不变量放在每轮都被重申的地方;流程放在恰好触发时才出现的地方;参考资料留在工具调用背后,在那里被当成数据冷处理,本来就是正确的行为。
关键洞察 🍅
在恰当的时刻把恰当的 markdown 文件装进上下文窗口是 harness 层需要聚焦处理的事。小文件改不动模型的任何权重,却能大幅改变任务表现,因为它作用在推理时真正支配 Agent 行为的那个变量上:做决策的那一刻,上下文里装着什么、摆在什么位置、有多大的重要性。
把 markdown 加载当成调度与通道分配问题来经营的 harness,才能得到一个遵守规则的、有序的 Agent。
The Problem: Do Not Blindly Dump Markdown 🍅
Every coding agent system eventually accumulates a pile of markdown: project conventions, architecture notes, deployment runbooks, task checklists. The naive integration is tempting because it is one line of code: concatenate everything into the prompt and let the model sort it out. In practice, this is where instruction-following quietly degrades, and it degrades for structural reasons rather than anything to do with model capability.
The first failure mode is instruction competition. A context window is a shared, fixed-size resource, and every injected document bids for the same attention. Outdated notes sit next to current instructions with identical formatting and identical apparent authority; the model gets no channel-level signal about which one wins. When a six-month-old runbook says “always use the staging database” and this turn’s task says otherwise, the conflict is resolved by luck.
The second is displacement. Long documentation competes not just with other instructions but with the most recent tool results, which are exactly the tokens the agent needs to reason over right now. In a long session, with compaction or truncation in play, a 2,000-line style guide can push the last test failure out of effective attention. The net effect is perverse: the agent receives more text and fewer actionable instructions.
The lesson is not “write less markdown.” The lesson is that what a file says matters less than when, and through which channel, it enters the context, and that managing this is a harness responsibility, not a documentation one.
Two Files, Two Contracts: AGENTS.md and SKILL.md 🍅
Coding agent systems have converged on a pattern that splits this markdown into two files with deliberately different loading contracts.
| File | Purpose | Loading trigger | Scope |
AGENTS.md | Workspace rules: how the agent should behave inside this specific project | Injected before the start of every turn | Persistent across all tasks in the workspace |
SKILL.md | Task workflows: step-by-step procedures and tool expectations for one task type | Loaded when the specific task type is triggered | Dedicated exclusively to the current workflow |
The split is not about content categories. It is about invariance. AGENTS.md holds what must stay true no matter what the agent is doing: build commands, review conventions, lines it must not cross. Because these constraints have to survive arbitrarily long sessions, the harness re-injects the file every turn, refreshing its position instead of letting it sink into the middle of a long history. SKILL.md holds procedures that are only true while a particular task is running: the release checklist matters during a release and is pure noise during a bug fix. Loading it on trigger gives it a recency advantage exactly when it applies, and zero context cost when it doesn’t.
Read as architecture rather than file naming, the split defines two layers:
AGENTS.md is the invariant instruction layer: project-level constraints with turn-level refresh, the closest thing to law a harness can express in prose.
SKILL.md is the task execution layer: procedural logic loaded on demand and scoped to the lifetime of the workflow that summoned it.
Injection Channel Determines Constraint Strength 🍅
The two-file split is one point in a larger design space. A harness has several ways to place an instruction in the model’s context, and the same sentence binds with very different force depending on which one delivers it. Laying them side by side makes the design logic visible.
| Injection method | When it enters context | Persistence | Constraint strength | Characteristic failure mode |
| Baked into the system prompt | Session start, fixed | Entire session | Strongest | Cannot adapt per project; every added rule taxes every task forever |
Per-turn re-injection (AGENTS.md) | Refreshed before each turn | Entire session, no positional decay | Strong | Bloat: each line is paid on every turn, so the file must stay near ~100 lines |
On-trigger load (SKILL.md) | At task activation | Duration of the workflow | Strong, locally | Trigger misses: if the task is not recognized, the procedure never loads at all |
| One-shot dump in the first user message | Session start, once | Decays as history grows | Medium, degrading | Constraints silently fall out of effective attention (or out of the window) mid-task |
| Retrieved chunks (RAG-style) mid-conversation | On semantic match | One turn | Weak | Treated as reference material to consult, not instructions to obey |
| Content inside tool results and file reads | Whenever a tool returns | One turn | Weakest, by design | The model is trained to distrust data-channel text; this is also the prompt-injection defense boundary |
Two regularities fall out of this table.
Constraint strength tracks the trust hierarchy, not the wording. Models are trained on an authority ordering: system instructions outrank harness-injected context, which outranks user messages, which outrank tool-returned data. The ordering exists to defend against adversarial prompt injection (instructions smuggled into a fetched web page, or into a file being read), but the same ordering weakens legitimate instructions placed in a low-authority channel. A convention sitting in a file the agent happens to Read mid-task arrives through the data channel and is correctly discounted; the identical sentence in AGENTS.md arrives through the instruction channel and binds. A harness that dumps markdown indiscriminately is voluntarily downgrading its own rules to the authority of scraped data.
Constraint strength falls as co-injected volume grows. Within a single channel, authority is split among the tokens that share it. A 100-line AGENTS.md where every line is load-bearing constrains harder than a 2,000-line one where the constraints are buried in background prose, because attention is spread across the whole payload before any instruction-following happens. This is why progressive disclosure is more than a token-cost optimization. Exposing lightweight metadata first (a skill’s name and a one-line description) and loading the full content only when it is needed keeps each channel’s payload small enough that what does get injected keeps its force.
The combined design rule: put an instruction in the highest-authority channel whose refresh schedule matches how often the instruction changes. Invariants go where they are re-asserted every turn. Procedures go where they appear exactly when triggered. Reference material stays behind a tool call, where being discounted as data is the correct behavior.
What the Harness Is For 🍅
Loading the right markdown into the context at the right moment is not a workaround or a prompt trick. It is the job the harness layer exists to do. Small files change no model weights, yet they move task performance out of all proportion to their size, because they act on the one variable that actually governs agent behavior at inference time: what occupies the context, at what position, with what authority, at the moment a decision is made. A harness that treats markdown loading as a scheduling and channel-assignment problem gets an agent that follows its rules. A harness that treats it as concatenation gets an agent that has read its rules, once, a long time ago.