Claude Code 的沙箱:笔记本电脑上的隔离代理环境
本地 Kubernetes 沙箱如何为编程代理提供专属机器、受限权限、出站访问白名单及集群视图,并分析构建方案与购买方案的利弊。
来源: Capsule : How I came to build an Agentic Developer Environment at Teads
重启如何清除你的工作记忆
想象一下同时打开六七个 Claude Code 会话的场景:有些在终端中运行,几个在 VS Code 中运行,还有一个在 IntelliJ 中运行——因为团队使用多种编程语言,每种语言都有其首选编辑器。这些会话分别处理不同的代码库、任务以及未完成的思路。随后笔记本重启了。
代码本身并没有问题,问题在于所有工作的状态记录都丢失了:哪个会话正在重构中,哪个在等待构建,哪个提出了问题却从未查看过答案。人们需要花费二十分钟从shell历史记录和混乱的git分支中重建工作记忆。到这时,原本糟糕的一天就开始显得像是一个设计缺陷。
重启只是最明显的症状,实际上还有三种不同的问题在逐渐损耗系统的效率。
混乱状况。启动智能体成本很低,但跟踪管理却十分耗资。每个新智能体都需要额外的终端标签页、编辑器窗口,以及占用你大脑中的额外记忆空间。笔记本电脑最终变成了一堆窗口的集合体,而人则成为唯一的协调层。现有的工具都假设一个智能体对应一项任务,并由一个人负责监控,但实际工作流程并非如此。
权限难题。默认设置中没有任何方案能解决这个问题。Claude Code要求对工具调用进行审批,但它可能会就一些无关紧要的事情向你询问,而对于那些可能造成严重后果的调用却保持沉默。虽然其行为有所改善,但核心问题依然存在——因为智能体以你的身份行事并拥有你的权限。GitHub组织管理员不可能合理地批准每一项API调用,也无法认为单次审批就是无害的。
还有两条路径可选。你可以持续调整允许列表,直到它变得如此复杂以至于同事都无法解读;或者你可以启用 --dangerously-skip-permissions 并寄希望于运气。那些可怕的故事都源于第二种路径,比如那个急于清理生产数据库的脚本。这两种方法都会失败,原因只有一个:该脚本承载着你的身份信息,而逐个批准命令只能暂时解决这个问题。
安装疲劳。不同技术栈上的多个代码仓库存在 JDK 缺失、Node 版本错误、SDK 不匹配、CLI 工具不一致等问题,还有半年前设定的版本约束如今已无人能解释其缘由。每次环境切换都需要花费数分钟时间操作包管理器。一旦笔记本电脑丢失或更换,问题会更加严重,因为每个环境都得逐个工具重新构建。经过数月时间对心仪的编码 CLI 进行优化后,依然存在一个疑问:这样的配置是否还能复现?还是只能重新开始,并试图记住那些关键设置。
为代理程序专用的一台机器
它最初并非作为一个平台项目而诞生的。Capsule原本只是个个人工具,旨在让某位工程师的工作周少些烦扰。其设计理念很简单:为该工具提供一个属于它自己的机器,而非使用你的机器,这样它就无法查看你的文件系统或使用你的凭证,而且说“尽管去做,无需询问”也不会显得鲁莽。此外,它的成本还必须足够低,这样才能让多个实例同时运行而无需过多考虑。
同事们注意到后也要求使用,随后其他人也开始跟风。它已不再只是某个人的工具,如今每天早晨都会出现在越来越多的工程师的屏幕上——从最初的少数用户发展到几十人,工程团队中的大部分人也很快会使用它。没有人被强制要求使用它,人们之所以采用它,是因为工作变得更轻松了,而这正是最值得信赖的采用迹象。新员工在笔记本电脑上安装Capsule后,从第一天起就能完全以代理模式工作。
简而言之,Capsule为Claude Code提供了一个私密的、现成的沙箱环境,让它可以独立处理你的代码仓库,从而不必拥有你所有的权限。
图片展示的是胶囊站。左侧列出了各个胶囊,所选代理的终端位于中间,而你拥有或被要求审核的拉取请求则位于左下角,从而在一个窗口中呈现整个集群的概览。
它的设计范围刻意较为狭窄。目前它既不是代理编排框架,也不是多代理产品,不过可能很快就会加入一些编排功能。它既不是集成开发环境,也不支持插件或编辑器整合,更不会分叉或取代 Claude Code,因为其内部实际运行的是以特定方式配置的普通 Claude Code。它不能替代 CI/CD,也不是托管型 SaaS 服务,因为所有操作都在你的笔记本电脑上完成。
最后这一点的重要性超出了预期。由于没有按座位收费,也无需额外运行成本,第十个胶囊机的使用费用与第一个相同,这使得并行工作从一种奢侈变为常态。机器的成本早已支付完毕,存储库也依然保留在最初的硬件上。
在胶囊机内部,Claude以--dangerously-skip-permissions模式运行,从不询问是否有权执行某条命令。它唯一关心的问题是意图,即要做什么,而从不涉及权限问题。之所以能设定这样的合理默认值,背后其实有两个原因。
沙箱机制
每个容器都在 OrbStack 已在 Mac 上搭建的 Kubernetes 集群中作为 Pod 运行。这样一来所有操作都在本地完成,无需额外基础设施,也不会产生云服务费用。无法访问主机文件系统,另有两个已声明的卷用于存储持久数据:工作区及 Docker 镜像缓存。三层机制限制了外部流量:
- 内核的
iptables规则会阻止该代理用户 ID 直接使用端口 80 和 443 进行外部连接。 - Kubernetes 的 NetworkPolicy 进一步将可用的端口限制为 DNS、80 和 443。
- 通过这些规则后剩余的流量还需经过 Squid 代理,该代理会执行明确的域名允许列表检查。
允许列表包括 GitHub、npm、Maven、ECR 以及 Anthropic API,其他所有目的地默认均被禁止。代理无法轻易连接到任意端点并上传源代码,要实现这一目标需要相当高的技巧。
在任何数据离开之前,有三道防线会进行拦截:内核规则、网络策略,以及允许列表代理。
最小权限凭证
这才是真正的价值所在。认证是在主机上以你自己的身份进行的,使用你通常拥有的所有角色权限。这些角色权限会保存在 macOS 的密钥链中,而不会传递到胶囊环境中。主机则会生成一个范围受限、有效期短暂的令牌并注入其中:
- 一个仅限于只读生产角色的临时 AWS STS 凭证
- 一个 GitHub 令牌,其权限范围在注入前会经过验证
- 一个只读的 BigQuery 服务账户,由代理程序冒充,这样你的原始凭证就不会涉及其中
如果提供范围更广的权限,比如具备生产管理职能的SSO角色或具有更多权限范围的令牌,主机就会完全拒绝注入此类权限。防御是默认设置,从内部来看,代理程序无法重新认证或获取更广泛的访问权限。身份信息依然得以保留,因此审计日志仍会将查询操作归因于你,但受影响的仅限于角色权限,不会波及到你本人。
你在主机上以自己身份登录,代理程序只能收到由此生成的、范围有限且有效期短暂的令牌。正是这种权衡让其他功能得以正常运行。允许代理程序无人值守运行并非基于对其更高的信任,而是为了让最坏的情况也不会造成严重后果。
消除障碍
安全性为自主运行提供了许可,但并不会带来良好的使用体验。大部分努力都投入在了消除各种障碍上。
容器启动时所使用的基础镜像已预装了 Go、Rust、Node、JDK、Maven、sbt 和 Scala 等工具链的固定版本。此外还有一个“Docker 中的 Docker”侧车容器,为每个容器提供独立的运行环境,从而使集成测试和 Testcontainers 测试能够在互不干扰的情况下执行。已登录的命令行工具也在等待使用,包括 GitHub CLI、AWS CLI、gcloud 和 bq。开箱即用的语言服务器(如 Metals、jdtls、gopls、rust-analyzer、vtsls)也让代理能够通过符号定位、查找引用和调用层级来浏览代码,而无需盲目搜索。
依赖项的缓存通过主机卷在各个容器之间共享。这看似是个小细节,但实际上并非如此。在第一个版本中,每个新环境都需要重新下载所有内容,而那种每次任务前都要花费二十分钟处理Maven的工具自然不会被采用。现在,一个已启动的容器大约只需二十到三十秒即可准备就绪。
最能改变代理行为的是一个真正的反馈循环。胶囊内部运行着一个内部平台命令行界面:它会检查主机的单点登录令牌,限制其使用范围并注入该令牌,从而使代理能够创建一个沙箱环境,部署刚刚构建的分支,并在那里运行冒烟测试。集成测试框架也在其中运行,它会获取真实的图像,并在侧车模块中启动实际的MySQL、Kafka和Cassandra服务。起初由于图像需要通过代理传输,速度较慢,但之后就会变得很快。这正是能够生成看似正常的代码的代理与能够判断代码是否正常运行的代理之间的区别。
该系统还内置了查询功能。每个容器都配有仅支持读取操作的内部MCP网关,提供数十种工具功能。这些工具可用于获取服务及容器的日志、通过PromQL和Thanos查询指标、查看Grafana仪表板、获取Kubernetes事件信息、了解CI构建状态、掌握值班人员情况及正在触发的警报、确定服务归属权,还能在Confluence和Slack中进行搜索。由于无法进行写入操作,因此在所有场景下启用该功能都不会带来风险。插件市场还提供了Maven构建、服务框架搭建、沙箱管理以及PR审核等团队所需功能,这样代理从一开始就能熟悉公司的规范流程。
这里有一个值得养成的习惯。维护一个私有的仓库,用来存放个人的斜杠命令和计划模板,Capsule会在创建的每个环境中复制该仓库的内容。这样你的工作流程就能跟随你一起移动。计划和记录也会通过这个仓库在各个胶囊之间传递,而交接技能可以标记会话的结束位置并保存总结,这样下一个胶囊就能在已有上下文的基础上开始工作,而不必从头开始。这只是一个普通的git仓库,因此智能体也可以在其中维护自己的工具,只需一条指令如“添加一个构建与测试命令,提交并推送它”即可。
暂存优于重新开始
随之出现了一个意料之外的效果。一旦创建独立智能体的成本变得很低,而且无论是否有人监控,每个智能体都会持续存在,工作就不再是一次只处理一件事了。
在平常的下午,会有四到五个胶囊处于活跃状态。一个在默默处理漏洞修复,一个用于真正的结对编程的SSH会话,一个重新运行那些不稳定的集成测试,测试通过后就会创建拉取请求,还有一个则在处理那些没人愿意看的依赖项升级任务。还有大约十个处于暂停状态:一些待回头的想法、以有趣方式失败的实验,以及一些仅初步考虑过的设计。暂停可以保留仓库、会话和缓存,而恢复只需几秒钟,因此某项思路并不会仅仅因为不是当天的优先事项就被放弃。
真正耗时的从来不是开始工作,而是将其搁置。而当某项工作完成后,只需删除对应的胶囊,既不会留下git工作树的混乱,也没有清理工作,所有的衍生内容都会一同消失。
完全的自主性消除了剩余的所有障碍。无需为 git 命令等待审批,不必在浏览器标签页中查找 CI 页面上的数字,也不需要翻阅构建日志来寻找那条关键信息。代理会自行处理这些事务,再加上沙箱机制和受限令牌的保障,这一切都不会变成纯粹的赌博行为。
四个胶囊,四种状态,无需等待人类干预。
同一个引擎具备两种模式:你可以在交互式的 tmux 会话中与代理协同工作,或者给出指令后让其自动运行。
这就是该界面能受到青睐的原因。虽然命令行工具功能强大,但在终端中反复运行list、ssh和status显然无法有效管理整个设备群。Capsule Station通过一个窗口解决了这一问题:侧边栏显示胶囊设备,每个设备都有独立的嵌入式终端,同时还能查看拉取请求和审核请求。切换不同代理就像切换浏览器标签页一样简单。该应用采用Tauri技术,大小约为10兆字节,并依赖系统自带的网页视图器,因为显示列表无需加载完整的Chromium引擎或占用1千兆字节的磁盘空间。它通常可以一整天保持打开状态,而集成开发环境则很少能做到这一点。
同样可以说它没有改进的地方。生成的代码质量并未提升。不过那些繁琐的操作——整理、审批、安装、重新认证以及容易丢失当前进度——都消失了,而这些恰恰是之前最大的障碍。
为何选择自行构建而非购买
现有的托管方案确实存在且日益完善,比如多家供应商提供的云代理沙箱以及可远程运行的代理程序。这些方案无需承担运营负担,且具备真正的扩展能力。但代码和凭证会离开你的安全边界,工具链较为通用,导致大型代码库的启动时间变长,同时也无法实现内部身份模型。此外还有开源项目可供选择,例如基于Kubernetes的沙箱、开发容器工具,以及供应商提供的本地沙箱实现方案。这类方案对供应商保持中立,基于稳定的基础架构构建,但属于低层级解决方案,需要你自行负责镜像、认证及整个用户体验。无论选择哪种方案,一个值得考虑的问题是:六个月后它是否仍会得到维护?毕竟现在大家都在推出相关产品,但能长久维持的却寥寥无几。
该架构位于两者之间。核心部分主要由组件构成:DevPod负责开发容器及容器的生命周期管理,Squid处理数据出口功能,OrbStack已提供的Kubernetes集群也参与其中,此外还有自定义的工作空间镜像、由主机实现的身份认证机制以及最上层的服务Station。这种设计使得各组件之间的绑定较为松散,便于更换。它适配现有的代码库和身份认证模型,除代理程序发送给模型API的数据外,所有代码都保存在笔记本电脑上,这与此处列出的其他选项一致。
身份凭证是在主机上生成的,而代理程序所操作的所有内容都在带有允许列表的代理服务器后的容器中运行。
还有一个灵活性优势,其重要性超出了预期。如果有人需要某个功能,只需提交拉取请求并进行讨论,该功能就能被加入系统。无需有人花费三周时间与产品经理沟通,试图将某个需求纳入明年的开发计划。
这一风险确实存在,值得明确指出:该团队负责应对,本质上这是一个有公司支持的单人项目。开发成本从未如此之低,而维护成本才是真正的未知数,目前还无人能给出答案。
接下来的计划
未来将把使用范围从几十名用户扩展到整个组织,会在镜像中集成更多功能和工具,并实现更多整合。不过最后这一点比听起来要困难,因为每一种新功能都需要明确在无询问模式下智能体可以执行哪些操作。只读访问很简单,但任何写入操作都需要经过认真讨论,并找到标记破坏性操作的方法。远程操作是目前最受期待的功能,因此即便关闭笔记本电脑,这些智能体仍能持续运行。
关于安全漏洞的警示
该系统刻意采用防御性设计,构建它带来了一个令人不安的教训:赋予代理自主权的工具最容易利用安全模型中的薄弱环节。良好的访问控制能让集成变得简单,而缺乏它则会立即带来问题,并清楚地显示出原因。
即便如此,沙箱也有其局限性。以完整权限运行代理就如同携带上了膛的枪支,无论是否开火都存在风险。Capsule则消除了这些风险。不过,只要在聊天中粘贴管理员令牌并指示代理使用它,权限又会重新回到代理手中。
开始构建吧
这是非凡的时代,很难高估一名工程师能够创造出的成果。这一切始于某个普通下午某个人的烦恼,后来发展成越来越多同事每天早上都会使用的工具。要实现它仍需满足两个条件:首先必须明确想要解决什么问题,其次需要支持——因为代币需要花钱,而且必须有人认同其价值。只要满足这两个条件,这项工作就会发生永久性的变化,所以去寻找问题并解决它们吧。