mcpField
D
driving-claude-code-sessions

driving-claude-code-sessions

github.com/obraAgent 工作流11336 次安装3 周前更新
代码仓库

关于 driving-claude-code-sessions

通过 CLI 在 tmux 中启动和控制 Claude Code、Codex 或 Pi 编码 Agent 工作进程的技能。它以统一命令接口支持多轮提示、事件监控、并行任务和人工接管。

主要功能

  1. 01在 tmux 中启动工作进程
  2. 02发送提示并管理轮次
  3. 03读取输出和生命周期事件
  4. 04并行运行多个工作进程
  5. 05将会话交接给人工

适用场景

  1. 01把不同任务分派给并行 Agent
  2. 02将生成的规范交给实现工作进程
  3. 03监控运行中的工作进程
  4. 04将现有 Claude 会话恢复为工作进程

安装

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

$npx skills add https://github.com/obra/claude-session-driver --skill driving-claude-code-sessions

安装后在 Claude Code 中输入/driving-claude-code-sessions确认已加载。

附带文件scripts/csd

详细介绍

驱动编码 Agent 会话

概述

你可以在 tmux 中启动编码 Agent 会话——Claude Code、Codex 或 Pi——将它们作为“工作进程”,向它们发送提示词,等待它们完成,读取它们的输出,并将它们交接给人工处理。工作进程以绕过权限检查的方式运行,因此无需提示即可执行工具调用。每个工作进程都会将生命周期事件写入 JSONL 文件,以便控制器观察其运行情况——Claude 和 Codex 通过各自的钩子系统实现,Pi 则通过 csd 加载到其中的原生扩展实现。

所有操作都通过单个 CLI 完成:csd。启动工作进程后,控制器会收到一个 shim 路径:/tmp/csd-workers/bin/<tmux-name>,其中已嵌入工作进程句柄。每个工作进程的所有操作都通过该路径进行——无需在调用之间传递位置状态,也无需预先添加绝对技能路径。少量环境变量可用于调整行为;请参阅底部的环境变量。

(工作进程目录已从 /tmp/claude-workers 移至 /tmp/csd-workers;使用默认路径时,csd 会创建向后兼容的符号链接 /tmp/claude-workers → /tmp/csd-workers,因此旧路径和肌肉记忆仍然适用。)

shim 路径是确定性的:如果你在启动时选择了一个好记的 tmux 名称,就可以在需要时重新构造 /tmp/csd-workers/bin/<tmux-name>。对于通过工具调用驱动的 Agent,这才是合适的方式——Shell 状态不会在调用之间保留,因此 SHIM=...; $SHIM cmd 这种模式只会徒增干扰。以下示例使用原始路径。

Harness

启动时使用 --harness 选择 Harness(默认为 claude):

$SKILL/csd launch --harness codex my-task /path/to/project
$SKILL/csd launch --harness pi    my-task /path/to/project

面向控制器的命令接口在三种 Harness 中 完全相同——无论使用哪种 Harness,launch、send、converse、wait-for-turn、read-turn、read-events、status、stop 和 handoff 的行为都相同。以下几点有所不同:

  • 身份验证。 每种 Harness 都从各自的主目录进行身份验证——Claude 使用 ~/.claude,Codex 使用 ~/.codex,Pi 使用 ~/.pi/agent。csd 会在启动时将相应登录信息复制到工作进程中,因此要轮换凭据,请重新启动。
  • adopt 仅适用于 Claude。 Claude 接受调用方指定的会话 ID,因此可以按 ID 恢复会话(claude --resume)。Codex 和 Pi 会在首次提示词时自行生成 ID,且不支持按 ID 恢复——请重新启动它们。
  • Codex 在收到首条提示词前无法查询。 Codex 只有在发送首条提示词时才会生成会话 ID,因此在 launch 与首次 send/converse 之间,codex 工作进程的 status、session-id 和 wait-for-turn 会返回 no worker known——它确实正在运行,只是尚未注册。converse 会在内部处理这一情况,因此常见的 launch→converse 流程没有问题;只有较低层级的命令会遇到这个空档。(Claude 在启动时就会获取 ID,Pi 则会在启动时注册,因此两者都可以立即查询。)

前置条件

  • tmux
  • 一个 Harness CLI——至少需要你启动的那个:claude(默认)、codex 或 pi

(不需要 jq,也不需要 bash 钩子:csd 是 TypeScript/node 工具,其钩子是 node 程序。需要 node,但凡是能运行 Claude Code 的环境都已具备它。)

设置

