Process

struct Options

What to run, and how.

args does NOT include the program itself. env of [] inherits the parent's environment; non-empty entries are NAME=value overlays on top of it, not a replacement. stdin: None gives the child an EMPTY stdin, not the parent's.

struct ProcessResult

What a finished process left behind.

exit_code is the child's own status: a non-zero one is an ordinary result, not an error. Failing to START the process is the Err.

let run (opts: Options): Result[ProcessResult, String]

A non-zero exit code is an ordinary Ok. Err means the process could not be started at all, including a program that was not found.

let start (opts: Options): Result[Child, String]

Every length is bound BEFORE any as_cstr, which is the ordering Net.write and File.write both spell out: the pointer is an interior one into the string's cell, and reading a length afterwards in the same argument list is how that bug was found on the wire. Named start, not spawn: spawn is a KEYWORD, the concurrency construct, so Process.spawn(..) does not parse at all. Making it parse would mean teaching the parser that a keyword after . is a member name, which is real grammar work for a naming preference. start also pairs with wait.