关于 minion-orchestrator
minion-orchestrator 是一项将持久后台工作路由到 Minions 的技能;Minions 是基于 Postgres 的任务队列。它涵盖确定性 Shell 任务和 LLM 子 Agent 任务,并支持监控、引导和生命周期管理。
主要功能
- 01路由 Shell 与子 Agent 任务
- 02网关重启后保留任务
- 03跟踪进度、Token 和会话记录
- 04通过消息引导运行中的 Agent
- 05暂停、恢复、取消或重放任务
- 06协调父子任务树
适用场景
- 01运行重启后仍需继续的长任务
- 02将研究拆分给多个并行 Agent
- 03监控并调整正在运行的 Agent
- 04管理可重复的脚本与 ETL 任务
MCP 相关
该技能介绍了可通过 MCP 调用的任务监控和生命周期操作,包括提交 Agent 任务。Shell 任务只能通过命令行提交;Agent 可通过 MCP 查看和管理 Shell 任务。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ garrytan/ gbrain --skill minion-orchestrator安装后在 Claude Code 中输入/minion-orchestrator确认已加载。
附带文件routing-eval.jsonl
详细介绍
Minion 编排器
约定
Minions 是一个基于 Postgres 的任务队列,用于持久化、可观测的后台工作。 这个单一 skill 处理两条通道:
- 确定性的 shell 任务(
gbrain jobs submit shell ...) - LLM 子 Agent 任务(
gbrain agent run ...)
何时路由到 Minions:需要在重启后依然存续、可被观测、需要扇出为多个并行任务,或需要跨会话持久化的工作。路由策略定义在 skills/conventions/subagent-routing.md 中——项目默认为 pain_triggered(优先使用原生子 Agent,只有特定痛点信号触发后才改用 Minions);Mode A(全部经由 Minions)为可选启用。
保证:
- 任务在网关重启后仍然存续(基于 Postgres)
- 每个任务都具备结构化进度、Token 计量和会话转录
- 运行中的 Agent 可以通过收件箱消息在执行过程中被引导
- 任务可随时暂停、恢复或取消
- 支持父子 DAG,并可配置失败策略
持久执行原则(Agent 遵循的路由约定,没有机制强制执行;参见下文“持久执行”):
- 预计超过约 2 分钟的操作应经由能力阶梯执行,绝不能使用会随会话一起终止的裸后台 shell。
- 死人开关检查需要验证结果已“回报”给用户,而不仅仅是进程已退出——一个被吞掉的完成事件,在用户看来与已死亡的任务完全相同。
- 死人开关只是第二道保险,并不是交付保证:它自身可能在触发前就已失效(调度器重启、条目被删除)。兜底方案是:在下一轮对话中,扫描
gbrain jobs list --status active以及最近的完成记录,查找结果从未送达用户的逾期工作。 - 死人开关检查是幂等的。重复触发,或与正常完成回报发生竞争的触发,应当静默;检查时应先查看已回报状态,并且在任何补报中标注任务 ID,以便能够识别重复项。
- 只有经过新鲜度检查的检查点或进度文件才可信。过期的检查点会永远显示为“仍在运行”;应将其时间戳与预期的进度间隔以及
gbrain jobs get <id>的结果进行比较。
路由请求:Shell 任务还是子 Agent
| 条件 | 操作 |
|---|---|
| 用户要求运行确定性的命令或脚本 | Shell 任务(CLI:gbrain jobs submit shell ...) |
| 用户要求“在 minions 中运行”并给出明确的命令或 argv | Shell 任务(CLI,--params 中包含 cmd 或 argv) |
| 用户要求研究、推理或迭代式 Agent | 子 Agent 任务(CLI:gbrain agent run) |
| 用户要求引导、暂停或恢复 Agent | 子 Agent 任务生命周期工具(可通过 MCP 调用) |
| 耗时在约 30 秒以内的单一简单操作 | 优先考虑内联执行 |
| 需要重启持久性或可观测性 | 提交为 Minion 任务 |
| 预计超过约 2 分钟的操作 | 经由下方的持久执行阶梯处理 |
| 并行工作(2 个及以上流) | gbrain agent run --fanout-manifest,或父子子 Agent |
如果意图不明确,只提出一个澄清问题: “您需要的是确定性的 shell 命令任务,还是 LLM Agent 任务?”
Shell 任务(确定性脚本)
适用于可复现的命令执行、ETL 步骤、定时任务,以及无需 LLM 推理循环的可脚本化工作。
前提条件(提交第一个 shell 作业前请先阅读)
- 必须使用
gbrain jobs work --allow-shell-jobs启动 worker(等效做法是在 worker 上导出环境变量GBRAIN_ALLOW_SHELL_JOBS=1;worker 目录中的.env无法设置该变量)。 shell 处理器始终处于注册状态,但受到门控保护:未开启该标志的 worker 一旦认领 shell 作业,就会立即将其转入死信(UnrecoverableError,直接进入dead状态,不重试),并在error_text中写明所需标志。若作业长期停留在waiting状态,说明根本没有任何 worker 在运行,请检查gbrain jobs supervisor status。门控逻辑位于src/core/minions/handlers/shell.ts。 - 安全性: 将
GBRAIN_ALLOW_SHELL_JOBS=1设为开启,即授权在 worker 上执行任意命令。在共享队列上,这构成远程代码执行入口。应将其视为特权基础设施授权来对待。 - 执行模式——二选一:
- Postgres + 守护进程:
gbrain jobs work运行一个常驻 worker,从队列中认领并执行作业。 - PGLite + --follow:
gbrain jobs submit ... --follow以内联方式运行。PGLite 不支持守护进程模式(存在独占文件锁)。详见docs/guides/minions-shell-jobs.md。
- Postgres + 守护进程:
- MCP 边界: shell 作业的提交仅限命令行。通过 MCP 执行
submit_job name="shell"会抛出错误码为permission_denied的OperationError;通用的远程提交仅接受sync、import、lint和lint-fix。 Agent 可以通过get_job/list_jobs/get_job_progress观察 shell 作业(这些操作不受保护),但无法提交它们。提交由运维人员或 autopilot 完成;Agent 负责观察。 - 验证配置: 完成配置后,运行
gbrain jobs stats(命令行)以确认 worker 已注册并正在消费队列。
提交(命令行,运维人员或 autopilot)
shell 作业通过 --params 传入命令,参数为一个 JSON 对象,包含 cmd(字符串)或 argv(数组),以及 cwd 和可选的 env。
命令字符串形式:
gbrain jobs submit shell --params '{"cmd":"echo hello","cwd":"/abs/path"}'
Argv 形式(不进行 shell 展开):
gbrain jobs submit shell --params '{"argv":["bash","-lc","echo hello"],"cwd":"/abs/path"}'
在 PGLite 或任何一次性部署上进行内联执行:
gbrain jobs submit shell --params '{"cmd":"echo hello","cwd":"/tmp"}' --follow
gbrain jobs submit --help 提供的队列与生命周期标志:--queue、--priority、--delay、--max-attempts、--max-stalled、--backoff-type、--backoff-delay、--backoff-jitter、--timeout-ms、--idempotency-key、--dry-run。
监控(Agent 或运维人员)
以下操作可通过 MCP 调用,适合 Agent 使用:
list_jobs --name shell --status active
get_job ID
get_job_progress ID
可从 get_job 中查看结构化结果字段(退出码、stdout/stderr 尾部输出、尝试次数、耗时等)。如需查看 worker 与队列的健康仪表盘(包括队列卡死信号),请使用 get_job_stats(MCP)或 gbrain jobs stats(命令行)。
控制(可通过 MCP 调用)
cancel_job id=ID
replay_job id=ID
replay_job 不受保护,受保护的仅是 shell 提交。Agent 无需命令行访问权限即可取消或重放 shell 作业。
对于周期性的 shell 工作负载,请使用幂等键,以避免重复执行。
子 Agent 作业(LLM 编排)
适用于开放式推理、需要调用工具的研究以及扇出式综合任务。
面向用户的入口: gbrain agent run <prompt> 是提交子 Agent 工作的标准方式。它负责处理提权信任相关的底层逻辑——subagent 和 subagent_aggregator 是受保护的作业名称。远程 Agent 应使用专用的 submit_agent 操作,并绑定其配置的来源、工具和 slug;通用的 submit_job 不接受这些作业名称。
阶段 1:提交
gbrain agent run "Research Acme Corp revenue" --tools "search,query"
--tools 接受以逗号分隔的 BRAIN_TOOL_ALLOWLIST 子集(参见 src/core/minions/tools/brain-allowlist.ts):query、search、get_page、list_pages、get_backlinks、traverse_graph、list_link_sources、resolve_slugs、get_ingest_log、put_page、add_timeline_entry、get_recent_salience、find_anomalies。附件工具和仅限本地的操作不可用。在重新提交引用已移除工具的作业之前,请更新旧绑定。远程绑定必须非空;显式设置为空的本地工具列表不授予任何工具。
对于使用扇出清单的并行工作:
gbrain agent run --fanout-manifest companies.json
该清单描述 N 个子任务加 1 个聚合器。每个子任务在底层运行 name="subagent",聚合器运行 name="subagent_aggregator",并在所有子任务终止后才会认领。参见 src/core/minions/handlers/subagent.ts 和 src/core/minions/handlers/subagent-aggregator.ts。
参数(来自 src/commands/agent.ts):
--subagent-def <name>:命名的子 Agent 定义--model <id>:覆盖模型--max-turns <N>:限制 LLM 循环次数--tools <csv>:允许使用的大脑工具白名单(见上文)--timeout-ms <N>:每个作业的硬超时--fanout-manifest <file>:N 个子任务加 1 个聚合器--follow/--no-follow:流式输出日志并等待(在 TTY 上默认开启)--detach:提交后立即返回
gbrain agent run 不提供队列、优先级和重试的调优选项;如果需要这些设置,请通过 gbrain jobs submit 直接提交原始 subagent 处理器(需要 CLI 信任)。
准入控制(v0.46.11.0)。 完全相同的无父级 subagent 提交(相同的所有者通道、负载和执行选项)会合并到已存在的等待中作业上:gbrain agent run 会输出 coalesced 并附上匹配的作业 ID,submit_agent MCP 响应会带有 coalesced: true。请将其视为成功——监控匹配的 ID,不要重新提交。超过 TTL 仍在等待的作业(subagent 默认为 48 小时;minions.ttl_waiting_hours.<name>)将被取消,原因前缀为 waiting_ttl_expired。如果运维人员配置了等待配额(minions.quota_max_waiting.<name>),超过上限的提交将返回结构化的、可重试的 rate_limited 错误——请退避,并在重试前检查 gbrain jobs stats 中是否有 DIVERGENT QUEUE 行。
阶段 2:监控
list_jobs --status active # MCP — what's running?
get_job ID # MCP — full details + logs + tokens
get_job_progress ID # MCP — structured progress snapshot
gbrain jobs stats # CLI — queue health dashboard
gbrain agent logs ID --follow # CLI — streaming transcript + heartbeat
进度信息包括:步骤数、总步骤数、消息、token 用量、最近调用的工具。
阶段 3:引导
向正在运行的 Agent 发送消息以改变其方向:
send_job_message id=ID payload={"directive":"focus on revenue, skip headcount"}
Agent 处理器会在每次迭代时读取收件箱消息,并将其作为上下文注入。消息会被确认(跟踪已读回执)。
只有父作业或管理员可以发送消息(发送者验证)。
阶段 4:生命周期
pause_job id=ID # freeze without losing state
resume_job id=ID # pick up where it left off
cancel_job id=ID # hard stop
replay_job id=ID # re-run with same or modified params
replay_job id=ID data_overrides={"depth":"deep"} # replay with changes
所有生命周期操作均可通过 MCP 调用。
阶段 5:审查结果
get_job ID # result, token counts, transcript
Token 计量:每个作业都会跟踪 tokens_input、tokens_output、tokens_cache_read。子作业的 token 在完成时会自动汇总到父作业。
持久化执行(耗时超过 2 分钟的操作)
后台 Shell 会悄无声息地终止:会话压缩、Harness 重启、工具超时。长时间运行的 gbrain 操作(extract all、embed --stale、完整的 sync --all)通常需要 10 到 60 分钟,会超过上述所有时限。即使任务本身没有中断,完成事件也可能丢失(工作进程重启、通知被丢弃),导致用户面对沉默,而已完成的结果却没有被报告。持久化执行同时覆盖这两个环节:任务能够存活,并且结果报告必定送达。
凡是预计超过约 2 分钟的操作,都应通过本部署所支持的最高层级执行。这是 Agent 所遵循的 Harness 路由约定,而非机械性保证——除非本 Skill 明确禁止,否则没有任何机制能阻止裸后台 Shell 的使用。
付费任务须先获得同意再提交。 任务在无终端环境中运行,因此付费命令(embed --stale,或任何调用模型服务商的其他命令)若未携带用户的授权,将以退出码 3 和同意请求载荷而终止。请先在对话中获得授权:运行该命令的预览(例如 gbrain embed --stale --dry-run),告知用户预估结果,只有在用户同意后,才可将授权写入提交的命令中(gbrain embed --stale --yes --max-usd <上限>,上限为用户批准的金额),或依赖用户通过 gbrain config set consent.preapprove.paid.max_usd_per_run <usd> 设置的常驻授权。未经用户明确回复,绝不可添加 --yes。当任务以退出码 3 或 confirmation_required 代码结束时,请将其消息转达给用户并停止操作;不得加上 --yes 重新提交。
第一层级——Minion 任务 + 死人开关(Postgres + 工作进程)
要求:Postgres 引擎、正在运行的 gbrain jobs work 工作进程,以及(若使用 Shell 通道)以 --allow-shell-jobs 启动的工作进程(或在其上导出 GBRAIN_ALLOW_SHELL_JOBS=1)。上文所有前置条件仍然有效:该标志默认关闭,Shell 任务提交仅限命令行,跨越 MCP 信任边界时不可用,且 PGLite 没有工作进程守护进程(见第三层级)。本节内容不会放宽上述约束。
-
作为任务提交,以便工作在重启后仍能存活:
gbrain jobs submit shell \ --timeout-ms 3600000 \ --params '{"cmd":"gbrain extract all","cwd":"/abs/path","inherit":["database_url"]}'需要大模型判断的工作应改走子 Agent 通道(即上文的
gbrain agent run)——提交后却从不检查的 Agent 任务,与未受监控的 Shell 任务是同一类错误。 -
在同一操作块中设置死人开关(模式见下文)。只提交而不设置,是典型的半成品修复:任务存活了,沉默却没有解决。
第二层级——定时检查进度文件(无可唤醒 Agent 的调度器)
当没有调度器能唤醒 Agent,但主机具备普通 crontab(或工作完全在队列之外运行)时:让操作在推进过程中写入进度/心跳文件(对于队列任务,也可依赖 get_job_progress),并注册一个周期性的主机 cron 检查,将文件的新鲜度与预期的进度间隔进行比较。Agent 也会在下一轮开始时检查该文件。若检查点停止推进,应判定为已停滞,而非"仍在运行"——新鲜度比较正是本层级的全部价值所在。
第三层级——前台执行 + 输出缓冲(PGLite / 无工作进程 / 无调度器)
按照 skills/conventions/exec-output.md,在前台内联运行操作——在 PGLite 上即 gbrain jobs submit ... --follow,或直接运行原始命令——并将所有输出缓冲到文件中,分段读取有界片段。长时间命令之后工具返回空结果,属于输出截断,而非 Shell 已失效。本层级没有静默终止的保险机制,因此应将操作保留在前台并持续监控;此处若转入后台,就会重蹈本层级级联设计所要防止的故障。
死人开关模式
这是一种一次性的、会自行删除的定时检查,在预计完成时间加上余量的时刻触发,并验证结果是否已被报告,而不只是进程是否退出。请在与提交操作相同的操作块中设置它(不要之后再设,也不要“如果我记得的话”)。
- 诚实地估算
expected_minutes;向上取整。 - 截止时间 = 当前时间 + 估算时长 + 余量,其中
margin = max(10 分钟, 估算时长的 50%)。重启会延迟交付——设得太紧会误触发,设得晚几小时则失去意义。 - 使用宿主提供的任意一次性调度器创建检查:带有“运行后删除”语义的 harness cron 工具、
at,或是检查在首次触发时自行删除的 crontab 条目。检查的指令如下:- 验证结果是否已报告给用户。
gbrain jobs get <id>可获取任务状态;已报告检查会询问完成消息是否真正送达用户。 - 已报告 → 不做任何操作,保持沉默,自行删除。
- 已完成但未报告(事件被吞掉)→ 通过
gbrain jobs get <id>获取结果,并立即发布恢复报告,附上任务 ID 标记。 - 仍在运行 → 发布一行状态信息,附上新的 ETA,并以原估算时长的 +50% 设置一个后续死人开关。后续开关最多一个——不允许无限链式设置。
- 已死亡/失败 → 报告其在终止前产生的内容(来自
gbrain jobs get <id>的stderr_tail),并提供gbrain jobs retry <id>选项。
- 验证结果是否已报告给用户。
- 正常完成时解除。 当完成事件到达并且你已报告它时,移除死人开关。即使它仍然触发,已报告检查也会使其成为静默的空操作——双重保险。
该模式必须应对的故障模式(在契约和反模式中有对应内容):死人开关本身在触发前失效(第二道保险,由下一轮的逾期扫描兜底)、重复触发(幂等的已报告检查加上带任务 ID 标记的报告),以及过期检查点(在相信“仍在运行”之前先做新鲜度检查)。
随该模式引入的评估契约——死人开关的部署按以下标准评判:
- ARMED_ON_SPAWN —— 是否与长时间提交操作在同一操作块中创建?
- SELF_DELETING —— 是否为一次性,并且一切正常时保持沉默?
- DETECTS_SWALLOWED —— 是否验证结果已被报告,而不只是任务已退出?
- RECOVERS —— 遇到被吞掉的事件时,是否拉取输出并发布恢复报告?
- RIGHT_DEADLINE —— 截止时间是否为预计完成时间加合理余量,既不误触发也不晚几小时?
硬性失败项:长时间的面向用户操作没有设置死人开关;完成事件正常到达时,死人开关仍发布噪音消息;用 sleep 或轮询循环模拟计时器,而不是使用调度器条目(休眠进程会随会话一同终止——这正是该机制要防范的失败)。
顺序执行与锁
维护操作共享锁(sync、embed、extract、integrity)。请按顺序串联执行:提交任务 1,并设置其死人开关;完成后提交任务 2,并设置下一个;最后运行 gbrain doctor 并报告健康状况的变化。如果任务在操作中途死亡,其锁会在 TTL 到期时失效(处于活动状态且最近刷新过的持有者受到窃取宽限期的保护)——切勿手动删除锁记录来“解除”队列阻塞。
典型长时间操作
耗时取决于语料库规模;请将以下数值仅视为 --timeout-ms 的数量级参考,而非承诺。
| 操作 | 典型耗时 | 建议的 --timeout-ms |
|---|---|---|
extract all | 大型 brain 上 30-60 分钟 | 3600000 |
embed --stale | 5-30 分钟(取决于缺失数量) | 1800000 |
sync --all | 5-20 分钟 | 1200000 |
integrity auto | 10-30 分钟 | 1800000 |
dream | 5-15 分钟 | 900000 |
附录:内容寻址的阶段检查点
对于包含昂贵中间环节的多阶段流水线(提取 → 评分 → 解释 → 渲染 → 验证,其中评分阶段会产生真实的 LLM 开销),可以将每个阶段设计为内容寻址的检查点,这样一旦崩溃、由 deadman 触发的重试,或 replay_job,都可以续跑而不必重新消耗开销:
- 为每个阶段生成键:基于以下内容的哈希值计算:该阶段自身的逻辑、其参数,以及其上游产物的哈希值。产物存放在流水线工作目录下的
.cache/目录中,并按内容哈希寻址。 - 热重跑为空操作:所有键都命中,不会重新计算任何内容,整条流水线会在不到一秒内完成回放。
- 失效正确级联:参数变更或逻辑编辑都会改变该阶段的键,从而重新计算该阶段,以及上游哈希发生变化的所有下游阶段。阶段自身的源代码必须纳入键的计算;若省略,逻辑编辑会悄无声息地复用过期产物。
- 记录溯源信息:每次运行生成一个溯源文件,记录每个阶段的键、输入、输出和计算时间,使每个产物都能追溯到生成它的确切逻辑与数据,并且"哪个阶段因何被重新计算"始终可以查明。
- 恢复时校验完整性:将现有产物与已记录的校验和进行比对;若不匹配,则重新计算或从缓存恢复,绝不静默复用。
这与流水线的分级机制是互补关系而非替代关系:分级机制保证流水线持续运行并能汇报状态;阶段检查点则让重试成本保持低廉。只要单个阶段的 LLM 开销超过零钱数目,就应当两者搭配使用。
评判维度:IDEMPOTENT(热重跑不重新计算任何内容)、CORRECT_BUSTING(变更恰好重新计算受影响的阶段)、PROVENANCE(每个产物都能追溯到逻辑、参数和上游)、INTEGRITY(损坏的产物被检测到,绝不被静默复用)。
输出格式
向用户汇报任务状态时:
Job #ID (name) — status
Progress: step/total — last action
Tokens: input_count in / output_count out (+ cache_read cached)
Runtime: Xs
Children: N pending, M completed
汇报完成时:
Job #ID completed in Xs
Tokens used: input / output / cache_read
Result: <summary>
汇报批量任务状态时(父任务及其子任务):
Parent #ID — waiting-children
#A subagent(Acme) — active, 3/5 steps, 2.5k tokens
#B subagent(Beta) — completed, 1.8k tokens
#C subagent(Gamma) — paused
Total tokens so far: 4.3k
失败时的处理
对于任何 gbrain 错误 code、退出码、[AGENT] 块或通知块,均遵循 agent operator protocol。针对本技能的具体情况:
- 通过 MCP 为受保护任务执行
gbrain jobs submit返回permission_denied:该命令必须在 brain 主机上通过受信任的本地命令行执行;需告知用户。 - Shell 任务立即进入死信队列,且
error_text中指明了相关标志(shell 任务已禁用):需告知用户主机运维人员必须设置哪个环境变量标志;不要重试。 - 提交上限触发的
rate_limited:在resubmit前等待所示的延迟时间;期间不要增加更多提交。 - 任务长时间处于
waiting状态且没有 worker:在重新提交前,先通过gbrain jobs get <id>确认已有 worker 注册。
反模式
- 不要为单个搜索查询启动 Minion(直接使用搜索工具)
- 不要只提交不检查结果(fire-and-forget)
- 在未先检查
gbrain jobs stats的情况下,不要同时启动超过 5 个 Agent - 当提交返回
coalesced时不要重复提交——工作已经排队;应监控匹配到的作业 ID - 对于子 Agent 工作,当 Minions 可用时,不要使用
runtime: "subagent"的sessions_spawn(应改用gbrain agent run) - 不要在紧密循环中轮询
get_job(轻量检查请使用get_job_progress) - 不要以裸后台 Shell 的方式运行预计超过约 2 分钟的操作——它会随会话一起终止;应通过持久执行阶梯来运行
- 在没有已武装的 deadman 或确定会触发的定时检查的情况下,不要说“完成后我会回报”
- 当完成通知已正常到达时,不要让 deadman 发出多余通知——先检查已报告状态,保持静默,并自行删除
- 不要用
sleep或轮询循环模拟 deadman 计时器——休眠的进程会随会话一起终止,而这正是需要防范的失败情形 - 没有新鲜度检查,不要信任检查点或进度文件——过期的检查点会永远被误读为“仍在运行”
- 不要同时运行需要获取锁的维护操作(
sync、embed、extract、integrity),也不要手动删除锁记录来解除阻塞(锁会在 TTL 到期后自动失效)
使用的工具
- 提交后台作业 —
submit_job(MCP:仅限sync、import、lint和lint-fix,遵循docs/guides/authorization-upgrade.md中的约定;Shell 作业使用本地 CLI,远程子 Agent 使用submit_agent) - 获取作业详情 —
get_job(MCP) - 按过滤条件列出作业 —
list_jobs(MCP) - 取消作业 —
cancel_job(MCP) - 暂停作业 —
pause_job(MCP) - 恢复已暂停的作业 —
resume_job(MCP) - 重放已完成/失败的作业 —
replay_job(MCP) - 发送旁路消息 —
send_job_message(MCP) - 获取结构化进度 —
get_job_progress(MCP) - 队列统计 —
get_job_stats(MCP;通过 HTTP 访问需要管理员权限范围,与此处的其他作业操作相同,包含队列卡死导致的静默停滞信号)或gbrain jobs stats(CLI)