CLI 位于 <skill>/scripts/csd。顶层子命令需要技能路径:

  • csd launch [--harness <claude|codex|pi>] <tmux-name> <cwd> [-- harness-args...] — 启动一个工作器(harness 默认为 claude)
  • csd adopt <tmux-name> <cwd> <session-id> [-- claude-args...] — 将现有 Claude 会话重新接管为工作器(仅适用于 Claude;参见重启后恢复工作器)
  • csd list [--all] — 列出工作器
  • csd grant-consent — 为绕过权限运行的工作器授予一次性同意

启动工作器后,后续命令请使用 /tmp/csd-workers/bin/<tmux-name> 执行:

SKILL=/abs/path/to/skill/scripts
$SKILL/csd grant-consent                          # one-time per machine
$SKILL/csd launch my-task /path/to/project        # stdout: /tmp/csd-workers/bin/my-task
/tmp/csd-workers/bin/my-task status               # use the shim directly

启动时请选一个容易记住的 tmux 名称;随后 shim 路径便是确定的。(在交互式 shell 中,可以将其存入 shell 变量,但对于由 Agent 驱动的工作流,直接使用路径更简单——各次调用之间无需保留 shell 状态。)

工作流

以下示例中,$SKILL 是 skills/driving-claude-code-sessions/scripts 的绝对路径。WORKER 是不带引号的 shim 路径(例如 /tmp/csd-workers/bin/my-task)——请替换为工作器对应的确定路径。

1. 启动
$SKILL/csd launch my-task /path/to/project
# stdout: /tmp/csd-workers/bin/my-task
# stderr: Worker launched. tmux/session_id/cwd/events/reproduce

csd launch:

  • 在 /tmp/csd-workers/bin/my-task 写入一个 3 行的 shim
  • 启动 tmux,并在其中启动 harness
  • 阻塞等待工作器就绪——Claude(其会话 ID 由调用方指定)会等待 session_start 事件;Codex 和 Pi 会在首次提示词时生成自己的 ID,因此启动流程会等到它们的 TUI 初始化完成,而工作器的元信息会在触发首个事件时自动注册
  • 在 stdout 输出 shim 路径(一行)
  • 在 stderr 输出“Worker launched”面板——其中的 reproduce: 行是使用相同参数重新启动的确切命令

在 -- 分隔符后传入 harness CLI 参数,或者使用 --harness 选择非默认 harness:

$SKILL/csd launch my-task /path/to/project -- --model sonnet
$SKILL/csd launch --harness codex my-task /path/to/project
2. 对话(典型用法)
/tmp/csd-workers/bin/my-task converse "Refactor the auth module" 300

converse 会发送提示词,等待工作器完成,并在 stdout 输出最终的助手文本。对于工具调用较多、单纯文本会省略关键信息的轮次,请使用 --with-turn 获取完整的 Markdown:

/tmp/csd-workers/bin/my-task converse --with-turn "Run the failing tests" 600

多轮对话可直接进行——等待过程会自动跟踪轮次边界:

/tmp/csd-workers/bin/my-task converse "Write tests for the auth module" 300
/tmp/csd-workers/bin/my-task converse "Add edge cases for expired tokens" 300
3. 低级控制

如果需要更直接地驱动工作器:

/tmp/csd-workers/bin/my-task send "Refactor the auth module"     # send without waiting
/tmp/csd-workers/bin/my-task wait-for-turn 300                   # block until stop or session_end
/tmp/csd-workers/bin/my-task status                              # idle | working | terminated | gone | unknown
/tmp/csd-workers/bin/my-task read-turn                           # last turn as markdown (tool results truncated to 5 lines)
/tmp/csd-workers/bin/my-task read-turn --full                    # last turn with complete tool results
4. 监视工作器的操作

每次工具调用都会发出一个 pre_tool_use 事件,其中包含工具名称和输入。跟踪事件流即可实时监视:

/tmp/csd-workers/bin/my-task read-events --follow &
MONITOR_PID=$!
# ... do other work ...
kill $MONITOR_PID

也可以事后拉取事件:

/tmp/csd-workers/bin/my-task read-events                       # all events
/tmp/csd-workers/bin/my-task read-events --last 5
/tmp/csd-workers/bin/my-task read-events --type pre_tool_use

--type 接受以下值之一:session_start、user_prompt_submit、pre_tool_use、post_tool_use、stop、session_end。未知事件名称会立即报错。(Claude 工作器会发出 pre_tool_use,但不会发出 post_tool_use;Codex 和 Pi 两种事件都会发出。)

如果发现不希望发生的操作,请停止工作器:

/tmp/csd-workers/bin/my-task stop
5. 停止并清理
/tmp/csd-workers/bin/my-task stop

