Skip to content

Commands

cross.stream commands use Nushell expressions to define reusable operations that can be called on-demand with arguments. Unlike handlers which maintain state between invocations, or generators which run continuously, commands are stateless and execute independently each time they are called.

Defining Commands

To create a command, append a definition string with the topic <command-name>.define:

Terminal window
r#'{
# Required: Command closure
run: {|frame|
# frame.topic - always <command>.call
# frame.hash - contains input content if present
# frame.meta.args - contains call arguments
let input = if ($frame.hash != null) { .cas $frame.hash } else { null }
let n = $frame.meta.args.n
1..($n) | each {$"($in): ($input)"}
}
# Optional: Module definitions
modules: {
"my-util": "export def format [x] { $\"formatted: ($x)\" }"
}
# Optional: Control output frame behavior
return_options: {
suffix: ".output" # Output topic suffix (default: ".recv")
ttl: "head:1" # Keep only most recent frame
}
}'# | .append repeat.define

The command definition requires:

  • run: A closure that receives the call frame and can return a pipeline of results

Each value in the closure’s output pipeline becomes a .recv event automatically.

Calling Commands

Commands are called by appending to <command-name>.call with input content and arguments:

Terminal window
# Call the repeat command with input and args
"foo" | .append repeat.call --meta {args: {n: 3}}

Lifecycle Events

Commands emit events to track their execution:

EventDescription
<command>.recvOutput value from the command’s pipeline
<command>.completeCommand execution finished successfully
<command>.errorError occurred during command execution

All events include:

  • command_id: ID of the command definition
  • frame_id: ID of this specific invocation

Error Handling

If a command encounters an error during execution, it will:

  1. Emit a <command>.error frame with:
    • The error message
    • Reference to both command_id and frame_id
  2. Stop processing the current invocation

Unlike generators, commands do not automatically restart on error - each invocation is independent.

Modules

Commands can use custom Nushell modules:

Terminal window
r#'{
run: {|frame|
my-math double (frame.meta.args.number)
}
modules: {
"my-math": "export def double [x] { $x * 2 }"
}
}'# | .append calculator.define

This allows you to modularize your commands and reuse code across different commands.

Key Differences

FeatureCommandsHandlersGenerators
StateStatelessStateful between callsStateless
ExecutionOn-demandEvent-drivenContinuous
ResultsStreamed immediatelyBatched on completionStreamed
ParallelismMultiple parallel callsSequential processingSingle instance
Error HandlingPer-invocationUnregisters handlerAuto-restarts
ModulesSupportedSupportedNot supported