资讯详情

Kiln 云沙箱启动闭环:用 Claude Code 用户级 SessionStart Hook 自动运行 setup_startup.sh

📅 2026/10/14 15:56:38 | 华诺云谱 👁 阅读
Kiln 云沙箱启动闭环:用 Claude Code 用户级 SessionStart Hook 自动运行 setup_startup.sh
人工智能AI 应用AI 评测RAG微调提示工程开发工具桌面应用【免费下载链接】KilnBuild, Evaluate, and Optimize AI Systems. Includes evals, RAG, agents, fine-tuning, synthetic data generation, dataset management, MCP, and more.项目地址https://gitcode.com/gh_mirrors/ki/Kiln点击查看免费下载本文以 Kiln 仓库specs/projects/cloud_sandbox_dx项目的 Phase 6 计划phase_6.md为核心详解 Kiln 如何用setup_env.sh新加入的--create-startup-script开关把一个 Claude CodeSessionStarthook 注册进用户级~/.claude/settings.json从而在没有仓库跟踪文件、没有人工提示词的前提下关闭无人值守云 Agent 不知道该运行哪个启动脚本的循环引导问题。读完后你将理解 hook 注册、settings.json 安全合并、shim 守卫脚本与 provisioning marker 四个组件的完整实现逻辑以及会否挤掉云端 launcher 自带 hook这一关键风险的实证验证过程。一、问题本质循环引导Circular Bootstrap在 Phase 6 之前的云沙箱方案中见 project_overview.md 与 functional_spec.md 的 F5/F8Kiln 把环境工作拆成两层机器级.config/utils/setup_env.sh在云环境构建时运行一次随后整个磁盘被快照后续会话不再运行它会话级.config/utils/setup_startup.sh在每个会话开始前校验硬性依赖、重写 agent 配置、补跑uv sync与npm install。但留下一个已知限制F5没有任何东西告诉云 Agent 去运行setup_startup.sh。运行它这条指令写在AGENTS.md里而AGENTS.md被复制到CLAUDE.md——CLAUDE.md恰恰是那个启动脚本自己生成的文件。于是形成闭环早期方案把这件事交给操作者由人类在任务提示词里写明先运行该脚本同时把一个是否要提交一个被跟踪的.claude/settings.json的决策无限期搁置。Phase 6 指出这两个方案都已经被推翻依据是三个事实Claude Code 在云会话中会加载用户级~/.claude/settings.json其中注册的 hooks 确实会触发通过一次真实会话实测确认~/.claude/位于被快照的文件系统上构建环境时写入的 hook 会随快照进入每个后续会话hook 在 Agent 读取任何文件之前运行——所以它不依赖有人告诉过 Agent这件事。三者合起来VM 构建脚本即setup_env.sh的云模式可以自行安装这个 hook不需要仓库文件、不需要被跟踪的.claude/、不需要人工指令闭环在 Agent 的第一轮对话之前就已经闭合。这一点也同步改写进了 project_overview.md 的决策 10 与 functional_spec.md 的 F10 章节其中明确写道 The bootstrap is circular, and F10 breaks the circle。二、前置风险裁定用户级 hook 会挤掉 launcher 的 SessionStart 吗这是 Phase 6 中必须先解决的问题其结论直接决定该方案是否可取。云端会话本来就存在一个来自~/.claude/launcher-settings.json的SessionStarthook——session-start-git-identity.sh它负责把user.email固定为noreplyanthropic.com并安装让提交能在 GitHub 上通过校验的commit-msgtrailer hooks。如果在settings.json里新增hooks.SessionStart会替换掉它那么本阶段将在后续每个会话中悄悄破坏提交签名——这是一个比Agent 不会自动跑脚本糟糕得多的结果。文档给出了两条独立确认结论是不会挤掉。1. 实证在本机。用隔离的HOME/CLAUDE_CONFIG_DIR跑一次真实的claude -p用户settings.json携带一个SessionStarthook同时通过--settings文件携带另一个这正是 CCR 的用法——ps显示现场会话的进程参数就是--settings /root/.claude/launcher-settings.json。结果是两个 hook 都触发两个标记文件都被写入--settings文件里的Stophook 也照常触发。2. 实现层面。从 Claude Code 的实现看各配置来源按userSettings, projectSettings, localSettings, flagSettings, policySettings的顺序合并其中数组的合并规则是if (Array.isArray(a) Array.isArray(b)) return uniq([...a, ...b])——hook 数组跨来源拼接而不是覆盖。唯一有文档记载的丢失 launcher hook 的方式是仓库配置里写disableAllHooks: true而运行器对此有明确警告本阶段不设置该项。因此 launcher hook 与 Kiln hook 同时运行两者的先后顺序用户设置在前也不重要因为它们互不依赖。三、功能入口--create-startup-script与路径常量setup_env.sh增加了一个默认false的开关--create-startup-script命令行 flag对应CONFIGURATION块中的CREATE_STARTUP_SCRIPT变量。默认关闭的意义很明确本地运行绝不应触碰贡献者本人的 Claude Code 配置——一个依赖安装脚本不该在开发者机器上为其本人所有仓库的每一个会话都挂一个只服务于某个仓库的脚本。在仓库当前源码 setup_env.sh 中可以逐一对照 Phase 6 的步骤 1~3CONFIGURATION 块setup_env.sh#L31-L43CREATE_STARTUP_SCRIPT默认false并在 for a Claude Code cloud setup script use 注释中与其余云配置项并列# For a Claude Code cloud setup script use: # UPGRADE_TOOLStrue BEST_EFFORTtrue WARM_CACHEtrue CREATE_STARTUP_SCRIPTtrue # ADD_PLAYWRIGHTtrue ... CREATE_STARTUP_SCRIPTfalse # true: run setup_startup.sh from a Claude Code SessionStart hook (cloud VMs)路径常量setup_env.sh#L59-L71紧挨着已有的VM_SETUP_DIR系列常量VM_SETUP_DIR${KILN_VM_SETUP_DIR:-/opt/kiln-vm-setup} ... STARTUP_HOOK_SHIM$VM_SETUP_DIR/kiln_session_start_hook.sh CLAUDE_USER_SETTINGS${CLAUDE_CONFIG_DIR:-$HOME/.claude}/settings.json两个细节值得注意CLAUDE_CONFIG_DIR是 Claude Code 自身认可的用户设置目录变量尊重它既正确、也让整个机制可以在临时目录上测试shim 的文件名刻意带有仓库专属性kiln_session_start_hook.sh因为这个 basename 就是后续合并操作里的幂等键——它保证本脚本永远只匹配自己写入的条目。参数解析与 usageflag 出现在参数解析器setup_env.sh#L152和usage()帮助文本setup_env.sh#L126-L130中帮助说明其为云 VM 设计、默认关闭、且merges into ~/.claude/settings.json。云侧的调用形态有两处证据。其一是 functional_spec.md Environment-side changes 给出的粘贴式配置块HUMAN_MODEfalse UPGRADE_TOOLStrue # was false AGENTall BEST_EFFORTtrue # was false WARM_CACHEtrue # was false CREATE_STARTUP_SCRIPTtrue # was false其二是仓库当前实际提供的云环境脚本 claude_code_vm_setup.sh它比粘贴全文更进一步的思路是——只粘贴这个很小的 fetch 包装脚本运行时通过 HTTPS 拉取.config/utils/setup_env.sh并执行从而避免粘贴副本在脚本变更后悄悄过期。该脚本以完整的云 profile 调用claude_code_vm_setup.sh#L73-L78bash $script \ --upgrade-tools \ --best-effort \ --warm-cache \ --create-startup-script \ --add-playwright完整的环境配置说明网络白名单、MCP 信任、会话变量等见 claude_cloud_setup.md。四、Shim 脚本在共享环境里对每个仓库的会话都安全因为用户级 hook 会在这台机器上的每个仓库的会话里触发而云环境是跨仓库共享的shim 必须找到 Kiln checkout 才做事否则立即退出 0。生成的 shim 核心逻辑由 setup_env.sh#L419-L463 的 heredoc 写出与 Phase 6 步骤 4 一致dir${CLAUDE_PROJECT_DIR:-$PWD} dir$(cd $dir 2/dev/null pwd) || dir$PWD while [ ! -f $dir/.config/utils/setup_startup.sh ]; do parent$(dirname $dir) [ $parent $dir ] exit 0 # / and . are their own parents dir$parent done设计要点CLAUDE_PROJECT_DIR由 Claude Code 为SessionStarthook 设置。文档通过运行一个探针 hook 验证了两点它存在它等于会话的工作目录而非 git 根目录。云会话里两者通常相同但向上遍历成本为零可以覆盖从子目录启动会话的情形。[ $parent $dir ] exit 0是对/和.这两类自己是自己父目录的兜底保证遍历永不空转。先把CLAUDE_PROJECT_DIR解析为绝对路径相对路径会沿真实目录树向上走目录不存在则回退$PWD。即便 cwd 怪异setup_startup.sh自己还会做一次根发现setup_startup.sh#L117-L155所以走不到根在任何情况下都可生存。从最初的草图bash $s || true到成品shim 增长了两个关键点二者同时也排除了草图里的exec方案捕获双流并在 stdout 上重放。因为SessionStarthook 只有 stdout 会成为会话上下文stderr 不会而setup_startup.sh的所有失败信息都走 stderr见 setup_startup.sh#L100-L115 的bad_environment。用exec会把一次Agent 永远看不到的静默失败交出去——比没有 hook 更糟。捕获文本截断在约 4 KB保留头部 1500 字节 尾部 2000 字节中间插一行[...trimmed...]。正常输出只有约 15 行但这段文本是从上下文窗口里花掉的而一次失败的uv解析或npm install可以无限长。失败原因总在尾部所以简单的head截法是错的。此外/dev/null是因为 hook 的 stdin 是事件 JSON下面的脚本不应去读它shim无条件 exit 0——hook 永远不应该是会话启动失败的原因——仅在脚本失败时追加一行写明退出码如(script exited 1. Fix the above before building or testing.)。shim 的第二道防线在setup_startup.sh自身它的容器门setup_startup.sh#L71-L98只接受CLAUDE_CODE_REMOTEtrueClaude Code 云会话自动设置或IS_CONTAINERIZED手工逃生口开发机上一切都会以一行提示和 exit 0 结束。五、用 python3 把 hook 条目合并进 settings.json合并是强制要求而非锦上添花该文件已经携带enableAllProjectMcpServers: true机器级的 MCP 信任开关见 functional_spec.md MCP trust 一节覆盖写会悄悄禁用项目 MCP 服务器。实现位于register_session_start_hook()setup_env.sh#L491-L610是一段内嵌python3脚本行为规则与 Phase 6 步骤 5 逐条对应文件缺失或为空→ 从{}起步父目录不存在则创建非法 JSON、顶层非对象、hooks或hooks.SessionStart类型不对→拒绝并保持文件原样输出一条指明文件名的警告。注释写得很直白修复别人的错误设置不是本脚本的职责截断它们比不装更糟幂等按 shim 的仓库专属 basename 匹配先丢弃任何已存在的本条目这一步同时自愈KILN_VM_SETUP_DIR迁移后的陈旧路径再追加恰好一条被过滤空的组一并删除持有其他内容的组原样保留——每个无关的SessionStart条目都不受触动写入安全写到同目录的临时文件后os.replace覆盖目标并保留原文件权限mode写失败不会把正在使用的 settings 截断成零字节json.dump(..., ensure_asciiFalse)否则会把别人无关设置里的非 ASCII 字符重写成转义——语义虽等价但本函数的契约就是只动自己的条目变化才报告合并前后序列化比对无变化则打印 already registered 并退出 0。条目形状{ matcher: startup|resume|fork, hooks: [{ type: command, command: /opt/kiln-vm-setup/kiln_session_start_hook.sh, timeout: 600, statusMessage: Preparing the Kiln checkout }] }三个参数的取舍matcher 是正则匹配事件source字段取值域为startup, resume, clear, compact, fork从 CLI 自带 schema 读出的。clear与compact被刻意排除重跑虽是一次便宜的 no-op但会把 hook 输出重新注入上下文窗口而长会话会反复 compact。fork保留因为分叉会话可能落在一台本 hook 从未运行过的文件系统上timeout单位是秒刻意给足 600没有热node_modules树的 VM 首跑约 32 秒真正改了依赖的分支还要更久失败一律是警告而不是fail与热缓存同样的理由这是便利层一台 uv 和 Python 都正常的 VM 不应以 Resolve the errors above 收场python3缺失时一行提示跳过。install_session_start_hook()的执行顺序也编码了一个重要区分setup_env.sh#L400-L480shim 先以$$临时文件 chmod xmv -f的方式落盘避免会话在写到一半时执行半个脚本注册成功后才置位STARTUP_HOOK_INSTALLEDtrue——磁盘上有 shim 文件不等于有 hook因为注册步骤会拒绝触碰损坏的 settings.json。六、Marker 记录session_start_hook三值语义调用点放在write_vm_setup_marker之前setup_env.sh#L845-L848让 marker 能记录结果同时放在以下一切都需要 checkout的退出之前——云环境构建时根本没有 checkout而这正是该功能存在的场景。marker 文件$VM_SETUP_DIR/.setup_for_kiln_repo_v1setup_env.sh#L758-L834新增字段session_start_hook取值规则setup_env.sh#L788-L795情形值本次运行成功注册shim 的绝对路径本次尝试注册但被拒绝registration_failed本次未带 flag继承上一次 marker 的答案与热node_modules的 commit 字段同一规则从未尝试过none之所以不简单地shim 文件存在就报路径是因为那样会让一台实际没有 hook注册被拒的 VM 在 marker 里显示有——把读 marker 的排障人引开唯一需要被记录的那个失败点。_v1契约版本号不升setup_startup.sh只测试 marker 是否存在setup_startup.sh#L167-L182而没有 hook 的 VM并不是配置错的 VM。七、成本与修正后的测量数据Phase 6 把代价说得很直白并纠正了此前发布在 phase_5.md、functional_spec.md F8/F9 等处的热页缓存数字测量项发布值修正值会话内首次setup_startup.sh有热树2.2 s22.9 sreal 22.890s, user 3.495s, sys 5.398s同场景、禁用热树—32.3 s热树省下的时间隐含 ~20 s9.4 scp -al热树0.54 s0.54 s热页缓存下冷启动播种是 22.9 s 的一部分同一会话内重跑5.9 s / 2.2 s~2 s且这是热值22.9 s 中 CPU 时间不足 9 s说明瓶颈在磁盘其中约 16 s 是npm install报告 up to date 时对约 46,000 个文件做 stat。用户对保留 9.4 s 收益的热树的决策保持不变——修正的目的只是诚实地陈述权衡。三条代价陈述会话启动同步变慢。22.9 s 在 Agent 第一轮之前支付每个会话都付。这不是新工作而是本来迟早要发生、且此前可被跳过的工作被移到了无法跳过的位置——但用户感受到的是输入框处的延迟而非一次工具调用。异步模式被刻意不用。hook 可以返回{async: true}在后台完成但这会破坏方案成立的前提CLAUDE.md、.claude/skills/、.mcp.json是在会话上下文组装时被读取的后台写它们会非确定性地输掉这场本来要赢的赛跑。正确性优先于延迟。它会在没人要求的会话里运行——这台 VM 上的每个会话、每个共享该环境的仓库。正因如此shim 在非 Kiln 目录立即 exit 0而setup_startup.sh的容器门是第二道防线第四、五节的实现。八、行为验证清单与文档联动setup_env.sh的这一层是 Shell JSON 文档所以没有单元测试文档声明所有用例都以行为方式被执行且全部在临时HOME/CLAUDE_CONFIG_DIR与临时KILN_VM_SETUP_DIR上进行真实会话的~/.claude/settings.json从未被触碰。验证清单对应 phase_6.md 的 Tests 一节合并已有键的文件enableAllProjectMcpServers与无关顶层键原样保留hooks.SessionStart恰好增加一条幂等跑两遍shim 对应的SessionStart条目只有一条settings.json 不存在文件及目录被创建只含该 hook非法 JSON文件逐字节不变运行警告退出码仍为 0已存在无关SessionStarthook幸存Kiln 条目追加在其后hooks类型错误如字符串拒绝文件不变shim 守卫非 Kiln 目录静默 exit 0什么都不跑shim 守卫Kiln checkout运行setup_startup.sh从子目录启动同样成立KILN_VM_SETUP_DIR迁移后陈旧条目被替换而非重复默认关闭不带 flag 的setup_env.sh不写 shim、不读也不写settings.json无 checkout --create-startup-scriptshim 与 settings 条目都写入——即云环境构建场景产物可解析生成的 settings 文件是合法 JSONhook 条目形状符合 Claude Code 自身 schema 接受的matcher/type/command/timeout/statusMessage非 ASCII 幸存无关设置中的échoué → naïve ✅ 日本語原样保留、不被转义marker 不夸大安装成功 → shim 路径注册被拒 →registration_failed即便 shim 已在磁盘上后续不带 flag 的运行 → 继承上值从未尝试 →none输出截断约 335 KB 的setup_startup.sh输出被压到 4 KB 以内头、尾含真实原因所在行都完整正常输出原样通过相对或不存在的路径CLAUDE_PROJECT_DIR先解析为绝对路径相对路径也能找到 checkout不存在则回退$PWD遍历不会空转端到端、真实 CLI隔离HOME/CLAUDE_CONFIG_DIR下已安装的 hook 加上--settings文件的第二个SessionStarthook同时运行——launcher git 身份 hook 未被挤掉的最终证据matcher 加入后复跑确认startup会话仍能命中。收尾验证uv run ./checks.sh --agent-mode全绿checks.sh入口见 checks.sh测试套件保持 6369 passed / 10020 skippedgit status --porcelain只显示预期内的编辑。文档层面的联动Phase 6 步骤 7~9functional_spec.md新增 F10 并把 F5 的已知限制改写为指向 hookarchitecture.md增加变更清单行与 §1.3cimplementation_plan.md增加 Phase 6、退役操作者提示词复选框与悬而未决的SessionStart决策并把CREATE_STARTUP_SCRIPTtrue写入它让用户粘贴的云CONFIGURATION块。从当前仓库状态看根目录 AGENTS.md 尚未包含setup_env.sh参数表文档主体仍以 setup_env.sh 内注释与 functional_spec.md F10 为最完整的说明来源而claude_code_vm_setup.sh与claude_cloud_setup.md的 fetch 式云脚本则代表该计划落地后的当前形态。小结Phase 6 的实质是一次把指令放进文件系统之外的重构既然该运行什么脚本这句话所依赖的文档CLAUDE.md本身就是被运行者生成的产物那么唯一自洽的位置就是先于所有文档被读取的用户级 hook。整套设计围绕三个纪律展开——默认关闭以保护本地贡献者、合并而非覆盖以保护机器级 settings、幂等键 拒绝式失败以保护他人配置代价每会话约 23 s 的同步延迟被明确测量、诚实披露并且拒绝了用异步掩盖延迟的捷径。对任何在共享、快照化云环境中运行代码 Agent 的团队而言这是一个可以直接对照移植的模式一个带仓库守卫的 shim、一个幂等的 settings 合并器、一个三值语义的 provisioning marker。赞分享人工智能AI 应用AI 评测RAG微调提示工程开发工具桌面应用【免费下载链接】KilnBuild, Evaluate, and Optimize AI Systems. Includes evals, RAG, agents, fine-tuning, synthetic data generation, dataset management, MCP, and more.项目地址https://gitcode.com/gh_mirrors/ki/Kiln点击查看免费下载相关推荐Kiln 云沙箱开发体验实战setup_env.sh / setup_startup.sh 如何零知识启动 Claude Code 云会话Kiln 云沙箱开发体验实战setup_env.sh / setup_startup.sh 如何零知识启动 Claude Code 云会话 本文基于 Kiln人工智能AI 应用AI 评测RAG微调提示工程开发工具桌面应用MLOpsKiln 云端沙箱会话启动检查setup_startup.sh 的设计与实现Kiln 云端沙箱会话启动检查setup_startup.sh 的设计与实现 在 Kiln 的云端沙箱如 Claude Code cloud session人工智能AI 应用AI 评测RAG微调提示工程开发工具桌面应用MLOpsRalph E2B 云沙箱执行指南在云端隔离环境运行 Claude Code 自主循环Ralph E2B 云沙箱执行指南在云端隔离环境运行 Claude Code 自主循环 本篇技术指南围绕 Ralph 项目Autonomous AI dev人工智能AI 应用自主智能体CLI开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