🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

绿测循环器 dancingteeth/agent-looper

DeepSeek Harnessv0.7.3
dancingteeth2 天前有提交已提供中文文档扫描:含敏感能力

智能体循环器@dancingteeth/agent-looper

32.9/100
综合分
4
GitHub 星标
564
npm 周下载
—/5
用户评分

数据截至 2026/11/3 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add @dancingteeth/agent-looper
npm 源 · @dancingteeth/agent-looper 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么[目录]—
dsh 原生插件 · dev
暂无时间戳·判据 →
装得上吗[实装验证]✓
本站已在 dsh 0.2.1-rc.2 下真实安装成功(非静态推断);本次验证针对插件 v0.8.4,当前版本为 v0.7.3
L5 · 运行时冒烟等级说明 →
数据截至 2026/10/28·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/04·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 2 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包@dancingteeth/agent-looper @ 0.7.3
✓Node 引擎要求 >=22 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/18 00:24:14

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 48 处,展示前 45 条)
  • 读取密钥环境变量
    dist/cli/check.js:42
    const key = process.env.CURSOR_API_KEY?.trim();
  • 读取密钥环境变量
    dist/cli/check.js:163
    const codexKey = process.env.CODEX_API_KEY?.trim();
  • 读取密钥环境变量
    dist/cli/check.js:164
    const openAiKey = process.env.OPENAI_API_KEY?.trim();
  • 读取密钥环境变量
    dist/cli/check.js:200
    const key = process.env.DEEPSEEK_API_KEY?.trim();
  • 读取密钥环境变量
    dist/cli/check.js:234
    const metaKey = process.env.META_API_KEY?.trim();
  • 读取密钥环境变量
    dist/cli/check.js:273
    if (process.env.ANTHROPIC_API_KEY?.trim()) {
  • 读取本地文件
    scripts/prepare-package.mjs:13
    readFileSync(join(packageRoot, 'scripts/dist-manifest.json'), 'utf8'),
  • 读取本地文件
    scripts/prepare-package.mjs:20
    return required.filter((rel) => !existsSync(join(baseDir, rel)))
  • 读取本地文件
    scripts/prepare-package.mjs:36
    if (!existsSync(srcRoot)) return 0
  • 读取本地文件
    scripts/prepare-package.mjs:39
    for (const entry of readdirSync(dir, { withFileTypes: true })) {
  • 读取本地文件
    scripts/prepare-package.mjs:50
    const mtime = statSync(full).mtimeMs
  • 读取本地文件
    scripts/prepare-package.mjs:69
    if (!existsSync(full)) return 0
  • 执行外部命令固定命令
    scripts/prepare-package.mjs:97
    const build = spawnSync('pnpm', ['run', 'build'], {
  • 执行外部命令固定命令
    dist/context/defaultBranch.js:3
    return execFileSync('git', args, { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim();
  • 执行外部命令来自配置/变量
    dist/cli/detectRuntimes.js:41
    const result = spawnSync(binary, ['--version'], { encoding: 'utf8', stdio: 'ignore' });
  • 执行外部命令来自配置/变量
    dist/loop/loopVerify.js:10
    const result = spawnSync(command, {
  • 执行外部命令来自配置/变量
    dist/loop/loopSetup.js:13
    const result = spawnSync(command, {
  • 读取密钥环境变量
    dist/agents/cursorAgent.js:111
    const apiKey = process.env.CURSOR_API_KEY?.trim();
  • 执行外部命令固定命令
    dist/review/loopPostReview.js:18
    return execFileSync('git', ['merge-base', 'HEAD', baseBranch], {
  • 执行外部命令固定命令
    dist/review/loopPostReview.js:26
    return execFileSync('git', ['diff', '--stat', `${base}...HEAD`], {
  • 执行外部命令固定命令
    dist/review/loopPostReview.js:33
    const out = execFileSync('git', ['diff', '--name-only', ...args], {
  • 执行外部命令来自配置/变量
    dist/integrations/loopNotifyCommand.js:12
    const output = execFileSync(input.command, {
  • 执行外部命令固定命令
    dist/integrations/loopNotifyChannels.js:82
    const output = execFileSync('gh', ['pr', 'view', '--json', 'number', '-q', '.number'], {
  • 执行外部命令固定命令
    dist/integrations/loopNotifyChannels.js:143
    const output = execFileSync('gh', ['pr', 'comment', String(pr), '--body', input.body], {
  • 执行外部命令来自配置/变量
    dist/agents/opencodeServe.js:78
    const result = spawnSync(command, ['--version'], { encoding: 'utf8', env, timeout: 15_000 });
  • 执行外部命令来自配置/变量
    dist/cli/promptFlow.js:137
    const child = spawn(process.execPath, [resolveAgentLoopRunBin(), 'run', bundleLabel], {
  • 执行外部命令来自配置/变量
    dist/cli/promptFlow.js:162
    const child = spawn(command, {
  • 执行外部命令固定命令
    dist/integrations/taskwarrior.js:41
    const uuid = execFileSync('task', [
  • 执行外部命令固定命令
    dist/integrations/taskwarrior.js:60
    execFileSync('task', buildHitlCheckTaskArgs(description, taskwarriorProject), {
  • 执行外部命令固定命令
    dist/integrations/taskwarrior.js:81
    execFileSync('task', [`uuid:${parsed}`, 'done'], { encoding: 'utf8', stdio: 'pipe' });
  • 执行外部命令来自配置/变量
    dist/integrations/taskwarrior.js:93
    const output = execFileSync(syncCommand, {
  • 执行外部命令固定命令
    dist/loop/loopGit.js:3
    return execFileSync('git', args, { cwd, encoding: 'utf8', maxBuffer: 1024 * 1024 }).trim();
  • 执行外部命令固定命令
    dist/loop/loopStallProbes.js:52
    return execFileSync('git', args, {
  • 执行外部命令固定命令
    dist/loop/loopStallProbes.js:60
    return execFileSync('git', args, { cwd: repoRoot, maxBuffer: 256 * 1024 * 1024 });
  • 执行外部命令固定命令
    dist/loop/loopStallProbes.js:246
    out = execFileSync('git', ['check-ignore', '--no-index', '-z', '--stdin'], {
  • 请求外部主机api.linear.app
    dist/integrations/hitlCheckpoint.js:54
    const res = await fetch('https://api.linear.app/graphql', {
  • 发起网络请求
    dist/integrations/hitlCheckpoint.js:54
    const res = await fetch('https://api.linear.app/graphql', {
  • 执行外部命令固定命令
    dist/integrations/hitlCheckpoint.js:145
    const output = execFileSync('gh', ['issue', 'create', '--title', title, '--body', body], {
  • 执行外部命令来自配置/变量
    dist/integrations/hitlCheckpoint.js:166
    const output = execFileSync(input.command, {
  • 执行外部命令固定命令
    dist/agents/processTree.js:26
    const out = spawnSync('pgrep', ['-P', String(pid)], { encoding: 'utf8' });
  • 执行外部命令固定命令
    dist/agents/processTree.js:70
    spawnSync('taskkill', ['/pid', String(rootPid), '/T', '/F'], { windowsHide: true });
  • 执行外部命令固定命令
    dist/agents/processTree.js:100
    spawnSync('taskkill', ['/pid', String(rootPid), '/T', '/F'], { windowsHide: true });
  • 执行外部命令固定命令
    dist/agents/claudeAgent.js:33
    const probe = spawnSync('claude', ['--version'], { encoding: 'utf8' });
  • 读取密钥环境变量
    dist/agents/clineAgent.js:14
    const apiKey = process.env.CLINE_API_KEY?.trim();
  • 读取密钥环境变量
    dist/agents/codexAgent.js:53
    const apiKey = process.env.CODEX_API_KEY?.trim() || process.env.OPENAI_API_KEY?.trim() || undefined;
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包
涉及外部主机:api.linear.app

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • shell校验循环
  • 每轮全新上下文

修到通过为止的智能体循环,以 shell 校验为准,可插拔多运行时 worker(Cursor/Cline/OpenCode/Codex/DSH/Pi),每轮迭代都用全新上下文。

v0.8.42026-10-25
从 humanlayer/humanlayer 借鉴两个小改动。 · 标题 · 研究地图对 GOAL 视而不见——templates/RESEARCH.example.md 和 unknowns 预检现在要求分两遍写 RESEARCH.md:先把 GOAL 转成关于代码当前如何运作的中立问题,再在不读 GOAL 和工单的情况下回答这些问题。朝着想要的改动去写的地图,只会找到它预期的东西。 · DSH 插件 0.1.2:不再过滤检查输出——DSH bash 守卫会拒绝把 verify.sh、test、typecheck 或 lint 的输出直接管道给 head/tail/grep/sed/awk(截断会藏住失败,还多耗一轮迭代)。| tee 和过滤已保存的文件仍然允许。用 blockCheckOutputFilter 开关(默认 true)。守卫的 shell 拆分器不再在 & 处拆坏 2>&1。 npm · tag
v0.7.42026-10-19
· 0.7.4 — 2026-10-19 运行时:opencode 可与 OpenCode 2.x 命令行配合使用。仓库若没有本地 opencode-ai 版本锁定,过去会回退到 PATH 上的 2.x opencode,并在服务器启动时超时。 · 头条 · 支持 OpenCode 2.x — harness 会在解析出的二进制上运行 opencode --version(优先仓库 node_modules/opencode-ai,其次 PATH),并通过 @opencode/client 与 2.x 服务器通信;1.x 仍沿用 @opencode-ai/sdk 不变。2.x 更换了服务器 API(Basic 认证、新路由、用 session.execution.* 取代 session.idle),所以 1.x SDK 无法驱动它。用 2.x 命令行时,需执行 pnpm add -D @opencode/client;没装的话循环会直接报出这条安装提示,而不是等 30 秒超时。 · 2.x 服务商密钥改用 OpenCode 的凭据存储 — OpenCode 首次启动时会迁移 v1 的 auth.json;OPENCODE_API_KEY / OPENROUTER_API_KEY / AI_GATEWAY_API_KEY 只添加一次,不再每次运行都加。 · agent-check opencode 会做真实的 serve 握手 — 它启动一个临时服务器,用匹配的客户端发起一次带认证的调用,这样 SDK/命令行不匹配会在检查阶段就失败,而不是拖到第一次循环。以前只凭 opencode --version 就判定通过。 · opencode-go/kimi-k3 重回 Go 目录 — 0.7.2 的排除是错的:OpenCode Go 确实提供 Kimi K3。该 slug 回到 OPENCODE_GO_LOOP_MODELS 和价格表($3/$15,缓存读取 $0.30),设置向导会重新提供它,预算上限也会给它定价。EXCLUDED_MODEL_SLUGS 仍作为应急开关保留,现在为空。 npm · tag
v0.7.32026-10-15
· 0.7.3 — 2026-10-15 OpenCode Go 目录重新同步到 models.dev:已弃用的 DeepSeek V4 Flash 条目被移除,新增两条条目,pnpm sync:models:check 重新通过。 · 头条 · Go 移除已弃用的 Flash slug —— models.dev 现将 opencode-go/deepseek-v4-flash 和 opencode-go/deepseek-v4-flash-vision-exp 标记为已弃用,因此同步时不再收录它们。Go 的 slug 仍按形态做软性限制:仍固定使用其中任一 slug 的循环可以继续运行,但该 slug 没有定价(报告中显示为 $0),预算上限会将其视为未定价的 worker 或升级模型而拒绝。请改用 opencode-go/deepseek-v4.1-flash(默认)或 opencode-go/deepseek-v4-pro。 · Go 新增 gemini-4-argon-contributor 和托管 $0 的 cat-jam-free —— Gemini 4 Argon 属于贡献者层级,价格为 $4/$20,上下文 1M;Cat Jam 是纯文本推理,支持工具调用,价格为 $0。两者都会出现在安装向导中,并配有预先写好的简介。两者都不是 worker 或 judge 的默认值,minmax 仍会跳过 Gemini。 · pnpm sync:models:check 已通过 —— 自上次目录提交以来它一直报告有偏差(cat-jam-free / gemini-4-argon-contributor 加入,已弃用的 Flash slug 移除)。
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
tags: - documentation - agents 智能体循环器(@dancingteeth/agent-looper) 给编码智能体用的「修到全绿」工具。 你给它一个冻结的目标,再加一个你本来就信得过的 verify.sh。它每轮跑一个全新的 worker 智能体,直到检查命令退出码为 0;还可以挂一个 judge,由它审查结果,不合格就把 worker 打回去重做。 可搭配 Cursor、Claude Code、Codex、OpenCode、Cline、Pi、DeepSeek Harness(DSH)和 Muse,用作 worker、judge,或两者兼用。也可以混搭:便宜的 worker 配更强的 judge,这是最常见的组合。 如果你现在就在手动循环: 智能体说做完了,CI 还是红的,你贴日志,再开一个新对话。你自己就是那个验证步骤。这个包做的就是这套循环,只是中间不用你。 落地页: looper.dancingteeth.net(静态站点在 site/)。
展开完整文档(README 剩余 1 节)
tags:
- documentation
- agents

智能体循环器(@dancingteeth/agent-looper)

给编码智能体用的「修到全绿」工具。 你给它一个冻结的目标,再加一个你本来就信得过的 verify.sh。它每轮跑一个全新的 worker 智能体,直到检查命令退出码为 0;还可以挂一个 judge,由它审查结果,不合格就把 worker 打回去重做。

可搭配 Cursor、Claude Code、Codex、OpenCode、Cline、Pi、DeepSeek Harness(DSH)和 Muse,用作 worker、judge,或两者兼用。也可以混搭:便宜的 worker 配更强的 judge,这是最常见的组合。

如果你现在就在手动循环: 智能体说做完了,CI 还是红的,你贴日志,再开一个新对话。你自己就是那个验证步骤。这个包做的就是这套循环,只是中间不用你。

落地页: looper.dancingteeth.net(静态站点在 site/)。

Core CLI only (init, setup, --version). Add the SDK for the runtime you will run:
pnpm add -D @dancingteeth/agent-looper @cursor/sdk # example: Cursor worker/judge
pnpm exec agent-loop-init
pnpm exec agent-loop-setup # pick worker + judge runtimes (one-screen wizard)
or draft a loop from an idea: pnpm exec agent-loop-prompt --out .cursor/loops/my-task
edit GOAL.md
put the check you keep re-running in verify.sh

pnpm exec agent-loop run .cursor/loops/my-task

每个运行时还需要各自的 SDK 或命令行工具和密钥,例如 Cursor 要 @cursor/sdk + CURSOR_API_KEY,Claude Code 要 PATH 里有 claude,OpenCode 要 opencode。docs/runtime-map.md 列出了全部;pnpm exec agent-check <runtime> 可以确认某个运行时已经接好。命令行参数和其他内容见下文。第一次跑出全绿之前,你不需要看这些。

循环是怎么搭起来的:README.intro.md。技术深入解析:ARCHITECTURE.md(含 §1.1 —— 这套 harness 是一张小型控制流图;Ralph 循环跑在 worker 节点内部)。npm 发版:docs/releasing.md。已发布内容:CHANGELOG.md(当前 0.8.5)。把本包作为库依赖嵌入另一个 ADE:docs/embed-api.md。报告漏洞:SECURITY.md。
支持可插拔的 agent SDK worker(runtime)和评审器(reviewRuntime)。目前已内置:Cursor、Cline(Pass / Credits)、OpenCode(Go + BYOK)、Pi、Codex、DSH(PATH dsh)、Muse(PATH muse)、Claude(PATH claude,--safe-mode)。默认值与成本说明见 docs/runtime-map.md。dsh web 的 DSH 配套插件(提供技能 + 脚手架,不是第二个 harness)见 docs/dsh-plugin.md。OpenCode 配套插件(1.x + 2.x:技能、分离式 agent_loop_start、shell 守卫)见 plugins/opencode-agent-looper/。Muse Code 见 docs/muse-runtime.md。Claude Code 见 docs/claude-runtime.md。要在冻结的循环上测量廉价 worker 的说法,见 docs/runtime-cost-bench.md。未设置 reviewRuntime 时,评审器跑在 worker 的 runtime 上(每个 runtime 都有自己的评审模型,例如 OpenCode → DeepSeek V4 Pro,Claude → Opus);设置 reviewRuntime + reviewModel,就能给廉价 worker 配一个不同的评审器。

功能一览

| 层 | 做什么 | 会阻塞完成吗? |
| Worker | 每轮迭代开一个全新的 agent SDK 会话(runtime);按 GOAL.md 实现 | —(负责干活) |
| Verifier | Shell verify / finalVerify(退出码 0)。可选 verifyMode: skill 先跑一个验证智能体(VERIFY_RESULT: PASS/FAIL),再跑 shell。 | 会 — 硬性关卡 |
| Review | 成功后做 LLM 质量评审 → review.md(主评审器由 reviewRuntime 指定,默认 cursor)。可选 reviewGate 只对会拦截的问题重新打开修复循环。 | 仅当 reviewGate: true |
| Human | HITL 检查点(hitlProvider)、reviewGateHitl / hitlCheck / hitlOnFailure、完成通知(Telegram / webhook / notifyCommand / PR 评论) | 收尾 / 告警 |

评审栈(除注明外均需手动开启):

1. 影响-严重度 — 只有 severity: error 且带可识别 impact 标签的问题才拦截(data-loss、security-boundary、false-closure、cross-dispatch、verify-bypass)。表面问题只作提示。
2. 先复现再上报 — reviewReproduce:在改动文件集合里找不到可引用路径的 error+impact 拦截项,直接丢弃。
3. 独立复现智能体 — reviewReproduceAgent:再开一个评审会话,对剩余拦截项做 KEEP/DROP 判定(与主评审器用同一个 reviewRuntime)。
4. 第二评审器 — reviewSecondaryRuntime(任意 worker/评审 runtime):把它的拦截项与主评审器取并集;主评审器为 PASS/ADVISORY 且零拦截时跳过。

工厂级规模: agent-loop-batch(串行 + 元循环 probe→fix)、agent-loop-meta-review(对 N 个 bundle 做只读的跨循环报告)。
运维: 停滞检测、failure-domains.ndjson、Telegram 完成报告、密钥通过环境变量或你的密钥管理器传入(CURSOR_API_KEY、CLINE_API_KEY、OPENCODE_API_KEY、OPENROUTER_API_KEY、AI_GATEWAY_API_KEY、AGENT_LOOP_TELEGRAM_、AGENT_LOOP_CURSOR_TIMEOUT_MS)。

编写验证清单:见 docs/verification-as-skill.md。冻结一份四部分完成线(结果、记分板、权限、预算),外加可选的 golden 产物 —— 见 templates/GOAL.template.md。指标循环:比基线差就回滚 —— 见 templates/GOAL.metric.template.md。视觉 / 品味循环(首页、mockup、截图即主视觉):见 templates/GOAL.visual.template.md。

安装

需要 Node.js 22+。从 npm 安装(云端智能体和任何使用方仓库都能用)。

命令行遥测(需主动开启,默认关闭): 设置 AGENT_LOOPER_TELEMETRY=1,即可向 PostHog EU 发送匿名使用事件(looper_init、looper_run_started、looper_run_finished)。需要 POSTHOG_PROJECT_API_KEY 或 AGENT_LOOPER_POSTHOG_KEY。只发送包版本、运行时、操作系统平台、Node 主版本号、验证通过/失败、耗时和 review-gate 标记 —— 绝不发送仓库路径、提示词或密钥。营销站点 looper.dancingteeth.net 不使用分析像素。

Cursor-only (minimum)
pnpm add -D @dancingteeth/agent-looper @cursor/sdk

Optional workers
pnpm add -D @cline/sdk # Cline Pass / Credits
pnpm add -D @opencode-ai/sdk opencode-ai # OpenCode Go / BYOK (CLI 1.x)
pnpm add -D @opencode/client # …or with an OpenCode 2.x CLI on PATH
pnpm add -D @earendil-works/pi-coding-agent # Pi BYOK
pnpm add -D @openai/codex-sdk # Codex (ChatGPT / OpenAI)
pnpm add -D @muse-code/sdk # Muse Code (PATH muse)

用 pnpm exec(或 npx)调用命令行工具,这样无需全局安装:

pnpm exec agent-loop-init
pnpm exec agent-loop-setup --out .cursor/loops/my-task # Ink TUI; --plain / --answers for agents
pnpm exec agent-loop-prompt --out .cursor/loops/my-task # idea → GOAL/verify draft → freeze → watch
pnpm exec agent-check cursor
pnpm exec agent-loop run .cursor/loops/my-task --runtime cursor --review-gate

快速开始

pnpm add -D @dancingteeth/agent-looper @cursor/sdk
export CURSOR_API_KEY=… # or wrap with your secret manager (Doppler, etc.)

pnpm exec agent-loop-init
Humans: pnpm exec agent-loop-setup --out .cursor/loops/my-task
writes repo defaults (runtime, models, review, notify) into
.cursor/agent-loop.repo.json. Later sparse loop.json files inherit them;
explicit loop.json keys win. Agents skip the TUI — use --answers or copy templates and set verify only.

编辑 .cursor/loops/my-task/GOAL.md + verify.sh

pnpm exec agent-check cursor
pnpm exec agent-loop run .cursor/loops/my-task --runtime cursor --review-gate

其他 worker(先安装对应的可选 peer): bash

ClinePass / Credits

export CLINE_API_KEY=…
pnpm exec agent-loop run .cursor/loops/my-task --runtime cline-pass
pnpm exec agent-loop run .cursor/loops/my-task --runtime cline

OpenCode(需要 PATH 上有 opencode-ai 提供的 opencode)

export OPENCODE_API_KEY=… # and/or OPENROUTER_API_KEY / AI_GATEWAY_API_KEY for BYOK
pnpm exec agent-check opencode
pnpm exec agent-loop run .cursor/loops/my-task --runtime opencode

Pi BYOK

export OPENROUTER_API_KEY=…
pnpm exec agent-check pi
pnpm exec agent-loop run .cursor/loops/my-task --runtime pi
pnpm exec agent-loop run .cursor/loops/my-task --runtime pi --review-runtime pi --review-gate

Codex(需要 SDK 提供的 codex 命令行,来自 @openai/codex)

export CODEX_API_KEY=… # or OPENAI_API_KEY / ChatGPT login
pnpm exec agent-check codex
pnpm exec agent-loop run .cursor/loops/my-task --runtime codex

DeepSeek Harness(需要 PATH 上有 dsh;Node ≥ 22.15)

export DEEPSEEK_API_KEY=… # or DSH credentials-local
pnpm exec agent-check dsh
pnpm exec agent-loop run .cursor/loops/my-task --runtime dsh

runtime: docs/dsh-runtime.md — dsh web companion: docs/dsh-plugin.md

Muse Code(需要 muse 命令行 + @muse-code/sdk)

export META_API_KEY=… # optional; muse login is enough
pnpm exec agent-check muse
pnpm exec agent-loop run .cursor/loops/my-task --runtime muse

Claude Code(需要 PATH 上有 claude 2.1.169+;claude login)

leave ANTHROPIC_API_KEY unset so -p uses subscription quota

pnpm exec agent-check claude
pnpm exec agent-loop run .cursor/loops/my-task --runtime claude

typical: cheap worker + Claude judge — docs/claude-runtime.md

指定另一个 checkout: bash
pnpm exec agent-loop run /path/to/repo/.cursor/loops/fix-foo --repo-root /path/to/repo

使用方脚本示例: json {
"scripts": {
"agent:loop": "doppler run -- agent-loop run",
"agent:check": "doppler run -- agent-check cursor",
"agent:init": "agent-loop-init"
}
}

维护 Harness 本身、要开发这个仓库的人:用 pnpm build 构建本地 dist/,再通过 pnpm agent:loop 运行(见 docs/dogfood.md)。发布 / 可信发布:docs/releasing.md。

仓库配置档

.cursor/agent-loop.repo.json:

| 字段 | 用途 |
| taskwarriorProject | 当 hitlProvider 为 taskwarrior 时,HITL 使用的 Taskwarrior 项目 —— TW HITL 必填 |
| hitlProvider | taskwarrior(默认)、file、github、linear 或 command —— 见 docs/hitl-providers.md |
| hitlFileDir | file 服务商的目录(默认 .cursor/hitl) |
| hitlCommand | command 服务商使用的 shell |
| hitlLinearTeam | 当 hitlProvider 为 linear 时,Linear 团队 key 或 id |
| syncCommand | 成功后执行的 Shell(或 null) |
| notifyCommand | 可选,每次 CLI 退出时执行的 Shell(LOOP_ 环境变量) |
| notifyWebhook | 可选,发送 JSON POST(url 或 AGENT_LOOP_NOTIFY_WEBHOOK_URL) |
| notifyPrComment | CLI 退出后在打开的 PR 上留言(gh pr comment) |
| defaultBranch | 循环结束后的 diff 基准(main) |
| agentsFile / reviewsFile | 提示词与评审叠加层的路径 |
| loopRiskProfile | 可选,为 postQualityReview: "auto" 合并关键词(见 REVIEWS.md ## Loop risk inference) |
| skillsGlob | 系统提示词里的技能提示 |
| clientName | Cline 客户端标签 |
| telegramNotify | 可选,chat id + onSuccess / onFailure |

loop.json 里可按循环覆盖:taskwarriorProject、taskwarriorUuid、hitlCheck、hitlOnFailure、requireNotify,以及可选的 hitlProvider / hitlFileDir / hitlCommand / hitlLinearTeam。

Taskwarrior: 在 GOAL.md 和 loop.json 的 taskwarriorUuid 里用 UUID —— 数字 ID 会被回收。成功且开启 syncOnSuccess 时,harness 会把该 UUID 标记为完成。

循环包 text .cursor/loops/my-task/ GOAL.md # frozen spec (four-part finish line + optional golden) RESEARCH.md # optional — frozen brownfield map (indexed in the worker prompt) loop.json # verify, runtime, optional taskwarriorUuid verify.sh # measurable shell checks (exit 0 = pass; 75 / 127 = env) setup.sh # optional — harness bootstrap before the first worker VERIFY.skill.md # agent-readable verify procedure (optional; required for verifyMode: skill) log.ndjson # append-only iteration log (runtime) assistant.stream # live token/thinking tail for watch (runtime) run-report.md # report card + iteration timeline (when exportRunReport) transcript.ndjson # tool timeline (when exportTranscript) setup.log # optional — bootstrap evidence (runtime) verify-logs/ # optional — sidecar verify stdout/stderr (verifyLogMode) failure-domains.ndjson # optional — stagnation / max iterations / gate exhaust failure-context.md # optional — written by meta-loop probe for fix loop lessons.md # optional — verify gotchas from prior green runs (harness-owned)

验证(verify / verifyMode)

| 字段 | 默认值 | 用途 |
| verify | (必填) | 每轮迭代执行的 Shell 命令(通常是 bash …/verify.sh)。退出 0 = 通过。退出 75(EX_TEMPFAIL)、退出 127(找不到命令),或输出 VERIFY_CLASS=env 行,都会挂起为环境限制(status: waiting,HITL)—— worker 不再迭代。其他非零退出属于产品失败,循环继续。 |
| verifyMode | command | command = 仅 shell。skill = 验证智能体读取 verifySkill,输出 VERIFY_RESULT: PASS/FAIL,PASS 后再运行 shell verify。技能验证与 worker 使用同一个迭代智能体(推理阶梯 / escalateModel 生效)。 |
| verifySkill | — | VERIFY.skill.md 的路径(verifyMode 为 skill 时必填)。 |
| finalVerify | — | 内层 verify 通过后,再做更严格的外层检查。 |
| verifyLogMode | sidecar | 验证的 stdout/stderr 如何传给下一个 worker。sidecar(默认)写入 <loop-dir>/verify-logs/,并在提示词里放一段偏向尾部的预览和路径。inline 只粘贴内存中捕获的内容(过长时取头+尾)。 |

默认是 sidecar,这样 vitest/Playwright 刷屏末尾的失败仍然可见,又不会撑大每条提示词。验证输出总是很短时,设 "verifyLogMode": "inline"。写入 sidecar 之前,内存捕获有上限(约 64KB,取头+尾)。

旧版 loop.json 字段 syncPostgres 映射到 syncOnSuccess。

loop.json — 循环控制

| 字段 | 默认值 | 用途 |
| runtime | cursor | Worker:cursor \| cline-pass \| cline \| opencode \| pi \| codex \| dsh \| muse \| claude。设了 costPreset 时留空,好让检测来绑定。见 docs/runtime-map.md。同任务成本方法:docs/runtime-cost-bench.md。 |
| costPreset | — | 命名的 worker+judge 组合:minmax(效率优先——最便宜的够用 worker + 包含的最强 judge;装了 Cursor 就用 Grok)、balanced(升级档 worker,同一 judge)、cursor(Composer + Grok)。解析时若 runtime/model 未设,按检测绑定;显式键优先。不是 Auto。 |
| model / escalateModel | (默认值) | Worker 模型;验证器出现相同停滞时升级,或 worker 挂起/超时后立即升级(OpenCode/Pi/Codex/DSH/Muse/Claude:超过阈值后;Cline:超过推理上限后——worker 自身故障则跳过上限)。Cursor worker 固定是 Composer 2.5,没有升级 slug——省略 escalateModel(仓库默认值里漏出的 Go 升级档会被丢弃)。judge 是 reviewRuntime / reviewModel,不是 escalateModel。 |
| maxIterations | 8 | 实现迭代次数上限。 |
| setup | — | Harness 引导 shell,在第一个 worker 之前运行一次。未设置时,若 GOAL.md 旁边存在 setup.sh 就用它。失败则置 status: waiting(不启动 worker),并在 setup 改动了冻结的 spec 文件时恢复它们。模板:templates/setup.example.sh。 |
| maxCostUsd | — | 预算金额的美元上限:runtime 报告金额大于 $0(PAYG)时按实际账单,否则按 API 标价,这样 $0 的订阅额度也能拦住。两者不同时,watch/report 会同时显示标价和账单(--max-cost)。省略 = 不设上限。 |
| stagnationThreshold | 3 | 验证器连续 N 次相同失败后停止(0 = 关闭)。 |
| mode | forward | reverse = 净室重建(templates/GOAL.reverse.template.md) |
| pauseAfterIteration | false | 每轮迭代后等待按 Enter(仅 TTY) |
| injectFailureContext | false | 把 failure-context.md 读进提示词(元循环修复轮) |
| lessons | false | 可选开启:读写 lessons.md —— 记录早前绿灯运行中踩过的验证坑,有界,以数据形式引用在稳定提示词头部 |
| deliverables | — | worker 必须创建的仓库相对路径文件(绝对路径或 .. 路径会被拒绝);缺失或为空时,harness 在验证前重新提示 |
| deliverableNudges | 2 | deliverables 仍缺失时,每轮迭代最多额外调用 worker 的次数(0–5) |
| syncOnSuccess | true | 成功后运行仓库配置档的 syncCommand |
| notifyTelegram | true | 配好 Telegram 环境变量和配置档后,发送完成报告 |
| telegramAttachReview | true | 把 review.md 作为第二条 Telegram 消息附上 |
| hitlOnFailure | false | 循环结束时仍未完成,就打开 HITL 检查点 |
| requireNotify | false | Telegram 预检失败就中止(也可用 --require-notify) |
| completionSignal | true | 命令行退出时向 stdout 输出 AGENT_LOOP_DONE(本地 Cursor 唤醒;Cloud Agents 暂时还挂不上 watcher) |
| notifyCommand | — | 为本轮循环覆盖仓库配置档的 notifyCommand |
| exportPack | true | 把整理好的产物复制到 .cursor/loop-exports/<slug>/(方便提交) |
| notifyPrComment | — | 为本轮循环覆盖配置档的 notifyPrComment |
| preview | — | 可选的本地预览 shell;agent-loop-prompt 会做信任校验,并在成功 grind 后运行它(agent-loop run 不执行) |
| reasoningEffort | — | low \| medium \| high \| xhigh \| none,前提是运行时支持(Cline、Pi、Muse)。省略或 none = 不额外思考。Cursor / OpenCode / Codex / DSH / Claude 会忽略它。 |
| escalateReasoningEffort | — | 推理阶梯上限(支持的运行时同 reasoningEffort)。对 worker 和 skill-verify 都生效。 |
| reasoningEscalationStep | 1 | 每轮迭代提升的档数(1 或 2) |
| escalateModelReasoningEffort | — | 升级模型上的推理档位 |
| escalateAfterStagnation | 2 | 切换模型前允许的相同失败次数(在推理上限之后)。worker 超时 / 无工具停滞会立即切换,不等这个计数。 |
| stallProbes | false | 设为 true 后,相同失败第一次触发 escalateAfterStagnation 时,harness 会启动两个引导方式不同的探测 worker(一个给流程提示,一个给仓库事实),保留更好的工作区,然后恢复正常升级流程——每次运行最多一次。工作区快照存为 git 对象(worktree + index,不用 stash);恢复时放回分支和 HEAD,只重写有差异的路径,不跟随符号链接,保留文件权限,不删除快照忽略规则所忽略的路径,也不删除 .cursor/loops/ 下的内容。限制: 被忽略的文件不会进快照;恢复会回滚探测轮次中的所有改动——每个 worktree 只跑一个循环,探测运行时不要编辑。 |
| skills | — | 显式指定 …/SKILL.md 路径(与 GOAL 中的引用合并)。默认提示词是索引(名称、描述、路径)——worker 需要时自己 Read 文件。 |
| skillDisclosure | index | index = 渐进式披露(0.4.0 默认;0.3.0 始终内联)。inline = 粘贴完整 SKILL.md 正文。任何必须保留旧版提示词内 runbook 的循环,都要固定这个字段。 |
| plugins | — | Agent Plugins 包目录——会发现 skills//SKILL.md(docs/agent-plugins.md) |
| research | — | 可选,指向冻结的 brownfield 地图。不设置时,只要 GOAL.md 旁边存在 RESEARCH.md,harness 就会索引它。提示词里只放路径和一行说明(worker 自己 Read);正文不内联。模板:templates/RESEARCH.example.md。 |

loop.json — 审查与质量

| 字段 | 默认值 | 用途 |
| postQualityReview | auto | 运行循环后审查(true / false / auto,按推断的风险决定) |
| reviewRisk | auto | 为 postQualityReview: "auto" 覆盖推断出的风险(high / medium / low) |
| loopRiskProfile | — | 按循环合并关键词,用于风险推断(high / medium / low 数组) |
| reviewGate | false | 设为 true 后,阻断性审查问题会重新进入修复循环(最多 maxReviewCycles 次) |
| reviewRuntime | worker 的 runtime | 主评审运行时(枚举同 runtime)。不设置 → 用 worker 的运行时及其默认评审模型。 |
| reviewModel | (自动解析) | reviewRuntime 的评审模型。Cursor 默认:worker 为 cursor 时用 grok-4.7,否则用 composer-2.5(Grok 4.6 和 4.5 仍可用)。OpenCode 评审(reviewRuntime: "opencode")默认 opencode-go/deepseek-v4-pro(worker 仍用 Flash)。DSH 评审(reviewRuntime: "dsh")默认 deepseek-official/deepseek-v4-pro。Codex 评审(reviewRuntime: "codex")默认 gpt-5.6-sol(worker 仍用 Luna;可选 gpt-6-astra)。Muse 评审(reviewRuntime: "muse")默认 muse-spark-1.3(worker 仍用 contributor)。Claude 评审(reviewRuntime: "claude")默认 opus(Claude Code 最新的 Opus,目前是 Opus 5;worker 仍用 Sonnet)。Pi / Cline 评审用该运行时的 worker 默认值。cursor 上绝不用 Composer Fast。 |
| maxReviewCycles | 2 | reviewGate 开启时,评审触发的修复轮数 |
| reviewGateHitl | false | 门禁耗尽时,打开 HITL 检查点(hitlProvider),而不是只做硬失败 |
| unparseableReviewRetries | 2 | 无法解析评审结论时的重试次数 |
| reviewBlockerRecheck | true | 在 BLOCKERS 修复轮中,改用范围更小的轻量复查 |
| reviewReproduce | false | 对 error+impact 类阻塞项做路径过滤(变更文件集) |
| reviewReproduceAgent | false | 对门禁阻塞项启动全新的 KEEP/DROP 会话(需开启 reviewReproduce;使用主 reviewRuntime) |
| reviewSecondaryRuntime | (未设置) | 第二复核判官(cursor \| cline-pass \| cline \| opencode \| pi \| codex \| dsh \| muse \| claude);未设置 = 关闭 |
| reviewSecondaryModel | (默认) | 二次评审使用的模型(按该 runtime 的默认值) |
| trustConfig | false | 把本循环的 shell 命令标记为已预审(配合 --trust-config 门禁使用)。仅在严格模式(--require-trust-config)下生效;默认情况下,未受信任的命令只警告,仍会执行。 |
| exportRunReport | true | 循环结束时写出 run-report.md(评分卡 + 时间线) |
| exportTranscript | true | 把工具事件记录到 transcript.ndjson,把每轮的工具计数记录到 log.ndjson |

阻塞项语法:从 templates/REVIEWS.md 分发 REVIEWS.md。库:reviewVerdictAllowsCompletion 接收完整的 ParsedReview,用于影响严重度门禁。

loop.json — 保留字段(实验性)

这些字段能在 loop.json 中通过校验,但对应的流水线钩子尚未执行。
配置了这些字段时,harness 每次运行(命令行、批处理、直接调用库)都会记录一条 loop extension preflight 提示 —— 不要指望它们能拦住任何东西:

| 字段 | 状态 |
| smokeScripts | 保留 —— 验证后钩子未实现 |
| siblingRepos | 部分接通 —— 记录到 log.ndjson;跨仓库验证未实现 |
| verifyPreflight | 保留 —— 未实现 |

postQualityReview: "auto" 与循环风险

当 postQualityReview 为 "auto"(默认)时,harness 根据 GOAL.md 中的关键词和 verify 命令推断风险等级为高 / 中 / 低。等级不是 low 时才运行评审。
reviewGate: true 则始终运行评审,不受等级影响。

合并顺序(每一层追加关键词;先匹配者胜,按高 → 中 → 低):

1. Harness 默认值(loopRiskProfile.ts 中的 DEFAULT_LOOP_RISK_KEYWORDS)
2. REVIEWS.md → ## Loop risk inference → ### HIGH / MEDIUM / LOW
3. .cursor/agent-loop.repo.json → loopRiskProfile
4. loop.json → loopRiskProfile(按循环合并)

完全覆盖推断结果:在 loop.json 中设置 "reviewRisk": "high" | "medium" | "low"。

不运行循环,先预览: bash agent-loop-review-preview .cursor/loops/my-task

仓库覆盖配置示例(agent-loop.repo.json;完整示例见 templates/agent-loop.repo.json.example): json {
"loopRiskProfile": {
"high": ["stripe-webhook", "crm-admin"],
"medium": ["checkout"],
"low": ["copy-only"]
}
}

单循环覆盖示例(loop.json): json { "postQualityReview": "auto", "reviewRisk": "auto",
"loopRiskProfile": { "high": ["payment-refund"] }
}

命令行覆盖:--mode reverse、--pause-after-iteration、--review-gate、--no-telegram、--review-runtime <id>、--review-model <id>、--review-secondary-runtime <id>、--review-secondary-model <id>。

评审门禁流程

当 reviewGate: true 且 verify 通过时: text primary review (reviewRuntime + reviewModel) → optional reviewReproduce path filter → optional reviewReproduceAgent KEEP/DROP → optional reviewSecondaryRuntime merge (verdict merge, not error fallback) → gating blockers remain? → fix iteration (up to maxReviewCycles) → else PASS / ADVISORY → complete

如果主评审会话出错(超时、服务商故障、只有文本没有工具调用),harness 会重试一次,然后把 reviewSecondary 当作兜底评审跑一遍(不再对同一模型做第二轮合并)。两者都失败时,本次运行挂起(status: waiting,命令行退出码 2,failure-domains.ndjson 记录原因 review_judge_failed)——此时 verify 已经通过。

无法解析的裁决会重试(unparseableReviewRetries)。门禁耗尽可以升级到 HITL(reviewGateHitl)。门禁条目(severity: error 加一个可识别的影响标签)会让门禁保持开启,即使同一个 review.md 后面又出现 ### Verdict — PASS 标题。标题与正文的 token 结论不一致、又没有门禁条目时,视为无法解析。

run-report.md 包含计费 token 行(按 worker 与 judge 分别列出未缓存输入 / 输出 / 缓存读取 / 缓存写入),以及一张预期工具错误表——只要有会话记录到 tool_end 失败或纯文本工具停滞,就会出现这张表。

对齐 Ralph loop

实现 Ralph loop 模式:

- 单体式 —— 一个仓库、一个进程、每轮一个任务
- 每轮迭代都用全新上下文;进度落在文件和 git 里
- Shell 背压(verify / finalVerify)作为确定性的完成信号
- 验证即技能 —— verify.sh + VERIFY.skill.md;可选 verifyMode: skill
- 盯住循环 —— log.ndjson、run-report.md、transcript.ndjson、停滞检测、可选 --pause-after-iteration
- 完成哨兵 —— 命令行退出时向 stdout 打印 AGENT_LOOP_DONE {…}(供挂接的本地 Shell notify_on_output 或日志 grep 使用;不要把任务放到后台——见下文)
- 失败域 —— 停滞、达到最大迭代次数或评审门禁耗尽时写入 failure-domains.ndjson
- 元循环 —— 探测 → failure-context.md → 修复 → 再探测

正向 = 增量修复直到全绿。反向 = 干净房间式的提示词引导;用 verify 和 GOAL.md 约束范围。

元循环(探测 → 修复 → 再探测)

在 loop-batch.json 中: json {
"metaLoop": {
"probe": "system-smoke",
"fix": "fix-from-smoke",
"maxCycles": 3
},
"hitlCheck": "Manual QA after meta-loop",
"taskwarriorProject": "my-project"
}

循环:探测 → 失败时把 failure-context.md 写进修复包 → 用 injectFailureContext 修复 → 重新探测。探测通过或 maxCycles 耗尽时停止。见 templates/loop-batch.meta.example.json。

顺序批处理与逐项评分标准

loops[] 里每一项要么是同级循环的名字/路径(字符串),要么是 { "path": "...", "rubric": "..." }。设了 rubric 时,批处理运行器会往该循环的 worker 提示词里注入一段易变的 Batch rubric 小节;shell verify 仍是退出闸门。见 templates/loop-batch.example.json。

跨循环元评审

对 N 个循环包做只读聚合(不会重跑 worker,也不会翻转各循环的 complete 标志): bash agent-loop-meta-review .cursor/loops --out-dir /tmp/meta-out agent-loop-meta-review .cursor/loops --review-runtime opencode --review-model openrouter/anthropic/claude-sonnet-4 agent-loop-meta-review .cursor/loops/a .cursor/loops/b --hitl --project my-project

收集最新的 review.md、log.ndjson、failure-domains.ndjson,以及与 defaultBranch 的 diff 统计。循环内文件缺失时(云端 clone 后常见——这些路径被 gitignore 了),回退到 .cursor/loop-exports/<slug>/。提示词说明:docs/meta-review-prompt.md。

命令行

| 命令 | 说明 |
| agent-loop run <dir> | 单个循环 |
| agent-loop watch <dir> | 实时进度:Ink 监视视图(TTY)或结构化阶段行;--snapshot / --pulse 打印一帧后退出。Ink 里按 s 刷新 pid/log/stream 健康状态;助手 token 与 Cursor thinking/tools 在面板里滚动显示。 |
| agent-loop-batch <dir> | loop-batch.json 顺序执行或元循环 |
| agent-check cursor\|cline\|opencode\|pi\|codex\|dsh\|muse\|claude | SDK + API key 冒烟检查(dsh:PATH 命令行 + Node ≥ 22.15;muse:PATH muse + @muse-code/sdk;claude:PATH 命令行 2.1.169+ + --safe-mode,不消耗配额) |

| agent-loop-init | Scaffold templates + check-running-loops skill (.cursor/skills and .agents/skills) |
| agent-loop-setup | Ink TUI / --plain / --answers wizard: repo defaults in .cursor/agent-loop.repo.json plus loop.json for --out |
| agent-loop-prompt | Ink TUI: type an idea → judge scaffolds GOAL/verify → freeze lint + confirm → agent-loop run watch; optional preview after success. Failed runs print a Doppler-wrapped resume when DOPPLER_PROJECT / DOPPLER_CONFIG are set. |
| agent-loop-doctor | Validate install / dist/ integrity; model pricing drift vs CLINE_PASS_LOOP_MODELS |
| agent-loop-meta-review | Cross-loop meta-review (read-only) |
| agent-loop-review-run | Post-loop quality review for one bundle |
| agent-loop-review-preview | Preview review risk / prompt |
| agent-loop-export-run | Regenerate run-report.md from log.ndjson (+ optional transcript.ndjson) |

Architecture
text
GOAL.md + loop.json
→ fresh worker agent
→ verify (command or skill + command)
→ optional review gate
→ log.ndjson
→ run-report.md (+ transcript.ndjson when enabled)
→ .cursor/loop-exports/<slug>/ (curated pack; commit-friendly)
→ repeat

Post-success (when postQualityReview runs): quality review → review.md using the repo REVIEWS.md overlay. With reviewGate: true, only gating blockers re-enter the fix loop; a quoted ### Verdict — PASS cannot close the gate while those bullets remain. Completion requires PASS or ADVISORY with no gating blockers. Then: optional linked-task completion (e.g. Taskwarrior done) → hitlCheck (via hitlProvider) → syncCommand.

Stderr prints token totals and estimated USD (ClinePass may include cached-input counts).

| Layer | Role | Blocks loop? |
| Shell verify / finalVerify (+ optional skill pre-pass) | Deterministic judge | Yes |
| postQualityReview (no gate) | Advisory LLM | No |
| reviewGate: true | Gate on gating blockers / unparseable verdict | Yes |

Threat model

For trusted checkouts you control:

- verify / finalVerify / syncCommand run via shell: true — malicious config = arbitrary shell.
- Verifier stdout/stderr is injected into the next worker prompt (soft guardrails only).
- On start, the CLI prints configured shell commands and flags obvious exfil patterns (curl, wget, | sh, backticks, $()).

Trust gate (opt-in strict mode):

- Default is permissive: the run proceeds after printing the warning + tip (--trust-config after review). Nothing is blocked unless you enable strict mode below — do that before running loop bundles you did not author.
- --require-trust-config or AGENT_LOOP_REQUIRE_TRUST_CONFIG=1: abort unless you pass --trust-config, set trustConfig: true in loop.json, or AGENT_LOOP_TRUST_CONFIG=1.
- Dogfood / CI: set trustConfig: true on known-safe loop bundles, or export AGENT_LOOP_TRUST_CONFIG=1 in Doppler.

Only run on repos and loop bundles you trust. Review loop.json and .cursor/agent-loop.repo.json first.

Environment variables

| Variable | Role |
| CURSOR_API_KEY | Cursor SDK auth (worker and/or default judge) |
| CLINE_API_KEY | Cline SDK auth (optional peer runtime / secondary judge) |
| OPENCODE_API_KEY | OpenCode Go auth (optional peer; https://opencode.ai/go) |
| OPENROUTER_API_KEY | OpenRouter BYOK for OpenCode / Pi workers and judges (including :free slugs) |
| AI_GATEWAY_API_KEY | Vercel AI Gateway BYOK for OpenCode (vercel/… models; harness auth.set) |
| CODEX_API_KEY / OPENAI_API_KEY | Codex SDK auth (optional; else ChatGPT CLI login) |
| META_API_KEY | Muse Code Model API (optional; else muse CLI login) |
| AGENT_LOOP_VERBOSE | 1 / true — extra stderr stream detail |
| AGENT_LOOP_CURSOR_TIMEOUT_MS | Cursor run timeout in milliseconds (default 2700000 = 45m). Must be a positive number; validated before Agent.create so a bad value fails without burning a paid run. On timeout the harness cancels the remote run. |
| AGENT_LOOP_MUSE_TIMEOUT_MS | Muse run timeout in milliseconds (default 2700000 = 45m). On timeout the harness closes muse serve immediately. |
| AGENT_LOOP_TRUST_CONFIG | 1 — treat shell config as reviewed/trusted |
| AGENT_LOOP_REQUIRE_TRUST_CONFIG | 1 — abort unless trust is set (CLI / env / loop.json) |
| AGENT_LOOP_TELEGRAM_BOT_TOKEN | Telegram bot token (fallback: TELEGRAM_BOT_TOKEN) |
| AGENT_LOOP_TELEGRAM_CHAT_ID | Telegram chat id (or telegramNotify.chatId in the repo profile) |
| AGENT_LOOP_NO_COMPLETION_SIGNAL | 1 — skip AGENT_LOOP_DONE stdout line on CLI exit |
| AGENT_LOOP_NOTIFY_WEBHOOK_URL | JSON webhook URL when notifyWebhook is enabled without inline url |
| AGENT_LOOP_PR_NUMBER | PR number for notifyPrComment (fallback: GH_PR_NUMBER, then gh pr view) |

Telegram completion reports

On finish (success or failure), optional short report:

- Status, repo, bundle/batch, iterations, reason
- Token/cost line
- Review verdict when present
- Last verifier snippet on failure

Optional second message: attach review.md as a document. Opt out with "telegramAttachReview": false or profile "attachReview": false.

Setup:

1. Bot token in env: AGENT_LOOP_TELEGRAM_BOT_TOKEN (or TELEGRAM_BOT_TOKEN)
2. Chat id: AGENT_LOOP_TELEGRAM_CHAT_ID or telegramNotify.chatId in the repo profile
3. Inject secrets the same way you already run the loop (doppler run, direnv, CI secrets, …)

Opt out: "notifyTelegram": false or --no-telegram. Notify send failures are non-blocking for exit code, but if Telegram was configured and a failure report did not land, the harness opens a HITL checkpoint (notify_failed) via hitlProvider. Use --require-notify / requireNotify: true to abort before the loop when getMe preflight fails.

Running from Cursor chat

Cursor’s agent Shell is not a terminal. block_until_ms: 0 (or the IDE background button) is a child the IDE reaps at ~5 minutes (status: aborted, exit_code: unknown, often pnpm 255) while the worker is still mid-turn. That is not the harness: TTFB stall is 3 min with no events; OpenCode no-tool stall is 8 min of text without tools; overall timeout is 45 min*.

If you are the agent in this chat, you start the loop. Do not print a command and tell the human to run it. Walk-away is not your fallback.

| Intent | How |
| This chat (default) | Shell attached: block_until_ms ≥ 45m (2700000). notify_on_output on ^AGENT_LOOP_DONE . |
| Human asked to walk away | Their terminal (pnpm agent:loop …). Telegram / HITL / webhook wake them. |

Never block_until_ms: 0 for agent-loop or agent-loop-batch. Re-attach after an abort; do not treat it as a harness failure.

AGENT_LOOP_DONE is a stdout sentinel for an attached watcher or log grep. Opt out: --no-completion-signal, "completionSignal": false, or AGENT_LOOP_NO_COMPLETION_SIGNAL=1.

Example payload:
text
AGENT_LOOP_DONE {"v":1,"kind":"loop","bundle":".cursor/loops/my-task","complete":true,"exitCode":0,"reason":"Verifier passed (exit 0).","iterations":2,"runReport":".cursor/loops/my-task/run-report.md"}

exitCode in the JSON matches the CLI process exit code:

| Code | Meaning |
| 0 | Success (complete: true) |
| 1 | Fatal harness error (uncaught throw, bad argv) |
| 2 | Incomplete or parked — verify/review gate/stagnation (status: continue) or human/provider park (status: waiting; budget, env/setup, judge unavailable, transient worker cap; complete: false) |

Human logs stay on stderr; the sentinel is written with fs.writeSync(1, …) so piped stdout is not lost before process.exit. Side channels (notifyWebhook / notifyCommand / PR comment) run after the sentinel and are time-capped so a hung hook cannot delay wake.

Cloud Agents

Cloud Agent Shell does not expose notify_on_output today, so this chat cannot attach a regex watcher even though the harness still emits AGENT_LOOP_DONE. Until Cursor adds that (or an equivalent wake), treat cloud completion as:

- notifyWebhook — JSON POST to Slack/Discord/n8n (AGENT_LOOP_NOTIFY_WEBHOOK_URL in Doppler)
- notifyPrComment: true — gh pr comment on the branch PR (set when the cloud agent already opened a PR)
- Telegram (notifyTelegram + env; --require-notify to fail closed)
- HITL (hitlOnFailure, Linear / file / github with an issue-capable token)
- Export packs — commit or attach .cursor/loop-exports/<slug>/ so meta-review and humans can read reviews without gitignored mid-run files

Do not promise in-chat wake from AGENT_LOOP_DONE on Cloud Agents.

Export packs (cloud / PR audit)

In-loop review.md / log.ndjson / run-report.md / verify-logs/ stay gitignored (noisy mid-run). agent-loop-init adds a block for loop artifacts including .cursor/loops//verify-logs/. When exportPack: true (default), each finished loop also writes a curated snapshot to:
text
.cursor/loop-exports/<slug>/
SUMMARY.md
meta.json
run-report.md # when present
review.md # latest review when present
log-tail.ndjson # last ~40 log lines
failure-domains.ndjson

Commit that directory (or attach it on the PR) so cloud clones and meta-review are not a black box. Cloud agent tip: after the loop, git add .cursor/loop-exports && git commit && git push on the loop branch. Batch completion webhooks/PR comments list every existing child export pack (comma-separated / bullet list). Packs are skipped when the loop dir is outside the repo (vitest tmpdirs) so .cursor/loop-exports does not fill with ..__var__folders__… slugs.

notifyWebhook + PR comments

Repo profile:
json
{
"notifyWebhook": { "onSuccess": true, "onFailure": true },
"notifyPrComment": true
}

Put the URL in Doppler as AGENT_LOOP_NOTIFY_WEBHOOK_URL (or set notifyWebhook.url). Payload is JSON (v, kind, bundle, complete, exitCode, reason, exportPack, …). POSTs are aborted after ~8s; stderr logs redact query/hash from the URL.

notifyPrComment runs gh pr comment for the current branch’s PR (or AGENT_LOOP_PR_NUMBER). Same gh auth as GitHub HITL — works with a user/PAT that can comment; GitHub App tokens often can comment on PRs even when they cannot issue create.

notifyCommand (shell fallback)

Optional shell with LOOP_ env (LOOP_EXPORT_PACK, LOOP_RUN_REPORT, …) when you need custom logic beyond JSON webhook. Non-blocking; ~15s timeout; shell-trust gated. Opt out: --no-notify-command.

License

MIT
预览分享卡片长什么样 ↓dancingteeth/agent-looper
分享 · DeepSeek Harness Hub
dancingteeth/agent-looper

智能体循环器@dancingteeth/agent-looper

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部