Skip to content

概述

Harness 是一个可执行协议,使任何 Agent 任务能够在多个会话中持续运行,同时支持自动进度恢复、任务依赖解析、失败回滚和标准化错误处理。

适用场景:

  • 跨上下文窗口的睡眠/恢复周期
  • 需要从中途失败中恢复的部分状态
  • 分布式工作跨多个 Agent 会话

核心设计原则:

  • 为 Agent 而非人类设计 — 测试输出、文档和任务结构是 Agent 的主要接口
  • 进度文件即上下文 — 上下文窗口重置时,进度文件 + git 历史 = 完整恢复
  • 防止过早完成 — 结构化任务列表具有明确的完成标准
  • 一切皆可 grep — 错误在同一行、结构化时间戳、一致前缀
  • 幂等一切 — 初始化脚本、任务执行、环境设置均可安全重运行

命令

bash
/harness init <project-path>     # 初始化项目中的 harness 文件
/harness run                     # 启动/恢复无限循环
/harness status                  # 显示当前进度和统计
/harness add "task description"  # 添加任务到列表

激活标记 (.harness-active)

Hooks 仅在 .harness-active 标记文件存在于 harness 根目录时生效。

  • /harness init/harness run 必须创建此标记:touch <project-path>/.harness-active
  • 当所有任务完成(无 pending/in_progress/retryable 剩余)时,移除它:rm <project-path>/.harness-active
  • 无此标记时,所有 hooks 为空操作 — 立即退出 0

进度持久化(双文件系统)

harness-progress.txt(追加式日志)

跨会话记录所有 Agent 操作的纯文本日志,永不截断。

[2025-07-01T10:00:00Z] [SESSION-1] INIT Harness initialized for project /path/to/project
[2025-07-01T10:00:05Z] [SESSION-1] INIT Environment health check: PASS
[2025-07-01T10:00:10Z] [SESSION-1] LOCK acquired (pid=12345)
[2025-07-01T10:00:11Z] [SESSION-1] Starting [task-001] Implement user authentication (base=def5678)
[2025-07-01T10:05:00Z] [SESSION-1] CHECKPOINT [task-001] step=2/4 "auth routes created, tests pending"
[2025-07-01T10:15:30Z] [SESSION-1] Completed [task-001] (commit abc1234)
[2025-07-01T10:15:31Z] [SESSION-1] Starting [task-002] Add rate limiting (base=abc1234)
[2025-07-01T10:20:00Z] [SESSION-1] ERROR [task-002] [TASK_EXEC] Redis connection refused
[2025-07-01T10:20:01Z] [SESSION-1] ROLLBACK [task-002] git reset --hard abc1234
[2025-07-01T10:20:02Z] [SESSION-1] STATS tasks_total=5 completed=1 failed=1 pending=3 blocked=0 attempts_total=2 checkpoints=1

harness-tasks.json(结构化状态)

json
{
  "version": 2,
  "created": "2025-07-01T10:00:00Z",
  "session_config": {
    "concurrency_mode": "exclusive",
    "max_tasks_per_session": 20,
    "max_sessions": 50
  },
  "tasks": [
    {
      "id": "task-001",
      "title": "Implement user authentication",
      "status": "completed",
      "priority": "P0",
      "depends_on": [],
      "attempts": 1,
      "max_attempts": 3,
      "started_at_commit": "def5678",
      "validation": {
        "command": "npm test -- --testPathPattern=auth",
        "timeout_seconds": 300
      },
      "error_log": [],
      "checkpoints": [],
      "completed_at": "2025-07-01T10:15:30Z"
    }
  ],
  "session_count": 1,
  "last_session": "2025-07-01T10:20:02Z"
}

任务状态流转: pendingin_progress(执行中临时状态)→ completedfailed

并发控制

锁机制

使用便携式 mkdir 获取排他锁(在所有 POSIX 系统上原子操作):

bash
ROOT="$PWD"
SEARCH="$PWD"
while [ "$SEARCH" != "/" ] && [ ! -f "$SEARCH/harness-tasks.json" ]; do
  SEARCH="$(dirname "$SEARCH")"
done
if [ -f "$SEARCH/harness-tasks.json" ]; then
  ROOT="$SEARCH"
fi

PWD_HASH="$(printf '%s' "$ROOT" | (shasum -a 256 2>/dev/null || sha256sum 2>/dev/null) | awk '{print $1}' | cut -c1-16)"
LOCKDIR="/tmp/harness-${PWD_HASH:-unknown}.lock"

