Community编程与开发github.com

zheref/en

将一个开放拉取请求驱动至已验证的就绪状态,并在强制性的执行周期上限内完成。当 $mukai 移交其 PR 时,或当维护者对 <CODE>#<N> 调用 $en 时使用。

en 是什么?

En 是一个复合型 AI 代理技能,专注于将一个开放的 GitHub PR 驱动至“就绪”状态,并严格限制在最多 N 个执行周期内。它管理从初始报告、代码审查、修复推动到最终状态验证的整个流程,但不执行合并(除了一个特定的已记录的 Futon 堆叠交付例外)或清理。该技能在多种场景下被调用,例如由 mukai 在打开 PR 后自动启动,由 getsuga 用于发布提案,由 futon 用于其集成 PR,或由维护者手动调用。其核心是 Izanagi 驱动的周期上限机制,该上限是语法强制要求的,无法被默认或忽略,从而确保代理不会无限期运行。En 与多个下游技能紧密协作,包括 murasaki(推送)、sharingan(审查)、spiritual-message(报告)和 jutaisho(通知),但它本身不处理清理工作,而是通过 cleanup 技能提供钩子进行后续处理。

兼容平台✓Claude Code✓Codex CLI~Cursor✓Antigravity
npx skills add https://github.com/zheref/hatsu/tree/HEAD/surfaces/codex/en

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

共享策略位置: docs/DISCOVERY.md、docs/WORKFLOW.md、 docs/LAUNCH-MIGRATION.md、docs/STANDALONE-ENTRY.md、docs/PROCESS.md、docs/using/README.md 和 docs/using/mirrors.md 属于已解析的 Hatsu 插件根目录,而非消费仓库。在已安装的表面上,请使用 ten 打印的绝对根路径来读取这些文件(如果不可用,则通过该技能重新解析)。下面的相对链接标识了源位置;缺失的消费者 docs/ 副本并非缺失的策略,且不得触发重复归档。绝不要在目标仓库中复制或发明第二个策略。

En —— 围绕一个 PR 直至其就绪的闭环

性质:操纵者。 En 所做的一切都面向看板——驱动、报告、通知、观察。Kurapika 在运行它时会这么说。当一个周期将他送回变更本身——审查者发现需要代码修改时——该修复的模式就是变更自身的模式(强化者、具现化者、变化者),在该周期内明确说出,并在之后交还。

专注于这个 PR:报告它,观察每次当前头部的检查和审查,将其驱动至已验证的就绪状态,在其人工网关处通知一次——并在最多 N 个执行周期后停止。

En 是本地平面的最后一个复合体,也是唯一一个可能需要在 PR 被打开之后持续关注的复合体。$mukai 通过提供这个移交来结束自己——仅在 nen/workflow.json → mukai.autoEn(裁决 2026-09-28)下自行启动它;从那里起 PR 归属于 En——并且仅在 autoEn 路径上,用户的活跃回合仍有效,从提议处的键入开始算作其自身回合——直到 Sharingan 证明它就绪,或者一个具体的阻塞器/上限/终止状态/取消结束 En 的运行。合并是维护者后续的行为,除了 § 5 中已记录的 Futon 交付异常。本次运行不进行收割也不进行清理。 当 En 完成时,调用者通过选择器提供收尾工作(cleanup § 2,行 wrap-up;裁决 2026-10-13)——仅在 cleanup § 2 的两个先决条件(HR-366)下;一个处于 § 5 提示下的就绪 PR 不满足任何一个:$cleanup 为必需,$third-hand 为可选伴随后者——这些是独立的技能,在本文件的协议返回后启动,绝不应作为 En 的一个步骤。

本文件进行组合。它不重新规定。 下面的每个步骤都属于另一个已命名并链接的技能,其过程、退出码反应、拒绝和残留都在那里。如果你在这里发现一个规则实际上属于那个技能,那么它就在错误的文件中——去它被编写的地方阅读它,因为一个在两处重复的规则会在其中一处发生漂移。

真正属于 En 自身的是上限、观察的形状以及会话结束时的边界。 这三者分别属于 § 2、§ 6 和 § 7,并且它们是本文件唯一断言任何事物的位置。Third-Hand 不在那个边界内。


1. 调用

P1 —— 本次运行以 $ten en 开始(ten § 6 会在其自身名义下补足此阶段缺失的先决条件;本次运行调用的阶段跳过其自身的先决条件)。

