关于 summon-cc
已归档且不再维护的技能,用于让 Agent 通过 tmux 启动并监督独立的 Claude Code 会话。它以追加式文件信号传递状态,替代解析终端输出;新项目应考虑其继任者 conclave。
主要功能
- 01在 tmux 中启动 Claude Code 工作会话
- 02通过文件信号等待状态与结果
- 03向暂停会话转发问题并提交回答
- 04向运行中的工作会话发送后续指令
- 05按工作范围并行组织多个工作者
- 06提供会话状态检查与清理流程
适用场景
- 01从其他 Agent 环境委派编码任务
- 02等待工作会话完成并读取报告
- 03处理工作者提出的选择或问题
- 04组织实现与独立审查流程
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ anfreire/ summon-cc --skill summon-cc安装后在 Claude Code 中输入/summon-cc确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
hooks/on_ask_question.shon_post_tool.shon_prompt_submit.shon_session_end.shon_session_start.shon_stop.shscripts/spawn.shwait.sh详细介绍
summon-cc — 通过任意 Agent 执行 Claude Code 会话
已弃用。 summon-cc 已归档且不再维护。它的后继项目是 conclave(https://github.com/anfreire/conclave),可通过一个 CLI 在 Claude Code、Codex 或 OpenCode 上启动 Agent,无需操作 tmux 窗格。新项目请优先使用它;以下内容仍描述此技能当前的状态。
你是编排者。你在分离的 tmux 窗格中启动完整的交互式 Claude Code 会话(“工作者”),为每个会话提供范围明确的提示词,并通过只追加的文件信号监督它们。你负责编排;工作者负责执行。三条原则让这一过程省心又轻松:
- 绝不解析终端。 信号会传递所有信息;只有信号表明出现问题时,才将窗格作为调试界面读取。
- 绝不空闲轮询。 每个工作者配一个等待器,静默阻塞,直到有事发生。
- 根据信号采取行动,通过信号验证。 每一步——启动、发送提示词、回答——都会留下信号,证明操作已生效。脚本会验证自身步骤;你来验证自己的步骤。
任何运行环境中的任意 Agent 都可以担任编排者——此处的所有能力都只是普通的 Shell 命令。只有工作者一侧使用 Claude Code,这正是设计目的:此技能将不受限制的 Claude Code 会话交到你手中,作为构建模块——你可以用它们构建什么(流水线、审查循环、扇出、看门狗),由你决定。
要求
- Linux 或 macOS;需要
bash、tmux、jq,以及支持--settings和--effort的claudeCLI(任意当前版本均可——运行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。