Building AI Coding Agents for the Terminal: Scaffolding, Harness, Context Engineering, and Lessons Learned

Paper: arXiv:2603.05344 Code: opendev-to/opendev Code reference: main @ f1a27b9b (2026-05-26) Metadata note: batch title is Building AI Coding Agents for the Terminal: Scaffolding, Harness, Context Engineering, and Lessons Learned; arXiv/PDF title is Building Effective AI Coding Agents for the Terminal: Scaffolding, Harness, Context Engineering, and Lessons Learned.

1. Motivation (研究动机)

这篇论文关注的不是“让 LLM 会写更多代码”,而是一个更工程化的问题:当 coding agent 从 IDE 插件走向 terminal-native CLI agent 后,系统必须长期持有项目上下文、运行 shell/build/test、调用外部工具、在多轮任务里保持安全边界,并在上下文窗口持续膨胀时仍能可靠执行。作者用 OPENDEV 作为实例,试图把这些实践拆成可复用的 scaffolding、agent harness、context engineering 和 lessons learned。

terminal agent 的特殊难点在于它直接处在开发者真实工作面:source control、build、test、deploy、文件系统和 long-running process 都在同一个 shell 环境中。相比 IDE autocomplete,这类 agent 的失败模式更危险:误执行 destructive command、忘记未完成 todo、被旧 tool output 填满 context、在 planning 阶段越权写文件,或者因为远距离 instruction fade-out 而提前宣布完成。论文把这些问题归结为两个核心约束:安全必须通过架构限制而不是事后提醒来保证context 必须像 CPU/memory 一样被预算化管理

Figure 1 解读:OPENDEV 把工作拆成 session → agent → workflow → LLM 四层。一个 session 可以包含多个 specialized sub-agents;每个 agent 又有 Execution、Thinking、Compaction 等 workflow;每个 workflow 可以绑定不同 LLM。这张图直接解释了论文反复强调的 compound AI system:不是一个模型负责所有环节,而是用系统结构把任务分给不同能力/成本/延迟的模型。

2. Idea (核心思想)

核心思想可以概括为:把 terminal coding agent 做成一套可约束、可降级、可观测的操作系统式 harness,而不是一段 prompt 加一组 tools。OPENDEV 的主要创新不是某个新算法,而是把 planning/execution 分离、per-workflow model routing、lazy tool discovery、adaptive compaction、system reminders、memory pipeline 和 persistence/undo 组合成一套面向长程软件工程的架构。

论文的三条设计原则是 separation of concerns、progressive degradation 和 transparency over magic。separation of concerns 让 model selection、tool dispatch、context management、safety enforcement 可以独立替换;progressive degradation 要求 token budget、iteration budget、network availability 等资源不足时系统仍然优雅退化;transparency over magic 要求 tool call、安全 veto、compaction、memory update 都可观察、可覆盖。

从 code-agent 研究角度看,这篇论文的价值在于它把“agent 能力”从 benchmark score 转到系统工程约束:一个 agent 是否可靠,取决于 ReAct loop 外围是否有足够强的 scaffolding。比如,Plan Mode 的 safety 不是靠模型听话,而是 read-only tool schema;MCP 工具不是一次性把所有 schema 塞进 prompt,而是先暴露 discovery interface;completion 不是信任模型自称 done,而是由 todo/background task/reminder 机制拦截。

3. Method (方法)

3.1 四层系统架构

OPENDEV 的 architecture 被组织成四层:Entry & UI、Agent、Tool & Context、Persistence。用户输入先经过 CLI/Web/TUI entry,再进入 Agent layer 的 harness;Agent 通过 Tool & Context layer 执行 file/shell/web/LSP/MCP/subagent 等能力,同时 context subsystem 负责 prompt composition、memory、tool result optimization、compaction;最后 session、operation log、config、provider/model cache 等进入 Persistence layer。

这个分层的关键是把“LLM 思考”放在一个被包围的核心里。LLM 不是直接访问文件系统或 shell,而是通过 ToolRegistry、approval、permission、hooks、stale-read detection、plan-mode restriction、doom-loop detection、iteration cap 和 cancellation 等边界执行动作。论文称其为 defense-in-depth safety:单层失败不应让危险动作直接穿透到底层 OS。

3.2 Agent harness:把 stateless LLM 变成长程执行器

Agent harness 的中心是 extended ReAct loop,但外围还有七类支撑系统:message injection queue、prompt composition、tool registry、safety system、context engineering、memory/session service、multi-model routing。论文把每轮执行拆成 pre-check/compaction、thinking、self-critique、action、tool execution、post-processing。这样做的目的不是增加仪式感,而是给系统插入可控的检查点:compaction 在调用模型前处理 token pressure,thinking/action 可以绑定不同模型,tool execution 可以做 approval 与 post-processing,completion 可以被 todo/background task 阻断。

Plan Mode 与 Normal Mode 的差别是 schema-level safety:Planning agent 只能看到 read-only tools,写操作不是被 runtime filter 掉,而是根本不存在于它的 tool schema 中。用户批准计划后才进入 Normal Mode 执行。这比“要求模型不要改文件”更强,因为绕过 runtime check 的攻击面被前移到了 schema construction 阶段。

