dsh-nix-dev-shell:让 DSH 的 bash 自动进入工作区 Nix devShell

前言

在 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 并打日志告警。

核心功能

祖先目录查找 flake

按 spec.workdir 向上查找 flake.nix(默认文件名可配置,最多向上 40 层),行为类似 direnv 的祖先查找。命中后对该 flake 目录的 devShell 生效;未命中则不注入任何东西。

两种运行模式

  1. env(默认):对 flake 目录一次性运行 nix print-dev-env(含 shellHook),与当前进程环境做差集后缓存,注入到每次 spawn 进程的 env。后续每条命令没有 nix 启动开销,shellHook 的标准输出也不会混进工具结果。
  2. 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 为准。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