mcpField
S
summon-cc

summon-cc

github.com/anfreireAgent 工作流181 次安装6 周前更新
代码仓库

关于 summon-cc

已归档且不再维护的技能,用于让 Agent 通过 tmux 启动并监督独立的 Claude Code 会话。它以追加式文件信号传递状态,替代解析终端输出;新项目应考虑其继任者 conclave。

主要功能

  1. 01在 tmux 中启动 Claude Code 工作会话
  2. 02通过文件信号等待状态与结果
  3. 03向暂停会话转发问题并提交回答
  4. 04向运行中的工作会话发送后续指令
  5. 05按工作范围并行组织多个工作者
  6. 06提供会话状态检查与清理流程

适用场景

  1. 01从其他 Agent 环境委派编码任务
  2. 02等待工作会话完成并读取报告
  3. 03处理工作者提出的选择或问题
  4. 04组织实现与独立审查流程

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/anfreire/summon-cc --skill summon-cc

安装后在 Claude Code 中输入/summon-cc确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

hooks/
on_ask_question.sh
on_post_tool.sh
on_prompt_submit.sh
on_session_end.sh
on_session_start.sh
on_stop.sh
scripts/
spawn.sh
wait.sh

详细介绍

summon-cc — 通过任意 Agent 执行 Claude Code 会话

