我的智能体编程环境
自从摆脱企业束缚以来,我尝试了各种 AI 辅助开发方法。经过几个月的摸索,我对目前的设置相当满意,想要记录并分享它。
事物变化非常快,我并不幻想这将是永恒的智慧结晶。但与一些朋友交谈并浏览 X 上的帖子,似乎我确实掌握了一些尚未普及的技术。至少,这将是一个美好的时间胶囊,当我们进一步进入奇点时可以回顾。最终状态相当不错:我最终获得了让前沿模型通过手机在火车上修复生产错误的能力。
1、我的要求
在使用原始 Claude Code 几个月后,我清楚地认识到我缺少什么:
代理需要在 Linux 上运行。在 Windows 上进行代理编码基本上是不可能的,因为代理经过大量 Bash 和其他 Unix 工具的训练。尽管有些假装支持 PowerShell,但它们总是在引号问题、UTF-8 支持差距等方面自找麻烦。
我希望能够从台式机或笔记本电脑工作,无缝交接项目进度,包括保留代理会话、工作树状态和 gitignore 文件(如 .env 文件或构建工件)。
即使我关闭笔记本电脑转换位置,我也希望工作继续进行。
我希望各种用户全局设置(如 AGENTS.md、技能、工具配置)无论我在哪里工作都可用,并且有备份和版本控制。
我希望能够在 Visual Studio Code 中审查代理的当前工作,而不仅仅是在它们的工具 UI 中或作为 GitHub 拉取请求检查点的一部分。
我希望代理能够启动反映其当前工作的开发服务器供我查看。在某些情况下,这些服务器需要是安全上下文,即 https: 或 http://localhost。理想情况下,只有我应该能够访问它们。
我希望能够在同一项目上运行多个并行工作流,而不会让代理相互踩踏。
我希望尽量减少批准中断,理想情况下一直到 --dangerously-skip-permissions / --yolo 模式,这样我可以运行并行工作流并离开计算机。(剧透:这意味着一个一次性虚拟机。)
这些要求都不难,其中几个还能协同作用。这只是找到并缝合所有正确工具的问题,尽量减少麻烦。我将在下面概述我的设置,但不是作为分步指南。既然你现在有代理,你可以让它们做那些繁琐的部分。
2、关键要素
最大的解锁是使用 Tailscale 和在始终开启的家用台式机上运行的专用 Linux 虚拟机。如果你结合 ChatGPT 桌面应用(前身为 Codex)的各种功能,你基本上就搞定了。一些额外的好处来自使用 Portless 和 chezmoi。
2.1 虚拟机和 Tailscale
首先,我们需要一个一次性 Linux 虚拟机。你可以使用云托管的虚拟机,但我一直保持台式机运行,所以我只是使用 Ubuntu Server ISO 设置了一个。给它足够的内存和磁盘空间,并确保启用嵌套虚拟化支持,因为我们希望代理能够根据需要启动自己的容器或虚拟机。
(你可能认为 Ubuntu Server 相比 Ubuntu Desktop 会有限制,因为没有图形界面,你无法登录网站或截取开发中的工作截图。实际上这对我来说不是问题,因为当你要求代理执行需要这些工具的任务时,它们完全能够安装和使用 Playwright 或 Xvfb 等工具。)
起初,虚拟机访问起来有点烦人。我们希望能够 SSH 进入它,既为了简化初始设置,也为了我们宏伟计划的一部分。这就是 Tailscale 的用武之地。
Tailscale 是一款美妙的软件,我在这次冒险之前并不知道它。它将你所有的机器——在我的情况下,是我的台式机、笔记本电脑和 Linux 虚拟机——连接成一个私有网络,它们可以通过主机名通过 SSH、HTTP(S) 等相互访问。所以即使我在咖啡店使用一些随机 Wi-Fi,我也可以运行 ssh agents-base,我就会进入我的虚拟机,与我的代理一起工作。或者我可以访问 https://agents-base.tail234567.ts.net:8443/ 来查看我的代理为我启动的 Web 服务器。由于 SSH 是我们技术栈其他部分的基础技术,如代理工具本身和 VS Code,Tailscale 的"跨互联网的神奇 SSH"让其他一切都能正常工作。
(另外,它是免费的!他们有一篇很好的文章解释为什么它保持免费。)
因此,在设置虚拟机后立即在其上和所有其他机器上安装 Tailscale。然后你可以 SSH 进入并通过安装常用工具来设置你的开发环境。或者,安装 Claude Code / Codex CLI 并让它们安装它们预计需要的任何东西。
我的 Tailscale 配置接近默认,但我做了以下自定义:
我在所有机器上启用了 Tailscale SSH,将规则从 "check" 更改为 "accept",并禁用了密钥过期,以避免频繁重新认证。(如果你不需要虚拟机上的代理从客户端机器获取文件,你可以选择仅在虚拟机上启用 Tailscale SSH。)
我启用了 HTTPS 证书,以便代理的开发服务器可以是安全上下文。
我设置了 Taildrive 支持,以便更容易从我的 Windows 客户端在机器之间移动文件。
2.2 代理工具和客户端
接下来,我们需要在虚拟机和客户端机器上安装和配置代理工具。在虚拟机上,这意味着 Claude Code 和 Codex CLI。(面对现实吧,没有其他工具处于前沿。)
客户端变得更加有趣。当我仍然沉迷于 Claude Code 时,我花了一些时间直接通过 SSH 使用它,然后引入 tmux 来保持会话在后台运行,即使我的 SSH 会话断开连接(例如,因为我关闭了笔记本电脑盖子)。但我发现这相当笨拙。在我获得可接受的滚动和窗口调整大小行为之前,tmux 需要大量调整,即使那样它也经常以奇怪的方式出现故障,例如,在断开连接后破坏我的客户端终端,或者当我的笔记本电脑和台式机都试图 tmux 到同一个 Claude Code 会话时表现不佳。
幸运的是,有一个更好的解决方案:Claude 和 ChatGPT 桌面应用。它们都有充当瘦客户端的模式,而代理、其会话和你的代码都位于远程机器上,如我们的虚拟机。
真正的赢家是 ChatGPT 应用。它的 SSH 支持非常流畅。它原生理解你可能在本地或远程工作,例如在其设置屏幕的分区方式中。它优雅地处理断开连接。唯一不太理想的部分是,访问同一远程虚拟机的多个客户端之间的项目和会话列表不能完美同步,但我通常可以通过一些调整让它们同步,例如在正确的文件夹中启动新的远程会话会导致其余的出现在侧边栏中。
不幸的是,Claude 应用要差得多。我永远搞不清楚它是试图通过 SSH 工作,还是通过其基于互联网的远程控制协议,或者某种组合。会话根本不同步,所以如果你想要会话交接,你需要回到 tmux 方法。同样,即使是远程会话,如果从桌面应用发起,如果你关闭桌面客户端,它们会在大量错误中死亡。没有原生的按文件系统文件夹分组,所以你必须在侧边栏中手动创建"项目"并将你的会话移入其中。总体而言,感觉 Claude 客户端团队专注于 Claude Code(CLI),并将桌面应用视为非程序员的东西。但是,当我将此发布到 X 时,一位 Anthropic 工程师说事实并非如此,所以希望它会随着时间的推移而改善。
2.3 安全态势和影响范围
所以。我们希望代理尽可能自主,不需要批准。这意味着编辑 ~/.codex/config.toml 以包含
approval_policy = "never"
sandbox_mode = "danger-full-access"
和 ~/.claude/settings.json 以包含
{
"permissions": {
"defaultMode": "bypassPermissions"
},
"skipDangerousModePermissionPrompt": true
}
我还强烈建议将你的用户放入 sudoers 文件中。这允许代理在虚拟机上安装和配置新工具而没有摩擦。(不知道怎么做?问代理。)
此外,我建议安装 gh CLI 并使用你的凭据登录,以便你的代理可以做诸如操作私有存储库、打开拉取请求、照管你的 GitHub Actions CI 运行以及使用 GitHub API 搜索其他存储库而没有速率限制等事情。
这安全吗?不,不太安全。有了这些配置,代理可以开始删除你的 GitHub 存储库,将你的 gitignore 秘密上传到互联网,以你的名义回复 GitHub 问题,或者意外擦除虚拟机的整个主目录。天哪,一个足够有动机的代理可以逃脱虚拟机并开始入侵网络上的服务器。
但在实践中,结果很好。代理似乎是对齐的且非恶意的,至少目前是这样。最糟糕的情况是一场事故弄乱了虚拟机并丢失了所有尚未上传到 GitHub 的工作,或者一个过于热心的代理误解了提示并影响了生产。(例如:我对 ChatGPT 5.6 Sol 说"让我们为此发送一个拉取请求并将其合并到 main",切换回应用程序后,我看到它已经按照我的要求将拉取请求合并到 main,而不是按照我的意思等待审查。)
如果你想防止这些,你可以尝试在虚拟机内使用每个项目的开发容器,或者限制你授予 gh CLI 的令牌的权限。但对我来说,这些还没有达到成本/收益阈值。
确实能为自己买单的一件事,至少在安心方面,是尽早并经常将提交推送到 GitHub。(对某些项目使用私有存储库。)我喜欢知道我的工作在别人的服务器上,即使虚拟机被破坏也会留在那里。而且我得到了通常的好处,比如 GitHub Actions CI 检查我的工作,以及 GitHub Pages 或 Releases 部署供外部世界看到我精彩的项目。
2.4 工作树
回到技术话题。
很多人对 Git 工作树表示困惑。自己管理它们可能很烦人。但当代理为你做这件事时,包括处理 origin/main 同步、依赖安装、复制 .env 文件等,这轻而易举。它们专为我们的目的量身定制,允许多个代理在代码库上工作而不会相互踩踏。
更好的是,ChatGPT 和 Claude 桌面应用都有内置支持。在给定项目中启动新会话时,你只需勾选一个框,现在该会话就在其自己的工作树中!
这里的一个问题是工作树位置。ChatGPT 应用的默认设置是将所有工作树放在 ~/.codex/worktrees/ 中,效果很好。然而,Claude 应用的默认设置是将它们放在项目内的 .claude/worktrees/ 中,与其他软件的交互相当差:
node_modules发现遍历目录树,所以如果你在my-project/.claude/worktrees/cleanup/node_modules/中卸载了依赖项,工作树中的 Node.js 仍然可以从my-project/node_modules/加载旧版本。- 如果你使用任何递归到子目录的命令,如
deno task --recursive <task-name>,命令也会进入 Claude 工作树。 - 如果你在同一项目中使用 ChatGPT,它会定期被
.claude/文件夹的不同代码副本混淆,例如,当 Claude 工作树中的文件出现在rg和find结果中时。
修复此问题以允许类似 ChatGPT 的配置似乎是 Claude 的一个已知功能请求。Fable 告诉我有一些涉及配置 WorktreeCreate 钩子的黑客可用。但对我来说,这只是另一个在大多数项目中更喜欢 ChatGPT 的原因,直到 Claude Code/Claude 应用团队解决他们的工作树问题。
(请注意,Claude 桌面应用有一个"工作树位置"设置,但它对我们的目的无关紧要,因为它仅适用于客户端机器上的本地开发,在虚拟机上工作时被忽略。)
2.5 使用 VS Code 进行代码审查
要审查代理编写的代码,我仍然喜欢能够在 Visual Studio Code 中打开它们的工作树。ChatGPT 应用中的"审查"侧边栏对于小差异相当好,特别是用于向代理提交行注释。很多人都在 vibe-coding 他们自己的以审查为中心的酷应用。但目前我仍然坚持使用经典工具。
VS Code 的妙处在于它几乎内置了一个强大的基于 SSH 的远程开发系统。一旦你在目标虚拟机和客户端机器上安装了 Tailscale SSH,你只需在客户端 VS Code 中添加 Remote - SSH 扩展。然后你会在 Ctrl+Shift+P 菜单中获得一个新的"Remote-SSH: Connect to Host..."选项,让你可以像打开本地文件夹一样打开远程文件夹。甚至用 Ctrl+Shift+` 生成终端也会在远程主机上创建该终端,这对于快速命令非常方便。
更好的是,如果你使用 ChatGPT 应用并在远程会话中工作,每个聊天的右上角会出现一个带有 VS Code 图标的按钮,它直接打开一个连接到虚拟机并打开项目文件夹的 VS Code 实例。这特别方便,因为如上所述,代理通常在加密命名的 ChatGPT 管理的工作树文件夹中工作。(Claude 没有这样的运气,但你可以在应用程序中浏览,直到它告诉你当前工作树文件夹的名称,然后将其复制到 VS Code Ctrl+K,O"打开文件夹"菜单中。)
2.6 开发服务器
接下来,你需要一种简单的方法让你的客户端机器查看代理正在构建的任何 Web 服务器。起初我用端口转发来实现,但最终我采用了一种不那么繁琐、更 Tailscale 原生的方法。
在典型项目中,你会有一个像 npm run dev 或 python -m http.server 这样的命令来启动绑定到某个 127.0.0.1 端口的服务器。如果代理直接运行这些命令,那么生成的服务器将无法在虚拟机外部访问。你可以尝试绑定到 0.0.0.0,这将使服务器在网络上其他机器可用。但为了满足我们独特的开发拓扑而搞乱项目的 npm run dev 脚本定义感觉不太对。如果你直接通过 IP 地址访问服务器,例如 http://192.168.0.103:8000/,那不是安全上下文,所以各种 Web API 将不可用。另外,如果多个代理在同一项目上工作,它们可能都会尝试使用相同的端口,然后感到困惑并开始杀死彼此的服务器。
Portless 是一个旨在解决这个问题的小型 CLI。或者更确切地说,它解决了一个相邻的单机问题,但通过一些黑客技术,我们可以让它为我们的案例工作。如果你想要完整的故事背景,你可以阅读我与 ChatGPT 的对话,但最终结果是安装 portless CLI 后,我创建了 ~/.local/bin/tportless,内容为
#!/usr/bin/env bash
# 让代理管理的每个服务器也获得一个 tailnet URL,在专用端口上。
export PORTLESS_TAILSCALE=1
# 将本地代理从端口 443 移开,以避免需要 sudo。
export PORTLESS_PORT="${PORTLESS_PORT:-1355}"
exec portless "$@"
并更新了我的 AGENTS.md(见下文),添加了以下部分
## 预览服务器
在为用户设置预览服务器时,不要直接运行 `npm run dev` 或类似命令。而是使用 `tportless` 包装器:裸 `tportless` 通过代理运行项目的开发脚本,而 `tportless <app-name> <command…>` 适用于任何其他服务器命令。这将在 tailnet 上公开预览服务器。将 tportless 输出中的 Tailscale URL 报告给用户,而不是 localhost URL。
结果令人愉快:代理完成一些工作,启动服务器,通常使用 Playwright 进行一些冒烟测试,然后给我一个像 https://agents-base.tail234567.ts.net:8443/ 这样的 URL,我可以在这里查看它的工作。并行工作树中的其他代理将在自己的专用端口上启动服务器,没有冲突。这些 URL 在 tailnet 外部不可访问,所以没有它们被利用或我新兴的项目在准备好之前被泄露的危险。
2.7 使用 chezmoi 同步
随着时间的推移,你可能会积累关于代理如何工作的偏好,或代理工具配置文件的自定义,或适用于多个项目的漂亮代理技能。直接将这些存储在虚拟机中可以工作,但虚拟机应该是一次性的。在极少数需要在客户端机器上进行本地开发的情况下,例如开发原生 Windows 应用,至少你的一些配置将受益于同步到客户端机器。
这种同步和备份配置的问题是一个非常古老的问题,通常在"点文件"的名义下讨论。(因为在 Linux 世界中,大多数这些配置文件在文件名中使用前导 .。)显然最好的解决方案是一个叫做 chezmoi 的软件。它相当整洁:它支持模板来处理机器和操作系统之间的微小差异,通过 Git 同步,符号链接等。
但就我个人而言,这是那种我以前绝不会费心去做的事情……在编码代理之前。学习一个新的 CLI 并配置它就那样:太多工作了,当我可以通过一些手动复制和粘贴获得大部分相同结果的时候。现在,我只问 ChatGPT:
为我在这台机器(agents-base)上、SurfacePro11主机上和Domenic-Desktop主机上设置 chezmoi。遍历这些主机上的所有现有点文件,并生成一个合理的合成,带有适当的平台特定防护。确保调查~/AGENTS.md和~/skills/,并从 Claude 和 Codex 期望的位置到这些文件创建符号链接。请注意,在这台机器上,Claude 和 Codex 有完全权限,但在其他机器上,它们是受限的,所以我们需要有条件地保留命令允许列表等。我们的目标是一个私有 GitHub 仓库domenic/dotfiles,你可以为我创建它。
我喜欢生活在未来!
3、额外好处:基于手机的开发
它甚至不在我的原始要求中,但基于手机的开发几乎免费地从这个设置中产生。
一旦你安装了 ChatGPT 或 Claude 移动应用,它们可以被配置为控制与你的帐户关联的任何其他代理工具实例。(这照例对 Claude 来说有点麻烦,需要你手动启用"远程控制"功能。)如果你安装移动 Tailscale 客户端,你可以从任何网络行使这种控制,而不仅仅是你的家庭 Wi-Fi。
所以这种工作流程对我来说已经成为现实:
在旅途中注意到我的一个项目的实时 Web 部署中的一个错误。例如,在聚会上向某人展示时。
在回程火车上,打开 ChatGPT 移动应用,它通过 Tailscale VPN 连接到我的虚拟机。在项目的目录中启动一个新的远程会话,要求它修复我注意到的错误。
它工作一段时间,而我浏览 X,然后向我发送一个包含 tailnet 可访问的预览服务器 URL 的推送通知,我可以用它来确认错误已修复。如果没有,我们一起迭代几个回合。
一旦我满意,我告诉它打开一个拉取请求。我浏览差异并从我的手机合并它。
几分钟后,GitHub Actions 或 Netlify 部署管道,修复已经到达实时站点,通常在我到达家用火车站之前。
修复手机错误,从手机。
未来!我们生活在其中!
4、回顾和剩余差距
所以回顾我们的要素,以及它们如何帮助我们满足原始要求:
一次性 Linux 虚拟机为代理提供了非 Windows 环境,并允许我们将其配置为零批准,同时对该宽松策略的影响范围感到满意。
使用 Tailscale 让我们所有的机器无论在什么网络上都能访问该虚拟机,并让代理公开安全上下文开发服务器。
Git 工作树和 Portless 确保我们的代理可以在同一项目上并行工作而不会相互踩踏。
Visual Studio Code 的 Remote - SSH 扩展让我们可以审查代理创建的任何给定工作树中的代码。
GitHub 仓库作为我们所有项目的保存点,以防虚拟机需要重置,chezmoi 让我们同步和备份我们的 AGENTS.md、技能和其他配置。
ChatGPT 桌面应用为我们提供了轻松的会话交接和同步。Claude 桌面应用在各方面都不太好,所以我们通常不得不求助于 Claude Code 加 tmux 来获得该功能。
什么可以更好?
好吧,如上所述,如果有开发容器,这一切都会稍微安全一些。它们还有其他好处,比如让你在每个容器中安装冲突的全局工具集。现在我让我的 AGENTS.md 推广使用 fnm 和 uv,所以我还没有遇到很多这样的冲突,但我可以想象它们将来会出现。
在用户体验方面,我通常不喜欢每个编码工具中的"会话"模型如此强烈地绑定到虚拟机上的文件夹路径。如果你重命名或移动项目文件夹,ChatGPT 和 Claude 应用会感到困惑,并且通常会丢失该文件夹中的所有会话历史记录。你可以通过让代理找到隐藏引用并更新它们来修复此问题,但这很痛苦,需要在客户端和主机机器上都完成。
同样,我希望有某种方法将会话历史记录备份到持久的地方(如私有 GitHub 仓库)。至少,我怀疑它们几年后会很好地用于怀旧。但有时会话记录是某些设计决策的唯一记录,或者解释为什么代码看起来像这样的被弃用方法。
以上所有都可以通过我端的一点工作来修复,例如编写小型实用程序和包装器。但我怀疑它们不会真正无缝,直到它们内置到工具应用中。所以,我希望 ChatGPT 应用团队解决它们。并且 Claude 应用团队首先总体上整理好自己的东西,然后开发这些功能。
这是我的设置。一个一次性虚拟机,一个神奇的 VPN,两个前沿工具,和一些额外的工具。如果你在六个月后读到这个,我假设它都古雅地过时了。但这就是时间胶囊的意义所在。
多么美好的时代!
原文链接: My Agentic Coding Setup, July 2026
汇智网翻译整理,转载请标明出处