📍 无忆研习社 › 开源解码 › gnhf 深度解析:让 AI 编码助手在你休息时自动提交代码的开源编排器

gnhf 深度解析:让 AI 编码助手在你休息时自动提交代码的开源编排器

摘要:gnhf 是一款基于 Git 纪律的 AI 编码 Agent 编排器,能让 Claude Code、Codex 等主流编码助手在无人值守下持续迭代工作,每次成功改动生成独立 Git 提交,失败自动回滚,通过 notes.md 跨迭代共享上下文,只需一行命令即可实现代码重构、补充测试等机械性工作的高效自动化。
字号 100%
行距 2.05
当前可见 60% 的内容
莫潇羽 @ 无忆研习社(www.wuyi.wiki)原创文章,转载请注明出处。

快速摘要

核心结论:gnhf(good night, have fun)是一款基于 Git 纪律的 AI 编码 Agent 编排器,它能让 Claude Code、Codex、GitHub Copilot CLI 等主流编码助手在无人值守的情况下持续迭代工作。每一次成功的改动都会生成一个独立的 Git 提交,失败则自动回滚,全程通过 notes.md 维持跨迭代的上下文共享。只需在终端输入一行命令并设定目标,第二天醒来就能看到一个充满干净提交记录的专用分支。

关键信息速览:

  • 安装方式:npm install -g gnhf,需要 Node.js 20+
  • 核心机制:状态机迭代循环 + Git commit/reset + notes.md 共享记忆
  • 支持 Agent:Claude Code、Codex、Rovo Dev、OpenCode、GitHub Copilot CLI、Pi
  • 适用场景:重构降复杂度、补充测试、清理重复逻辑等机械性重复工作

往下看有每个模块的详细原理拆解与操作说明。


一、一个真实的开发困境:机械性工作该怎么处理

相信很多开发者都遇到过这样的情况:有一批代码质量需要提升,比如某个模块测试覆盖率为零,或者有大量重复的逻辑片段散落在各个文件里,又或者某个核心函数的复杂度已经高得令人头疼——明明知道该做,但每次打开编辑器面对这些工作,总感觉又重复又枯燥,不如先去做那些更有意思的新功能。

这类工作有一个共同的特征:它们不需要创造性的设计决策,不需要深入理解业务,只需要大量耐心和时间。给一个函数拆分成更小的单元,给一组相似的代码提取公共逻辑,为一个类补上单元测试——这些事情 AI 编码助手完全有能力处理,但你必须守在旁边,一遍遍地接受结果、提交代码、再发出下一个指令。

更麻烦的是,AI 编码助手处理大型任务时经常遇到上下文窗口的限制。一次对话只能处理有限的代码量,当你需要在一个几万行的代码库里做系统性重构时,人工介入、切分任务、维持上下文连续性,这些本身就成了额外的负担。

举个具体的例子:假设你接手了一个几年前的 Node.js 项目,代码风格混乱,有几百个函数都缺少 JSDoc 注释,还有大量用 var 声明的变量、嵌套三四层的回调函数、以及一堆没有测试的工具函数。你打开 Claude Code,对话到第十个函数的时候,Token 窗口已经开始变长,Agent 开始"忘记"之前的改动,你不得不重新解释一遍背景。与此同时,你还要手动在每次改动后跑一遍测试,确认没有引入 Bug,然后再手动 commit,再告诉 Agent 继续下一个函数。这种重复性的机械操作,本质上是用你宝贵的时间来充当一个"胶水层",把 AI 的能力粘合到项目的工作流上。

也有人尝试直接把目标丢给 AI 然后离开,结果回来发现 AI 在某个中间步骤卡住了,或者虽然"完成"了但工作区里全是混乱的未提交改动,根本无法追溯哪一步是正确的。更糟糕的情况是,AI 对后面的函数做了修改,却不小心引入了一个错误,而因为整个过程没有中间提交点,你不得不逐行 diff 才能找出问题所在。

这种痛点在中大型项目里尤为突出:代码库越大,需要 AI 处理的技术债越多,人工维持 AI 工作流所需要的时间就越长,反而把"效率工具"变成了"效率负担"。

gnhf 正是为了解决这个具体问题而生的。它的设计者把这款工具命名为 "good night, have fun",含义相当直白:晚上临睡前告诉它目标,然后放手去睡觉,有什么结果明天起来再看。