发送 /exit,最多等待 10s 以接收 session_end;如果 tmux 会话仍在运行,则将其终止,并删除元信息、事件和 shim 文件。

stop 会造成破坏性影响:工作器将被移除,shim 路径也将失效。如果还要继续使用该工作器进行后续轮次或并行工作流,请在用完之前不要调用 stop。若要以相同名称恢复工作,请重新启动——再次运行 csd launch my-task /path/to/project——这样会在相同 shim 路径下获得一个全新的工作器。

执行 stop 后,shim 不复存在,因此再次调用它会显示类似 no such file or directory: /tmp/csd-workers/bin/my-task 的 shell 错误(具体措辞取决于所用的 shell)。这是预期行为;工作器已被移除。

6. 移交给人工
/tmp/csd-workers/bin/my-task handoff

输出连接说明,供人工接管 tmux 会话。

查找工作器
$SKILL/csd list                      # live workers (idle/working/terminated)
$SKILL/csd list --all                # include 'gone' workers (tmux already exited)
$SKILL/csd list api                  # substring filter on tmux name
$SKILL/csd prune                     # remove dead workers + orphaned sidecars/shims

参考

csd launch [--harness <claude|codex|pi>] <tmux-name> <cwd> [-- harness-args...]
csd adopt <tmux-name> <cwd> <session-id> [-- claude-args...]   # claude-only
csd list [--all] [<pattern>]
csd prune                          # remove dead/orphaned worker state
csd grant-consent

<shim> converse [--with-turn] <prompt> [timeout=120]
<shim> send <prompt>
<shim> wait-for-turn [timeout=60] [--after-line N]
<shim> status
<shim> read-events [--last N] [--type T] [--follow]   # --last caps the --follow backlog
<shim> read-turn [--full]
<shim> stop
<shim> handoff
<shim> session-id
<shim> events-file

<shim> 是 /tmp/csd-workers/bin/<tmux-name>。运行 csd help 可查看相同的命令说明。

常见模式

扇出:并行运行多个工作器
$SKILL/csd launch worker-api ~/proj
$SKILL/csd launch worker-ui ~/proj

/tmp/csd-workers/bin/worker-api send "Add pagination to /users"
/tmp/csd-workers/bin/worker-ui send "Add a loading spinner to the user list"

/tmp/csd-workers/bin/worker-api wait-for-turn 600
/tmp/csd-workers/bin/worker-ui wait-for-turn 600

/tmp/csd-workers/bin/worker-api stop
/tmp/csd-workers/bin/worker-ui stop
工作流:工作者 A 产出,工作者 B 消费
$SKILL/csd launch spec ~/proj
/tmp/csd-workers/bin/spec converse "Write an OpenAPI spec for /users to /tmp/api.yaml" 300
/tmp/csd-workers/bin/spec stop

$SKILL/csd launch impl ~/proj
/tmp/csd-workers/bin/impl converse "Implement the endpoint defined in /tmp/api.yaml" 600
/tmp/csd-workers/bin/impl stop

不要轻信工作者 B 对其工作内容的总结——请检查产出的文件。工作者可能报告成功,但实际写入了错误内容(参见 重要说明)。

边缘情况

工作者在回合中途崩溃

wait-for-turn 会匹配 stop 或 session_end,因此工作者退出时它会返回。之后调用 status:如果状态为 gone,说明工作者崩溃了。

converse 超时后,先检查 status,再调用 wait-for-turn

直接调用 wait-for-turn 时,它会以事件文件当前末尾为基准,等待下一次回合结束。如果 converse 超时,工作者通常会在这段间隔内完成——stop 事件已经写入,因此后续调用 wait-for-turn 会在整个超时时间内一直阻塞,等待一个永远不会开始的回合。超时后先调用 status:idle 表示回合已经结束(调用 read-turn 读取内容);working 表示仍在进行。

重启后恢复工作者

工作者运行时状态(/tmp/csd-workers 下的 meta/events/shim 文件)存储在 /tmp 中,macOS 重启时会清空该目录——tmux 窗格也会随之消失。但对话仍然保留:Claude Code 会将每个会话的记录保存到 ~/.claude/projects/<encoded-cwd>/<session-id>.jsonl。csd adopt 可将会话恢复为可驱动的活动工作者(仅适用于 claude——Codex 和 Pi 会自行生成会话 id,且不支持按 id 恢复,因此应重新启动它们):

$SKILL/csd adopt my-task /path/to/project <session-id>
# stdout: /tmp/csd-workers/bin/my-task   (same shim contract as launch)

