A plugin that helps Claude write Nushell (nu) code idiomatically.
# 1. Ensure your Nushell version is compatible
version | get version # >= 0.114.0
# 2. Add the plugin marketplace
claude plugin marketplace add zaynram/code-marketplace
# 3. Install the `nu-fluency` plugin
claude plugin install nu-fluency@ramda-code-marketplaceWhen first introducing Claude to nu, we both agreed that it seemed like an
LLM's optimal shell; it's natural language semantics and first-class support
for structured data bridges the gap between human and machine readable data.
This insight led to the construction of my
nushell-mcp.
After testing out the MCP with Claude, he would often treat it as "bash with
weird syntax", which we hypothesize is the result of POSIX convention being
over-represented in his training distribution.
This highlighted a need to teach Claude about Nushell and its
built-in primitives, as the default behavior of reaching for bash patterns
bottlenecked the advantages of nu semantics and structured-data support.
This plugin counteracts that bias by combining authoritative tooling (nu-lint)
with educational scaffolding.
This plugin uses the nushell-mcp server, automatically installed
from its NPM package listing.
It provides a curated set of nu utilities to Claude including but not limited
to: nu_exec (one-shot nu pipeline execution) and nu_repl (persistent nu
REPL sessions piggybacking off of Nushell's built-in nu --mcp).
The commands packaged in this plugin prefer to delegate diagnostics to nu-lint.
nu-lint is a deterministic community linter for Nushell with ~150 rules across
idioms, posix-replacement, parsing, dead-code, runtime-errors, and more.
Most rules have auto-fixes, and the rules themselves respect the nuance of diverging from the status quo in the age of LLM.
# `--git <url>` - Build from latest source code
# `--locked` - Pins the lockfile's dependency versions.
cargo install --git https://codeberg.org/wvhulle/nu-lint --lockedThe hook system is inert by default, and will not warn or error when nu-lint is
unavailable. The only downside is losing out on deterministic diagnostics.
The plugin declares an LSP configuration with Nushell's built-in language server.
After plugin installation and the language server connects, Claude sees inline diagnostics, hover info, and auto-fixes any time it edits a Nushell file.
| Type | Count | Purpose |
|---|---|---|
| Skills | 10 | /nushell-{idioms,records,env-scoping,strings,control-flow,modules}, /inspect-shape, /env-snapshot, /audit-pipeline, /command-help |
| Agents | 1 | Fallback review agent for /audit-pipeline when nu-lint isn't installed (experimental) |
| Hooks | 1 | Post-nu_exec hook that runs nu-lint on the executed pipeline |
| LSP | 1 | nu --lsp via lspServers in .claude-plugin/plugin.json |
| Configs | 2 | configs/hook.nu-lint.toml, configs/strict.nu-lint.toml |
/nushell-idioms— (entry point) deep syntax lookup reference (cheat-sheet.md),bash→nuequivalents, pointers to nu-lint./inspect-shape <expr>— runs<expr> | describe+ a sample row throughnu_exec. Structural intuition./env-snapshot [keys...]—$env | select --optional <keys>with sensible defaults./audit-pipeline <pipeline>— runs nu-lint (or falls back to the experimental agent if nu-lint isn't installed)./command-help <name>— inline help lookup vianu_doc_help.
nushell-records— records, tables, cell paths,items | where | into record.nushell-env-scoping—$env,do --env,with-env,forvseachpropagation, automatic env vars.nushell-strings—parsetemplates,strnamespace, interpolation,from <format>.nushell-control-flow—for/each/reduce/any/all/take while, conditionals,try/catchvs?.nushell-modules—module/use/export def/export-env/main.
Post-tool-use hook on MCP nu_exec calls.
Reads the tool's pipeline argument from stdin (JSON),
pipes it through nu-lint --stdin --format compact using the narrow
configs/hook.nu-lint.toml, and surfaces findings as a block reason iff
there are diagnostics surfaced.
The hook config is intentionally conservative
— posix, idioms, parsing groups only
— so it fires on bash-translation patterns and skips stylistic noise.
For broader analysis, use /audit-pipeline
(which uses the strict.nu-lint.toml config).
The hook + nu-lint catches most of these mechanically, but for completeness they are also enumerated here.
- When a
letchain forms, ask whether each step is carrying state or expressing a transform. Transforms collapse into pipeline stages. - Records are nu's primary data structure.
- Env mutations propagate through keyword blocks
(e.g.
for/while/loop,match,if/else if/else), and certain commands with flags (i.e.collect --keep-env, anddo --env). The closures used ineach/items/reduceand baredo/collectdo not propagate environment mutations. - Optional access (
<cell-path>?) postfix on cell paths returnsnull. Prefer it overtry/catchfor safe property/nested property access without errors. - NUON string quoting is context-dependent.
Assert via in-
nuequality checks, not raw NUON comparison. - The last expression in a closure or pipeline is its return value, akin to
rust. Don'tprintwhat you're returning.
MIT.