这种设计理念不算新鲜,它借鉴了软件工程领域已有的"自动研究"(autoresearch)和"ralph"风格工作流的思路——把一个大目标拆解成无数个小的、可验证的步骤,每一步成功就持久化,失败就回退,靠积累推动进展。但 gnhf 的特别之处在于,它把这个理念和 Git 的版本控制机制结合得非常紧密,使得整个执行过程既可追溯、又安全,而且对开发者的日常 Git 工作流几乎没有侵入性。你第二天醒来打开 git log,看到的是一排排描述清晰的提交记录,就像有一位助手在你休息期间一直在有条不紊地工作,并且每完成一步都认认真真地写了工作日志。

这篇文章,莫潇羽@无忆研习社 将从工作原理到实际操作,把 gnhf 拆解得尽可能彻底,方便你判断它是否适合自己的工作流,以及如何用对它。


二、gnhf 是什么:一句话不够,多说两句

2.1 项目定位

gnhf 是一个 AI 编码 Agent 的外部编排器(Orchestrator),或者说是一个"包裹层"。它本身不是一个 AI 模型,也不是一个代码编辑工具,而是一个负责调度和管理 AI 编码助手的控制程序。

你可以把它想象成一个项目经理,而 Claude Code 或 Codex 是它雇用的程序员。这个"项目经理"会把一个大目标分解成一次次小任务,安排"程序员"去执行,检查执行结果,记录过程,在出错时要求"程序员"撤销改动重来,最终把所有成功的工作整齐地归档在 Git 分支里。

