jcode Spawn Hook 完整指南:用 tmux、kitty、zellij 接管会话窗口的创建与路由
发布时间:2026/9/13 13:52:42 锦皓数字建站

jcode Spawn Hook 完整指南用 tmux、kitty、zellij 接管会话窗口的创建与路由【免费下载链接】jcodeThe most RAM efficient harness项目地址: https://gitcode.com/GitHub_Trending/jcod/jcode本文以 docs/SPAWN_HOOK.md 为核心骨架结合 jcode 仓库中 crates/jcode-terminal-launch/src/lib.rs、crates/jcode-base/src/terminal_launch.rs 与 crates/jcode-app-core/src/session_launch.rs 的源码实现系统讲解 jcode 的spawn hook生成钩子机制它让外部程序接管有头会话的终端窗口创建从而把 swarm 代理、resume-in-new-terminal、self-dev 等会话精确路由到 tmux 窗格、kitty 标签页或自定义脚本指定的位置。读完本文你将掌握 spawn hook 的配置方式、调用契约、元数据环境变量、多终端路由原理并拿到可直接复制的 tmux / kitty / zellij / 自定义路由脚本实战方案。Spawn Hook 解决什么问题jcode 会在多条流程中打开新的终端窗口swarm 代理生成swarm spawn且spawn_modevisibleresume-in-new-terminal在新终端中恢复会话self-dev 会话重启恢复restart restoresjade relay 启动。默认情况下jcode 自行探测系统中已安装的终端模拟器kitty、wezterm、alacritty、gnome-terminal……并打开一个新的操作系统窗口。从源码看这个内置探测的候选顺序在 crates/jcode-terminal-launch/src/lib.rs 中定义在 tmux 内优先使用当前客户端的右侧分屏窗格随后按 herdr、handterm、zellij、screen、kitty、wezterm、alacritty、ghostty再到 gnome-terminal、konsole、xterm、foot 依次尝试。spawn hook 让一个外部程序完全接管这次生成由它决定会话出现在哪里、以何种形态出现一个 tmux 窗格、一个 kitty 标签页、一个 zellij 窗格、一个 wrapper 应用如 herd里的标签页甚至是某个特定显示器/工作区。快速配置配置文件与环境变量方式一config.toml在~/.jcode/config.toml的[terminal]段配置# ~/.jcode/config.toml [terminal] spawn_hook tmux new-window方式二环境变量export JCODE_SPAWN_HOOKtmux new-window # 空值用于禁用配置文件中的 hook export JCODE_SPAWN_HOOK环境变量永远优先于配置文件。这一优先级在 crates/jcode-base/src/config/env_overrides.rs 中实现环境变量存在时直接覆盖self.terminal.spawn_hook且显式空值会把配置文件的 hook 置为None即禁用。默认配置文件模板 crates/jcode-base/src/config/default_file.rs 中给出了完整注释包括JCODE_SPAWN_*元数据变量的说明和三个示例tmux new-window、kitty launch --typetab --、~/bin/jcode-spawn-router。调用契约hook 如何被执行当发生一次有头生成且配置了 hook 时jcode 执行spawn_hook jcode-binary args...契约要点如下Shell 风格解析但直接执行hook 命令行按 shell 风格解析引号和反斜杠转义都可用但不经过 shell 直接 exec。解析器实现在 crates/jcode-terminal-launch/src/lib.rsparse_hook_command空白分隔参数、单双引号分组、双引号内反斜杠转义空输入、未闭合引号、结尾转义都会报错。jcode 二进制与完整参数列表作为追加的 argv即大家熟悉的$TERMINAL -e cmd约定。build_hook_spawn_command在 crates/jcode-terminal-launch/src/lib.rs 中把解析出的 hook 前缀参数与command.program、command.args拼在一起。工作目录hook 的工作目录是会话工作目录cwd。分离运行hook 进程被 detachjcode 不等待它结束。启动失败回退如果 hook 无法启动二进制缺失、解析错误jcode 记录警告并回退到内置终端探测。源码层面crates/jcode-base/src/terminal_launch.rs 的spawn_via_hook还做了更细的处理hook 启动后有2 秒启动窗口——若 hook 在这期间以非零退出立即判定失败并回退若 hook 存活超过 2 秒则视为启动成功随后在后台线程异步收割该进程因为长期运行的 hook 可能有意持有自己的终端进程。这一行为有对应测试 crates/jcode-base/src/terminal_launch.rsexit 1的 hook 会触发回退并报出hook exited with错误。元数据环境变量hook以及内置回退路径启动的终端都会收到以下环境变量变量含义JCODE_SPAWN_KIND生成原因swarm-agent、resume、selfdev、restart、jade-relayJCODE_SPAWN_SESSION_ID该窗口将运行的 jcode 会话JCODE_SPAWN_TITLE建议的窗口/标签页标题含会话图标与名称JCODE_SPAWN_CWD会话工作目录JCODE_SPAWN_PROGRAM要执行的 jcode 二进制路径JCODE_SPAWN_COMMAND完整命令行shell 转义供需要单个 shell 字符串的 hook 使用JCODE_SPAWN_SWARM_IDswarm 生成时agent 加入的 swarmJCODE_SPAWN_COORDINATOR_SESSION_IDswarm 生成时发起生成的协调者会话JCODE_FRESH_SPAWN当本次生成是新窗口交接时为1这些变量由spawn_metadata_env统一构造crates/jcode-terminal-launch/src/lib.rs其中JCODE_SPAWN_COMMAND使用shell_command对每个参数做sh_escape单引号转义保证拼接后的字符串可以被bash -lc之类的 shell 安全消费。额外的 swarm 元数据JCODE_SPAWN_SWARM_ID等通过TerminalCommand::extra_env最后追加发生键冲突时后者胜出。客户端终端环境多终端路由jcode 的 server 进程是长驻的它在启动时捕获一次终端标识环境变量ZELLIJ_SESSION_NAME、TMUX、DISPLAY、KITTY_WINDOW_ID……。当你之后在新的终端/tmux/zellij 会话中连接客户端到同一个 server 时server 持有的这些副本已经过时于是由 server 执行的 spawn hook 会错误地定位到旧终端。为解决这个问题issue #405每个连接的客户端会快照自己的终端标识环境变量并发送给 server。spawn hook 运行时server 会重新导出发起请求的客户端的值使 hook 跟随用户当前实际所在的终端原生变量如ZELLIJ_SESSION_NAME被客户端的值覆盖直接读取它的 hook 会定位到正确的会话同时导出JCODE_CLIENT_NAME别名如JCODE_CLIENT_ZELLIJ_SESSION_NAME、JCODE_CLIENT_TMUX、JCODE_CLIENT_DISPLAY让 hook 能显式区分客户端终端与 server 终端。覆盖的键位包括终端复用器zellij、tmux、screen、终端模拟器kitty、wezterm、ghostty、alacritty、iTerm、Windows Terminal、handterm以及显示服务器DISPLAY、WAYLAND_DISPLAY。完整清单CLIENT_TERMINAL_ENV_VARS见 crates/jcode-terminal-launch/src/lib.rs其中还包含 herdr 相关变量HERDR_ENV、HERDR_PANE_ID等。只有客户端实际设置的变量才会被转发snapshot_client_terminal_envcrates/jcode-terminal-launch/src/lib.rs。apply_client_terminal_envcrates/jcode-terminal-launch/src/lib.rs的注释点明了一个关键细节先移除全部已知键再写入客户端快照——对共享 server 而言空的客户端快照绝不能泄露碰巧启动 server 的那个窗格的身份。并发客户端之间通过 task-local 隔离互不污染这在 crates/jcode-base/src/hooks.rs 的并发测试中得到了验证两个客户端分别携带HERDR_PANE_IDpane-left与pane-right并行执行互不干扰。实战示例tmux每个 agent 一个窗口[terminal] spawn_hook tmux new-window当 jcode 探测到发起请求的客户端位于 tmux 内时它的内置启动器默认会把有头生成放进请求方TMUX_PANE的右侧分屏窗格覆盖/split、/fork、resume-in-new-terminal、self-dev 与可见 agent 生成。若想覆盖这种自动分屏行为可以用tmux new-window jcode --resume ses_x——命令会跑在当前 tmux server 的一个新窗口中。若想显式保留右侧分屏行为[terminal] spawn_hook tmux split-window -h注意内置的 tmux 右分屏实现crates/jcode-terminal-launch/src/lib.rs会额外传入-t TMUX_PANE精确定位请求方窗格而配置 hook 时该细节由你的命令自行决定。kitty每个 agent 一个标签页远程控制[terminal] spawn_hook kitty --to unix:/tmp/kitty.sock launch --typetab --自定义路由脚本需要完全控制放置位置、标题、swarm 与 resume 的差异化路由时把 hook 指向一个脚本[terminal] spawn_hook ~/bin/jcode-spawn-router#!/usr/bin/env bash # ~/bin/jcode-spawn-router # argv: the jcode command to run ($). Env: JCODE_SPAWN_* metadata. case $JCODE_SPAWN_KIND in swarm-agent) # Swarm workers as tmux panes in a window named after the swarm. tmux new-window -n swarm:${JCODE_SPAWN_SWARM_ID:0:8} $ 2/dev/null \ || tmux split-window $ ;; *) # Everything else as a normal terminal window. kitty --title $JCODE_SPAWN_TITLE -e $ ;; esac重要hook 启动后以非零退出且未启动任何东西不会触发内置回退——jcode 只在 hook进程无法启动时回退。因此路由脚本必须自己处理回退逻辑如上例中的|| tmux split-window。这一点在 crates/jcode-base/src/terminal_launch.rs 的 2 秒启动窗口逻辑中体现hook 存活超过启动窗口即视为成功之后它自己退出与否不再影响 jcode。单 shell 字符串消费者有些启动器想要一条 shell 命令字符串而非 argv此时用$JCODE_SPAWN_COMMAND#!/usr/bin/env bash zellij action new-pane -- bash -lc $JCODE_SPAWN_COMMAND程序化发现wrapper 集成包装 jcode 的程序如 herd 风格的会话管理器可以在其启动的jcodeserver 进程环境中设置JCODE_SPAWN_HOOK。此后 server 执行的每一次有头生成——包括协调者通过 socket 协议请求的 swarm agent——都会路由到 wrapper 的 hook。这让 wrapper 无需改动 jcode 源码即可统一接管所有窗口放置。Focus Hook把已有会话窗口带到前台jcode 想把已存在的会话窗口带到前台时例如启动 self-dev 窗口之后在 X11 上默认做一次尽力而为的 wmctrl/xdotool 标题搜索。但这种方式在 Wayland 下、以及终端复用器内部都不奏效——而且既然 wrapper 拥有放置权焦点控制也应该由它负责[terminal] spawn_hook tmux new-window focus_hook ~/bin/jcode-focus # env: JCODE_FOCUS_SESSION_ID, JCODE_FOCUS_TITLE#!/usr/bin/env bash # ~/bin/jcode-focus tmux select-window -t $(tmux list-windows -F #{window_id} #{window_name} \ | grep -F $JCODE_FOCUS_TITLE | head -1 | cut -d -f1)环境变量覆盖为JCODE_FOCUS_HOOK空值禁用配置文件中的 hook。若 hook 无法启动jcode 回退到内置焦点路径。源码层面crates/jcode-app-core/src/session_launch.rs 实现了focus_session_via_hook与focus_session_window_best_effort先尝试配置的 focus hook携带JCODE_FOCUS_SESSION_ID与JCODE_FOCUS_TITLE并转发请求客户端的终端环境失败后再执行内置的wmctrl -a/xdotool search --name ... windowactivate尽力而为回退。focus_hook与spawn_hook的配置定义集中在 crates/jcode-config-types/src/lib.rs 的TerminalConfig中二者配套使用才能实现谁放置窗口、谁负责聚焦的完整闭环。与生命周期 Hook 的关系spawn hook 与[hooks]生命周期钩子turn_start、turn_end、session_start、pre_tool等见 crates/jcode-base/src/hooks.rs共享同一种命令解析与执行约定shell 风格解析、直接执行、JCODE_HOOK_*元数据环境变量但职责不同生命周期钩子观察/门控 agent 行为spawn hook 专管会话窗口出现在哪里。二者可以独立配置、独立使用。小结spawn hook 把 jcode 的窗口放置策略完全外置化无论是追求一个 agent 一个 tmux 窗口的隔离工作流还是 kitty 标签页式轻量并行抑或 herd 这类 wrapper 的深度集成都可以通过一行spawn_hook配置或环境变量实现并且配套的JCODE_SPAWN_*元数据、客户端终端环境转发issue #405与 focus hook 保证了 hook 总是知道谁发起的、要放在哪个终端、该怎么聚焦。建议进一步阅读仓库中的 docs/SPAWN_HOOK.md本文依据、docs/HERDR.mdherdr 集成场景、crates/jcode-terminal-launch/src/lib.rs解析、快照与内置启动实现以及 crates/jcode-base/src/terminal_launch.rshook 启动与回退逻辑来深入理解各平台的细节差异。【免费下载链接】jcodeThe most RAM efficient harness项目地址: https://gitcode.com/GitHub_Trending/jcod/jcode创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。