harness-engineering-agent
v1.0.1
Published
Minimal OpenCode harness plugin package.
Readme
Harness Engineering Agent
面向复杂项目工程的 OpenCode 自动开发插件,也是 OpenCode 之上的确定性控制平面。
插件通过一个专用 primary harness Agent 和七个内部 Harness Agent 协调完成需求理解、入口编排、规划执行、独立验证、最终验收、失败归因与修复规划。插件全局安装,按项目配置运行,不依赖 Sisyphus、OMO 或 OpenSpec 运行时。
Harness 是确定性的控制平面,内部 Agent 是受约束的概率执行器。primary harness 负责理解意图、选择处理路径、对轻量问题直接兜底,并把复杂任务调度给内部 Agent;只有 Controller 才能推进全局状态,Agent 输出只是结构化建议,不能绕过 Guard Condition。
核心能力
- 选择
harnessAgent 后,使用自然语言发起start、status、resume、pause、cancel、answer、waive、report生命周期操作,或直接提问由主控做轻量兜底与路由。 - primary 会先区分普通对话、实时查询、生命周期操作、轻量工程任务、标准/复杂工程任务和需要澄清的请求;普通对话和实时查询不会创建 Harness Execution,工程任务通过 Controller 进入受控协调链路。
- 普通对话的 passthrough 指令采用条件化策略:要求 primary 先核对会话实际可用的工具;存在网页抓取类工具(如 webfetch)时,对实时数据请求先尝试已知可靠来源(如 wttr.in、中国天气网),无法获取或无法验证时效性时才如实降级,不得在尝试前宣称没有工具,不得编造数据。
- passthrough 指令按 variant 注入:同会话仅首次注入完整指令(default,或存在待恢复任务时 recovery),后续普通对话注入 minimal 短提示(保留 marker 与"不要移交协调"约束);关于 harness/OpenCode 自身能力、工具或协议的元提问始终注入 minimal variant。去重记忆为进程内存态,进程重启后首轮重新注入完整版。
- 插件只在当前消息的
agent === "harness"时触发 Harness 协调。普通 Agent 和普通聊天不会自动拦截。 - OpenCode Session 负责用户消息、工具调用和上下文;Harness Execution(兼容存储名称仍为 Run)只保存工程任务的 Requirement、Task、Evidence、预算、失败和验收状态。
- 自然语言工程请求先进入内部 Intake Session,转换为严格 JSON intent,再由确定性的 RunController 执行对应操作;普通请求不会触发 Intake、Git preflight 或 Run 生命周期。
chat.message采用两阶段非阻塞流程:前台先返回包含真实runId和初始状态的 synthetic 受理结果,协调工作在后台运行;后台完成后再向同一父会话补发 Harness 内部完成消息,供harnessAgent 做最终总结与入口层反馈。- 所有内部 Session 显式绑定到 Harness 自有 agent,并同时保留稳定兼容 ID 与英文显示名映射。
- 8 个 Agent 遵循版本化能力合同(
HARNESS_TOOL_CAPABILITY_VERSION = "1.0.0"),工具权限按角色白名单分配,输出必须符合版本化 JSON Schema。 - Git 基线、脏工作区、外部修改、scope drift、merge conflict 与 verification evidence gap 全部由 Controller 的确定性状态机保护,不能被 Agent 自报绕过。
- 验证命令通过结构化 argv、
shell: false、工作区包含校验、嵌套解释器/包管理器绕过检查和审批元数据约束执行,不接受 Agent 自报"已通过"替代命令证据。 resume会从.harness/runs/<run-id>/的快照与事件恢复上下文,不会重复已完成 Task 或丢失既有 evidence。- 稳定 criterionId 和逐项证据追踪:每个验收项(
criterionId)从需求到 Task 覆盖、TaskReview、RunAcceptance 全程追踪,确保证据链完整。 - 主控结果诚实性:Harness primary 只依据 Controller 和 synthetic result 反馈运行事实,区分 Worker、TaskReview、integration verification 与 RunAcceptance;单个 Task 通过不会被总结为整体完成。
- Planner 契约与状态投影:Planner 使用与 TaskGraphSchema 同源的完整契约;无效图不会进入 Worker,父会话只接收有界状态投影并区分规划失败、等待恢复和后台推进。
- Agent 协议容错与进度事件:内部 Agent 输出统一经过安全 JSON 规范化、角色/版本校验和脱敏错误分类;子 Agent 生命周期通过 synthetic progress result 向父会话报告真实阶段,不会因单个阶段完成而误报整体完成。
- 阶段推进闭环与僵死看护:推进循环仅以终态/停止状态收敛,不因阶段状态未变而提前退出;子 Agent 会话 settle(completed/failed)后若该 Run 无在途推进会自动重踢推进;推进期间按分钟级心跳保活,心跳超时的活跃 Run 由 watchdog 迁移到
paused(可 resume)或failed(重复僵死)。 - 子 Agent 产出投影:planner 在 context 捕获与计划评审两个持久化点写入
run.stage.progress事件,run_status通过agentProgress字段返回最近一条摘要与假设证伪结论。 - escalate 假设标注:
harness_escalate支持可选hypotheses参数承载未经验证的判断;假设随 requirement 持久化,planner 必须逐条核实,证伪结论进入ContextPackage.refutations并可投影到run_status。 - IntentGate 弹性流水线:Nuwa 在 Intake 阶段输出结构化复杂度评估(
complexityAssessment),Controller 根据客观指标校验后决定执行路径(direct/streamlined/full/parallel),简单任务跳过不必要的规划与审查阶段。 - 三层复杂度模型:Run 级、Task 级、动态重评估,支持按复杂度路由到不同模型配置,优化资源使用。
正常主链
需求从自然语言开始,经过结构化、两阶段规划、两阶段审查、执行、验证、Run 级验收,最终生成报告:
用户自然语言
|
v
Harness (primary)
|
v
Nuwa (Intake) ── 结构化 HarnessIntent;start 携带 Requirement + complexityAssessment
|
v
Controller.resolveRoute() ── 先解析治理路径,再按每个 ready frontier 决定调度批次
|
├── direct (trivial) ── 仅用于已验证的单 TaskGraph,复用 Worker/验证/证据闭环
|
├── streamlined (standard) ── Fuxi 单阶段(跳过 ContextPackage)→ Luban → Zhulong TaskReview(跳过 PlanReview)
|
├── full (complex) ── 完整流水线:Fuxi → Zhulong PlanReview → Luban → Zhulong TaskReview → Yinglong
|
└── scheduling=parallel ── 与治理路径正交;每个 ready frontier 独立判断
|
v
最终报告 (final-report.md)IntentGate 弹性流水线
Nuwa 在 Intake 阶段输出结构化复杂度评估(complexityAssessment),包含:
tier: trivial | standard | complexestimatedFileCount: 预估影响文件数estimatedCrossModuleDeps: 预估跨模块依赖数suggestedRoute: direct | streamlined | full | parallelconfidence: high | medium | low
Controller 将 Nuwa 的评估视为建议并进行保守校验;TaskGraph 生成后,再依据真实任务、路径、依赖和工作区事实解析最终治理与调度决策:
estimatedFileCount > 10→ 强制 complexestimatedCrossModuleDeps > 3→ 强制 complexconfidence === "low"→ 强制 complexestimatedFileCount <= 2 && estimatedCrossModuleDeps === 0 && confidence === "high"→ 允许 trivial
执行路径
| 治理路径 | 适用场景 | 跳过阶段 |
|------|----------|----------|
| direct | 已通过 TaskGraph 最低资格检查的 trivial 任务 | 未通过检查时显式降级到 streamlined |
| streamlined | standard 任务(多文件但单模块) | ContextPackage、Zhulong PlanReview |
| full | complex 任务(跨模块、架构变更) | 无 |
调度模式独立为 serial 或 parallel。parallel 不是 full 的下一级;Controller 按当前 ready frontier、路径、依赖和验证资源重新判断,资格不满足时在同一治理路径回退 serial 并记录原因。
自动升级
当低路径失败时,自动升级到更高路径:
direct失败 → 升级到streamlinedstreamlined失败 → 升级到fullfull失败 → 进入失败分析、有限重试或修复链
升级时保留已有 evidence,不重复已完成的工作。
三层复杂度模型
Run 级 Tier
Nuwa 评估 + Controller 校验后确定 resolvedTier(trivial/standard/complex)。
Task 级 Tier
Task 默认继承 Run 的 resolvedTier。Fuxi 可以根据 executionCategory 覆盖:
- 降级不限:complex → trivial
- 升级最多一级:trivial → standard(不能直接到 complex)
动态重评估
每个 Task 完成后,Controller 对比实际 vs 预估复杂度:
deviationRatio > 3.0或 Task 失败 → 升级剩余 Task 到 complexdeviationRatio > 2.0→ 升级剩余 Task 到 standard(如果当前是 trivial)- 所有已完成 Task 的
deviationRatio < 0.3→ 降级剩余 Task(最多一次)
Tier → 模型路由
每个 tier 可配置独立的 provider/model:
complexityTiers:
trivial:
provider: deepseek
model: deepseek-v4-lite
standard:
provider: deepseek
model: deepseek-v4-pro
complex:
provider: openai
model: gpt-5.5模型解析优先级:Task.modelProfile > Task.complexityTier > Run.resolvedTier > executionCategory > 角色级
失败修复链
当验证或验收失败时,进入归因与修复闭环:
失败证据
|
v
Xingtian (Failure Analyzer) ── 可先请求受控只读诊断探针,确认根因后分类
|
v (根因确认且需要修复时)
Jingwei (Repair Worker) ── 基于 rootCauseFingerprint 生成收窄 RepairTask
|
v
Luban (Worker) ── 在受限 allowedPaths 内执行修复
|
v
重新验证 ──> Zhulong(逐 Task TaskReview)──> Yinglong(RunAcceptance)──> 报告或再次归因每个 Task 拥有有限 retry budget。预算耗尽后进入 PAUSED 或 FAILED,不会无限循环。RepairTask 包含 version 字段跟踪修复迭代,rootCauseFingerprint 用于去重。
Agent 总览表
8 个 Agent 均遵循版本化能力合同(HARNESS_TOOL_CAPABILITY_VERSION = "1.0.0"),工具权限按角色白名单分配,输出必须符合版本化 JSON Schema。
| 英文名 | 中文名 | 稳定 ID | Session role | 写权限 | 主要产物 |
|---|---|---|---|---|---|
| Harness | 工程总控 | harness | primary | 无(只读编排) | 用户交互摘要、运行状态展示、入口路由结果 |
| Nuwa | 女娲,需求塑形智能体 | harness-intake | intake | 只读 | HarnessIntent JSON;start Requirement |
| Fuxi | 伏羲,规划编排智能体 | harness-planner | planner | 只读 | ContextPackage → PlanReview(含 TaskGraph) |
| Luban | 鲁班,实现执行智能体 | harness-worker | worker | edit/write/patch/bash | WorkerOutput JSON、代码变更 |
| Zhulong | 烛龙,独立验证智能体 | harness-verifier | verifier | 只读 | PlanReview + 逐 Task TaskReview |
| Yinglong | 应龙,最终验收智能体 | harness-acceptance | acceptance | 只读 | RunAcceptance JSON(Run 级一次性验收) |
| Xingtian | 刑天,失败归因智能体 | harness-failure-analyzer | failure-analyzer | 只读 | FailureAnalyzerOutput JSON(可请求受控诊断探针) |
| Jingwei | 精卫,修复规划智能体 | harness-repair-worker | repair-worker | 只读 | RepairTask(根因确认后生成收窄修复建议) |
只有 Luban 可以 edit/write/patch/bash。其他内部 Agent 全部只读。Jingwei 只生成 Repair Task,不直接修改代码。
Agent 详细说明
Harness(工程总控)
- 稳定 ID:
harness - Session role:primary
- 定位:用户与 Harness 控制平面之间的唯一入口,承担意图解析、轻量兜底与子 Agent 编排。
- 主要职责:识别用户请求属于生命周期操作、普通对话还是工程任务;对轻量问题直接回应;对工程任务选择处理路径并调度 Controller / 子 Agent;在后台协调结束后做入口层总结。
- 输入:用户在 OpenCode 中发送的自然语言请求;内部完成消息(带
<!-- HARNESS_INTERNAL_RESULT -->标记的 synthetic result 是唯一权威完成结果)。 - 输出:面向用户的运行状态、阻塞原因、下一步操作说明,以及本次请求走的是直接回答还是进入协调链路。
- 权限边界:
task/edit/write/patch/bash全部禁用,不直接编辑文件、执行 shell、委派子 Agent 或声明未完成的任务已完成。可以使用宿主注入的只读研究工具(如 codegraph、grep、read)做入口调查,不使用 Harness 插件的原生研究工具。 - 反馈边界:用户可见总结按当前状态、已确认事实、阻塞或风险、下一步组织;
clarification_required表示需要补充业务信息,evidence_gap表示需求明确但证据不足。只有 Controller 判定 Run 完成后,primary 才能报告整体完成。 - 上下游关系:接收用户请求后先做入口判断,再交给 Controller;Controller 完成后再将结果返回给 Harness 做入口层总结。
Nuwa(女娲,需求塑形智能体)
- 稳定 ID:
harness-intake - Session role:
intake - 定位:将自然语言请求整理为结构化生命周期意图。
- 主要职责:识别
start/status/pause/answer/resume/cancel/waive/report/clarification;对于start,提炼 title、summary、acceptanceCriteria 形成 Requirement 输入。发现阻塞性歧义时返回 clarification,不会猜测。 - 输入:用户自然语言请求(通过 Controller 转发)。
- 输出:HarnessIntent JSON;
startintent 内包含结构化 Requirement 字段。 - 权限边界:只读。
task/edit/write/patch/bash全部禁用,不调用任何工具。 - 上下游关系:上游是 Harness primary;生命周期意图交给 Controller 执行,其中
start的 Requirement 再传给 Fuxi 规划。
Fuxi(伏羲,规划编排智能体)
- 稳定 ID:
harness-planner - Session role:
planner - 定位:根据 Requirement 生成可执行、可验证的 TaskGraph,采用两阶段规划。
- 主要职责:
- 第一阶段:生成 ContextPackage,收集仓库引用、外部引用、未解决问题和约束条件。
- 第二阶段:基于 ContextPackage 生成 PlanReview,包含 TaskGraph、coverage(每个 criterionId 的任务覆盖映射)和 findings。
- 输入:Requirement JSON + runId。
- 输出:ContextPackage → PlanReview(含 TaskGraph JSON)。每个 Task 包含
executionCategory(quick/deep/visual-engineering/ultrabrain)、allowedPaths、verificationPlan、retryBudget和acceptanceCriterionIds。 - 权限边界:只读。可使用全部研究工具(Context7、grep.app、LSP),但不编辑文件、不执行 shell、不委派子 Agent。
- 上下游关系:上游是 Nuwa,下游是 Zhulong(PlanReview)和 Luban(Task 执行)。Controller 在接受 PlanReview 前执行结构校验(ID 唯一、依赖存在、图无环、文件范围不冲突、criterionId 覆盖完整)。
Luban(鲁班,实现执行智能体)
- 稳定 ID:
harness-worker - Session role:
worker - 定位:唯一被允许修改代码的 Harness Agent,按
executionCategory路由执行策略。 - 主要职责:
- executionCategory 路由:根据 Task 的
executionCategory(quick/deep/visual-engineering/ultrabrain)选择执行深度和验证强度。 - allowedPaths 前置授权:只能在 Task 指定的
allowedPaths范围内实现代码变更。 - 事后对账:Controller 验证实际
changedPaths是否在allowedPaths内,超出范围触发暂停。
- executionCategory 路由:根据 Task 的
- 输入:Task JSON + Requirement JSON + allowedPaths + executionCategory。
- 输出:WorkerOutput JSON(包含 summary、changedPaths、verificationCommands、evidence)。
- 权限边界:
edit/write/patch/bash全部允许,permission.edit=allow,permission.bash=allow。可使用全部研究工具。必须严格遵守 allowedPaths,不得请求父会话完整历史。 - 上下游关系:上游是 Fuxi(通过 Controller 分发 Task),下游是确定性验证和 Zhulong。修复链中,Jingwei 生成的 Repair Task 也交回 Luban 执行。
Zhulong(烛龙,独立验证智能体)
- 稳定 ID:
harness-verifier - Session role:
verifier - 定位:独立于 Luban 的验证判定者,执行两阶段审查:PlanReview 和逐 Task TaskReview。
- 主要职责:
- PlanReview 阶段:审查 Fuxi 的 PlanReview 输出,验证 coverage(每个 criterionId 是否被 Task 覆盖)、findings 和 reviewedTasks 的一致性。
- 逐 Task TaskReview 阶段:对每个 Task 的 WorkerOutput 执行独立审查,输出
spec-compliance(规格符合性)和code-quality(代码质量)两个维度的 verdict(pass/fail)和 findings。
- 输入:PlanReview + Task JSON + WorkerOutput + Evidence 列表。
- 输出:PlanReview 判定 + 逐 Task TaskReview JSON(包含 status、specCompliance、codeQuality、changedPaths、acceptanceCriterionIds)。
- 权限边界:只读。
task/edit/write/patch/bash全部禁用。可使用全部研究工具辅助审查,但不执行修改、不执行 shell。 - 上下游关系:上游是 Controller(传递 evidence 和 WorkerOutput),下游是 Yinglong(所有 Task 通过后)或 Xingtian(失败时)。Zhulong 不能修改代码。
Yinglong(应龙,最终验收智能体)
- 稳定 ID:
harness-acceptance - Session role:
acceptance - 定位:Run 级一次性最终验收,仅在所有 Task 的 TaskReview 和 Run 级 integration verification 全部通过后执行一次。
- 主要职责:
- Run 级验收:检查整个 Run 的需求、验收项和 evidence 的闭环完整性,不是逐 Task 验收。
- criterionId 逐项追踪:为每个
criterionId生成CriterionDecision,记录 status(accepted/blocked/waived/unknown)、关联的 taskIds、taskReviewIds、evidenceIds、failureIds 和 changedPaths。 - 一次性执行:Yinglong 在整个 Run 生命周期内只执行一次 RunAcceptance,不会重复调用。
- 输入:Run 状态 + 所有 TaskReview + integration verification evidence + Requirement。
- 输出:RunAcceptance JSON(包含 status、summary、criterionDecisions)。
- 权限边界:只读。
task/edit/write/patch/bash全部禁用。可使用 grep.app 和 LSP 工具辅助审查,不使用 Context7。 - 上下游关系:上游是 Zhulong(所有 TaskReview 通过后)和 Controller(integration verification 通过后),下游是 Controller(Controller 再执行确定性 Guard Condition 决定是否进入 COMPLETED)。Yinglong 不能修改代码。
Xingtian(刑天,失败归因智能体)
- 稳定 ID:
harness-failure-analyzer - Session role:
failure-analyzer - 定位:根据实际失败证据分类根因并给出结构化恢复建议,可先请求受控只读诊断探针确认根因。
- 主要职责:
- 受控诊断探针:在归因前可请求 Controller 执行受控的只读诊断命令(如日志查询、状态检查),收集额外证据确认根因,而不是仅依赖既有失败证据。
- 根因分类:将失败分类为
context-gap、requirement-ambiguity、dependency-blocked、implementation-defect、verification-environment、scope-drift、merge-conflict、model-failure,并生成rootCauseFingerprint用于去重。 - 恢复建议:给出对应恢复动作,只有确认根因后才允许 Jingwei 生成 RepairTask。
- 输入:Task JSON + Requirement JSON + Failure + Evidence 列表 + 可选诊断探针结果。
- 输出:FailureAnalyzerOutput JSON(包含 action、category、summary、rootCauseFingerprint、evidenceIds)。
- 权限边界:只读。
task/edit/write/patch/bash全部禁用。可使用全部研究工具辅助归因,可请求受控诊断探针,但不执行修改。 - 上下游关系:上游是 Controller(传递失败证据),下游是 Jingwei(需要修复时,且根因已确认)或 Controller(需要澄清、等待或终止时)。Xingtian 不能修改代码。
Jingwei(精卫,修复规划智能体)
- 稳定 ID:
harness-repair-worker - Session role:
repair-worker - 定位:根据 Xingtian 确认的根因输出结构化修复建议,只建议,不直接修改代码。
- 主要职责:
- 根因确认前置:只有 Xingtian 完成根因分类并生成
rootCauseFingerprint后,Jingwei 才能生成 RepairTask。 - 收窄修复范围:基于根因和失败证据生成受限的 RepairTask,包含
allowedPaths(比原 Task 更窄)、minimalFailureSet(最小失败验证集)和fullVerification(完整验证集)。 - 版本化 RepairTask:每个 RepairTask 有
version字段,跟踪修复迭代。
- 根因确认前置:只有 Xingtian 完成根因分类并生成
- 输入:Task JSON + Requirement JSON + Failure + Evidence 列表 + Xingtian 的 rootCauseFingerprint + allowedPaths + retryBudget。
- 输出:RepairWorkerOutput JSON(包含 status、summary、repairTask、evidenceIds)。RepairTask 包含
sourceTaskId、sourceFailureId、rootCauseFingerprint、repairEnabled、phaseEvidenceKinds(red/green/refactor 三阶段)。 - 权限边界:只读。
task/edit/write/patch/bash全部禁用。可使用全部研究工具辅助分析,但明确禁止直接修改代码或调用写工具。 - 上下游关系:上游是 Xingtian(通过 Controller 传递失败上下文和根因确认),下游是 Luban(Controller 将 RepairTask 交给 Luban 在受限范围内执行)。Jingwei 不直接修改代码。
权限矩阵
Luban / harness-worker:
task=false, edit/write/patch/bash=true
permission.edit=allow, permission.bash=allow
其他全部 Harness agent:
task/edit/write/patch/bash=false
permission.edit=deny, permission.bash=denyharness primary 同样不具备直接执行权限(edit/write/patch/bash/task 均禁用),但可以使用宿主注入的只读研究工具做入口调查,并拥有一个受控的 harness_escalate 工具。当当前会话无法独立完成工程任务时,Primary 必须通过该工具把原始需求移交给 Harness Controller;Controller 再自动调度内部 Agent。
Harness 研究工具
Harness 插件直接提供 7 个原生研究工具和 1 个 Primary 专用控制工具,OpenCode 内使用不要求另配 MCP。研究工具能力版本为 HARNESS_TOOL_CAPABILITY_VERSION = "1.0.0",按角色白名单分配权限。
插件原生工具(推荐)
插件加载后自动注册以下工具,工具名以 harness_ 为前缀:
harness_context7_resolve、harness_context7_query:直连 Context7 官方 HTTP API。harness_grep_app_search:通过自研 Streamable HTTP MCP 客户端调用 grep.app 官方searchGitHub。harness_lsp_status、harness_lsp_diagnostics、harness_lsp_definition、harness_lsp_references:通过自研 JSON-RPC stdio 客户端访问 JDT LS 和 TypeScript Language Server。
工具使用权限按角色分配:
- 全部研究工具:Fuxi(Planner)、Luban(Worker)、Zhulong(Verifier)、Xingtian(Failure Analyzer)、Jingwei(Repair Worker)。
- grep.app + LSP:Yinglong(Acceptance)。
- 不使用 Harness 插件研究工具:Nuwa(Intake)。Harness(primary)不注册 Harness 插件的原生研究工具,但可以使用宿主(OpenCode 环境)注入的只读研究工具(如 codegraph、grep、read)做入口调查;primary 始终没有 edit/write/patch/bash/task 权限,不直接修改文件、不执行 shell、不委派子 Agent。
- Primary 专用控制工具:Harness(primary)可使用
harness_escalate;该工具不暴露到 MCP,且不能指定内部 Agent、任务图、命令或写入范围。
stdio MCP(外部兼容入口)
对于非 OpenCode 宿主或需要独立 MCP 进程的场景,Harness 提供 stdio MCP Server:
npx -y harness-engineering-agent-mcpMCP Server 注册相同的 7 个工具(context7_resolve、context7_query、grep_app_search、lsp_status、lsp_diagnostics、lsp_definition、lsp_references),但不实施角色白名单,调用方自行负责权限控制。
LSP 只提供只读查询,不实现重命名或代码写入。JDT LS 数据目录位于系统临时目录,并在 MCP Server 退出时清理。
Context7 默认匿名访问,可通过环境变量 CONTEXT7_API_KEY 提升限额。JDT LS 命令可通过 HARNESS_JDTLS_COMMAND 覆盖。
项目架构
本项目采用分层架构设计,主要包含以下核心模块:
配置层 (src/config/)
负责 Harness 配置的解析、验证和合并:
config-schema.ts: 配置模式定义config-errors.ts: 配置错误处理config-merge.ts: 配置合并逻辑load-harness-config.ts: 配置加载器
控制器层 (src/controller/)
核心运行控制器,负责执行和协调整个工程流程:
run-controller.ts: 主运行控制器task-executor.ts: 任务执行器worktree-scheduler.ts: 工作树调度器failure-analysis.ts: 失败分析repair-loop.ts: 修复循环report-factory.ts: 报告生成
领域层 (src/domain/)
定义核心领域模型:
run.ts: 运行状态管理task.ts: 任务模型requirement.ts: 需求模型evidence.ts: 证据模型failure.ts: 失败模型
插件层 (src/plugin/)
OpenCode 插件集成:
create-harness-plugin.ts: 插件入口harness-coordinator.ts: 协调器harness-chat-hook.ts: 聊天钩子harness-intent.ts: 意图解析
工具层 (src/tools/)
集成自研工程工具:
context7-client.ts: Context7 官方 API 客户端grep-app-client.ts: grep.app 搜索客户端lsp-client.ts: LSP 客户端(JDT LS/TypeScript)harness-research-tools.ts: 研究工具统一接口
会话层 (src/session/)
会话管理适配器:
opencode-session-adapter.ts: OpenCode 会话适配器fake-session-adapter.ts: 模拟会话适配器(测试用)
会话上下文采用版本化快照边界:Run/Task 的目标、约束、允许路径、验收标准、证据摘要和未解决问题由 Controller 生成 ContextSnapshot,每个内部 Session 通过 contextId、版本和摘要哈希关联到该快照。不同角色按上下文层级和预算接收最小必要信息,不继承父会话完整历史;Evidence 默认以带来源、新鲜度和摘要哈希的引用传递。
Session 生命周期同时绑定 runId、taskId、attempt 和不可复用 leaseId。超时、取消、释放和迟到结果由 Controller 幂等处理,旧 Attempt 的结果不得推进当前 Run。上下文快照、澄清状态和 Session 事件只持久化结构化摘要、指纹和引用,不保存完整 Prompt、源码或敏感工具输出;Session 索引缺失时以事件日志重建。
harness-agent-names.ts: Agent 名称映射
存储层 (src/store/)
运行状态持久化:
filesystem-run-store.ts: 文件系统存储实现run-event.ts: 运行事件模型
验证层 (src/verification/)
验证命令执行与策略:
command-policy.ts: 命令策略检查verification-runner.ts: 验证运行器node-process-runner.ts: 进程执行器
工作区层 (src/workspace/)
Git 与工作区管理:
git-workspace-adapter.ts: Git 工作区适配器git-worktree-adapter.ts: Git Worktree 管理git-baseline.ts: Git 基线捕获
功能特性
Agent 生命周期管理
- 支持
start、status、resume、pause、cancel、answer、waive、report操作 - 自然语言请求转换为严格 JSON intent
- 两阶段非阻塞流程:先返回持久化 Run 的
runId,后台协调运行 - Run 执行期间可在同一或其他 Harness 会话中查询、暂停、取消、恢复或生成报告
内部 Agent 链
当前激活链:Nuwa → Fuxi(ContextPackage → PlanReview)→ Zhulong(PlanReview → 逐 Task TaskReview)→ Luban → deterministic verification → Run 级 integration verification → Yinglong(RunAcceptance)
失败处理:Xingtian(诊断探针 + 根因确认)→ Jingwei(收窄 RepairTask)→ Luban 有限修复
只读工程工具
插件直接提供 7 个原生研究工具(不需要另配 MCP):
- Context7: 直连官方 HTTP API(
harness_context7_resolve、harness_context7_query) - grep.app: 通过 Streamable HTTP MCP 客户端搜索(
harness_grep_app_search) - LSP: 自研 JSON-RPC 客户端访问 JDT LS 和 TypeScript LS(
harness_lsp_status、harness_lsp_diagnostics、harness_lsp_definition、harness_lsp_references)
工具能力版本为 HARNESS_TOOL_CAPABILITY_VERSION = "1.0.0",按角色白名单分配权限。stdio MCP 仅为外部兼容入口。
确定性恢复
- 快照与事件持久化到
.harness/runs/<run-id>/ - 原子替换写入,追加持久化带幂等键
- 恢复时重放快照和事件
并行执行
- 依赖、路径范围和验证资源无冲突时启用
- 独立 git worktree 执行
- 冲突时保留诊断 worktree refs
配置诊断
Harness 提供 doctor 命令用于诊断配置问题,支持人类可读和 JSON 两种输出格式:
# 人类可读输出
harness-engineering-agent-doctor
# JSON 输出
harness-engineering-agent-doctor --jsondoctor 命令检查以下内容:
- config:OpenCode 配置文件是否存在
- package:Harness 包入口、doctor 子路径与 MCP bin 是否正确声明
- compatibility:OpenCode SDK 和 Plugin SDK 版本兼容性
- plugin:Harness 插件是否正确注册,Agent 名称是否冲突
- agent:将注册的 8 个 Harness Agent 是否正常
- tool:Harness 能力目录包含的工具数量(当前 7 个)
- harness_mcp:Harness MCP 自连接测试
- mcp:其他配置的 MCP Server 连接状态(单个第三方 MCP 失败由 doctor 隔离归因,不影响整体诊断)
退出码:0 表示通过,1 表示存在问题。
快速开始
环境要求
- Node.js >= 24
- pnpm >= 11
- Git
安装依赖
pnpm install构建插件
pnpm build配置 OpenCode
OpenCode 会自动加载 ~/.config/opencode/plugins/ 下的插件。开发环境可创建符号链接或文件:
// ~/.config/opencode/plugins/harness-engineering-agent.ts
export { server } from "/path/to/harness-engineering-agent/dist/index.js"修改插件或配置后需要重新执行 pnpm build,并重启 OpenCode 使变更生效。运行中的 OpenCode 会话不会热加载插件变更。
发布到 npm
交互式发布脚本会调用 npm 官方登录流程。用户名正常显示,密码由 npm 隐藏读取,不会作为命令参数、环境变量或脚本变量保存。账号启用 2FA 时,npm 会继续提示输入 OTP。
先执行不发布的完整检查:
pnpm publish:npm -- --dry-run确认包名和版本无误后执行真实发布:
pnpm publish:npm脚本依次执行登录、版本占用检查、类型检查、Lint、测试、构建、打包预览和发布确认。npm 不允许覆盖已有版本,后续发布前先升级版本:
npm version patch --no-git-tag-versionnpm registry 要求发布者启用双重验证。账号密码登录后先执行:
npm profile enable-2fa auth-and-writes重新运行 pnpm publish:npm,发布阶段按 npm 提示输入 OTP。另一种方式是在 npm 网站创建 granular access token,为目标包授予 Read and write 权限并启用 Bypass 2FA。运行脚本时隐藏输入 token:
pnpm publish:npm -- --token-auth脚本将 token 临时写入权限为 600 的 npmrc,并仅通过 NPM_CONFIG_USERCONFIG 传给 npm 子进程。pnpm test/build 不会继承该认证文件。脚本结束后自动删除。token 不会写入命令参数、shell 历史、项目文件或日志。该参数不能绕过 npm registry 的服务端权限校验。
如果 token 曾经出现在日志、聊天或公开文件中,应立即在 npm 网站撤销并重新创建,不要继续使用泄露的 token。
OpenCode npm 引用
发布后在 opencode.json 中加载插件。根据使用场景选择以下两种配置方式之一:
方式一:插件-only(推荐)
插件直接提供 harness_* 原生研究工具,不需要配置 MCP:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["harness-engineering-agent"]
}这是最简单的配置方式。插件加载后自动注册 8 个 Harness Agent、7 个研究工具和 1 个 Primary 控制工具,按角色白名单控制权限。
方式二:插件 + 可选 MCP(外部兼容)
如果需要在 OpenCode 之外使用 Harness 研究工具(如独立脚本或其他 MCP 客户端),可以额外配置 stdio MCP:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["harness-engineering-agent"],
"mcp": {
"harness": {
"type": "local",
"command": ["npx", "-y", "harness-engineering-agent@latest"],
"enabled": true,
"timeout": 30000
}
}
}注意:MCP 配置是可选的。插件已经提供了所有研究工具,MCP 仅为外部兼容入口。两者同时配置时,OpenCode 会同时加载插件工具和 MCP 工具,但插件工具已包含角色权限控制,MCP 工具不包含。
OpenCode 会通过包的 ./server 导出加载专用插件入口;根入口仍保留完整 SDK 导出,供其它 npm 调用方使用。
启动后 Harness 插件注册的用户可见 Agent 只有 harness,并在插件注入顺序中优先显示。
内部 Agent 仍以 harness-intake、harness-planner、harness-worker 等稳定 ID 注册,
供 Harness 控制平面按角色调度,但会标记为 hidden,不进入用户侧 Agent/Model 选择列表。
重要:修改插件或配置后需要重新执行 pnpm build,并重启 OpenCode 使变更生效。运行中的 OpenCode 会话不会热加载插件变更。
项目配置
在目标项目创建 .harness/config.yaml:
schemaVersion: "1.0.0"
enabled: true
harness:
provider: openai
model: gpt-5.5
planner:
provider: openai
model: gpt-5.5
worker:
provider: deepseek
model: deepseek-v4-pro
verifier:
provider: openai
model: gpt-5.5
acceptance:
provider: openai
model: gpt-5.5
failureAnalyzer:
provider: openai
model: gpt-5.5
maxRunAttempts: 3
sessionTimeoutMs: 600000
stateDirectory: .harness/runs
allowNonGitWorkspace: falseharness profile 只用于专用 harness Agent 和内部 Intake Session。不要在这里重新引入 maxSteps 等 OpenCode Agent 运行时字段。
Profile 继承规则:
acceptance缺省继承verifier的 provider/model。failureAnalyzer缺省继承planner的 provider/model。repair-worker(Jingwei)当前复用workerprofile,而不是单独配置项。- 三者都参与实际控制链,不是预留配置。
工作区配置:
allowNonGitWorkspace:是否允许在非 Git 工作区中运行(默认false)。设为true时,Harness 进入降级模式:使用文件 hash 追踪变更并按allowedPaths做范围校验,但不提供 Git dirty 检测、Git diff 校验、回滚或 worktree 并行执行。降级模式下的最终报告会标注 "non-git mode: limited verification"。- 当 OpenCode 从父级容器目录启动,且具体项目位于子目录时,可在需求中显式指定目标项目目录。Git 子仓库保持原有保护;非 Git 子项目只有在启用
allowNonGitWorkspace后才会被接受。
会话超时保护:
sessionTimeoutMs:单个内部 Agent 会话(intake/planner/worker/verifier/acceptance/failure-analyzer/repair-worker)允许挂起的最长时间(毫秒,默认600000)。会话超时会被中断并产生agent.failed/session.released事件,进入既有重试预算或失败路径,Run 不会永久卡死。调用点显式指定的timeoutMs优先于全局默认值。- 空输出(会话完成但无文本内容)会被分类为
empty-output失败进入重试,不会误报为 JSON 解析错误。 - 任意角色合同失败会输出
HARNESS_AGENT_DIAG结构化诊断(intake 同时保留HARNESS_INTAKE_DIAG),便于从日志直接定位 role、attempt、reasonCode 与输出片段。
进度查询:
- 在
harnessAgent 中用自然语言询问运行进度(如"进度怎么样了"、"进展如何"、"跑到哪了"、"还在运行吗")会触发真实状态查询:会话中存在唯一未完成 Run 时直接返回该 Run 的实际状态;存在多个或没有可查询的运行时,会要求补充 runId。
配置优先级:插件默认值 < 用户全局配置 < 项目 .harness/config.yaml < 当前 Run 覆盖。
使用指南
启动运行
- 在 OpenCode 中选择 primary
harnessAgent - 发送自然语言请求,例如:"启动一个 run,目标是实现用户登录功能"
- Harness 首轮返回已持久化的
runId和初始状态,规划、实现、验证和验收在后台继续
不需要打开或部署独立控制面板。Harness 会话和 runId 就是长任务的控制入口:
status <runId>
pause <runId> 等待人工确认
resume <runId>
cancel <runId>
report <runId>使用要点:
start请求必须能被 Intake 提炼成 title、summary、acceptanceCriteria。如果缺少必要信息,Harness 会返回 clarification 响应而不是猜测。status、resume、cancel、report必须显式提供runId。Harness 不会默认选择"最近一次运行"。status、pause、cancel、resume和report不受父会话后台任务锁阻塞;重复推进同一 Run 不会创建重复内部 Agent Session。evidence_gap只表示当前环境无法取得的外部事实或需要用户确认的业务事实;仓库中可通过搜索、LSP 或只读验证获得的接口、路由、配置和调用链信息会继续进入调查任务。- 对于可恢复的
evidence_gap或规划阻塞,补充证据后执行resume <runId>;状态反馈会包含缺失证据和下一步动作。后台消息的投递完成不代表 Run 完成,只有嵌套 Run 状态为completed才能报告整体完成。 - 工程请求由 primary 通过
harness_escalate唯一移交;聊天 Hook 只注入受理协议,避免同一消息重复创建协调任务。显式生命周期命令仍可由 Hook 直接处理。 - 在同一父会话只有一个未完成 Run 时,可以发送“继续”“接着”或“恢复”恢复该 Run;“回复运行”“继续跑”“接着推进运行”等口语化表述同样按恢复处理。没有候选或存在多个候选时,Harness 会要求补充或明确
runId,不会静默选择。 - 会话存在唯一 Run(含
failed但可恢复的终态 Run)时,“回复运行”“运行怎么样”“说说运行”等状态询问会触发真实状态查询,返回实际状态、失败摘要与可复制的恢复命令,不会被当作普通对话直通。 - 同一会话发送"没有恢复""未恢复"等恢复失败确认时,按恢复请求处理:会话存在唯一未完成 Run 或唯一待恢复任务时会自动恢复,避免阻塞后流程中断。
- Planner 使用分阶段合同:Context 阶段输出
PlannerContextOutput,后续阶段才输出TaskGraph。Planner 合同失败表示目标工程尚未完成调查,修复 Harness 合同后才能通过resume重试。 - 契约失败按真实角色归因:
planner-contract/verifier-contract/worker-contract(未知角色兜底agent-contract),errorCode 相应为PLANNER_CONTRACT_*/VERIFIER_CONTRACT_*/WORKER_CONTRACT_*/AGENT_CONTRACT_*(HARNESS_AGENT_DIAG诊断输出格式不变,PLANNER_CONTRACT_*保持历史取值)。streamlined 路径的 verifier 图审查契约失败会携带具体 schema 原因重试,预算耗尽后按 verifier 角色归因终止。
基本操作
| 操作 | 说明 | 必填参数 |
|------|------|----------|
| start | 启动新运行 | title, summary, acceptanceCriteria |
| status | 查询状态 | runId |
| resume | 恢复运行 | runId |
| pause | 暂停运行 | runId |
| cancel | 取消运行 | runId |
| report | 生成报告 | runId |
| answer | 回答问题 | runId |
| waive | 放弃要求 | runId, requirementId |
恢复运行
resume run-abc将从 .harness/runs/run-abc/ 快照恢复上下文。
阻塞后恢复(dirty workspace)
Run 启动前工作区存在未提交变更时,Harness 会返回阻塞澄清并列出变更文件,同时把该需求保存为待恢复任务。处理方式:
- 自行提交或暂存变更后恢复(推荐):完成
git commit/git stash后,在同一会话回复「继续」(或「已经提交」),Harness 会用阻塞前解析好的结构化需求自动恢复 Run,无需重新描述任务。该恢复基于磁盘持久化的待恢复任务,OpenCode 重启后依然有效。 - 授权 Harness 处理已有变更:明确说明要提交的文件,例如"先提交并推送
package.json,然后继续处理",Harness 会先提交授权路径再恢复运行。 - 保留变更继续只读任务:只读任务可回复"保留当前变更,不提交不暂存,继续"。
恢复成功后待恢复任务会被清理;恢复尝试再次被阻塞时任务保留,可继续处理工作区后重试。阻塞澄清文案中包含对应的恢复指令提示。
验证策略
验证命令执行受严格策略约束:
- 必须使用结构化 argv
shell: false执行- 工作区包含校验
- 嵌套解释器/包管理器绕过检查
- 审批元数据约束
不允许 Agent 自报"已通过"替代命令证据。
测试
# 运行所有测试
pnpm test
# 运行单元测试
pnpm test:unit
# 运行集成测试
pnpm test:integration
# 运行 E2E 测试
pnpm test:e2e项目结构
harness-engineering-agent/
├── src/
│ ├── config/ # 配置管理
│ ├── controller/ # 核心控制器
│ ├── domain/ # 领域模型
│ ├── plugin/ # 插件集成
│ ├── session/ # 会话管理
│ ├── store/ # 状态存储
│ ├── tools/ # 工程工具
│ ├── verification/ # 验证执行
│ ├── workspace/ # 工作区管理
│ └── index.ts # 入口文件
├── tests/ # 测试用例
│ ├── config/
│ ├── controller/
│ ├── domain/
│ ├── e2e/
│ ├── integration/
│ ├── plugin/
│ ├── session/
│ ├── store/
│ ├── tools/
│ ├── verification/
│ └── workspace/
├── harness/ # 设计文档
├── package.json
├── tsconfig.json
└── biome.json环境变量
| 变量 | 说明 | 默认值 |
|------|------|--------|
| CONTEXT7_API_KEY | Context7 API Key | 匿名访问 |
| HARNESS_JDTLS_COMMAND | JDT LS 命令覆盖 | 自动检测 |
| HARNESS_ADMISSION_DEBUG | 设为 1/true 时在 stderr 输出 HARNESS_ADMISSION 调试行 | 关闭(静默) |
状态恢复与证据
.harness/runs/<run-id>/state.json使用原子替换写入,events.jsonl追加持久化并带稳定幂等键。FilesystemRunStore在读取时重放快照后的事件,并拒绝未知 major schema version。- Evidence Ledger 记录 requirement、acceptance criterion(
criterionId)、task、changed paths、verification command、输出摘要 digest 和 redaction metadata。 - 稳定 criterionId 和逐项证据追踪:每个
criterionId从需求定义、PlanReview coverage、TaskReview、RunAcceptance criterionDecisions 全程追踪,确保证据链完整可审计。 - Bug 修复与
repairEnabledTask 要求 RED/GREEN/REFACTOR 三阶段 evidence。Design Bundle 场景要求 requirement / acceptance / tasks / evidence / report 结构可追踪。 - 最终报告汇总
traceability、unfinishedTasks、verificationSummaries、failures、evidenceGaps和residualRisks,不会因为 run 结束就抹平历史失败记录。
目录结构
.harness/
config.yaml # 项目级 Harness 配置
runs/<run-id>/
requirement.json # 结构化需求
state.json # 完整 Run 状态快照(含需求、任务、Agent 结果、失败和 evidence)
events.jsonl # 不可变事件日志(追加)state.json 使用临时文件校验后原子替换,events.jsonl 使用稳定幂等键追加。report 操作根据当前 Run 生成结构化报告并返回给用户;当前实现不自动写入 final-report.md。目标项目应将配置的运行状态目录(默认 .harness/runs/)和临时 worktree 元数据加入自身 .gitignore。
验证命令
当前项目验证命令:
pnpm typecheck # 类型检查
pnpm lint # Biome lint
pnpm test # Vitest 测试(当前 630 个测试全部通过,76 个测试文件)
pnpm build # 构建设计文档
许可证
本项目采用 MIT License 开源协议。
