Devcontainer 附加组件
为仓库提供一个可复现、隔离的开发容器——人、编辑器和编码代理都能使用。在 DWP v7(技能包 v7.9.0)中,这个附加组件集成了 devcontainer-kit——一个脱离 Deep Work Plan 也能使用的 MIT 产品。它是可选的:一个仓库不带它也完全符合规范。
devcontainer-kit 提供什么
- 一个模板,基于 Dev Containers 规范构建,由
dck init以固定布局渲染进仓库:.devcontainer/devcontainer.json、docker/local/<service>/Dockerfile、docker/local/docker-compose.yaml和dev.sh。之后再次运行时,它会进行协调,绝不覆盖你的修改;对既有文件的任何更改都会先展示出来,并需要你的同意。 - 仓库自己的容器。 Dockerfile 从运行时的官方镜像起步,并按摘要固定——
node-24、python-3.13或debian——再把工具包的构建步骤复制到docker/local/<service>/dck/。不涉及任何共享基础镜像。 dev.sh与dck。bash dev.sh up在普通终端中构建、启动并接入容器;shell、rebuild、doctor等其余命令有没有 VS Code 或 Cursor 都可以使用。- Herdr 双向互通。 主机上的 Herdr 通过一个仅监听回环地址的 SSH 服务器,把每个容器作为一台机器接入;容器打开时带有标准侧栏:App、Editor、Development 和 Agents。每个工作区和窗格(包括之后新打开的)都从应用路径(默认为
/app)启动。在容器内部,herdr-peers 让代理可以向主机上以及其他容器中的代理提问。 dck-dockerfile技能。 代理可按需创建或重新生成仓库的容器,并通过一次真实构建加以验证。
安装
git clone --branch v1.1.1 https://github.com/DailybotHQ/devcontainer-kit && ./devcontainer-kit/install.sh
cd your-repo && dck init && bash dev.sh up
要求:Linux 或 macOS 主机上的 bash 3.2 或更新版本和 python3 3.11 或更新版本,以及用于容器命令的 Docker 与 Compose v2。可使用发布版本的 SHA256SUMS 资产对其进行校验。请固定 v1.1.1:v0.2.0 不受支持。
| 项目 | 值 |
|---|---|
| 产品 | DailybotHQ/devcontainer-kit,标签 v1.1.1,接口 2 |
| 注册表键 | .dwp/config.json 中的 devcontainer |
| 每仓库配置 | .devcontainer/dck.toml |
| 检测 | dck doctor --json |
自 v1.0.0 起稳定。 公共接口遵循语义化版本,仅在新的主版本中才会发生不兼容变更(对于文件而言,还会提升接口编号):dck 动词及其文档化的参数和退出码(0 成功、1 失败、2 用法错误、3 配置错误、4 环境错误、5 已拒绝),dck.toml、主机配置文件和 dck doctor --json 的模式(接口 2),以及渲染契约——dck init 写入并拥有的文件、它所保留的 dck:managed 标记和用户块,以及入口点读取的环境。从 v0.3.7 升级不会破坏任何内容:运行 dck init 和 dck rebuild,让镜像带上新的固定版本(herdr-peers v1.1.0、coding-agents-kit v1.1.0 和 DeepWorkPlan Vim v1.0.1)。
层
每个容器都携带开发工具——git、gh、ripgrep、一个 SSH 服务器、Herdr 和 herdr-peers——除非你选择启用主机账户,否则不含任何机密。其余部分都是你在 dck.toml 中选择的层:
| 层 | 默认 | 添加内容 |
|---|---|---|
agents |
关闭 | 来自已校验发布版本的 coding-agents-kit 以及你列出的 CLI,每个 CLI 都有自己的持久卷,另含 classic(claudex、codexx、…)和 providers(claude-glm、codex-azure、…)预设。代理默认以自主模式运行——容器本身就是沙箱。退出方式:在服务的 .env 中设置 AGENTKIT_PERMISSIONS=ask。 |
editor |
开启 | 带按标签固定的 DeepWorkPlan Vim 的 Neovim;关闭时提供一个普通编辑器。 |
dailybot |
关闭 | Dailybot CLI,供 dailybot 附加组件使用。 |
登录状态、gh、Herdr 配置和 git 身份在 bash dev.sh rebuild 之后依然保留。启用 agents 层时,镜像还携带 coding-agents-kit 的三个技能(agentkit、agentkit-setup、agentkit-orchestrate),每次启动时都会链接到每个代理的技能目录中,因此重新创建的容器仍会保留它们。
状态卷(SSH 主机密钥、~/.ssh、gh 登录、Herdr 客户端状态、历史记录)名为 state。当多个服务共享同一个 compose 项目时,请在 dck.toml 中用 [compose] state_volume(或 dck init --state-volume NAME)为每个服务指定各自的名称;否则它们都会挂载同一个卷,dck doctor 会指出这一点。
跨机器的代理
自 v0.2.3 起,在 Docker Desktop 上,dck up 无需任何手动步骤即可连通一个双向网格:
- 容器与主机。 容器内的代理可以访问主机上、其他每个 dck 容器中以及主机 Herdr 已管理的其他 loopback 容器中的 Herdr 代理,这些代理也能反向访问。每个对等方都带有固定的主机密钥;不会在首次使用时信任任何对象。
- 可选的主机监听器。
dck setup会一次性提供一个位于127.0.0.1的用户级 SSH 服务器,它只接受 dck 密钥,并由 launchd(macOS)保持运行。如果你已经在运行一个 loopback 监听器,可改为让主机配置文件指向它。dck host listener disable会将其移除。 - 重建后依然保留。 容器的 Herdr 机器目录存放在卷中,因此
bash dev.sh rebuild会保留其中注册的每台机器。自v0.3.2起,rebuild、start和restart执行与up相同的步骤:容器重新注册到主机的 Herdr,其主机密钥重新固定,网格重新推送,因此从零构建的容器能立即访问主机及其对等方。 - 容器内的 Codex 窗格。 Codex 代理需要
HERDR_PEERS_SELF(即主机上保存的该容器的机器 id)才能询问其他机器上的对等方。自v0.3.3起,工具包会在每次注册时记录该 id,并由容器的登录 shell 导出它,因此任何代理都无需手动设置;dck doctor会标记不一致。自v0.3.4起,容器自己的 Codex 配置会跳过 Codex 的启动更新检查及其后台守护进程(工具包固定了每个 CLI 的版本),绝不触碰你主机上的 Codex home 或共享的配置档。 - 主机同样可以回复。
dck setup会在主机上安装经过校验的 herdr-peers,因此dck agents和dck ask在主机上同样可用,主机上的代理通过herdr-peers reply回复。 - 非工具包创建的容器。 在主机配置文件的
[ssh] authorized_extra下列出它们登录所用的公钥,它们也就能访问 dck 容器。
在主机和容器中都搭配 coding-agents-kit 使用,同一个 ak 即可在两侧启动代理。
容器内的主机账户
容器可以使用你在主机上已有的账户,就像 git 已经通过主机的 SSH agent 工作一样,容器内无需登录。该功能需主动启用,配置位于你的主机配置文件中,绝不在仓库的 dck.toml 中:
[agents]
host_profiles = true # 默认 false
host_env_keys = ["ZAI_CODING_API_KEY"] # 允许共享的环境变量名称列表
开启 host_profiles 后,dck up 只共享仓库所安装 CLI 的配置档:
- Claude Code:每个配置档通过一个长期令牌共享——
@default使用CLAUDE_CODE_OAUTH_TOKEN,@name使用CLAUDE_CODE_OAUTH_TOKEN_<SUFFIX>(后缀转为大写,A-Z、0-9和_以外的任何字符都替换为_)。 - Codex:通过其认证文件共享,适用于
@default和每个配置档。 - 工具包的 env 文件:只读,并精简为
host_env_keys中列出的名称。
整个 agentkit home 从不挂载,包含主机绝对路径的配置档会被跳过。以读写方式共享的 Codex 登录可能被两个写入者同时刷新:每个 Codex 账户只保留一个活动代理。主机配置文件中的 [agents] default_profile(例如 { claude = "@work3" })会让容器内不带参数的 ak claude 使用该共享账户(coding-agents-kit ≥ v0.5.2);macOS 上的 @default Claude 登录存放在钥匙串(Keychain)中,无法共享。自 v0.3.4 起,容器的 shell 还会把不带参数的 claude 或 codex 指向该账户,因此 Herdr 恢复的窗格会直接在该账户上打开,而不是显示登录界面。在容器内,同样的 ak <kind> @<profile> 与在主机上一样使用同一个账户运行,这使主导者能够把 ak pick 选出的账户交给容器中的通道——参见运行多个代理。
多个仓库,一个 compose 栈
自 v0.3.3 起,如果一个仓库的服务只是更大 compose 项目的一部分(API、Web 应用、worker 和数据库共享同一个项目),它无需手动编辑 dck 渲染的内容即可加入该项目。所有设置都是增量的:未设置这些键的仓库,渲染结果与以前完全相同。
- 一个项目,每个服务一个状态卷。
[compose] project在每个仓库中指定共享的项目名称;state_volume、[compose] networks和[compose] volumes让各服务的状态以及栈的数据卷和网络彼此分开。 - 用户块。 dck 服务内位于
# >>> user:<service> >>>与# <<< user:<service> <<<之间的行会被原样保留:dck 不渲染的内容(depends_on、healthcheck)使用普通键,dck 会渲染的键使用x-dck-merge:。只包含部分 dck 标记的文件会被拒绝并给出修复方法,而不会被重写。 - 端口字符串。
ssh_port和ports接受 compose 表达式,例如"${API_PORT:-8000}:8000";除非字符串指定了主机 IP,否则它们保持在127.0.0.1上。 - 共享构建与自有启动脚本。
[build] context和[build] dockerfile适用于多个服务共享的 Dockerfile;dev_sh = false会保留仓库自己的dev.sh。 - 工作区卫星实例。 自
v0.3.5起,服务的第二个实例在其自己的 compose 项目中通过 dck 启动和停止(dck --project P --compose-file F --service S up或down),因此它获得与主实例相同的主机密钥、账户、git 身份和 Herdr 机器;up --seed-state-from VOLUME只把登录信息复制到它空的状态卷中。在覆盖(overlay)文件中,extends必须指明它所扩展的文件。 - 供代理使用的 Node。 代理自己的 Node 位于
/opt/dck/node下,绝不替换镜像中的 Node;当仓库的工具链需要时,[agents] node_first = true会把它放在 PATH 的最前面。
容器内的主机 SSH 密钥
有些工具只读取密钥文件而忽略转发的 agent:例如 gh auth login 会提议生成一个新密钥。自 v0.3.2 起,你可以选择启用,且只能在你的主机配置文件中启用(仓库的 dck.toml 无法设置它;dck setup 会询问一次,默认否):
[ssh]
copy_keys = true # default false
启用期间,dck up 会把主机的 ~/.ssh 以只读方式绑定到 ~/.ssh_host,每次启动都会把其中的 id_* 密钥复制到容器的 ~/.ssh 中(私钥权限为 0600),并与主机保持同步。agent 转发保持不变;关闭该选项后,副本会在下次启动时被移除。代价是:整个主机 ~/.ssh 在容器内可读,私钥存放在状态卷中。
安全默认值
- 每个发布的端口都绑定到
127.0.0.1,除非dck.toml设置了bind。 - 通过 SSH 使用 git 时经由主机的 SSH agent——使用其 socket,绝不使用密钥文件,也绝不挂载
~/.ssh或~/.gitconfig,除非你在主机配置文件中启用了copy_keys。git 身份来自dck setup填写的DCK_GIT_*值。 - SSH 主机密钥在运行时生成到每个项目独立的卷中,绝不内置于镜像;服务器只接受公钥,不允许 root 登录,也不使用密码。
- 模板不添加
cap_add、不使用privileged模式,也不挂载 Docker socket。 - 每次下载都按版本固定并经校验和验证;基础镜像按摘要固定。
- 让一个容器中的代理访问其他容器的 Herdr 网格默认开启,其关闭开关记录在工具包的威胁模型中。主机监听器允许运行中容器内的代码以你的身份在主机上打开 shell:它需要主动启用,仅限 loopback,只接受 dck 密钥,并可通过
dck host listener disable移除。
备注
可选且绝非必需。一个仓库在不带任何可选附加组件时即完全符合规范。支持 Linux 和 macOS 主机;容器之间的网格需要 Docker Desktop。