已弃用。 summon-cc 已归档且不再维护。它的后继项目是 conclave(https://github.com/anfreire/conclave),可通过一个 CLI 在 Claude Code、Codex 或 OpenCode 上启动 Agent,无需操作 tmux 窗格。新项目请优先使用它;以下内容仍描述此技能当前的状态。

你是编排者。你在分离的 tmux 窗格中启动完整的交互式 Claude Code 会话(“工作者”),为每个会话提供范围明确的提示词,并通过只追加的文件信号监督它们。你负责编排;工作者负责执行。三条原则让这一过程省心又轻松:

  1. 绝不解析终端。 信号会传递所有信息;只有信号表明出现问题时,才将窗格作为调试界面读取。
  2. 绝不空闲轮询。 每个工作者配一个等待器,静默阻塞,直到有事发生。
  3. 根据信号采取行动,通过信号验证。 每一步——启动、发送提示词、回答——都会留下信号,证明操作已生效。脚本会验证自身步骤;你来验证自己的步骤。

任何运行环境中的任意 Agent 都可以担任编排者——此处的所有能力都只是普通的 Shell 命令。只有工作者一侧使用 Claude Code,这正是设计目的:此技能将不受限制的 Claude Code 会话交到你手中,作为构建模块——你可以用它们构建什么(流水线、审查循环、扇出、看门狗),由你决定。

要求

  • Linux 或 macOS;需要 bash、tmux、jq,以及支持 --settings 和 --effort 的 claude CLI(任意当前版本均可——运行 claude --help 确认)。
  • 无需安装或配置任何内容。 启动时会在启动命令行中通过 --settings 为每个工作者注入六个生命周期钩子:不会触碰用户的任何设置文件;未由你启动的会话也完全不会加载这些钩子。
  • 两个脚本位于 scripts/ 中,与此 SKILL.md 并列;请使用绝对路径 调用它们(你的工作目录通常在别处)。下文中的 <skill-dir> 指此技能所在目录。

快速开始 — 从头到尾运行一个工作者

brief="$(mktemp)"   # a fresh file per worker
printf '%s\n' 'Fix the failing test in src/foo. END YOUR TURN with a one-paragraph report.' > "$brief"
bash <skill-dir>/scripts/spawn.sh fixer "$brief"
# → SUMMONED id=fixer-6a53bd1e00002f40 state=/home/you/.local/state/summon/workers/fixer-6a53bd1e00002f40
bash <skill-dir>/scripts/wait.sh fixer-6a53bd1e00002f40  # silent until → EVENT=STOP + the report
tmux kill-session -t '=fixer-6a53bd1e00002f40'           # done with it ('=' = exact match)

SUMMONED 会输出两个句柄:id(用于 wait、send-keys、kill)和状态目录 (包含所有信号文件)——即下文的 <id> 和 <state>。所有操作都基于这两个句柄。

启动

将工作者的提示词写入一个文件(多行内容作为一个整体粘贴)。提示词不能以 /、! 或 # 开头——这些是 TUI 的输入前缀(斜杠命令 / bash 模式 / 记忆),否则文本会作为命令运行,而不是提交;启动脚本会明确拒绝这类文件。然后:

bash <skill-dir>/scripts/spawn.sh <name> <prompt-file> [effort] [cwd] [permissions]
  • effort — 原样传递给 claude --effort:可用值由 claude 决定 (claude --help 会列出);default(默认值)保留会话自身的设置。这是即发即忘式的调优:未知值不会中止启动——claude 会静默使用其默认值,窗格中也不会发出警告;STOP 行会显示 claude 报告的实际 effort(effort=…)——这是确认设置已生效的唯一方式。
  • cwd — 工作者的项目目录(默认:当前目录)。
  • permissions — bypass(默认值 → --dangerously-skip-permissions:分离的窗格无法响应权限提示,因此工作者会自行把关——参见“工作者提示词”) · inherit(不添加标志:使用 claude 在该 cwd 下的默认设置) · 其他值会原样传递给 --permission-mode(claude --help 会列出可用模式)。无效模式会导致启动失败,并显示 claude 自身的错误信息。
  • SUMMON_CLAUDE_ARGS — 可选环境变量,其额外标志会原样追加到启动命令行:--model haiku 可用于低成本侦察;--resume <session_id> 可在新窗格中恢复已退出工作者的对话(其 session_id 位于 <state>/events.jsonl)。

启动流程会端到端自验证(启动、粘贴、提交——全部根据钩子信号验证,并自行重试)。如果失败,会明确说明原因,同时提供窗格末尾内容和解决办法;首次运行时通常是两个同意对话框导致失败(见“注意事项”)。

循环

spawn → wait → act on the event → wait again → … → down

bash <skill-dir>/scripts/wait.sh <id> [max_secs]     # default 1800

如果你的运行环境支持,请在后台运行(它会保持静默,直到退出);否则请阻塞运行。工作进程运行期间不会占用你的任何资源,并会以一个自包含的区块退出:

  • EVENT=STOP — 工作进程结束了当前轮次;其最终消息紧随其后,由 Stop 钩子捕获(绝不会解析 transcript)。通常这是你要求的报告,但工作进程有时只是结束轮次来告诉你一件事:请阅读,然后继续操作或再次等待。即使 Stop 行无法读取,事件仍为 EVENT=STOP——区块会说明消息无法读取,并指向 transcript,因此 Stop 绝不会被藏在 IDLE 后面。
  • EVENT=QUESTION — 工作进程暂停在 AskUserQuestion;后面会列出编号选项。请作答(见下一节),然后再次等待。
  • EVENT=IDLE — 达到上限,没有发生任何事情;后面会显示心跳时间和近期工具活动。长时间静默很正常(可能正在思考、运行子 Agent 或长时间子进程)——重新发出同一命令即可。只有在有实际证据表明进程卡住时才介入。
  • EVENT=DEAD — 工作进程已不存在:窗格已被杀死,或 claude 已退出并留下一个空 shell(区块会说明具体情况,并提供事后检查指引)。

重新发出命令时,命令完全相同——游标(保存在工作进程目录中)会从上次报告的事件继续。

回答问题

选项按 question.json 中的顺序编号;窗格会在真实选项之后追加自己的条目(“Type something”、“Chat about this”),因此你看到的编号对应的都是真实选项。

  • 单个问题——输入数字即可选择并提交:tmux send-keys -t <id> 2
  • 多个问题——输入数字会自动进入下一题;完成最后一题后,按 Enter 提交复核步骤: tmux send-keys -t <id> 1; sleep 1; tmux send-keys -t <id> 3; sleep 1; tmux send-keys -t <id> Enter
  • [multi-select] — 输入数字切换选项,按 Enter 提交。
  • 也可以输入自由文本(“Type something”选项),但操作繁琐——建议优先选择列出的选项。
  • 请核实,不要想当然。 答案提交后,会在 <state>/events.jsonl 中追加一行 QuestionAnswered(包含选定的标签),下一次等待会跳过该问题。单个问题输入数字后会立即提交——不会出现复核界面——因此选择很重要时,请查看 QuestionAnswered 行。多问题流程会停留在一个需要按 Enter 才能继续的复核界面:提交有破坏性的选择前,请先查看: tmux capture-pane -t <id> -p | tail -30

向正在运行的 worker 发送消息

仅在没有待处理问题时(<state>/question.json 不存在)。问题模态框弹出时,输入的文本会被模态框捕获,随后按下的 Enter 会选择当前高亮项——这会意外回答问题,而不是将消息加入队列。请先回答问题,或中断以取消问题。

  • 将后续消息加入队列(worker 在下一轮交接时读取;-l 表示按字面发送,因此像 Up 这样只有一个单词的消息不会被当作同名 tmux 按键发送): tmux send-keys -t <id> -l 'your message' && tmux send-keys -t <id> Enter
  • 较长或包含大量引号的后续消息——按 spawn 的方式粘贴(每个 worker 使用独立的缓冲区名称,避免并行发送时互相串扰): tmux load-buffer -b poke-<id> <file> && tmux paste-buffer -t <id> -b poke-<id> -p -d && sleep 1 && tmux send-keys -t <id> Enter
  • 发送消息时绝不要以 /、! 或 # 开头——这些是 TUI 输入前缀,无论键入还是粘贴都一样: / 会运行斜杠命令(/exit 会终止 worker),! 会在 worker 的工作目录中执行后续内容作为 shell 命令,# 会打开记忆选择器;这些都不会提交提示词(不会触发 UserPromptSubmit)。需要发送以这些字符开头的字面内容?在前面加上其他内容(例如“注意:/foo …”)。
  • 中断生成以重定向:tmux send-keys -t <id> Escape,然后发送消息。Escape 是 TUI 自带的中断键,对空闲的 worker 不起作用——但只发送一次:快速连续按两次 Escape 会打开 Rewind 菜单,这是信号无法检测到的模态框,可能会还原代码和对话。如果消息似乎被吞掉了(没有出现 UserPromptSubmit 行),先重新发送 Enter——粘贴延迟会让文本留在输入框中,再按一次 Enter 就会提交(先重新粘贴会叠加第二份副本)。还是没反应?说明有模态框弹出:按一次 Escape 将其关闭,然后重新发送消息。 绝不要按 C-c——快速连续按两次 C-c 会彻底退出 claude,而误判卡顿时恰好最容易按到它。被中断的轮次不会触发 Stop——你的消息所在的下一轮完成后才会触发。如果中断时有待处理问题,该问题会被取消;孤立的 question.json 会在你提交下一条消息时自动归档。
  • 新启动的 worker 上下文为空——要继续使用某个 worker,请向其窗格发送消息,不要重新启动。

结果、状态与调试

  • 最终消息——wait 在 STOP 时打印;可随时重新读取: grep '"event":"Stop"' <state>/events.jsonl | tail -1 | jq -r .last_assistant_message
  • 已给出的答案——grep '"event":"QuestionAnswered"' <state>/events.jsonl | tail -1 | jq -c .answers
  • 所有 worker—— find "${SUMMON_STATE:-$HOME/.local/state/summon}/workers" -name meta.json -exec jq -r '"\(.id) \(.name) \(.cwd)"' {} + 2>/dev/null ——通过 tmux ls 交叉核对运行状态,通过 find "${SUMMON_STATE:-$HOME/.local/state/summon}/workers" -name question.json 2>/dev/null 查看待处理问题。
  • 即时探测——bash <skill-dir>/scripts/wait.sh <id> 0 会立即返回:任何尚未消费的事件,否则返回 IDLE 快照(心跳时长 + 最近活动)。与任何 wait 一样,采用相同的单次调用、游标安全语义——探测不耗费任何资源。
  • 查看(仅用于调试——每次捕获窗格都会消耗编排器上下文;通常应使用上述信号):tmux capture-pane -t <id> -p | tail -40

清理

消费完某个 worker 的结果后:tmux kill-session -t '=<id>'——保留 =: 它会锁定精确名称;当精确会话不存在时,单独使用 -t 会退回前缀匹配(参见“注意事项”)。Claude 对话记录无论如何都会保留在磁盘上。使用完相关证据后,删除状态目录:rm -rf <state>。Id 不会重复使用——过期目录不会发生冲突。

Worker 提示词 — 编排奏效的关键

  • 独立完整且范围明确。 Worker 不共享你的任何上下文:说明目标、确切范围、范围之外的内容,以及“自行阅读 X 和 Y”。每个 Worker 只做一项工作。
  • 告诉它如何收尾:“结束本轮前,报告 A/B/C。”停止信号表示任务已完成,因此结束本轮——并在最终消息中提供你需要的信息——也是 Worker 的工作之一。你应该始终只需查看最终消息。
  • 让 Worker 自行把关高风险操作(在 bypass 模式下尤为重要):指示 Worker 在进行任何不可逆、破坏性或超出范围的操作前暂停,并通过 AskUserQuestion 询问——这会通过 QUESTION 事件将决策交给你,并附上可通过输入数字作答的编号选项。
  • 独立审查能发现更多问题:对于流水线,让一个 Worker 执行步骤,再让一个全新的 Worker 审查;重复此过程,直到审查者未作任何更改并予以批准。

决策路由

Worker 提问时:如果任务约束已经决定了答案,或该选择可以挽回,就由你自行回答,以保持工作推进。只有真正新颖、影响重大或不可逆的事项才升级给人工处理。不确定某事是否可逆时,应视为需要升级。提前与人工确认这一界限。

逐个执行与批量执行

  • 逐个执行:启动 → 等待完成 → 处理 → 关闭 → 下一个。每个结果都决定下一步;适用于简单的流程管理。依赖步骤默认采用此方式。
  • 批量执行:启动 N 个 Worker(名称各不相同,每个 Worker 配一份简短文件;记录每个打印出的 id 和状态),为每个 Worker 启动一个等待器,哪个先退出就先处理哪个,并且只重新启动该 Worker 的等待器。每个信号文件都专属于对应的 Worker——并发 Worker 之间不会串线。你的运行环境不支持后台执行?使用较短的上限轮流等待——wait.sh w1 60; wait.sh w2 60; …——等待是单次且游标安全的,因此轮流等待不会造成遗漏。并发数量应控制在机器和你的注意力所能承受的范围内——一批 Worker 同时启动可能导致 claude 的启动时间超过 spawn 的 45s 启动窗口。

状态目录 — 参考

每个 Worker 一个:${SUMMON_STATE:-~/.local/state/summon}/workers/<id>/(由 spawn 打印)。

文件含义
meta.json启动时的配置:名称、cwd、提示词文件、工作强度、权限、额外参数
settings.json--settings 注入此 Worker 的内容:六个钩子、promptSuggestionEnabled: false
events.jsonl生命周期:SessionStart、UserPromptSubmit、AskUserQuestion、QuestionAnswered、Stop(包含最终消息、权限模式、工作强度)、SessionEnd——每个事件占一行,内容完整或不存在
question.json待处理的 AskUserQuestion;存在即表示待处理(已回答或过期的副本会归档在它旁边)
heartbeat / activity.log上次工具调用的 epoch 时间 / 每次工具调用对应的一行记录
claude_exited退出标记:claude 出于任何原因退出时,面板中的 shell 会立即创建此文件(启动期间 spawn 会据此快速失败;如果 claude 退出时没有 SessionEnd——例如被强制终止、发生 OOM——wait 会将其判定为 DEAD)
cursor等待器的状态记录——自动管理,请勿触碰

注意事项

  • Stop 表示完成;SessionEnd 只是记录 — 对于任何一次退出,SessionEnd 都可能触发,也可能不触发:正常执行 /exit 会写入一条记录,tmux kill-session 有时也会写入,强制终止则绝不会。只有它是否存在才有意义——绝不要等待它,也不要从它的缺失中推断任何信息。wait.sh 编码了所有这些情况:claude 已退出但窗格中的 shell 仍存活时,会读取到 DEAD——如果 SessionEnd 触发了,就通过它;如果没有触发(SIGKILL、OOM),就通过 claude_exited 标记——绝不会永远处于 IDLE。
  • 首次运行对话框会阻塞启动(在 SessionStart 步骤中大声报错退出):从未接受过 --dangerously-skip-permissions 的机器,或 Claude 尚不信任的工作目录,会先显示交互式对话框。解决方法:在该目录中交互式运行一次 claude,接受后重新启动。不要编写脚本绕过这些对话框——它们是同意门槛。
  • 不可绕过权限的工作进程可能会卡在权限对话框上——权限和计划审批提示不是 AskUserQuestion:不会触发钩子,也不会出现信号,心跳只会过期。在不可绕过权限的工作进程上,若处于 IDLE、心跳时间较早且没有待处理问题 → 查看窗格;用 send-keys 回答对话框,或在 bypass 模式下重新启动。
  • 词汇定义在 claude 中,不在这里。 努力级别和权限模式会原样传递,且从不验证——claude --help 是准确信息来源。
  • 工作进程的输入框中不会有幽灵文本。 TUI 建议的下一条提示词——每轮结束后显示的灰色文本,窗格捕获会将其打印得像已输入一样——已在每个工作进程注入的设置中关闭(promptSuggestionEnabled: false),因此工作进程输入框中的文本都是真实输入:延迟的粘贴内容或排队等待发送的 poke。
  • 当没有完全匹配的名称时,tmux -t 会进行前缀匹配——此时已退出工作进程的 id 可能会匹配到名称相似的会话。多层防护:id 为固定长度,启动时会拒绝名称中包含 id 格式字符串的情况(因此一个 id 永远不能嵌套另一个——不要将旧工作进程的 id 作为新工作进程的 name 传入),拆除命令则通过 = 固定目标。如果希望 send-keys/paste/capture 的窗格目标命令也采用相同的固定方式,可使用 -t '=<id>:'。
  • 钩子以 $SUMMON_ID 为门控条件,并按工作进程注入——没有由你召唤的会话不会加载或写入任何内容。每条事件行都出现两次?第二份钩子注册在 claude 为该工作目录加载的设置文件中——用 grep -l on_session_start.sh <cwd>/.claude/settings*.json ~/.claude/settings.json 找到它并移除;与此同时,信号能够容忍重复内容。
  • 工作进程使用 tmux 服务的环境变量,而不是你的环境变量——服务会保留启动它的用户的环境,因此在启动前导出的变量不会传到窗格中。每个工作进程的配置项应放在启动行(SUMMON_CLAUDE_ARGS)中,或放入注入的设置中,启动程序自身的设置就是通过这种方式传递的。
  • 不要使用 GNU 专属功能扩展脚本(date -d、sed -i、flock、timeout)——使用秒级 Unix 时间戳运算和普通 POSIX 工具,才能继续支持 macOS。

评论

支持 Markdown