仅适用于 claude——codex/pi 的对话在执行 stop 后不会保留。 Codex 和 Pi 在每个工作者专用的临时 home 目录下运行(包含配置、身份验证信息以及 rollout/会话记录),路径为 /tmp/csd-workers/homes/<name>/,而非你实际使用的 ~/.codex / ~/.pi。stop 会删除该 home 目录,因此会话记录也会消失,且无法恢复——重新启动会创建新会话。只有 claude 会将会话记录保存在工作者目录之外(位于 ~/.claude/projects),因此只有 claude 可以通过 adopt 恢复。

adopt 会先写入以 <session-id> 为键的 meta,然后启动 claude --resume <session-id>(此命令会保留 id,因此工作者会正常发出事件),并写入 shim——因此恢复后的对话完全可驱动(converse/status/read-turn/…),且保留所有先前上下文。如果同名 tmux 会话已存在(例如由 tmux-resurrect / tmux-continuum 恢复),adopt 会在原窗格中重新启动工作者,从而保留已恢复的布局;否则会新建一个窗格。

根据工作目录查找工作者的 <session-id>:在 ~/.claude/projects/<cwd with every / . _ replaced by -> 中,找到最新的 *.jsonl 文件。若要批量恢复(例如配合 tmux-continuum 的 @continuum-boot),examples/recover-workers.sh 会读取 tmux-resurrect 快照,推导每个 id,并为每个工作者调用 adopt——请先使用 --dry-run 运行。注意:工作者会作为恢复的会话重新启动,而不是恢复原有的工具/MCP 状态;请重新传入依赖的启动参数(例如 -- --model …)。

找不到 shim 路径

如果知道 tmux 名称,路径为 /tmp/csd-workers/bin/<tmux-name>。如果不知道,csd list 会列出所有内容;csd list <pattern> 会按 tmux 名称子串筛选。

长提示词

send 使用 bracketed-paste,可处理多行文本和特殊字符。对于长度达数十 KB 的提示词,请先写入文件,再让工作者读取:

echo "Long instructions..." > /tmp/instructions.txt
/tmp/csd-workers/bin/my-task send "Read /tmp/instructions.txt and follow it"

重要说明

  • 每个工作者只能由一个控制器控制。 两个控制器驱动同一个 tmux 会话会相互冲突。
  • 工作者不会与控制器共享状态,唯一例外是磁盘上的文件和事件流。
  • Shim 路径中写入了绝对技能路径。 如果在新位置重新安装插件,正在运行的工作者会失效;请重新启动它们。
  • csd 是透明中继,不是验证器。 converse/read-turn 会逐字返回工作者所说的内容,包括工作者自信地给出错误信息时。对于正确性至关重要的交接,请核验磁盘上生成的产物,而不是工作者的文字自述。

环境变量

csd CLI 支持少量环境变量,均为可选。

变量用途
CSD_CLAUDE_BIN / CSD_CODEX_BIN / CSD_PI_BIN各个执行框架二进制文件的路径。默认值为 claude / codex / pi(通过 PATH 解析)。如果二进制文件不在 PATH 中,或你想固定使用特定版本,可设置此项。
CSD_CODEX_MODEL / CSD_PI_MODELcodex / pi 工作进程可选的模型覆盖值。未设置 = 执行框架默认值(codex:gpt-5.5;pi:其配置的默认值)。
CSD_CONVERSE_DIAG_FILE设置后,csd converse 超时时会将事后诊断信息写入此路径,包括 ps 进程树、tmux capture-pane、工作进程会话 JSONL 的最后 30 行、csd 事件 JSONL 的最后 20 行,然后向 stderr 输出 csd-diagnostic: <path> 路径提示。每次超时都会覆盖该文件。未设置 = 不生成诊断文件。适用于将 csd 包装在某个执行框架中,且该框架能在工作进程被回收前将文件传出当前机器。
CSD_WORKER_DIR覆盖工作进程目录(默认值为 /tmp/csd-workers)。仅在使用默认值时才会创建向后兼容的 /tmp/claude-workers 符号链接。
CSD_SUBMIT_TIMEOUT / CSD_SUBMIT_RETRY_INTERVALsend:等待工作进程确认已粘贴提示词的秒数(默认值为 10),以及重试发送 Enter 的间隔秒数(默认值为 2)。如果较慢的 tmux 会话未能接收粘贴内容,请增大超时时间。
CSD_REGISTER_TIMEOUT首次向派生工作进程(codex/pi)发送 send/converse 时,等待其自行注册会话 ID 的秒数(默认值为 15)。
HOME用于定位 ~/.claude/projects/<encoded-cwd>/<sid>.jsonl(claude)和一次性同意文件(~/.claude/.claude-session-driver-consent)。

csd help 会显示相同的内容。

评论

支持 Markdown