Process Effects and Pipelines
On this page
Process execution is also exposed as the Proc effect. Production code can
perform commands while tests install a handler that returns deterministic
Output values without launching anything.
Mocks a deployment and intercepts a plain run() call through the nearest
Proc::run handler.
// Feature: process execution as the `Proc` effect — testable, sandboxable.
// Syntax: `Cmd.run()` and `perform Proc::run(cmd)` are ONE semantics with
// two facades. When a `Proc::run` handler is installed (handle ... with),
// every run() routes through it — mock a whole deploy without launching a
// single binary. Without a handler, run() executes directly.
// When to use: unit tests of scripts; later, sandbox policies and replay.
use std::cmd
// Production shape — the effect is explicit in the signature:
fn deploy() with Proc -> Result<str, CmdError> {
let head = perform Proc::run(sh"git rev-parse --short HEAD")?
let rev = head.stdout.trim()
perform Proc::run(sh"docker build -t app:{rev} .")?
perform Proc::run(sh"docker push app:{rev}")?
return Result.Ok(rev)
}
// Test shape — mock EVERY command; nothing real runs:
let result = handle deploy() with {
Proc::run(c) => Result.Ok(Output { stdout: "deadbeef\n", stderr: "", status: 0 }),
}
print("mocked deploy: {result}")
// Interception also works WITHOUT effect annotations — plain run() calls
// route through the nearest installed handler:
fn status() -> Result<Output, CmdError> {
return sh"git status --short".run()
}
let mocked = handle status() with {
Proc::run(c) => Result.Ok(Output { stdout: "M src/main.zolo", stderr: "", status: 0 }),
}
print("intercepted run(): {mocked.unwrap().stdout}")
// Outside any handler, the same code executes for real:
print("direct run: {status().is_ok()}")
Requires the Zolo CLI/host — open in the playground or run locally.
For system inspection, ps() returns structured ProcInfo values. Ordinary
array functions replace text parsing with typed filtering and sorting.
Filters and sorts process records, then prints selected fields as a table.
// Feature: structured pipelines — system data as typed values (Nushell-style).
// Syntax: `ps()` returns [ProcInfo] (pid/name/cpu/mem), not text. Compose
// with the pipe-flavored free functions and finish with `print_table`.
// Naming vs Bash: no awk, no cut, no locale-dependent column parsing.
// (`where` is a Zolo keyword and `table` is the Lua table module, so the
// stages ship as `filter` and `print_table`.)
let top = ps()
|> filter(|p| p.mem > 0)
|> sort_by(|p| p.mem)
|> first(5)
print("5 processes, ascending by memory:")
print_table(top, ["pid", "name", "cpu", "mem"])
// The method forms exist on arrays too — same data, no pipes:
let heavy = ps().filter(|p| p.mem > 0).sort_by(|p| p.mem)
print("total processes with memory: {heavy.len() > 0}")
Requires the Zolo CLI/host — open in the playground or run locally.
Use pipe_to when stdout from one process must become stdin for the next.
Unlike |>, this builds an operating-system process pipeline.
Connects two Git commands with a real pipe, then resumes value processing with
|>.
// Feature: .pipe_to() — a REAL process pipe (stdout → stdin, one shared fd).
// Syntax: `sh"a".pipe_to(sh"b")` builds a multi-stage Cmd; stages run in
// parallel at the OS level, exactly like `a | b` in a shell.
// Why a method and not `|`: bare `|` is already bitwise-or AND the lambda
// delimiter — and `|>` pipes VALUES, while .pipe_to pipes PROCESSES.
// git version | git hash-object --stdin → hash of the version string
let out = sh"git version"
.pipe_to(sh"git hash-object --stdin")
.run()
match out {
Result::Ok(o) => print("pipeline hash: {o.stdout.trim()}"),
Result::Err(e) => print("pipeline failed: {e}"),
}
// The composed Cmd displays like the shell command it replaces:
let three = sh"cat access.log".pipe_to(sh"grep ERROR").pipe_to(sh"wc -l")
print("composed: {three}")
// …and composes with the VALUE pipe afterwards: run() → Output → |>
let display = sh"git version".pipe_to(sh"git hash-object --stdin").run_raw()
|> tostring(_)
print("value-pipe after process-pipe: {display != nil}")
Requires the Zolo CLI/host — open in the playground or run locally.