Dan Begel / UnsplashEssay
并行 Vibe Coding 的密钥管理:一个 .envrc 搞定所有 Worktree#
用 Claude Code 等 Vibe Coding 工具做开发时,经常需要同时开多个 Agent 并行工作。最常见的做法是通过 Git Worktree 为每个 Agent 创建独立的工作目录——每个 worktree 有自己的文件和分支,互不干扰。
问题在于:每个新创建的 worktree 都是一个「干净」的工作目录,项目运行所需的密钥文件(API keys、OAuth tokens、各种 credentials)都不存在。于是每次创建 worktree 之后,都得手动把 .env 或密钥文件复制过去。手动维护这些密钥会严重阻塞工作流程。
经过一番研究,发现 direnv 可以很好地解决这个问题。
direnv 如何工作#
direnv 是一个 shell 扩展,用 Go 编写,支持 bash、zsh、fish 等主流 shell。它的工作方式很简单:
- 在每次 shell prompt 刷新前,direnv 检查当前目录及 父目录 中是否存在
.envrc文件。 - 如果存在且已授权,就在一个 bash 子进程中执行
.envrc,把导出的环境变量注入当前 shell。 - 离开该目录时,自动卸载这些环境变量。
「父目录继承」这个特性正好适用于 worktree 场景:只要在 worktree 的公共父目录放一个 .envrc,所有子目录中的 worktree 都能自动获取到密钥配置。
安装和配置:
# macOS
brew install direnv
# 在 ~/.zshrc 末尾添加 hook(zsh 为例)
eval "$(direnv hook zsh)"
安装完成后重启 shell 即可。direnv 有一个安全机制:新的或修改过的 .envrc 文件需要执行 direnv allow 才能生效,防止恶意目录注入环境变量。
路径一:VS Code GitLens Worktree#
使用 VS Code 的 GitLens 插件时,通过 Create Worktree 命令可以从当前仓库创建 worktree。假设当前仓库目录是 foo,新创建的分支是 feature/bar,GitLens 会将 worktree 放在与 foo 同级的 foo.worktree/feature-bar/ 下(分支名中的 / 会被替换成 -)。
目录结构如下:
foo/ # 主仓库
foo.worktree/ # GitLens worktree 根目录
├── .envrc # ← direnv 配置,所有 worktree 自动继承
├── feature-bar/ # feature/bar 分支的 worktree
├── feature-baz/ # feature/baz 分支的 worktree
└── bugfix-123/ # bugfix/123 分支的 worktree
只需要在 foo.worktree/ 目录下创建一个 .envrc 文件:
# foo.worktree/.envrc
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
export DATABASE_URL="postgres://..."
然后授权一次:
cd foo.worktree
direnv allow
之后无论创建多少个 worktree,进入任何一个子目录时 direnv 都会自动加载这些环境变量。不需要在每个 worktree 里再复制 .env 文件。
路径二:Claude Code 的 --worktree 参数#
Claude Code 提供了内置的 worktree 支持。通过 --worktree(或 -w)参数可以直接创建一个隔离的 Git worktree 并在其中启动 Claude:
# 指定名称创建 worktree
claude -w feature-auth
# 不指定名称,自动生成随机名(如 bright-running-fox)
claude -w
Worktree 会创建在 <repo>/.claude/worktrees/<name>/ 下,分支命名为 worktree-<name>,从默认远程分支派生。退出时,如果没有任何改动,worktree 和分支会被自动清理;如果有改动或 commit,Claude 会询问是否保留。
同样的思路,在 .claude/worktrees/ 目录下放一个 .envrc:
my-project/
├── .claude/
│ └── worktrees/
│ ├── .envrc # ← direnv 配置
│ ├── feature-auth/ # claude -w feature-auth 创建
│ ├── bugfix-login/ # claude -w bugfix-login 创建
│ └── bright-running-fox/# claude -w 自动生成
├── src/
└── ...
cd .claude/worktrees
cat > .envrc << 'EOF'
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
EOF
direnv allow
之后所有通过 claude -w 创建的 worktree 都会自动继承这些环境变量。
值得一提的是,Claude Code 的 subagent 也支持 worktree 隔离——在自定义 subagent 的 frontmatter 中设置 isolation: worktree,subagent 就会在独立的 worktree 中工作,同样可以享受到 direnv 的自动加载。
关于安全性#
需要注意的是:direnv 加载的环境变量会直接出现在 shell 环境中。Agent 执行 env 或 printenv 就能看到所有密钥的值。这个方案 并不能阻止 Agent 访问密钥。
它真正解决的问题是:
- 减少文件泄露风险:密钥不以
.env文件的形式存在于每个 worktree 的项目目录中,降低了被意外git add和git commit的概率。 - 免去重复操作:不需要每次创建 worktree 后手动复制密钥文件。
- 基本的授权审查:
.envrc文件必须通过direnv allow明确授权才会生效。如果文件内容被修改,需要重新授权。
如果需要更严格的密钥隔离,应该考虑 vault 类方案或在 CI/CD 层面注入密钥,而不是依赖本地环境变量。但对于日常的 Vibe Coding 并行开发场景,direnv 在便利性和安全性之间取得了不错的平衡。
.gitignore 配置#
使用 Claude Code 的 --worktree 时,官方建议在 .gitignore 中添加:
.claude/worktrees/
这样 worktree 的内容不会出现在主仓库的 untracked files 中。.envrc 文件放在 .claude/worktrees/ 下时也会被一并忽略,不用担心密钥被提交。
对于 GitLens 的方式,foo.worktree/ 目录本身就在主仓库外面,天然不会被 Git 追踪。