前言¶
在 DeepSeek Harness(DSH)里,Agent 通过 bash 工具改代码、跑构建。若项目用 Nix flake 定义 devShell,工具链和依赖都在 /nix/store 里;而 Harness 默认在宿主 shell 里执行命令,容易出现「本机没装 dune / ocaml」「PATH 不对」这类问题。手工每条命令前加 nix develop --command 不现实,模型也未必知道当前该不该用 Nix 环境。
下面介绍社区插件 dsh-nix-dev-shell(维护者 running-grass,分类:工作流):当命令工作目录或其上级目录存在 flake.nix 时,自动把 bash 放进该 flake 的 devShell,且不替换 DSH 自带的 shell 执行器,沙箱、超时、后台任务等行为保持不变。
这是什么¶
dsh-nix-dev-shell 是 Host 侧 JS 插件(MIT,当前 package 版本 0.3.0,需 Node ≥ 20)。它修饰 Harness 的 ctx.shell.execute,在 dsh-bash-* 执行器之上做一层装饰,而不是换掉执行器本身。
定位一句话:工作区有 flake 时,让 DSH 的 bash 命令等价于在 nix develop 环境里跑;没有 flake、没有 nix、或捕获失败时,原样退回原生 bash 并打日志告警。
- 目录页:https://www.skillhub.cn/plugins/running-grass/dsh-nix-dev-shell
- 源码:https://github.com/running-grass/dsh-nix-dev-shell
核心功能¶
祖先目录查找 flake¶
按 spec.workdir 向上查找 flake.nix(默认文件名可配置,最多向上 40 层),行为类似 direnv 的祖先查找。命中后对该 flake 目录的 devShell 生效;未命中则不注入任何东西。
两种运行模式¶
env(默认):对 flake 目录一次性运行nix print-dev-env(含 shellHook),与当前进程环境做差集后缓存,注入到每次 spawn 进程的env。后续每条命令没有 nix 启动开销,shellHook 的标准输出也不会混进工具结果。wrap:把命令改写成nix develop <flakeDir> --command bash -c '…',语义与手工nix develop一致,但每条命令多一次 nix 求值(README 称约 0.3–1s),且 shellHook 输出会出现在结果里。
与 Harness 其它能力的关系¶
因为始终调用原执行器,以下不受影响:文件沙箱(workspace-write / read-only / danger-full-access)与提权审批;超时、onExpiry、abort、输出截断;后台任务与 run_in_background;DSH_* 等受管环境变量(由 ctx.shellEnv 收集,优先级最高)。捕获 devShell 时通过未修饰的原执行器跑 helper,沙箱策略与调用方相同,不会额外提权。
沙箱内的 Nix 缓存¶
workspace-write 沙箱下 ~/.cache 只读,直接跑 nix develop 等会报 fetcher cache 无法打开。插件在 flake 工作区内、且命令受沙箱约束时,可注入 NIX_CACHE_HOME(默认相对 flake 根为 .dsh-plugins/.cache/nix),只影响 nix,不整体改 XDG_CACHE_HOME。danger-full-access 下不自动注入。
告诉模型「已在 devShell 里」¶
可选地向系统提示词贡献一句正面陈述(promptContext,默认开启):说明 bash 在指定 flake 的 nix develop 环境里,IN_NIX_SHELL=impure、工具来自 /nix/store。仅在已成功捕获 devShell 且 cwd 在 flake 子树内才出现;agent/created 时可预捕获(最多约 2.5s),便于首条系统提示词即准确。
缓存与失效¶
每个 flake 目录的戳记由 flake.nix、flake.lock 及目录三层内 *.nix(有界扫描)的 mtime/size 组成;捕获失败在 retryMs 内负缓存。刷新失败时优先复用上次成功捕获的环境,从未成功过才回退原生 shell。
安装与启用¶
官方安装命令(来自 README):
dsh plugin --profile web add github:running-grass/dsh-nix-dev-shell
Host 插件是 JS 模块,安装或更新后需要重启 DSH 进程才会加载新代码。
开发时也可在会话里通过 plugin_manager 从本地目录安装:
{ "action": "install_bundle", "target": "/abs/path/to/dsh-nix-dev-shell" }
安装后执行 plugin_manager list_plugins,应看到 include:nix-dev-shell 且 fiberPhase=active。
验证与典型用法¶
装好后,在含 flake.nix 的目录或其子目录执行:
echo $IN_NIX_SHELL # impure
command -v ocaml dune # /nix/store/…(宿主机上没有它们)
echo $NIX_CACHE_HOME # 沙箱可写的 nix 缓存目录
在不含 flake 的目录(例如 $HOME)应保持原生环境,插件不会注入。
常用配置项在 cordis.patch.yml 中已有默认值,可在行内 config 调整,例如:
| 键 | 默认 | 说明 |
|---|---|---|
enabled |
true |
总开关 |
mode |
'env' |
'env' 注入环境 / 'wrap' 走 nix develop --command |
flakeFile |
'flake.nix' |
向上查找的文件名 |
maxAncestors |
40 |
最多向上查找层数 |
injectCacheHome |
true |
沙箱内是否注入 NIX_CACHE_HOME |
promptContext |
true |
是否向系统提示词说明 devShell 已生效 |
prefetch |
true |
agent/created 时预捕获 devShell |
完整表格与 captureTimeoutMs、ttlMs、cacheDir、nixCommand 等见仓库 README。
卸载示例:
{ "action": "remove_bundle", "target": "dsh-nix-dev-shell" }
适用场景与注意¶
适合谁:用 Nix flake 管理 devShell 的仓库,在 DSH 里希望 Agent 的 bash 自动带上 flake 里的编译器、包管理器和 shellHook 导出的变量,又不想改每条命令或换执行器。
安全与边界:
- 祖先查找意味着:若
$HOME或上层目录有flake.nix,其子树内每条 bash 都会进该 devShell,第三方仓库首次命令也会跑其shellHook。只在可信仓库启用,或设enabled: false、调小maxAncestors。 - 只覆盖
ctx.shell(bash 工具、子代理、hooks、后台任务);PTY / tmux 不在范围内。 env模式不传 shell 函数、别名;与「替换ctx.shell服务」的插件不兼容。- 插件以当前 DSH 进程权限运行;安装前请阅读源码与 MIT 许可证,自行评估是否纳入工作流。
DSH 生态是「一切皆插件」;SkillHub 等社区目录为独立站点,与 DeepSeek / 幻方无官方从属关系。
结尾¶
dsh-nix-dev-shell 把「工作区有 flake 就用 devShell」做成透明装饰层:默认 env 模式低开销注入,沙箱下配合 NIX_CACHE_HOME,并可选告知模型当前环境。需要完整配置、性能实测与安全说明时,以 GitHub README 为准。