尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Plannotator Annotate Gates 与 JSON 结构化响应:从人工反馈到机器可读评审闸门

发布时间:2026/9/25 4:07:11

资讯中心
01
ARTICLE

Plannotator Annotate Gates 与 JSON 结构化响应:从人工反馈到机器可读评审闸门

Plannotator Annotate Gates 与 JSON 结构化响应:从人工反馈到机器可读评审闸门
【免费下载链接】plannotatorAnnotate and review coding agent plans and code diffs visually, share with your team, send feedback to agents with one click.项目地址https://gitcode.com/gh_mirrors/pl/plannotator点击查看免费下载plannotator annotate与plannotator annotate-last通过--gate、--json、--hook三个标志把原本面向人工的 Markdown 批注工具升级为带结构化输出的完整评审闸门review gate评审者可以显式批准、驳回或发送批注而 stdout 上输出的单行 JSON 让 Hook、插件与自动化流水线无需解析自由文本即可路由决策。本文以 annotate-gates-and-json-responses.md 为主线结合仓库源码annotate-output.ts、strict-annotate-result.ts、cli.ts与测试用例完整讲解三个标志的 stdout 契约、严格闸门--require-approval/--result-file的退出码与原子发布语义以及面向 spec 驱动开发、逐轮评审和程序化路由的实战配方。读完你可以在 Claude Code、Codex、Copilot CLI、Gemini CLI、OpenCode、Pi 等任何受支持 harness 上把 Plannotator 接入 PostToolUse/Stop Hook做成 fail-closed 的机器可读评审环节。三个标志如何协作能力总览plannotator annotate和plannotator annotate-last接受三个可组合标志把批注行为扩展成完整的评审闸门--gate在批注 UI 中增加一个Approve批准按钮。评审者在三种决策中选择approve批准、send annotations发送批注、close关闭。--json将每一次决策以结构化的 JSON 对象输出到 stdout让 Hook 和插件可以基于决策类型路由而不必解析自由文本。--hook输出与 Claude Code 和 Codex 的 PostToolUse/Stop Hook 协议直接兼容的 hook 原生 JSON。隐含--gate是 Hook 集成的推荐方式。三个标志可以任意组合使用单独用或一起用并且在所有受支持 harnessClaude Code、Copilot CLI、Gemini CLI、OpenCode、Pi、Codex上语义完全一致。CLI 用法面在 cli.ts 的annotate子命令帮助文本中有完整定义从源码结构看plannotator annotate-last与copilot-last共享同一组--gate/--json/--hook标志面cli.ts。Stdout 契约标志 × 决策 × 输出矩阵原文档给出的 stdout 契约矩阵是理解整套语义的核心完整保留如下Flags │ UX │ Approve │ Close │ Annotate ──────────────────────────┼──────────────────┼─────────────────────────┼──────────────────────────┼─────────────────────────────────────────────── (none) │ 2-button │ n/a │ empty │ feedback (plaintext) --gate │ 3-button │ The user approved. │ empty │ feedback (plaintext) --json │ 2-button │ n/a │ {decision:dismissed}│ {decision:annotated,feedback:...} --gate --json │ 3-button │ {decision:approved,feedback:...}│ {decision:dismissed}│ {decision:annotated,feedback:...} --hook │ 3-button │ empty │ empty │ {decision:block,reason:...}几个关键性质不带任何标志时是 2 按钮 UI没有 ApproveClose 输出空、Send Annotations 输出纯文本反馈——这是历史行为逐字节保持不变。--gate单独使用时Approve 在 stdout 上输出单行The user approved.让模板和 Agent 无需--json也能区分「批准」与「关闭」Close 不输出任何内容Send Annotations 输出反馈 Markdown。--json与--gate正交--json单独用保持 2 按钮 UI只产生annotated和dismissed两种决策--gate --json才解锁全部三种决策的结构化形式。每次调用只输出一行 JSON。一次调用、一个决策、stdout 上一行——这是 Hook 和插件可以稳定依赖的契约。JSON schema--json输出的对象遵循如下 schema{ decision: approved | annotated | dismissed, feedback: string (present for annotated decisions and approvals with notes) }feedback字段出现在annotated决策中以及「带备注批准」--gate --json下的approved决策中。从源码看序列化逻辑由 strict-annotate-result.ts 的serializeStrictAnnotateResult与 annotate-output.ts 的formatAnnotateOutcome实现approved仅在存在非空 feedback 时附带该字段...(result.feedback ? { feedback: result.feedback } : {})annotated总是携带 feedback可为空字符串dismissed永远只有{decision:dismissed}。示例输出Approved评审者点击 Approve--gate --json{decision:approved}如果评审者在批准的同时留下了备注结构化传输会同时保留两者{decision:approved,feedback:Keep the retry bounded.}Dismissed评审者点击 Close--json或--gate --json{decision:dismissed}Annotated评审者发送批注--json或--gate --json。feedback字段就是 Plannotator 在纯文本模式下输出的同一份 Markdown{ decision: annotated, feedback: # File Feedback\n\nIve reviewed this file and have 2 pieces of feedback:\n\n## 1. Remove this\nthe selected text\n I dont want this.\n\n## 2. Feedback on: \some highlighted text\\n This needs more detail.\n\n--- }测试 annotate-output.test.ts 覆盖了上述全部字节级输出形态包括 legacy 纯文本逐字节不变The user approved.、legacy hook 输出逐字节不变以及「只有 gate 下的直接 JSON 批准才携带非空 feedback」的语义。--gate三向评审决策--gate在批注 UI 的 Close 与 Send Annotations 之外增加一个 Approve 按钮让评审者显式声明意图Approve产物本身已经足够好Agent 应当继续执行。Send Annotations评审者有具体修改意见反馈原样返回。Close会话在没有决策的情况下结束——既不是对 Agent 的信号也不是一组指令。纯文本模式下Approve 在 stdout 上输出单行The user approved.模板和 Agent 不借助--json也能区分批准与关闭Close 不输出任何内容Send Annotations 输出反馈 Markdown。若要做 Hook 集成请改用--hook它直接输出 hook 原生 JSON。--gate的 Approve 标记常量定义在 annotate-output.tsAPPROVED_PLAINTEXT_MARKER The user approved.。--json结构化 stdout--json把每次决策输出为带decision字段、可选feedback负载的 JSON 对象。需要显式路由的 Hook 和插件把批准与驳回分开记日志、按决策类型做闸门判断、累积遥测数据都用它。--json与--gate正交的细节值得注意--json单独用保持 2 按钮 UI只产生annotated和dismissed决策。--gate --json解锁全部三种决策的结构化形式。直接的--gate --json批准可以携带 feedback。无法投递附注的传输transport会在丢弃 feedback 前发出警告并引导评审者改用Send Feedback。在 OpenCode 和 Pi 上--json被静默接受——这两个 harness 直接回写会话而不是走 stdout因此该标志在那里不生效。配方保持可移植。一个容易忽略的语义--gate --json下「批准时带备注」是非阻塞的指导性意见不是要求再来一轮修订而 Send Annotations 语义上仍然是「修订后重新打开」revise and reopen不是「批准并继续」。两者都体现在 annotate-output.ts 的supportsAnnotateApprovalNotes谓词gate json !hook中。--hookhook 原生 JSON--hook输出与 Claude Code 和 Codex 的 PostToolUse/Stop Hook 协议直接兼容的 hook 原生 JSON并隐含--gate始终是三按钮 UX。若同时传入--hook和--json--hook胜出cli.ts 的annotate帮助文本中亦注明此优先级见 annotate.md。决策到 stdout 的映射Approve→ 空 stdout → hook 通过 → Agent 继续。Close→ 空 stdout → hook 通过 → Agent 继续。Send Annotations→{decision:block,reason:feedback}→ hook 阻塞并携带反馈。{decision:block,reason:...}正是 Claude Code 和 Codex 在 PostToolUse/Stop Hook 中的原生协议格式因此不需要任何包装脚本。这正是 Hook 集成推荐--hook的原因。该输出逻辑在 annotate-output.ts 中实现hook 模式下approved或exit返回null空 stdout有 feedback 的批注输出{decision:block,reason:feedback}无 feedback 的批注同样返回null。--hook被刻意保持原样原生 hook 协议用空 stdout 表示批准因此它没有通道携带批准备注。需要带备注时使用Send Feedback来阻塞——该动作语义仍是「修订后重新打开」而非「批准并继续」。与--json同理该标志在 OpenCode 和 Pi 上被静默接受因为那些 harness 不使用 stdout 作为信号通道。严格直接闸门Strict Direct Gates对于 fail-closed 的直接 CLI 闸门可以在--gate --json之上叠加两个严格选项plannotator annotate docs/plan.md --gate --json \ --require-approval \ --result-file .tmp/plan-review-result.json--require-approval只有approved退出码为0。annotated和dismissed仍会先发布其合法的 JSON 决策然后以非零码退出。--result-file path以原子方式发布与 stdout 相同、以换行结尾的 JSON 字节。路径从调用工作目录解析见 strict-annotate-result.ts 的resolveResultFilePath。两个选项都要求--gate --json仅对直接的annotate调用可用且不能与--hook组合hook 的输出与退出行为不受影响。参数解析在 cli.ts 的parseStrictAnnotateOptions中实现测试 cli.test.ts 验证了严格选项可以在目标路径前后任意位置出现、可以单独使用任一严格选项、缺少值或重复指定会报错以及非annotate --gate --json组合包括--hook并存会被拒绝。结果文件的原子发布语义--result-file的发布保证是源码级可见的strict-annotate-result.ts 的writeAnnotateResultFile结果文件的父目录必须已存在且目标文件必须不存在assertResultPathAvailable会在目标已存在或父目录缺失时抛错strict-annotate-result.ts。Plannotator 在同一目录写一个私有0600权限的临时文件open(temporary, wx, 0o600)写入内容并追加换行后flush/close再以原子的 no-clobber 硬链接发布link(temporary, resultFile)随后删除临时文件。它从不覆盖已存在的目标也不会回退到非原子拷贝。因此每次调用都应使用唯一的 result 路径。stdout 决策记录先于结果文件写入。如果发布失败评审者的决策已经输出到 stdout——即使同时传了--result-file也务必捕获 stdout。两个关于发布保证的注意事项0600临时文件模式是 POSIX 权限在 Windows 上实际无效如果结果路径需要私有请在 Windows 上使用文件系统 ACL。原子链接与原子 rename 一样之后不会对父目录执行fsync。发布对并发读者是原子的但紧接着发生的机器崩溃仍可能丢失目录项。调用方侧行为保持源码路径稳定把被评审的源码放在稳定的项目路径上这样修订与版本历史能持续指向同一产物结果文件和诊断日志则可以放在范围受限的临时目录中。点击 Close 发布{decision:dismissed}。评审放弃abandonment的自动解析放弃评审同样发布dismissed决策。本地直接结构化闸门会跟踪其连接的评审表面review surface一旦至少一个表面连接过失去最后一个表面后开始30 秒重连宽限期到期后闸门以dismissed解析。刷新页面、离开再返回、或关闭多个标签页中的某一个都会重连或让另一个表面保持连接因此这些操作都不会触发 dismiss。Approve、Send Annotations 和 Close 仍然优先于待处理的过期事件。实现位于 packages/shared/annotate-client-lease.tsANNOTATE_CLIENT_LEASE_GRACE_MS 30_000第32行心跳间隔ANNOTATE_CLIENT_LEASE_HEARTBEAT_MS 5_000SSE 路由为/api/annotate/client-lease。该追踪器是无依赖的「最后客户端断开检测器」一旦最后一个客户端断开就启动宽限计时器等待重连如标签页刷新从未连接过的标签页永远不触发过期——还没有任何东西可以被放弃。被放弃的评审会保留其已保存的批注草稿你写的内容不会丢失。如果过期解析后某个陈旧标签页又回来了它的 Approve / Send Annotations / Close 会报错而不是假装生效——调用方收到的决策才是算数的。两种情形属于调用方侧恢复永远不会自动转为批准从未有评审客户端连接的会话浏览器启动失败会一直等待所以请自行传入启动超时半开传输丢失half-open transport loss连接只有通过失败的 heartbeat 写入才能被证明已死察觉时间可能超过宽限期。远程与共享会话完全关闭该行为因为隧道或代理断开不算放弃。该判定由 annotate-output.ts 的supportsAnnotateClientLease谓词统一给出只有gate json !hook !isRemote的本地直接结构化闸门才启用测试 annotate-output.test.ts 逐一验证了关闭路径另一个测试则扫描startAnnotateServer({的全部调用点强制每个调用点都通过该共享谓词而非硬编码布尔值。主要使用场景Spec 驱动开发框架spec-kit、kiro、openspec 这类 spec 驱动开发框架每个特性会生成多个 Markdown 产物spec.md、plan.md、tasks.md、research.md、data-model.md各自经历 clarify、review、approve 循环。Plannotator 的批注 UI 正好契合这类产物的评审对 Markdown 的行内、定向反馈正是这些工作流需要的。配合--gate在 Write 上挂一个 PostToolUse hookAgent 每次产出 spec 产物就触发一次完整评审闸门。评审者批准、批注或驳回Agent 相应继续、修订或跳过。逐轮评审Turn-by-turn review把plannotator annotate-last --gate接入 Claude Code 的 Stop hook每个 Agent 回合暂停等待人工评审Approve 干净地结束该回合Send Annotations 用评审者的反馈重新提示 AgentClose 结束回合而不注入任何内容。程序化决策路由当 hook 或插件需要区分批准与驳回时--json提供单行、稳定的契约。一次性决策变成机器可读事件——无需解析 stdout、没有脆弱性。Hook 集成配方速览--hook是 Hook 集成的推荐方式Approve/Close 输出空 stdouthook 通过、Agent 继续Send Annotations 输出{decision:block,reason:feedback}hook 阻塞并展示反馈。无需包装脚本。Recipe 1 — 评审 Agent 写下的每个文件spec 驱动框架的核心模式。加入.claude/hooks.json或其他 Agent 的等价文件{ hooks: { PostToolUse: [ { matcher: Write, hooks: [ { type: command, command: plannotator annotate \$CLAUDE_TOOL_INPUT_file_path\ --hook, timeout: 345600 } ] } ] } }timeout是 4 天秒。hook 会在评审者在浏览器中工作期间阻塞所以务必设高。Recipe 2 — 评审每个 Agent 回合Stop hook{ hooks: { Stop: [ { matcher: , hooks: [ { type: command, command: plannotator annotate-last --hook, timeout: 345600 } ] } ] } }Send Annotations 阻止 Agent 停止并用反馈重新提示Approve 或 Close 让回合正常结束。两者可组合PostToolUse hook 闸门单个文件写入Stop hook 闸门整个回合。hook 触发时Agent 会把工具输入暴露为环境变量——Claude Code 用$CLAUDE_TOOL_INPUT_file_path/$CLAUDE_PROJECT_DIRCodex 用$CODEX_TOOL_INPUT_file_path/$CODEX_PROJECT_DIR请按你的 Agent 替换。更多可复制配方含 OpenCode 与 Pi 的可移植变体见 hook-integration.md。退出码契约grep 惯例默认情况下每种决策都退出0——现有纯文本、JSON 和 hook 集成均保持不变。使用--require-approval后只有approved退出0annotated和dismissed先发布其 JSON 结果再以1退出。严格调用中配置错误或无法启动的调用退出2错误的标志组合、无效的--result-file目标以及所有 annotate 启动失败路径缺失或不可读、URL 不可达、空文件夹、歧义文件名、文件过大。这些启动失败在非严格调用中一如既往地退出1而在严格标志下1的含义是「评审者未批准」因此拼错的路径绝不能上报为驳回。原子发布失败也退出2但该代码的含义是结果文件未发布——评审者的决策已经写入 stdout。只有 stdout 写入失败才会完全不留记录。整体遵循 grep 惯例0 批准1 未批准2 闸门本身出错。该退出码契约与实现细节在 strict-annotate-result.ts 中有完整定义STRICT_GATE_ERROR_EXIT_CODE 2第25行、isStrictAnnotateInvocation严格调用判定第43-47行、annotateStartupFailureExitCode启动失败在严格调用下升为2第57-61行、annotateOutcomeExitCoderequireApproval !approved → 1第79-84行。端到端测试 annotate-cli.test.ts 通过真实进程 spawn 验证了非严格单 token 失败保持退出1、严格闸门绕过容错参数解析自然语言参数在严格调用下退出2且 stdout 为空、--tailscale发布失败在严格调用下退出2且不产生结果文件。落地建议Hook 集成默认用--hook协议原生、零包装脚本需要把决策当事件记录或做条件路由时再加--json类消费方。CI/流水线 fail-closed 闸门用--require-approval --result-file记住退出码语义0/1/2对应 grep 惯例为每次调用使用唯一 result 路径并同时捕获 stdout。OpenCode/Pi 上--json与--hook被静默接受harness 直接写回会话而非 stdout--gate行为在所有 harness 上一致——配方保持可移植。相关参考标志完整矩阵见 annotate.md含/api/plan、/api/feedback、/api/approve、/api/exit等服务端 API 与PLANNOTATOR_JINA、JINA_API_KEY环境变量可复制 Hook 配方见 hook-integration.md。赞分享【免费下载链接】plannotatorAnnotate and review coding agent plans and code diffs visually, share with your team, send feedback to agents with one click.项目地址https://gitcode.com/gh_mirrors/pl/plannotator点击查看免费下载相关推荐Plannotator Hook 集成用 --hook 把人工评审闸门嵌入 Agent 生命周期Plannotator Hook 集成用 hook 把人工评审闸门嵌入 Agent 生命周期 本篇基于 Plannotator 仓库中的官方指南 hook iplannotator OpenCode 插件 /plannotator-annotate 命令解析:从 Markdown 存根到注释反馈闭环plannotator OpenCode 插件 /plannotator annotate 命令解析:从 Markdown 存根到注释反馈闭环 本篇以 planPlannotator review 命令深度解析从 Skill 接入到浏览器式代码评审与反馈回传Plannotator review 命令深度解析从 Skill 接入到浏览器式代码评审与反馈回传 当 coding agent 在本地生成大量代码改动时在上一篇LoadingButtonAndroid状态管理详解从IDLE到DONE的完整流程下一篇JASONETTE-iOS JSON模板开发终极指南快速构建原生iOS应用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。