代码核验:crates/opendev-agents/src/react_loop/execution.rsReactLoop::run_inner 每轮 tick proactive reminders、运行 per-turn context collectors、构造 active tool schemas,并把 tool schemas 通过 core/activated 集合延迟发送给 LLM;crates/opendev-agents/src/react_loop/phases/tool_dispatch.rsexecute_sequential 处理 tool approval、permission、execution 和 post-processing,同时对 read-only batch 使用 execute_concurrent_batch 并发执行。

for each user turn:
  state.iteration += 1
  fire due proactive reminders into message list
  collect live context such as todos/git/plan/memory
  apply staged compaction before model call
  active_schemas = core_tools ∪ state.activated_tools
  call thinking/action model
  if tool calls: dispatch through ToolRegistry with approval and post-processing
  if completion: block if todos or background tasks are still incomplete

3.3 Context Engineering:动态 prompt、reminder、compaction 和 memory

Context Engineering layer 包含六个子系统:dynamic system prompt construction、dual-memory/tool result optimization、system reminders、error recovery、adaptive context compaction 和 context retrieval/assembly。论文的基本判断是:long-horizon coding agent 的主要瓶颈不是“模型不会推理”,而是 context window 里的信息分配错误。系统 prompt、tool schemas、历史 observation、file contents、command output、search hits、todo 状态和 memory bullet 都竞争同一个 token budget。

Prompt composition 用 priority-ordered sections 和 condition predicates 只注入当前环境需要的 instructions;provider-specific sections 可以利用模型供应商特性,例如 cache control。论文声称 stable system prompt 通常占总输入的 80—90%,因此对 cached portion 使用 provider prompt caching 可带来约 88% 的 input token cost reduction。代码侧,crates/opendev-agents/src/prompts/composer/mod.rs 实现 section registry、condition evaluation、priority sort 和 two-tier fallback。

System reminders 解决的是 instruction fade-out 和 premature completion。crates/opendev-agents/src/prompts/reminders.rsget_reminder() 从 embedded reminders.md section 中取模板并替换变量;inject_system_message() 把 reminder 包成 user-role <system-reminder>,并用 _msg_class 标记 Directive/Nudge/Internal。crates/opendev-agents/src/react_loop/phases/completion.rs 会在 output truncation、incomplete todos、background tasks 未完成时插入 reminder/nudge 并继续 loop。

Figure 11 的例子很典型:没有 reminder 时,agent 在还有一个 todo 未完成时宣布完成;有 reminder 时,ReactExecutor 在 completion 阶段检测到未完成 todo,把具体剩余项作为最近消息注入,迫使下一轮继续工作。这说明 reminder 不是泛泛的 system prompt,而是在关键事件发生后把局部约束放回模型注意力最近端。

Adaptive Context Compaction (ACC) 用五级阈值管理 observation 生命周期:70% warning,80% mask old tool results,85% prune old tool outputs,90% aggressive masking,99% full LLM-based compaction。crates/opendev-agents/src/react_loop/compaction.rsapply_staged_compaction() 调用 ContextCompactor::check_usage() 决定级别;crates/opendev-context/src/compaction/compactor/stages.rs 负责 mask_old_observations()prune_old_tool_outputs() 和 verbose tool output summarization。

这套设计比“满了再总结”更稳:低压时保留最近 observation;中压时把旧 tool result 替换成 [ref: ...];高压时 prune;只有接近 99% 才调用 LLM summarizer。论文报告 ACC 在 typical 30-turn sessions 中可把 observation peak context consumption 降低约 54%,并常常避免 emergency compaction。

3.4 Tool System、MCP lazy discovery 与并发执行

Tool layer 通过 ToolSchemaBuilder、ToolRegistry、category handlers 和 lifecycle hooks 把 LLM tool call 变成受控操作。file/shell/web/LSP/MCP/subagent 等工具共享 ToolExecutionContext,所以 permission、working directory、cancellation、artifact recording、post-processing 可以跨工具一致生效。代码侧,crates/opendev-tools-core/src/registry/mod.rs 管理 tool registration、aliases、core tools、schema selection;registry/execution.rs 做参数校验、middleware、timeout 和实际 execute()

MCP 的问题是 schema bloat:如果 100 个外部工具、平均每个 schema 200 tokens,仅工具定义就要 20,000 tokens。OPENDEV 的做法是把少量 core tools 常驻,把其他外部工具延迟到 search_tools/ToolSearch 之后再激活。ReactLoop::run_innercore_tool_names()state.activated_tools 共同决定发送给模型的 active schemas;论文和代码注释都把这个设计描述为将输入 tool schema 从约 13k 降到约 6k 的 deferral。

MCP bridge 本身由 crates/opendev-mcp/src/manager/tools.rsget_all_tool_schemas() 枚举 server schemas,再由 crates/opendev-tools-impl/src/mcp_tool.rsMcpBridgeTool::from_schema() 包成统一 BaseTool。因此 MCP tool 在 agent 侧不是特殊通道,而是进入同一个 ToolRegistry/ToolContext 执行框架。