项目目前托管在 GitHub(地址:https://github.com/kunchenguid/gnhf),完全使用 TypeScript 编写,以 ESM Bundle 的形式发布到 npm,支持 macOS、Linux 和 Windows 三个操作系统。

2.2 它解决的核心问题

从技术角度看,gnhf 主要解决了以下几个问题:

  • AI 长时间运行的稳定性问题:普通的 AI 编码助手会话不能无人值守运行,gnhf 提供了一个持久化的执行框架,让 Agent 可以运行几小时甚至整晚。
  • 中间状态的脏工作区问题:如果 AI 执行一半出错,未提交的改动会污染工作区。gnhf 在每次迭代开始时确保工作区是干净的,失败时强制回滚。
  • 跨迭代上下文丢失问题:AI 模型没有跨会话的记忆。gnhf 通过 notes.md 文件让每一轮迭代都能读取前几轮的执行摘要,实现"软记忆"传递。
  • 结果难以追溯的问题:gnhf 要求每次成功的迭代都生成一个独立的 Git commit,整个工作过程完全可以通过 git log 追溯和回溯。

2.3 "ralph / autoresearch 风格"是什么意思

gnhf 的 README 里提到它是一个"ralph、autoresearch 风格的编排器",这两个词对大多数人来说可能比较陌生,解释一下背景会有助于理解 gnhf 的设计哲学。

"ralph" 和 "autoresearch" 都是 AI Agent 编排领域的早期实验性框架,它们的共同思路是:不试图让 AI 一次性完成整个任务,而是把任务拆解成一系列小步骤,每一步都是独立的、可验证的操作,成功则积累,失败则重试。这种模式的灵感部分来自科学研究方法——不断提出假设、验证、记录结果、修正方向,靠迭代积累逼近目标。

这和直接把一个大任务扔给 AI 让它"一口气做完"的方式形成鲜明对比。后者在简单任务上没问题,但在复杂任务上风险很高:AI 可能做到一半出错,产生一个部分完成、内部状态混乱的代码库,比什么都没做还糟糕。"ralph 风格"用细粒度的迭代替代一次性大操作,通过增量提交保障每一步的可靠性,这正是 gnhf 的核心设计原则。

理解了这个背景,你就会明白为什么 gnhf 坚持"每次迭代只做一件小事、成功即提交"——这不是过度谨慎,而是在不可靠的 AI 输出上构建可靠系统的唯一务实方式。

2.4 技术栈一览

维度

详情

开发语言

TypeScript

构建工具

tsdown

测试框架

vitest

运行时要求

Node.js 20+

发布格式

单文件 ESM Bundle(dist/cli.mjs)

操作系统

macOS / Linux / Windows


三、核心工作原理深度解析

这是整篇文章最关键的部分。理解了 gnhf 的内部机制,你才能真正用好它,也才能预判它在什么情况下会表现出色,在什么情况下可能达不到预期。

3.1 初始化阶段:启动前的契约检查

gnhf 在执行任何实际工作之前,会做一系列严格的环境验证,这些步骤构成了它整个运行机制的"地基"。

第一步:Git 工作树洁净性验证。 gnhf 启动时会执行 git status 检查,确认当前工作区没有未提交的改动。如果存在脏文件(包括已修改但未暂存、已暂存但未提交),gnhf 会直接拒绝启动并给出提示。这个设计非常关键——它确保了每次迭代的起点都是一个明确的、已知的代码状态,不会因为工作区里混入了人工未提交的代码而产生混乱。

第二步:创建专用分支。 验证通过后,gnhf 会基于当前 HEAD 创建一个专用的工作分支,命名格式为 gnhf/<run-slug>,其中 run-slug 是根据你提供的目标描述自动生成的一个短标识符(比如 gnhf/reduce-complexity-20250501)。所有后续的 AI 工作都会发生在这个分支上,不会影响你的 main 分支或其他开发分支。

第三步:写入 prompt.md。 你提供的自然语言目标会被写入 .gnhf/runs/<run-slug>/prompt.md,作为整个 run 的"宪章"。这个文件在整个执行过程中不会改变,它是 Agent 在每次迭代中都能看到的最高指令。

第四步:初始化 notes.md。 空白的 notes.md 文件被创建在运行目录下,它是跨迭代"共享记忆"的载体,初始状态为空,随着迭代推进逐步积累内容。

3.2 迭代循环:状态机驱动的核心执行流

gnhf 的主体工作逻辑是一个 有限状态机驱动的迭代循环,每一轮迭代都经历相同的阶段序列。

(1)构建迭代 Prompt

每次迭代开始时,gnhf 并不是直接把原始目标扔给 AI,而是组装一个结构化的 prompt。这个 prompt 包含三个层次的信息:

  • 来自 prompt.md 的总体目标(不变的)
  • 来自 notes.md 的历史执行摘要(随迭代累积)
  • 当前迭代的具体指令(要求 Agent 在这一轮做出一个可提交的、有意义的小进展)

注入 notes.md 上下文是 gnhf 设计中最聪明的地方之一。它解决了 AI 模型跨会话"失忆"的问题。即使 Agent 在每次调用时都是全新的无状态会话,前几轮做了什么、遇到了什么问题、已经解决了哪些部分,这些信息都通过 notes.md 显式地告知 Agent,让它能做出更连贯的决策。

(2)以非交互模式调用 Agent

gnhf 调用 AI 编码助手时,强制使用非交互(non-interactive)模式。不同的 Agent 对应不同的非交互参数:Claude Code 使用 --json-schema 配合结构化输出,Codex 使用 --output-schema,GitHub Copilot CLI 使用 JSONL 输出格式,等等。

这里有一个重要的设计细节:gnhf 会自动为 Agent 加上默认的权限参数(比如 Claude Code 的 --dangerously-skip-permissions),但如果你在配置里已经显式指定了自己的权限参数,gnhf 就不会再叠加自己的默认值,完全尊重用户的设置。

(3)解析执行结果

Agent 执行完毕后,gnhf 解析其输出,判断本次迭代是"成功"还是"失败"。判断标准不仅仅是进程退出码,还包括对 Agent 输出内容的语义分析——如果 Agent 主动上报"没有找到合适的改动点"或"目标已达成",gnhf 也会做相应处理。

(4)成功路径:提交并更新记忆

如果本次迭代成功(Agent 做出了有效的代码改动),gnhf 会:

  • 自动执行 git add -A 暂存所有改动
  • 执行 git commit,提交信息格式默认为 gnhf #<N>: <agent 提供的摘要>,其中 N 是迭代序号
  • 把本次迭代的摘要追加写入 notes.md

每一次成功迭代都是一个独立的、带有摘要的 Git 提交,你事后可以用 git cherry-pick 挑选任意一次提交应用到其他分支,也可以用 git revert 精准撤销某一次迭代。

(5)失败路径:回滚与退避

如果本次迭代失败(Agent 报告错误,或者代码改动导致测试失败,或者发生了硬错误),gnhf 会:

  • 执行 git reset --hard HEAD,强制回滚所有改动到上一个提交状态
  • 如果是 Agent 主动报告的失败("soft failure"),立即进行下一次迭代,不等待
  • 如果是底层硬错误(比如 API 超时、进程崩溃),则采用指数退避策略,等待时间随连续失败次数以 2 的幂次增长(比如 1 秒、2 秒、4 秒……),避免密集重试占用资源

(6)熔断机制

gnhf 设置了一个"连续失败熔断器":如果连续 3 次(可配置)迭代都以失败告终,整个 run 会自动中止,并在终端输出清晰的停止原因。这防止了在目标本身不可达或者代码环境存在根本性问题时工具无意义地空转。

下面用流程图直观描述这个迭代循环:

gnhf 启动
    │
    ▼
验证 Git 工作树是否干净
    │
    ▼
创建 gnhf/<slug> 分支,写入 prompt.md
    │
    ▼
┌─────────────────────────────────┐
│   构建迭代 Prompt               │  ◄─────────────┐
│   (注入 notes.md 历史上下文)  │               │
└──────────────┬──────────────────┘               │
               │                                  │
               ▼                                  │
┌─────────────────────────────────┐               │
│   以非交互模式调用 Agent        │               │
└──────────────┬──────────────────┘               │
               │                                  │
               ▼                                  │
         本次成功?                               │
        ┌──┴──┐                                  │
       是     否                                  │
        │      │                                  │
        ▼      ▼                                  │
   git commit  git reset --hard                  │
   追加摘要    指数退避(硬错误)                 │
   到notes.md  立即重试(软错误)                │
        │      │                                  │
        └──┬───┘                                  │
           │                                      │
           ▼                                      │
   连续失败 >= 3?                               │
     ┌──┴──┐                                     │
    是     否 ──────────────────────────────────┘
     │
     ▼
   中止运行,输出报告

3.3 notes.md:跨迭代的"软记忆"机制

notes.md 是 gnhf 设计中值得单独拎出来讲的一个关键机制。

在 AI 编码助手的使用场景里,"上下文丢失"是长时间任务最大的痛点之一。每次新开一个 Agent 会话,它对之前做过什么一无所知。传统做法要么是把所有历史记录塞进 prompt(很快就会超出 token 限制),要么就是靠人工整理记录。

gnhf 采用的是一种务实的折中方案:不存储完整的执行历史,只存储每次迭代的结构化摘要。每轮迭代结束后,Agent 在提交改动时同时写入一段简短的说明——"本次做了什么,为什么这么做,还剩什么没做"。这段摘要追加到 notes.md,下一轮迭代开始时整个文件内容都会注入到 prompt 里。

随着迭代推进,notes.md 的内容大致是这样的:

## Iteration #1 (gnhf #1)
Extracted helper function `parseDate` from `utils.js` into `dateUtils.js`.
Reduced cyclomatic complexity of `parseDate` from 12 to 4.
Still to do: similar refactoring needed in `timeUtils.js`.

## Iteration #2 (gnhf #2)
Refactored `timeUtils.js::formatDuration`. Split into 3 smaller functions.
Reduced average function length in timeUtils from 45 lines to 18 lines.
Remaining: `validators.js` has several deeply nested conditionals.

## Iteration #3 (gnhf #3)
Simplified nested conditionals in `validators.js` using early return pattern.
All functions now have complexity ≤ 8.

这样的记录让 Agent 在第 10 轮迭代时仍然能准确知道前 9 轮做了什么、当前整体进展到哪里、还有哪些工作没有完成。

这里有一个关键的设计取舍值得理解:notes.md 的摘要是Agent 自己写的,而不是 gnhf 框架机械地记录文件 diff。这意味着摘要的质量取决于 Agent 的能力——一个优秀的 Agent 会写出条理清晰、有助于后续决策的摘要,而一个表现欠佳的 Agent 可能写出的摘要过于笼统,难以在下一轮提供真正有价值的上下文。这就是为什么选择哪个 Agent 以及 Agent 的质量,对 gnhf 整体效果有决定性影响。

另外需要注意的一点:notes.md 随着迭代次数增加会越来越长,累积到一定程度后,注入 prompt 的内容也会占用越来越多的 Token。对于超长时间运行(比如 50 次以上迭代),这可能会显著增加每轮的 Token 消耗。在实际使用中,可以通过合理设置 --max-iterations 把一个大目标拆成多个阶段性任务,每个阶段启动一个新的 run,这样 notes.md 不会无限积累,也让检查点更清晰。

3.4 提交信息格式与代码审查友好性

gnhf 生成的每次 commit 信息默认格式为:

gnhf #<迭代序号>: <Agent 提供的改动摘要>

比如:

gnhf #1: extract parseConfig helper from config.ts, reduce complexity 15→4
gnhf #2: split validateUser into 3 focused functions using early return
gnhf #3: replace nested ternaries in formatDate with explicit switch cases

这种命名方式有几个好处。首先,gnhf #N 前缀让你在 git log 里能立刻识别出哪些提交是自动化工具生成的;其次,序号是全局递增的,方便你按顺序快速定位到某一次迭代;最后,Agent 提供的摘要描述了本次改动的核心内容,不需要打开 diff 就能大致知道这次提交做了什么。

在做 code review 的时候,这种细粒度的提交历史特别有价值:你可以对每一次迭代单独做 git show,逐个评估 AI 的改动是否符合预期,而不是面对一个几百行 diff 的大块改动无从下手。对于不满意的提交,可以用 git revert gnhf#7 精准撤销,不影响其他迭代的结果。

3.5 Windows 平台的特殊处理

虽然 gnhf 在文档中把 Windows 列为支持平台,但有几个 Windows 特有的细节值得注意:

  • 睡眠防护在 Windows 上通过 PowerShell 调用 SetThreadExecutionState API 实现,这需要 PowerShell 可用(Windows 系统上通常默认安装)。如果 PowerShell 不可用,gnhf 会跳过睡眠防护但不报错,继续正常运行。
  • 路径处理方面,gnhf 在处理 agentPathOverride 时支持 Windows 风格的路径格式,以及 .cmd、.bat 等 Windows 脚本格式的可执行文件。
  • Git 调用全部通过 execFileSync 传入显式的参数数组,避免了 shell 元字符的注入风险,这在跨平台场景下尤其重要——无论在哪个操作系统,包含特殊字符的分支名或 prompt 内容都不会意外被 shell 解析。

一个常常被忽略但非常贴心的细节:gnhf 在运行时默认开启 防止系统休眠 功能。它的实现方式是平台原生的:

  • macOS:调用 caffeinate 命令,这是 macOS 自带的一个系统工具,专门用于防止系统进入睡眠
  • Linux:使用 systemd-inhibit,通过 systemd 的睡眠抑制器接口阻止系统挂起
  • Windows:通过 PowerShell 调用 SetThreadExecutionState,设置线程执行状态标志位防止系统休眠

技术实现上,gnhf 通过检测环境变量 GNHF_SLEEP_INHIBITED 来判断是否已经在睡眠防护进程下运行,避免重复触发。如果你不需要这个功能(比如 Agent 跑在服务器上),可以在配置里设置 preventSleep: false 关闭。

3.6 本地元数据与运行恢复

所有的运行元数据(prompt、notes、恢复状态)都存储在项目根目录下的 .gnhf/runs/ 目录里,这个目录应该被加入 .gitignore,因此不会出现在你的专用分支的提交历史里。你的分支里只有干净的代码提交,没有任何 gnhf 内部状态文件。

恢复机制非常实用:如果运行中途被打断(比如你按了 Ctrl+C 或者机器意外重启),只需要在同一个仓库目录下重新执行不带参数的 gnhf 命令,它会检测到已存在的 gnhf/<slug> 分支,自动从上次中断的位置继续,包括恢复 notes.md 的历史上下文。


四、安装与环境准备

4.1 前置条件清单

在安装 gnhf 之前,需要确认以下环境已经就绪:

  • Node.js 版本 ≥ 20:gnhf 使用 ESM 模块系统和一些相对较新的 Node.js API。可以用 node --version 确认,如果版本不足,推荐使用 nvm(Node Version Manager)切换版本。
  • Git 已安装且可用:gnhf 的核心功能高度依赖 Git 命令行操作,需要确保 git --version 能正常输出版本信息。
  • 至少一个已配置好的 AI 编码助手:gnhf 本身不包含 AI 能力,它需要调用你已经安装并配置好的 Agent。支持的 Agent 列表在后面章节详述。
  • 一个 Git 仓库:gnhf 必须在一个 Git 仓库目录内运行。如果你的项目目录还没有初始化 Git,需要先执行 git init。

4.2 npm 全局安装(推荐方式)

最简单、最推荐的安装方式是通过 npm 全局安装:

npm install -g gnhf

安装完成后,验证一下:

gnhf --version

如果输出了版本号(比如 gnhf v0.x.x),说明安装成功。

如果你使用 pnpm 或 yarn,也可以用对应的命令全局安装:

# 使用 pnpm
pnpm add -g gnhf

# 使用 yarn
yarn global add gnhf

4.3 从源码编译安装

如果你想跟进最新的开发版本,或者需要对源码做一些定制修改,可以从源码构建安装:

# 克隆仓库
git clone https://github.com/kunchenguid/gnhf.git
cd gnhf

# 安装依赖
npm install

# 构建(生成 dist/cli.mjs)
npm run build

# 链接到全局
npm link

npm link 命令会在全局 bin 目录里创建一个符号链接,指向当前构建产物,效果和全局安装相同,但代码来自本地源码目录,方便调试和修改。

如果需要开发模式(监听文件变化自动重新构建):

npm run dev

4.4 配置你的 AI 编码助手

gnhf 在调用 Agent 之前,该 Agent 必须已经在你的机器上独立安装并完成配置(包括 API Key 或账号登录)。以 Claude Code 为例:

# 安装 Claude Code
npm install -g @anthropic-ai/claude-code

# 登录(需要 Anthropic 账号)
claude login

gnhf 会自动检测系统 PATH 里的 Agent 可执行文件。如果 Agent 安装在非标准路径,可以通过配置文件的 agentPathOverride 字段手动指定,这在后面的配置章节会详细讲到。

4.5 准备你的项目仓库

进入你想要让 gnhf 工作的项目目录,确认 Git 工作区是干净的:

cd your-project
git status

输出应该类似于:

On branch main
nothing to commit, working tree clean

如果有未提交的改动,需要先处理掉(提交或储藏)。如果是全新的目录,先初始化 Git:

git init
git add .
git commit -m "initial commit"

五、快速上手:第一次完整运行

5.1 最基础的启动方式

一切就绪后,只需一行命令:

gnhf "reduce complexity of the codebase without changing functionality"

执行这条命令后,gnhf 会依次完成以下动作:

  • 验证工作区干净
  • 创建专用分支 gnhf/reduce-complexity-<timestamp>
  • 写入目标到 prompt.md
  • 开始第一轮迭代,调用默认 Agent(默认为 Claude Code)
  • 终端持续输出实时状态,包括当前迭代序号、Token 消耗、已提交次数

然后你就可以去做别的事情了。

在运行刚开始的几秒钟内,你会看到终端输出类似这样的初始化信息:

✓ Working tree is clean
✓ Created branch: gnhf/reduce-complexity-20250501
✓ Wrote prompt to .gnhf/runs/reduce-complexity-20250501/prompt.md
→ Starting iteration #1...

如果工作区不干净,gnhf 会立即停止并给出明确的错误信息,告诉你有哪些未提交的文件,需要你先处理再重新启动。

5.2 设置运行上限

对于不确定任务量的目标,建议设置运行上限,防止 Token 消耗超出预期:

# 设置最大迭代次数(适合午休或短时间任务)
gnhf "add unit tests for the auth module" \
  --max-iterations 10

# 设置最大 Token 消耗量(适合精确控制成本)
gnhf "reduce complexity of the codebase without changing functionality" \
  --max-iterations 30 \
  --max-tokens 5000000

--max-tokens 统计的是该 run 全程所有迭代累计消耗的输入+输出 Token 总量。当累计 Token 数超过设定值时,当前迭代完成后 gnhf 会在下一轮开始前停止。

5.3 指定使用的 Agent

如果你同时安装了多个 AI 编码助手,可以用 --agent 参数指定:

# 使用 Codex
gnhf "refactor the data processing pipeline" --agent codex

# 使用 GitHub Copilot CLI
gnhf "add docstrings to all public functions" --agent copilot

# 使用 OpenCode
gnhf "extract duplicate logic into utility functions" --agent opencode

5.4 使用 --stop-when 智能终止

除了硬性的迭代次数和 Token 上限,gnhf 还支持 --stop-when 参数,让你定义一个自然语言描述的"完成条件",当 Agent 认为目标已经达成时会主动上报并停止:

gnhf "add unit tests for the payment module" \
  --stop-when "all public methods in src/payment/ have at least one test" \
  --max-iterations 30

这个功能配合 --max-iterations 使用效果最佳:--stop-when 作为"正常完成"条件,--max-iterations 作为兜底的"超时"保护。

5.4 通过管道传递复杂目标

对于需要详细说明的复杂目标,可以把目标写成文件后通过管道传入:

# 直接 echo 一段较长的目标描述
echo "Refactor the UserService class: split into UserQueryService and UserMutationService, 
ensure all public methods have type annotations, and add corresponding unit tests 
for each extracted method." | gnhf

# 传入 PRD(产品需求文档)或设计文档
cat spec/refactor-plan.md | gnhf

# 也可以通过 < 重定向
gnhf < task-description.txt

这种方式在处理有详细要求的重构任务时特别有用,可以把背景信息、约束条件、验收标准都写进文件里,而不是压缩成一行命令行参数。

5.5 查看实时状态

在 gnhf 运行期间,终端会持续更新状态信息。终端标题栏也会实时显示当前状态,格式大致为:

gnhf | iter 7 | 1.2M tokens | 6 commits

这让你在任何时候切换到这个终端窗口,都能快速了解任务进展,而不需要滚动查看大量日志。

5.6 查看执行结果

任务完成后,切换到 gnhf 创建的专用分支查看结果:

# 查看分支列表,找到 gnhf/ 开头的分支
git branch | grep gnhf

# 切换过去
git checkout gnhf/reduce-complexity-20250501

# 查看完整的提交历史
git log --oneline

# 查看某次提交的具体改动
git show gnhf#5

git log --oneline 的输出大致如下:

a3f2c1d gnhf #12: extract parseConfig helper, complexity 15→4
b8e0a2c gnhf #11: simplify UserService.authenticate early return pattern
c1d4f9e gnhf #10: split formatDate into 3 focused functions
d7a3b2e gnhf #9: remove dead code in utils/string.ts
...

每一条提交都清晰地记录了本次迭代做了什么,就像一个清晰的工作日志。

5.7 恢复中断的运行

如果运行被意外中断,回到项目目录,直接执行无参数的 gnhf:

cd your-project
gnhf

gnhf 检测到已存在的 gnhf/<slug> 分支和 .gnhf/runs/ 下的运行元数据,会自动询问是否从上次中断的位置继续。确认后,它会加载 notes.md 中保存的历史上下文,无缝衔接执行。


六、进阶玩法:Worktree 多 Agent 并行模式

6.1 并行模式的工作原理

gnhf 的 --worktree 参数允许在同一个 Git 仓库上同时运行多个 Agent 实例,每个实例在完全独立的工作目录里操作,互不干扰。这个功能的底层依赖的是 Git Worktree,Git 的一项原生功能。

Git Worktree 允许将同一个仓库的不同分支同时 checkout 到不同的目录,每个目录都有独立的工作区,但共享同一个 .git 对象数据库。gnhf 利用这个机制,为每个并行 Agent 创建一个独立的工作目录:

your-project/                    ← 你的主仓库目录(保持不变,你继续在这里工作)
your-project-gnhf-worktrees/
    ├── run-slug-1/              ← Agent #1 的独立工作目录
    │   ├── src/
    │   ├── tests/
    │   └── ...
    └── run-slug-2/              ← Agent #2 的独立工作目录
        ├── src/
        ├── tests/
        └── ...

每个 worktree 都对应一个独立的分支(gnhf/<slug-1>、gnhf/<slug-2>),Agent 在各自的工作目录里独立提交,不会相互污染。

6.2 启动多个并行 Agent

# 在 main 分支(或任意非 gnhf/ 分支)上执行
# 使用 & 符号让每个进程在后台运行

gnhf --worktree "implement feature: user preferences persistence" &
gnhf --worktree "add integration tests for the payment module" &
gnhf --worktree "refactor the notification service to use event bus pattern" &

三个 Agent 会同时启动,分别在三个独立的 worktree 目录里工作,同时进行,节省大量时间。

如果你想给每个任务分配不同的 Agent 和运行参数:

gnhf --worktree "implement feature X" --agent claude --max-iterations 20 &
gnhf --worktree "add tests for module Y" --agent codex --max-iterations 15 &
gnhf --worktree "refactor API layer" --agent opencode &

6.3 监控并行任务状态

由于多个 gnhf 进程在后台运行,可以用标准的 Unix 工具查看状态:

# 查看所有 gnhf 进程
ps aux | grep gnhf

# 查看所有 gnhf/ 分支(确认工作进展)
git branch | grep gnhf

# 查看各个分支的提交数
git for-each-ref --format='%(refname:short) %(objectname:short)' refs/heads/gnhf/

6.4 合并并行结果

每个 Agent 完成工作后,对应的 worktree 分支上会有一系列提交。你可以根据需要选择处理方式:

# 方式一:把某个分支的所有提交合并到 main
git checkout main
git merge gnhf/implement-feature-x --no-ff

# 方式二:只挑选部分好的提交
git checkout main
git cherry-pick gnhf#3 gnhf#5 gnhf#7

# 方式三:查看后手动挑选需要的改动
git diff main gnhf/add-tests-for-module-y

6.6 Worktree 模式的磁盘空间考量

每个 worktree 实际上是完整的代码库副本(不含 .git 目录,所有 Git 对象共享),因此多个并行 worktree 会成倍增加磁盘占用。对于体积较大的代码库(比如包含大量 node_modules 的 JavaScript 项目),需要在启动并行任务前评估磁盘空间是否充足。

一个实用的技巧:在 worktree 目录里,node_modules 或其他构建产物通常需要在每个 worktree 里独立安装。对于 Node.js 项目,可以在 gnhf 目标里加一句"确保在每次操作前运行 npm install",让 Agent 处理依赖安装;或者提前在主目录里做好依赖安装,worktree 创建后通过符号链接共享 node_modules(但要注意有些工具不支持跨 worktree 共享依赖目录)。

6.7 使用 Worktree 模式的典型场景

场景一:同时推进多个独立模块的测试补充

一个中型项目有三个完全独立的模块(auth、payment、notification),需要分别补充测试覆盖。用 Worktree 模式可以同时跑三个 Agent:

gnhf --worktree "add comprehensive unit tests for src/auth/ module" &
gnhf --worktree "add comprehensive unit tests for src/payment/ module" &
gnhf --worktree "add comprehensive unit tests for src/notification/ module" &

三个任务互不干扰,原本需要三天分批做完的工作,一觉睡醒可能都有进展。

场景二:并行尝试不同的重构方案

对于某个模块有两种可行的重构思路,不确定哪个更好,可以让两个 Agent 分别探索:

gnhf --worktree "refactor UserService using Repository pattern" &
gnhf --worktree "refactor UserService using CQRS pattern" &

两个方案都跑完之后,你可以对比两个分支的结果,选择更合适的一个,或者从两个方案里各取所长。这种"AI 跑 A/B 方案"的思路,是 Worktree 模式带来的一个很有意思的使用模式。

  • --worktree 必须在非 gnhf 分支上执行,通常是从 main 或 develop 分支启动
  • 如果某个 worktree 在运行结束时没有任何提交(Agent 没有做出有效改动),对应的 worktree 目录会在退出时自动清理
  • 如果有提交内容,worktree 目录和分支会保留,供你查看、合并或删除
  • 多个 Agent 同时修改同一批文件可能产生后续合并冲突,建议给不同 Agent 分配尽量不重叠的工作范围
  • your-project-gnhf-worktrees/ 目录会在主项目旁边自动创建,确保父目录有足够的磁盘空间

七、配置文件完全指南

7.1 配置文件路径与初始化

gnhf 的配置文件位于用户主目录下:

~/.gnhf/config.yml

第一次运行 gnhf 时,如果这个文件不存在,它会自动以默认值创建。你也可以手动创建或编辑它。

7.2 完整配置文件示例与字段详解

# ============================================================
# gnhf 配置文件 (~/.gnhf/config.yml)
# ============================================================

# 默认使用的 Agent
# 可选值:claude | codex | rovodev | opencode | copilot | pi
agent: claude

# 连续多少次失败后中止整个 run
# 默认值为 3,可以根据任务稳定性调整
maxConsecutiveFailures: 3

# 运行期间是否防止机器进入睡眠
# 默认开启,长时间无人值守运行时建议保持开启
preventSleep: true

# 提交信息格式(可选,不填则使用默认格式)
# 默认格式:gnhf #<N>: <agent 提供的摘要>
# commitMessage: "auto: {summary}"

# 自定义 Agent 二进制文件路径(可选)
# 路径支持:绝对路径、~/ 前缀、相对于 ~/.gnhf/ 的相对路径、PATH 中的裸名
# agentPathOverride:
#   claude: /path/to/custom-claude
#   codex: /usr/local/bin/my-codex-wrapper
#   copilot: ~/bin/copilot-wrapper
#   pi: ~/bin/pi-wrapper

# 为每个 Agent 传入额外的 CLI 参数(可选)
# 可用
🔒
该内容仅对更高等级社区用户开放
请谨慎解锁时效性强且发布日期较早的文章
单篇解锁后若未显示全文请刷新页面
您当前:游客 · 可见 60% 内容 · 升级至 注册用户 可见 70%
👀
游客
可见 60%
✓ 当前
注册用户
注册用户
可见 70%
社区精英
社区精英
可见 100%
社区守护
社区守护
可见 100%
仅解锁本文,永久有效。如需PDF珍藏版,请联系站长获取。 当前单篇价格 ¥9.9
✏️ 发表评论

请先登录后发表评论

前往登录
📊 站点统计
今日发布0 篇
文章总数1107 篇
昨日发布1 篇
本月发布31 篇
建站时间456 天
🔍 搜索
站长微语

联系站长

QQ:2805463528
AIGC 技术社区
致力于解码 AI前沿技术 与经验分享
纯粹的技术应用社区

💡 欢迎您的建议与反馈,让社区变得更好

快速通道
联系站长
站长QQ二维码
AI交流群
AI交流群
仍在路上

那些寒夜里追赶过的方向

那些冷眼下没放弃的理想

一篇一篇写到现在

仍在路上

"不羁放纵爱自由"

—— 致敬 Beyond
持续创作中 莫潇羽 · 无忆研习社
▲