From 475fcc55f307c3c5f367dfd6e9f823686772577c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ryan4yin=20=7C=20=E4=BA=8C=E8=8A=B1?= Date: Sun, 18 Oct 2026 21:41:14 +0800 Subject: [PATCH] chore(agents): use dsh-nu from NUR (#475) --- agents/global-rules.md | 28 ++++++++++------------- flake.lock | 6 ++--- home/base/tui/agents/dsh.md | 38 +++++++++++++++---------------- home/base/tui/agents/packages.nix | 2 +- 4 files changed, 34 insertions(+), 40 deletions(-) diff --git a/agents/global-rules.md b/agents/global-rules.md index 1887fe10..905be0fd 100644 --- a/agents/global-rules.md +++ b/agents/global-rules.md @@ -143,21 +143,20 @@ For an impactful change, follow these steps in order, scaled to its risk: need authorization. - Never block a turn on CI, whatever its expected duration. After a push, report the head revision and the checks that started. Start a watch on the resolved run as a background job - (`gh run watch --exit-status`, or `gh pr checks --watch` once checks exist) following - Keep every turn steerable under Communication; collect and report the result when it finishes. Do + (`gh run watch --exit-status`, or `gh pr checks --watch` once checks exist), and collect + and report the result when it finishes. Keep the turn steerable meanwhile (see Communication); do not estimate the run's duration or wait it out because it looks short. - Create forks with only the default branch (`gh repo fork --default-branch-only`); the task adds its own development branch. ## Environment and shell +- Shell syntax guidance belongs to the active shell plugin or project docs; these rules keep only + cross-agent safety and operational constraints. - NixOS is non-FHS: agents MUST NOT assume FHS paths or install imperatively (`apt`, `nix-env`, `nix profile install`, global `npm`/`pip`). Use `nix shell nixpkgs# -c ` or `nix run` for one-off tools, and the project's existing toolchain (e.g. its flake, `uv`, `pnpm`) for its dependencies; ask before creating a flake or installing another way. -- The user's interactive shell is **nushell**, and shell work defaults to Nushell. Bash is only - started from within nushell, occasionally, for tasks nushell can't do. Put shell env, aliases, and - per-session secrets in the Nushell config, not in `bashrc`/`zshrc`. - Use `gh` for authorized GitHub operations; keep SSH for GitHub Git remotes and make sure the Nix-managed `~/.ssh/config` is used. - Code layout: `~/codes` = personal, `~/work` = work code, `~/src/` = source checkouts. @@ -175,13 +174,10 @@ For an impactful change, follow these steps in order, scaled to its risk: - Prefer native tool options to reduce output at the source, and the native read, grep, glob, write, and edit tools over their shell equivalents. A single shell dispatch is for genuinely shell work (git, ssh, nix, remote commands). -- Use the shell the runtime provides, in its own dialect, and never hand a command string to another - shell (`bash -c`, `sh -c`). Default shell work to Nushell. Compose multi-step work with code-mode - (PTC) for orchestration, returned tool results, loops, and state across calls; otherwise use - Nushell's structured pipelines when available, Python for general local processing, one runtime - invocation (`python -c ''`, `nu -c ''`), or a script written with the write tool. Set - the tool's working-directory parameter instead of `cd`. A remote command usually runs under a - POSIX shell: keep it to one runtime invocation or a copied script. +- Use the shell the runtime provides; dsh-nu fails closed rather than substituting another shell. + For genuinely shell work use the available runtime, `python -c ''` for complex local + processing, or a script written with the write tool. A remote command usually runs under a POSIX + shell: keep it to one invocation or a copied script. - Commands MUST NOT block: disable pagers and interactive prompts (confirm with the user instead of making a command interactive, e.g. `rm -i`), avoid commands that wait on stdin or never exit, and bound waits and retries with a total time limit the waiting command enforces itself, not an outer @@ -192,9 +188,9 @@ For an impactful change, follow these steps in order, scaled to its risk: when it fires; any poll MUST check the condition and exit as soon as it holds. A retry or protocol backoff MAY wait at most 5 seconds per attempt, never longer and never as a progress wait. Make a readiness check fail on an error response (e.g. `curl --fail`), not only on a refused connection. -- When output is filtered or trimmed, agents MUST keep the producer's own exit status: capture - output and status together (`| complete` in Nushell, `set -o pipefail` in a POSIX shell) or in - code, and never report a successful filter as a successful command. +- When output is filtered or trimmed, agents MUST keep the producer's own exit status. Capture + output and status together with the runtime's mechanism or in code, and never report a successful + filter as a successful command. - Start servers and watchers as runtime background jobs with their output going to logs; capture the job handle or PID when starting them, never by matching `ps` output or a shell `&`. @@ -203,7 +199,7 @@ For an impactful change, follow these steps in order, scaled to its risk: - Scripts added to a project MUST follow its language and target environment, defaulting to Python unless the project ecosystem or data format has a clearer supported runtime. - Script files agents create or modify, including temporary ones, MUST pass the available checks - (e.g. `shellcheck`, `nu-check`, `py_compile`, `tsc --noEmit`); report any unavailable check. + (e.g. `py_compile`, `tsc --noEmit`); report any unavailable check. ## Communication diff --git a/flake.lock b/flake.lock index 703c7bb7..81478ae5 100644 --- a/flake.lock +++ b/flake.lock @@ -1027,11 +1027,11 @@ ] }, "locked": { - "lastModified": 1792297214, - "narHash": "sha256-zRPv4X2ywq1gcBwbI2qCS7pur7oneze2eQAUPpODlnw=", + "lastModified": 1792330633, + "narHash": "sha256-ICHmCPVtJxn5E2yNzF2+c++AajG4G4YEESxmwbjqVX4=", "owner": "ryan4yin", "repo": "nur-packages", - "rev": "1a845e77e62f8a2a1653d994e60981c0684087f2", + "rev": "b96977d219e9b2dcc30c67f89a698ea961fb68c3", "type": "github" }, "original": { diff --git a/home/base/tui/agents/dsh.md b/home/base/tui/agents/dsh.md index 09044d3a..82ca9a76 100644 --- a/home/base/tui/agents/dsh.md +++ b/home/base/tui/agents/dsh.md @@ -53,27 +53,25 @@ on, `$DSH_AGENTS_HOME/AGENTS.md` — so no patch row is needed; identical conten ## Nushell-only shell -`nur-ryan4yin`'s `dsh.withPlugins [ ...dsh-nushell-only ]` replaces the two first-party shell -providers with Nushell: every `ctx.shell` consumer (model shell tools, background jobs, hook -bridges, in-process callers) runs `nu --no-config-file -c`, and a command that hands execution to -another shell is refused before it spawns. The plugin adds Nushell rules and a syntax guide, and -rewrites the shell-tool descriptions, so the model is told what actually runs. `nu` comes from the -NUR package, so it does not depend on `PATH`. +`nur-ryan4yin`'s `dsh.withPlugins [ ...dsh-nu ]` replaces the two first-party shell providers with +Nushell: every `ctx.shell` consumer (model shell tools, background jobs, hook bridges, in-process +callers) runs `nu --no-config-file -c`, and a command that hands execution to another shell is +refused before it spawns. The plugin adds Nushell rules and a syntax guide, and rewrites the +shell-tool descriptions, so the model is told what actually runs. `nu` comes from the NUR package, +so it does not depend on `PATH`. -The source is the `develop` branch of ryan4yin's fork carrying the reviewed patch set (Nu-builtin -denial facts, test-harness fixes, the `find` hint, persistent-terminal scoping), pinned by -`fetchFromGitHub` and `hashes.json` in `nur-packages`; nix-config locks that package set in its -`flake.lock`. `dsh.withPlugins` wraps the binary: each invocation gets a generated `--patch ` -overlay after the profile layer, while `dsh plugin` stays untouched. No `$DSH_HOME/cordis.patch.yml` -is written, so there is no home-layer state to resolve or roll back. Boundaries: preset rows that -spawn a shell themselves (`custom-bash.mjs`, `persistent-shell`) bypass `ctx.shell`. So does -`@deepseek-ai/dsh-experimental-terminal-bundle`: its `terminal_*` tools use a separate -`ctx.terminals` seam and run the platform shell (bash on the POSIX hosts this repository manages), -so they coexist with this plugin but stay outside the Nushell-only guarantee — keep the bundle off -for a strict Nu-only machine (the fork's `--with-terminal-bundle` integration run covers the -coexistence). Bash hooks now run under Nushell and need rewriting; remote hosts still run their own -POSIX shell. Rollback: install plain `dsh` or pass an empty plugin list; there is no home file to -delete. Tested on Linux; the same package also builds for Darwin, where it has not been boot-tested. +The source is the `dsh-nu` GitHub release tarball, pinned by `hashes.json` in `nur-packages`; +nix-config locks that package set in its `flake.lock`. `dsh.withPlugins` wraps the binary: each +invocation gets a generated `--patch ` overlay after the profile layer, while `dsh plugin` +stays untouched. No `$DSH_HOME/cordis.patch.yml` is written, so there is no home-layer state to +resolve or roll back. Boundaries: preset rows that spawn a shell themselves (`custom-bash.mjs`, +`persistent-shell`) bypass `ctx.shell`. So does `@deepseek-ai/dsh-experimental-terminal-bundle`: its +`terminal_*` tools use a separate `ctx.terminals` seam and run the platform shell (bash on the POSIX +hosts this repository manages), so they coexist with this plugin but stay outside the Nushell-only +guarantee — keep the bundle off for a strict Nu-only machine. Bash hooks now run under Nushell and +need rewriting; remote hosts still run their own POSIX shell. Rollback: install plain `dsh` or pass +an empty plugin list; there is no home file to delete. Tested on Linux; the same package also builds +for Darwin, where it has not been boot-tested. Verify after a switch: diff --git a/home/base/tui/agents/packages.nix b/home/base/tui/agents/packages.nix index a617c44a..04aaaa15 100644 --- a/home/base/tui/agents/packages.nix +++ b/home/base/tui/agents/packages.nix @@ -16,7 +16,7 @@ in # dsh from nur-packages: llm-agents.nix's dsh cannot boot on nixpkgs node # (node-addon-require-builtin probe), this one shims it. The Nushell-only # plugin rides in through the package's withPlugins wrapper. - (myNurPkgs.dsh.withPlugins [ myNurPkgs.dsh-nushell-only ]) + (myNurPkgs.dsh.withPlugins [ myNurPkgs.dsh-nu ]) # Docs lookup CLI behind the find-docs skill (agents/skills/find-docs). The skill's flags are # written against this package, not against upstream's npx instructions.