2026/10/14 15:52:48

Kiln 云沙箱加速实战:温 node_modules、Provisioning Marker 与容器门禁(cloud_sandbox_dx Phase 5)

Kiln 云沙箱加速实战:温 node_modules、Provisioning Marker 与容器门禁(cloud_sandbox_dx Phase 5) 人工智能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 5 规划文档讲解如何把一台被快照的 Claude Code 云沙箱 VM 变成每次会话都是热启动的环境通过WARM_CACHE预热缓存并把node_modules整棵温树放到仓库外供后续会话硬链接复用、用 provisioning marker 标记这台机器被setup_env.sh装配过、再给setup_startup.sh加一道容器门禁使本地开发机与云 VM 各走各的路径。读完本文你能完整理解这三块的实现位置.config/utils/setup_env.sh、.config/utils/setup_startup.sh、关键常量与失败兜底策略并能对照 Phase 5 规划 中的行为测试矩阵复现验证。一、为什么需要温 node_modulesuv 与 npm 缓存机制的不对称Phase 2 和 2b 阶段已经解决了 Python 侧的冷启动成本但 Node 侧几乎没动。根因在于两个包管理器取缓存的方式不同uv 从缓存中硬链接hardlink预热的~/.cache/uv让新会话的uv sync从Prepared 182 packages in 14.67s降到Prepared 3 packages in 428ms——约 300 MB 的下载、togethergit 依赖的 fetch、google-crc32c的 sdist 构建全部消失只剩三个本地 workspace 包仍在构建而这部分不可消除因为它们来自 checkout 自身的源码。npm 从缓存中复制copy即使~/.npm已温热把 748 个包物化进一个空的node_modules仍要 ~21 s24 s → 21 s几乎没改善。Phase 5 的解法是跳动物化本身把预热运行构建好的 pristinenode_modules整棵树放在仓库外/opt/kiln-vm-setup/node_modules使其存活进 VM 快照之后每个会话用cp -al硬链接复制进自己的 checkout。在/opt与/home/user同设备的条件下601 MB 的树只需 0.54 s且共享 inode。Phase 6 修正后的诚实数字0.54 s 这类逐命令数据是在热页缓存hot page cache下测得不是新快照会话真实看到的。在真实快照启动的会话上首次setup_startup.sh有温树耗时22.9 s无温树32.3 s——温树的真实价值是9.4 s而非组件数据暗示的约 20 s。温树仍然保留functional_spec.md F9 记录了修正后数字与取舍但应以冷启动数字为准。二、WARM_CACHE标志恢复粘贴脚本就是仓库文件的核心契约在 Phase 5 之前做预热的WARM_CACHE标志只存在于用户粘贴进云环境对话框的那份脚本副本里这破坏了项目的核心契约F1粘贴的脚本应当是仓库文件本身、只有CONFIGURATION块被编辑过。Phase 5 把标志落地到仓库源码中恢复该契约。2.1 CONFIGURATION 块与命令行标志setup_env.sh 的CONFIGURATION块新增默认false本地运行与其他复用该环境的仓库不受影响WARM_CACHEfalse # true: warm the machines caches from a throwaway clone (cloud VMs)参数解析器新增--warm-cache标志usage中同步补了说明行。云端环境的配置文件.config/utils/claude_code_vm_setup.sh以命令行方式传入--upgrade-tools --best-effort --warm-cache --create-startup-script --add-playwright。2.2 VM 装配目录常量紧挨UV_MIN定义setup_env.sh 定义了这组常量VM_SETUP_DIR${KILN_VM_SETUP_DIR:-/opt/kiln-vm-setup} VM_SETUP_MARKER$VM_SETUP_DIR/.setup_for_kiln_repo_v1 WARM_NODE_MODULES$VM_SETUP_DIR/node_modules KILN_REPO_URL${KILN_REPO_URL:-https://github.com/Kiln-AI/Kiln.git}设计要点一个目录同时承载 marker 与温树二者都在任何 checkout 之外因此能存活进快照文件名里的_v1是契约版本号当 setup 提供的内容发生不兼容变化时递增它让旧脚本装配的 VM 被正确报告为未装配而非已就绪KILN_VM_SETUP_DIR与KILN_REPO_URL可被环境变量覆盖使整套行为无需写/opt、无需走网络克隆即可测试。2.3warm_from_throwaway_clone只在一个精确场景下运行实现见 setup_env.sh。它仅在WARM_CACHEtrue且没有 checkout时运行——正是云环境构建的场景。流程浅克隆 Kiln 到$VM_SETUP_DIR/throwaway-clone。克隆放在$VM_SETUP_DIR内而不是/tmp是为了让最后node_modules的mv是同一设备上的 rename而不是 601 MB 的跨设备拷贝克隆后先写.python-version再同步——否则 uv 会按系统 Python 建.venv、缓存另一解释器的 wheels等于给错误解释器做了预热并行执行uv sync --frozen --all-packages与npm ci与正式依赖安装的wait-both 并行模式一致然后mv克隆中的app/web_ui/node_modules到$WARM_NODE_MODULES删除克隆若同时启用了 Playwright在移动和删除克隆之后用温树自己的 playwright 安装 e2e 浏览器——因为playwright install会在浏览器目录的.links注册调用者路径随后删除克隆会使该注册失效下一次 install 就会把刚装好的浏览器当作孤儿清除。失败语义是警告而非fail预热是纯优化若把失败计入fail会让结尾行翻转为 Resolve the errors above——对一台 uv 和 Python 都正常的机器这是误导。setup_startup.sh反正会在每个会话重新校验所有必须为真的前提。三、Provisioning Marker让启动脚本能分辨被装配过的 VMwrite_vm_setup_markersetup_env.sh在每一次运行的 checkout 与 no-checkout 两条路径上都会写$VM_SETUP_MARKER记录setup_version、时间戳、uv 版本、Python pin、温树路径、温树是否存在、温树由哪个 commit 构建、本次运行是否创建了它另加上 Phase 6 的session_start_hook与playwright_cli字段——足够事后诊断一台过期或错误的 VM。两条值得注意的设计规则目录不可写时只打印一条低调提示并继续本地机器上/opt可能不可写而 marker 只在 VM 上有意义树字段描述的是磁盘上现在的状态而不是本次运行做了什么。不带--warm-cache的重跑正是AGENTS.md给出的修复命令不会创建树但已存在的树继续存活并持续给每个会话播种。若此时把 marker 重写成createdfalse, commitnone等于对每个会话继承的 601 MB 的来历撒谎。因此只要树比创建它的运行活得更久previous_marker_value就把旧 marker 的 commit 传递下去只有当树存在却没有任何 marker 可解释它时才写unknown。写入方式本身也有讲究先写到带$$后缀的临时文件再mv -f覆盖——直接重定向到 marker 自身会先截断再写一旦失败会留下零字节文件而setup_startup.sh只检测 marker是否存在那样会把唯一站在会话与来路不明的 601 MB 树之间的检查变成恒真的假阳性。四、容器门禁setup_startup.sh只在容器里干活setup_startup.sh的存在理由是云会话从全新文件系统启动。但在开发机上环境已经装配好且被所有 checkout 共享——一个会从机器级温树播种node_modules的脚本在那里毫无存在必要。因此 Phase 5 在参数解析之后、项目根发现之前加了门禁setup_startup.shis_flag_set() { case $(printf %s ${1:-} | tr [:upper:] [:lower:]) in | false | f | 0 | no | n | off) return 1 ;; *) return 0 ;; esac } if ! is_flag_set ${CLAUDE_CODE_REMOTE:-} ! is_flag_set ${IS_CONTAINERIZED:-}; then echo Not running in a VM/container, will not run custom setup. # ... 告知本地开发者应改用 setup_env.sh或手动 uv sync / npm install exit 0 fi判定规则是非空且非假值CLAUDE_CODE_REMOTEClaude Code 在云会话中置为true或IS_CONTAINERIZED手工逃生口任一成立即视为容器内。假值列表覆盖人们真正会输入的拼法no、0、false等——如果有人设置了IS_CONTAINERIZEDno却被当成 yes是这个门禁唯一不可能被察觉的失败模式。两个变量都不成立时脚本打印提示本地应运行setup_env.sh --human或手动uv syncnpm install并exit 0——正常结局不是错误。五、Marker 检查与温树播种seed_warm_node_modules的完整机制5.1 Marker 检查非致命但禁用硬链接setup_startup.sh 使用与setup_env.sh相同的三个常量两脚本不能共享代码因为后者会被整体粘贴进云设置框在项目根发现之后、硬依赖检查之前做 marker 检查——这样它能框住随后很可能出现的失败原因。marker 缺失时打印显著警告块VM setup 脚本本应运行而未运行设置标志禁用硬链接播种——没有 marker 意味着温树如果有来路不明不应链接进任何 checkout其余流程照常继续。缺失 marker 是警告而非致命错误一台未装配但 uv、npm 正常的机器仍能以更慢的速度完成全部工作。5.2 播种的三个前置条件播种发生在依赖同步之前且仅当三者同时成立setup_startup.shcheckout 中没有node_modulesmarker 存在VM_WAS_PROVISIONEDtrue$WARM_NODE_MODULES存在。seed_warm_node_modules的动作序列是承重的顺序不可交换cp -al温树到目标旁的 staging 目录staging 必须落在目标文件系统上否则mv会退化成 601 MB 拷贝并丢掉所有硬链接Unshare对 staging 根部的普通文件逐个cp -pmv -f断开硬链接然后才把 staging rename 进node_modules位置。理由是硬链接意味着经由一个路径的写就是经由另一个路径的写npm install恰好会原地改写node_modules/.package-lock.json实测同 inode、新 mtime而该文件是 npm 记录已安装什么的依据漂移它就可能让后续npm install跳过真正缺失的包。实测本仓库当前工具链下seed npm install 完整npm run build之后46,375 个 inode 中只有这一个被原地改写vite 缓存与 npm 新增包都落在 checkout 自己的目录项新 inode 上——因此只需断开根部那几百 KB 的普通文件下面约 4.6 万个包文件保持链接。若树先 rename 再 unshare会存在node_modules已存在但完全共享的窗口此窗口内运行被杀下一次运行会看到node_modules存在而跳过播种其npm install就直接穿透硬链接写坏基线。unshare 失败即播种失败回退到普通npm install。5.3 三个防御性细节Staging 按 PID 命名.node_modules.warm.$$。共享命名被实测否决过两个播种竞争同一名称60 次中 57 次静默损坏node_modules一次rm -rf从另一棵树的cp -al中途 unlink 条目幸存项被 rename 进位或rm -rf对仍在创建的目录失败第二个cp -al复制进了它嵌套出一整棵树。按 PID 命名的代价是被杀运行会泄漏 staging于是每次运行无条件执行一次按年龄清扫回收app/web_ui下超过一小时的.node_modules.warm*。它必须无条件运行因为播种块在node_modules已存在时整体跳过——正是泄漏目录会永远滞留的状态。源码中同时澄清让清扫安全的是不存在第二个进程而不是年龄过滤——cp -al隐含--preserveall会把温树的 mtime 打到 staging 目录上快照恢复的 VM 上活着的 staging 目录一完成就可读作几天前architecture.md 对此有专节分析跨设备兜底温树在另一文件系统测试用/dev/shm时cp -al逐文件失败——实测 46,436 行、15 MB。诊断写入临时文件而非 shell 变量只打印前 3 行加一个总数grep -c 计数因为wc -l对无换行尾的单行会数成零——为打破沉默而写的函数自己沉默了然后清除 staging、落到今天本来就会执行的普通npm installmv -T收尾若node_modules在守卫之后才出现-T使 rename 失败而不是把 staging 静默吞成子目录——不播种是唯一比这更好的结局。六、文档配套修改Phase 5 的收尾步骤是文档AGENTS.md与 CONTRIBUTING.md 必须停止暗示setup_startup.sh会在所有地方同步依赖——容器外它现在是 no-op需说明本地贡献者应该怎么做functional_spec.md 的 F8 补上门禁、marker 与播种其 Environment-side changes 配置块补WARM_CACHEtruearchitecture.md §1 与 §1B 同步并补变更清单行implementation_plan.md 补 Phase 5 与更新后的云端CONFIGURATION块phase_2.md 与 phase_2b.md 各加一行指向 Phase 5 的扩展说明避免只读旧计划的读者被误导。七、行为验证无单元测试全部实跑Phase 5 只涉及 shell 与文档没有单元测试——验证是行为式的每个用例都是被执行而非被推理且KILN_VM_SETUP_DIR与KILN_REPO_URL两个覆盖变量让每个用例都不碰/opt与网络。核心用例包括用例期望结果门禁两个变量均未设置 /CLAUDE_CODE_REMOTEfalse/0/空 /IS_CONTAINERIZEDno打印 not running in a VM/containerexit 0不动 checkout门禁IS_CONTAINERIZEDtrue而CLAUDE_CODE_REMOTE未设置完整执行启动流程Marker 缺失即使有温树显著警告、不尝试硬链接运行仍 exit 0 且正常打印Ready.Marker 在、温树不在无警告、无播种、普通npm installMarker 在、温树在、node_modules缺失播种成功ls -i证明 checkout 与温树文件是同一 inode温树在另一文件系统/dev/shmcp -al跨设备失败打印上限内提示无 staging 残留npm install兜底node_modules已存在不播种行为不变原地写风险记录温树全部文件的 inode/size/mtime跑npm install与 web build 后重比证明 npm 与构建工具是替换文件安全还是原地编辑会污染快照基线setup_env.sh --warm-cache无 checkout克隆、同步marker 与满node_modules都留在$KILN_VM_SETUP_DIR克隆被删除setup_env.sh有 checkout写 marker、记warm_node_modules_created_this_runfalse、不克隆不带--warm-cache重跑覆盖已有温树marker 仍报告树存在且保留原始 commit跨设备回退输出有界三行加计数而非逐文件一行Unshare 失败播种失败、staging 被清除、回退npm install而不是谎报播种成功两个播种竞争同一 checkout对 52,037 项温树跑 30 次竞争每次都留下正确的node_modules且无 staging 残留对照的共享 staging 命名 10 次竞争损坏 10 次年龄清扫两小时前的.node_modules.warm.*被一次完全跳过播种的运行回收新鲜的不动最终门槛uv run ./checks.sh --agent-mode绿色测试套件保持 6369 passed / 10020 skippedgit status --porcelain除预期改动外为空。八、小结把机器与checkout的准备工作彻底分开Phase 5 的三块拼图合起来完成了一个清晰的职责划分setup_env.sh一次性、快照前准备机器——uv 缓存、npm 缓存、温树、markersetup_startup.sh每会话准备checkout——容器门禁、marker 校验、硬链接播种、分支级同步。所有性能数字都以 Phase 6 的冷启动修正版为准温树值 9.4 s / 601 MB 镜像增量的显式取舍所有失败路径都降级为失去加速、失去不了正确性。相关完整脉络可继续阅读 project_overview.md、research_findings.md、functional_spec.mdF8/F9/F10与 architecture.md §1.3b以及 Phase 6 的 SessionStart 钩子方案。赞分享人工智能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 单入口化改造的设计与实现Cloud Sandbox DX Phase 2Kiln 云沙箱环境setup_env.sh 单入口化改造的设计与实现Cloud Sandbox DX Phase 2 本文围绕 Kiln 仓库 clou人工智能AI 应用AI 评测RAG微调提示工程开发工具桌面应用MLOpsKiln 云端沙箱会话启动检查setup_startup.sh 的设计与实现Kiln 云端沙箱会话启动检查setup_startup.sh 的设计与实现 在 Kiln 的云端沙箱如 Claude Code cloud session人工智能AI 应用AI 评测RAG微调提示工程开发工具桌面应用MLOpsKiln 云沙箱开发体验实战setup_env.sh / setup_startup.sh 如何零知识启动 Claude Code 云会话Kiln 云沙箱开发体验实战setup_env.sh / setup_startup.sh 如何零知识启动 Claude Code 云会话 本文基于 Kiln人工智能AI 应用AI 评测RAG微调提示工程开发工具桌面应用MLOps创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考