$en [on <CODE>#<N>]

由 $mukai 在 mukai.autoEn 下无子句启动——PR 即为步骤 8 刚刚打开的那个——由 $getsuga § 3 为其刚刚打开的发布提案启动(在那里,en 运行步骤 1–5 并将其引用的裁决返回给 getsuga;步骤 6 的通知不响起,因为 getsuga § 3a 就是那个 PR 的合并),由 futon 的每个问题链为其工作打开的 PR 启动,或为其集成→主线 PR 启动(futon § 5 不向其集成分支打开 PR;它在本地合并到那里),或由维护者启动,指定一个已经打开的 PR(mukai 的提议行)。会话打开或导致打开的每个 PR 通过本次运行或引用裁决的方式送达维护者的规则是 docs/PROCESS.md § 报告阶段(zheref/hatsu#103)中引用的,而非重新陈述的:

nen parse en --grammar "on [<ref>]" --line "<调用内容,去掉 $en 前缀>"

在 v0.3.0(docs/ab/en.md § 2.1)处现场验证:on HA#41 → ref: HA#41 退出码 0,而一个裸的 on 在子句缺失时也能解析,同样退出码 0。子句锚定在一个字面量之后,原因如 $spiritual-message § 1 所记录——一个单独的括号中的槽位会被模板拒绝。

空行会被拒绝,这就是为什么复合体根本无法解析。 现场验证:--line "" 退出码 2,并显示 "该行必须以字面量 'on' 开头——它是引入 <ref> 的东西"。一个锚定的可选子句需要其锚点;“无子句”和“空行”是不同的输入,只有第一个能解析。所以 mukai 在 autoEn 下直接移交 PR,并且根本不调用 nen parse en——回显一个没人键入的行的解析将是演戏,而向其提供 "" 将产生一个毫无意义的拒绝。解析仅在维护者键入了子句时运行。

缺失的参数或配置项会被询问并内联设置(missing-argument、missing-configuration;WORKFLOW.md § 4 询问、设置、继续):维护者的一行若退出码为 2,或在会话未持有任何 PR 时未指定 PR,则触发在选择器中提供会话的开放 PR 并在得到答案后继续,而绝不结束运行。

一次性预先解析代码,并保留 slug 用于后续所有调用——绝不以第二种方式重新推导它(claude/agents/kurapika.md § 你的工作方式):

nen repo resolve <CODE> --repo <路径到目标仓库的检出>
nen ref format --code <CODE> --kind PR --number <N>

一个已关闭或已合并的 PR 会立即结束本次运行,并显示其发生的情况。没有需要降落的东西。

一个头部已发布的开放 PR 在每次继续时仍保留在 En 中。 当其分支落后于 PR 基分支时,或审查修复需要发布时,运行 En 的当前树证据步骤和 $murasaki 的受保护快进推送(§ 3 和 murasaki § 6)。不要将已发布的分支通过 $aka 的变基推送。首次发布遵循其调用工作流已携带的授权,无论是直接的 Aka 调用还是像 Futon 这样的复合体。En 仍会在 § 5 的单独人工合并门处停止。例如,PR #274 在 #273 推进了 main 时已经在 b5fddea 发布;其追赶合并保留了该已发布的祖先,并且 Murasaki 推送了验证后的后代 5de39c5。

此复合体调用的阶段会跳过它们自己的 ## 0. 独立入口 部分。 docs/STANDALONE-ENTRY.md 是手动键入到任意检出中的阶段的契约;从此处到达的阶段继承本次运行的 P1–P4——热身、定向、变更集和所有派生参数——而重新派生它们将对此复合体已解决的问题产生第二个答案。每个阶段会说明是哪个复合体在持有它。

2. 上限 —— 语法,而非默认值

En 会行动。 步骤 2 和 4 进行驱动;一个发现新审查意见的周期会回到变更中并推送修复。这使得 en 成为循环对中的可变一半,并且 $izanagi 的整个纪律约束着:一个会写入的循环需要一个界限,而一个只读取的循环则不需要,并且让界限成为语法的一部分意味着它永远不会被默认、继承或遗忘。

键文件用途键(或文件)缺失时的默认值
monitor.maxCyclesnen/workflow.json上限——执行周期的数量(§ 6)20
monitor.pollSecondsnen/workflow.json观察之间的间隔,作为 --interval-ms300(→ --interval-ms 300000)
branch.basenen/workflow.json§ 5 提示的基础。步骤 3 从中追赶,“落后”是相对于 PR 自身的 baseRefName(gh pr view <N> --json baseRefName),对于 en 提示的每个 PR 来说,它就是 branch.basemain
reports.dir / .sections / .retainnen/workflow.json步骤 7 的文件——backlog-board § 3 的键Reports / 必需,无默认值(WORKFLOW § 2 → reports)/ final-only
notifications.rungs / .soundnen/workflow.json步骤 6 的梯级——$jutaisho 的键["push","os","sound"] / Glass

在周期 1 之前,上限通过拒绝缺失上限的动词来明确说明:

nen parse izanagi "take <CODE>-PR-#<N> to its human gate until it is Ready up to <monitor.maxCycles>"

在 v0.3.0(docs/ab/en.md § 2.2)现场验证,两种方式:

$ nen parse izanagi "take HA-PR-#41 to its human gate until it is Ready up to 20"
task: take HA-PR-#41 to its human gate
until: it is Ready
cap: 20
exit=0

$ nen parse izanagi "take HA-PR-#41 to its human gate until it is Ready"
nen: no 'up to <N>'. Izanagi is the MUTATING half of the loop pair and the cap is required grammar,
never defaulted or inferred -- an invocation without it is refused rather than run once 'to see'.
  try: take HA-PR-#41 to its human gate until it is Ready up to <N>
exit=2

值来自 monitor.maxCycles;要求来自语法。 这是两件不同的事,区别是重点:文件提供了一个数字,而动词拒绝在没有数字的情况下运行。缺少 monitor 块的仓库会得到明确说出的 20——它不会得到一个无限制的观察,因为“文件什么都没说”正是继承和遗忘的默认值带来危险的情况。

在 nen 0.7 时退役:手动计数执行周期

每个执行周期在行动前被声明,并且上限通过拒绝该声明来强制执行——izanagi § 3 的退役,完整继承:

git rev-parse --path-format=absolute --git-common-dir   # <公共目录>,在 effort 工作树中
nen loop iterate --id en-<CODE>-<N> \
  --line "take <CODE>-PR-#<N> to its human gate until it is Ready up to <monitor.maxCycles>" \
  --repo <common>

退出码 0 打印 iteration <n>/<cap> 以及剩余次数——动词自身的词是 iteration,而 en 的周期就是它所声明的;退出码 1 就是上限,并在 § 6 的上限耗尽行结束本次运行,调用在 nen 自身的拒绝中命名。--line 是与上面 nen parse izanagi 回显的相同字符串,每次声明时重复,因此 monitor.maxCycles 不能在运行中被悄悄提高:携带不同 N 的声明会退出码 2 并命名两行(已针对此确切形状现场验证——up to 3 运行中,up to 20 被声明——docs/ab/izanagi.md § 在 nen 0.7 时退役)。

--id 是拉取请求,而非会话,并且这是一个值得说明其后果的决定:账本位于 git 公共目录 下的 .nen/loop/en-<CODE>-<N>.json,因此它比会话(§ 7)和 effort 工作树更持久,而清理会移除后者(docs/ab/en.md § 上限比工作树更持久),所以对同一 PR 重新调用 $en 会恢复相同的上限,而不是从周期 1 重新开始。这是“二十个执行周期以使此 PR 就绪”的诚实解读——一个会话边界重置的上限将是没有人拥有的上限。当就绪驱动真正结束时——就绪、已关闭或在门处移交给维护者——使用 nen loop iterate --id en-<CODE>-<N> --line "<same line>" --release "<why>" --repo <common> 关闭账本;处于上限的循环始终可以被释放,而之后的新上限是一个新的 --id,需要慎重选择并明确说出,绝不是重新键入的一行。

上限是一个天花板,而非目标。 达到它意味着未能达到就绪状态,并作为失败报告:什么仍然不成立,以及下一个周期本会做什么。izanagi § 4 的规则,不变。审查者轮次策略是 $sharingan § 6 的,在那里声明一次并在此处引用,绝不重新陈述:

  • 在 $hanten 解决后请求一个 Copilot 轮次,在此之前绝不请求。
  • 到达的审查意见会被修复,且欠下的轮次仅会在 sharingan § 6 的两个界限内(round_policy.maxRounds 次请求,round_policy.minRounds 已解决;行 cap-reached)直接重新请求,然后 en 继续观察;任一界限达到即为 § 6 的第五个停止点。
  • 在任何重新请求之前,nen wake verify --repo-slug <owner/name> --now <ISO> --author-pattern <维护者登录名> --run 会重新驱动一次被吞没的运行(action_required 或从未执行的 startup_failure);Copilot 机器人的 action_required 运行无法重试,并会照此报告。然后是无操作同步守卫:计算领先于最后审查头部的提交数(git rev-list --count <reviewed-head>..HEAD,只读)以及差异统计;零可审查的变更意味着不请求。
  • Copilot 在每个推送时自动审查,因此上限管理的是请求,而非到达;超出上限的到达仍会被修复并解决其线程。

超出最大值后,本次运行以未就绪状态与看板一同结束。两者都不是 G5。nen/workflow.json → monitor.maxCycles 是 en 的执行周期上限,一个不同的数字。

3. 运行顺序

#步骤拥有此步骤的技能时机
1着陆报告$spiritual-message as landing一次,在开始时 —— 00–07 加上 08 PR 主体 和 09 就绪度。如果此 En 是由 mukai (autoEn) 启动的,或者在同一环境下从其提议中键入且没有更新的人工请求,00 仍然响应那个 mukai 请求
2驱动$sharingan第一个阻塞条件

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

相关技能