AgentSkillsCN

nushell-style

在编辑、编写或审查任何 .nu 文件时加载此技能。提供符合 Nushell 语言习惯的模式、管道组合、命令选项以及格式化规范。

SKILL.md
--- frontmatter
name: nushell-style
description: Load this skill when editing, writing, or reviewing any .nu file. Provides idiomatic Nushell patterns, pipeline composition, command choices, and formatting conventions.

Nushell Code Style Guide

Contents

FileTopic
This fileQuick reference tables, do/don't checklists
patterns.mdPipeline composition, command examples, code structure
formatting.mdTopiary conventions, spacing, declarations
debugging.md--ide-check for agents, diagnostic parsing
nuon.mdNUON format, data serialization, config files
testing.mdnutest framework, snapshots, coverage
toolkit.mdtoolkit.nu, repo utilities, commit conventions

Agent Tip: Syntax Checking

bash
nu --ide-check 10 file.nu | nu --stdin -c 'lines | each { from json } | where type == "diagnostic" | to json --raw'

Runs from bash (as agents do). --stdin is required for the second nu to read piped input. See debugging.md for parsing diagnostics inside nushell.


Conciseness for Advanced Users

Write code that an experienced nushell user can quickly apprehend. Leverage implicit features:

VerboseConciseWhy
update field {|row| $row.field | str upcase}update field { str upcase }Closure receives field value directly
each {|x| $x | str trim}each { str trim }$in implicit, pipeline flows
where {|row| $row.status == "active"}where status == "active"where has field shorthand
$data | each { $in | process }$data | each { process }$in passed automatically to first command

Principle: If an advanced user knows how update, each, where work, they shouldn't need to parse redundant variable declarations.


Command Choices

TaskPreferredAvoid
Filteringwherefilter, each {if} | compact
List filteringwhere $it =~ ...where { $in =~ ... }
Parallel with orderpar-each --keep-orderpar-each (when order matters)
Pattern dispatchmatch expressionLong if/else if chains
Record iterationitems {|k v| ...}Manual key extraction
Table groupinggroup-by ... --to-tableManual grouping
Line joiningstr join (char nl)to text (context dependent)
Syntax check (human)nu -c 'open file.nu | nu-check'source file.nu
Syntax check (agent)nu --ide-check 10 file.nunu-check (unstructured)
Membershipin operatorMultiple or conditions
Field extractionget --optionaleach {$in.field?} | compact
Negation$x !~ ...not ($x =~ ...)

Pipeline Principles

Leading |

Place | at start of continuation lines, aligned with let.

Omit $in |

When body starts with pipeline command (each, where, select), input flows automatically.

Empty { } Pass-Through

Use empty { } for the branch that should pass through unchanged:

  • | if $cond { transform } else { } — transform when true, pass through when false
  • | if $cond { } else { transform } — pass through when true, transform when false

Stateful Transforms

Use scan for sequences with state: use std/iter scan

→ See patterns.md for detailed examples.


Script CLI Pattern

For toolkit-style scripts with subcommands (like nu toolkit.nu test):

nushell
# toolkit.nu
export def main [] { }  # Entry point (required, even if empty)

export def 'main test' [--json] {
    # nu toolkit.nu test
}

export def 'main build' [] {
    # nu toolkit.nu build
}

Key points:

  • def main [] — entry point when running nu script.nu
  • def 'main subcommand' [] — defines nu script.nu subcommand
  • Must define main for subcommands to be accessible
  • Use export def if script is also used as a module

Execution differs between script mode and module mode:

bash
# Script mode: `main` is stripped, subcommands are top-level
nu toolkit.nu           # runs main
nu toolkit.nu test      # runs 'main test'
nu toolkit.nu test --json  # with flags
nushell
# Module mode: `main` stays in the command name
use toolkit.nu
toolkit                 # runs main
toolkit main test       # runs 'main test' — note `main` is required
toolkit main test --json

→ See Nushell Scripts docs


Quick Reference

Do

  • Omit $in | when command body starts with pipeline command
  • Start continuation lines with |
  • Use empty else { } for pass-through
  • Use match for type dispatch
  • Use in for membership testing
  • Use get --optional for field extraction
  • Use scan for stateful transforms
  • Use where for filtering
  • Use where $it =~ ... for list filtering
  • Combine consecutive each closures when operations can be piped
  • Define data first, then filter
  • Include type signatures: ]: input -> output {
  • Use @example attributes (nutest)
  • Use const for static data
  • Keep custom commands focused
  • Export ALL commands from implementation files (enables testing helpers)
  • Control public API via mod.nu re-exports (not by removing exports)
  • Use par-each --keep-order for parallel with deterministic output

Don't

  • Start command bodies with $in | when a pipeline command follows
  • Use spread operator ... with conditionals (use data-first + where)
  • Wrap external commands in unnecessary parentheses
  • Over-extract helpers for one-time use
  • Create wrapper commands that just call an existing command
  • Use verbose names for local variables
  • Break the pipeline flow unnecessarily
  • Remove existing comments (preserve user's context)
  • Remove export from helpers to "make them private" (use mod.nu instead)

Formatting Summary

  • Run topiary format <file> when available — it is the canonical formatter
  • Empty blocks: { } with space
  • Closures: { expr } with spaces
  • Flags: --flag (-f) with space
  • Records: multi-line, no trailing comma
  • Variables: let x = (no $ on left)

→ See formatting.md for full conventions.