Nushell
Bash gets pipelines; Nushell gets pipelines and structure. A generated module wraps every operation so tensors come from and return to native Nushell values — no JSON wrangling.
Setup
After installing with Homebrew, tell Nushell where to find the installed module. This setup also works in ahsh; edit the configuration file that the shell loads. Find its location by running:
$nu.config-path
Open that config.nu in your editor. Add '/opt/homebrew/share/nutorch' to
its existing $env.NU_LIB_DIRS list. Preserve your other entries; this is a
full example, not an instruction to replace your entire configuration:
$env.NU_LIB_DIRS = [
($nu.default-config-dir | path join 'scripts')
($nu.data-dir | path join 'completions')
'/opt/homebrew/share/nutorch'
]
/opt/homebrew is the standard Apple-silicon Homebrew prefix. For a custom
installation, run brew --prefix and use that path followed by
/share/nutorch. Make sure a later NU_LIB_DIRS assignment does not overwrite
your addition. Keeping env.nu empty is fine for this interactive
configuration.
This adds a module search directory, not an automatic import. Reopen your shell, then explicitly load the module and try a matrix multiplication:
use nutorch.nu *
nutorch --version
let t = ([[1 2] [3 4]] | torch tensor)
$t | torch mm $t | torch value
The result is a native nested list with rows [7 10] and [15 22]. The version
command reports your installed package version.
Standalone scripts do not generally load config.nu. For those, explicitly
configure their module search path or import the installed module by full path;
do not assume this interactive setup is loaded in every script process.
A current copy of nutorch.nu also ships in the public source repo root;
regenerate it any time with:
torch nu-module | save -f nutorch.nu
Structured data in and out
let t = ([[1 2] [3 4]] | torch tensor)
$t | torch mm $t | torch value # a native table
torch tensors | where bytes > 1_000_000 | get handle | each {|h| torch free $h }
Wrappers honor the dual input pattern — pipe the leftmost tensor in as $in, or
pass handles as arguments and the CLI’s grammar fills the missing slots — and
every one of the 185 ops is wrapped, plus the registry and daemon verbs.
Non-finite values cross the boundary as REAL Nushell NaN/infinity floats; the
JSON dialect ("NaN", "Infinity", "-Infinity") is handled for you in both
directions.
Use ^torch when you explicitly want the external CLI’s raw text or JSON output
instead of the structured Nushell wrapper result. The old nutorch <op>
namespace remains as a compatibility alias for existing scripts.
Training, natively
The regression from neural networks, as Nushell:
use nutorch.nu *
torch manual_seed 42 | ignore
let x = ([[0.0] [1.0] [2.0] [3.0]] | torch tensor)
let y = ([[1.0] [3.0] [5.0] [7.0]] | torch tensor)
let model = (torch nn linear 1 1)
let opt = (torch nn sgd $model --lr 0.05)
for i in 1..200 {
let loss = ($x | torch forward $model | torch mse_loss $y)
$loss | torch backward
$opt | torch step
torch nn zero_grad $opt | ignore
}
The full script (with assertions) is scripts/train-regression.nu in the repo —
it converges to the same losses as its zsh twin.
Plain JSON everywhere else
The structured verbs also serve any other tool via --json:
torch tensors --json
torch ops --json
torch daemon status --json
torch nn info $m --json