概述
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=1harness-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"
}任务状态流转: pending → in_progress(执行中临时状态)→ completed 或 failed
并发控制
锁机制
使用便携式 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
任务执行循环
会话启动协议
- 读取状态 — 读取
harness-progress.txt最后 200 行 + 完整harness-tasks.json - 读取 git — 运行
git log --oneline -20和git diff --stat检测未提交工作 - 获取锁 — 根据模式获取排他锁
- 恢复中断任务 — 执行上下文窗口恢复协议
- 健康检查 — 运行
harness-init.sh(如存在) - 跟踪会话 — JSON 中递增
session_count
任务选择算法
- 依赖验证 — 循环检测 + 阻塞传播
- 选择优先级:
- P0 > P1 > P2,同优先级按 id 升序
pending任务(依赖全部completed)>failed任务(可重试)
任务执行步骤
- 声明(原子操作):记录
started_at_commit,设置status: "in_progress" - 执行并打检查点:每个重要步骤后记录
CHECKPOINT - 验证:运行
validation.command,超时使用timeout包装 - 记录结果:
- 成功:
status: "completed",git commit - 失败:回滚
git reset --hard <started_at_commit>,记录错误
- 成功:
停止条件
- 所有任务
completed - 所有剩余任务
failed(达到最大重试次数或被阻塞) max_tasks_per_session达到max_sessions达到- 用户中断
上下文窗口恢复协议
当新会话发现 status: "in_progress" 的任务时:
| 未提交? | 最近任务提交? | 检查点? | 操作 |
|---|---|---|---|
| No | No | None | 标记 failed:[SESSION_TIMEOUT] No progress detected |
| No | No | Some | 验证文件状态是否匹配检查点 |
| No | Yes | Any | 运行验证,通过则 completed,失败则回滚 |
| Yes | No | Any | 验证,未通过则回滚 |
| Yes | Yes | Any | 提交变更后验证 |
错误处理
| 类别 | 默认恢复 | Agent 操作 |
|---|---|---|
ENV_SETUP | 重新运行 init | 失败两次则 STOP |
CONFIG | STOP | 记录精确错误,停止 |
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=23blocked = 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"