if ! mkdir "$LOCKDIR" 2>/dev/null; then
  LOCK_PID=$(cat "$LOCKDIR/pid" 2>/dev/null)
  if [ -n "$LOCK_PID" ] && kill -0 "$LOCK_PID" 2>/dev/null; then
    echo "ERROR: Another harness session is active (pid=$LOCK_PID)"; exit 1
  fi
  # Stale lock - atomically reclaim
  STALE="$LOCKDIR.stale.$$"
  if mv "$LOCKDIR" "$STALE" 2>/dev/null; then
    rm -rf "$STALE"
    mkdir "$LOCKDIR" || { echo "ERROR: Lock contention"; exit 1; }
  fi
fi
echo "$$" > "$LOCKDIR/pid"
trap 'rm -rf "$LOCKDIR"' EXIT

模式

模式描述
Exclusive(默认)在整个会话期间持有锁
Concurrent(可选)仅在读取/修改/写入 JSON 时持有锁

并发模式要求:

  • 所有 worker 必须指向相同的状态根目录
  • 使用 git worktree 或独立克隆,勿在同一工作目录运行多个 worker

任务执行循环

会话启动协议

  1. 读取状态 — 读取 harness-progress.txt 最后 200 行 + 完整 harness-tasks.json
  2. 读取 git — 运行 git log --oneline -20git diff --stat 检测未提交工作
  3. 获取锁 — 根据模式获取排他锁
  4. 恢复中断任务 — 执行上下文窗口恢复协议
  5. 健康检查 — 运行 harness-init.sh(如存在)
  6. 跟踪会话 — JSON 中递增 session_count

任务选择算法

  1. 依赖验证 — 循环检测 + 阻塞传播
  2. 选择优先级:
    • P0 > P1 > P2,同优先级按 id 升序
    • pending 任务(依赖全部 completed)> failed 任务(可重试)

任务执行步骤

  1. 声明(原子操作):记录 started_at_commit,设置 status: "in_progress"
  2. 执行并打检查点:每个重要步骤后记录 CHECKPOINT
  3. 验证:运行 validation.command,超时使用 timeout 包装
  4. 记录结果
    • 成功:status: "completed",git commit
    • 失败:回滚 git reset --hard <started_at_commit>,记录错误

停止条件

  • 所有任务 completed
  • 所有剩余任务 failed(达到最大重试次数或被阻塞)
  • max_tasks_per_session 达到
  • max_sessions 达到
  • 用户中断

上下文窗口恢复协议

当新会话发现 status: "in_progress" 的任务时:

未提交?最近任务提交?检查点?操作
NoNoNone标记 failed[SESSION_TIMEOUT] No progress detected
NoNoSome验证文件状态是否匹配检查点
NoYesAny运行验证,通过则 completed,失败则回滚
YesNoAny验证,未通过则回滚
YesYesAny提交变更后验证

错误处理

类别默认恢复Agent 操作
ENV_SETUP重新运行 init失败两次则 STOP
CONFIGSTOP记录精确错误,停止
TASK_EXEC回滚,重试验证 started_at_commit 存在
TEST_FAIL回滚,重试分析测试输出针对性修复
TIMEOUT终止进程,执行清理,重试考虑拆分任务
DEPENDENCY跳过,标记阻塞记录依赖失败
SESSION_TIMEOUT上下文窗口恢复协议新会话评估

JSON 损坏恢复: 检查 harness-tasks.json.bak,如有有效备份则恢复。

日志格式

[ISO-timestamp] [SESSION-N] <TYPE> [task-id]? [category]? message

类型:INIT, Starting, Completed, ERROR, CHECKPOINT, ROLLBACK, RECOVERY, STATS, LOCK, WARN

常用过滤:

bash
grep "ERROR" harness-progress.txt                    # 所有错误
grep "ERROR" harness-progress.txt | grep "TASK_EXEC" # 执行错误
grep "SESSION-3" harness-progress.txt                # 会话 3 活动
grep "STATS" harness-progress.txt                    # 会话摘要

会话统计

[2025-07-01T10:20:02Z] [SESSION-1] STATS tasks_total=10 completed=7 failed=1 pending=2 blocked=0 attempts_total=12 checkpoints=23

blocked = pending 任务中依赖永久失败任务的数量(计算值,非存储状态)。

初始化脚本

harness-init.sh 在每个会话开始时运行,必须幂等:

bash
#!/bin/bash
set -e
npm install 2>/dev/null || pip install -r requirements.txt 2>/dev/null || true
curl -sf http://localhost:5432 >/dev/null 2>&1 || echo "WARN: DB not reachable"
npm test -- --bail --silent 2>/dev/null || echo "WARN: Smoke test failed"

Workflows / Orchestration / Execution