3.5 Paper-to-code mapping 与关键实现锚点

Code reference: main @ f1a27b9b (2026-05-26)

Paper ConceptSource FileKey Class / Function
ReAct harness / iteration loopcrates/opendev-agents/src/react_loop/execution.rs; crates/opendev-agents/src/react_loop/mod.rsReactLoop::run, ReactLoop::run_inner, LoopState
Staged context compactioncrates/opendev-agents/src/react_loop/compaction.rs; crates/opendev-context/src/compaction/compactor/mod.rs; .../stages.rsapply_staged_compaction, ContextCompactor::check_usage, mask_old_observations, prune_old_tool_outputs
Completion guardrails / reminderscrates/opendev-agents/src/react_loop/phases/completion.rs; crates/opendev-agents/src/prompts/reminders.rshandle_completion, get_reminder, append_nudge, inject_system_message
Tool dispatch and parallel read-only callscrates/opendev-agents/src/react_loop/phases/tool_dispatch.rsexecute_sequential, execute_concurrent_batch
Prompt compositioncrates/opendev-agents/src/prompts/composer/mod.rssection registration, condition evaluation, priority ordering
MCP bridge and deferred schemascrates/opendev-mcp/src/manager/tools.rs; crates/opendev-tools-impl/src/mcp_tool.rs; crates/opendev-tools-core/src/registry/mod.rsget_all_tool_schemas, McpBridgeTool::from_schema, get_schemas_for

4. Experimental Setup (实验设置)

这不是一篇以 SWE-bench 或 Terminal-Bench score 为主的实验论文;主线是 production system design + source-backed lessons learned。因此“实验设置”更接近 engineering validation:论文公开 arXiv source、完整 Rust codebase、架构图、appendix tool catalog/config/schema,并把关键 claim 绑定到代码路径和实现常量。本文核验时使用的 paper source 为 /tmp/paper-to-note/.../source_extracted,代码为 /tmp/paper-to-note/.../opendev

评估对象是 OPENDEV 这个 terminal-native coding agent,核心组件包括 CLI/Web/TUI entry、agent harness、ToolRegistry、MCP bridge、LSP/tools、context compactor、prompt composer、reminder scheduler、memory/session persistence 和 operation log/undo。系统目标不是单次 patch accuracy,而是长程任务中的可靠性:是否能在多轮 tool use 后保持 todo 约束、是否能避免 context bloat、是否能用 schema-level restriction 限制 planning、是否能以可配置模型路由适配不同 provider。

可量化的设置主要来自论文中的 engineering measurements 和实现参数:ACC 的压力阈值为 70/80/85/90/99%;tool output 在 typical session 中被观察为占 context 的 70—80%;MCP schema bloat 例子设为 100 tools × 200 tokens = 20,000 tokens;tool schema deferral 的注释和论文说明为约 13k → 6k input tokens;prompt caching 针对 stable prompt portion,论文给出 cached portion 约 88% input token cost reduction。

5. Experimental Results (实验结果)

最重要的结果是架构性而非 benchmark 性:OPENDEV 证明 terminal coding agent 的可靠性来自多层 harness,而不是单个强模型。per-workflow LLM binding 让 thinking/action/compaction 可以独立选模型;schema-level Plan Mode safety 把 write tools 从 planning agent 中完全移除;ToolRegistry 让 permission、approval、hooks、normalization、post-processing 和 artifact recording 统一落在工具边界上。

在 context 方面,论文报告 ACC 将 typical 30-turn sessions 中 observation peak context consumption 降低约 54%,并经常避免 emergency compaction。这个结果的含义是:长程 agent 不应把历史 observation 一次性总结掉,而应先 mask/prune 低价值旧 tool outputs,只在 99% 压力下启用 LLM compaction。结合 API-reported prompt_tokens 校准,系统能避免本地 token estimate 低估 provider-side injected content。

在 tool/schema 方面,lazy discovery 的收益是把 MCP 的 baseline token overhead 接近降为零:只有被搜索命中的外部工具才在后续 LLM call 中携带 full schema。论文给出的直观量级是 100 个 MCP tools × 200 tokens = 20,000 tokens,如果启动即注入会直接吞掉大量 context;而 core+activated schema 策略可把常驻 schema 从约 13k 降到约 6k。

在 behavior steering 方面,system reminders 的经验结论是:长期任务里“最重要的指令”必须在正确事件后重新靠近模型输出位置。completion guardrail 对 incomplete todos、background tasks 和 output truncation 的处理说明,可靠 agent 不能把“模型说 done”视为终止条件,而要由外部 state machine 验证工作状态。

局限性也很明确:论文没有给出标准 benchmark 上的大规模对比表,因此不能直接得出“OPENDEV 比某某 agent 更强”的结论;许多收益是 engineering measurement 或 production lesson,而非 controlled ablation。更适合从这篇论文中迁移的是系统设计模式:schema-level safety、staged context management、deferred tool schemas、event-driven reminders、source-backed persistence/undo,而不是某个单一算法。