Logo ProcessKit API Reference

Command Type

An immutable description of a process to run. Build it fluently — each method returns a new `Command`. The value is the *cold* description of a run; the process is launched only when a verb (`Runner.run`, `Command.start`, …) is invoked. Use the instance methods (`cmd.Arg "x"`) or the `Command` module's pipe-friendly functions (`cmd |> Command.arg "x"`).

Constructors

Constructor Description

Command(program)

Full Usage: Command(program)

Parameters:
    program : string

Returns: Command

Start a new command for the given program (resolved on PATH unless a path is given). `program` must be non-empty and must not contain an embedded NUL (`'\000'`) — either would let the actual spawned command diverge from the one requested (see `CommandConfig.rejectEmbeddedNul`).

program : string
Returns: Command

Instance members

Instance member Description

this.Arg

Full Usage: this.Arg

Parameters:
    value : string

Returns: Command

Append a single argument. `value` must not contain an embedded NUL (`'\000'`) — see `CommandConfig.rejectEmbeddedNul`.

value : string
Returns: Command

this.Args

Full Usage: this.Args

Parameters:
    values : string seq

Returns: Command

Append several arguments, in order. Every element must be non-null (a null element inside an otherwise non-null `seq` — a C#-reachable shape `ArgumentNullException.ThrowIfNull values` on the sequence itself cannot catch) and must not contain an embedded NUL (`'\000'`); the exception names the offending element by index (`Args[2]`).

values : string seq
Returns: Command

this.Arguments

Full Usage: this.Arguments

Returns: IReadOnlyList<string>

The arguments, in order.

Returns: IReadOnlyList<string>

this.CancelOn

Full Usage: this.CancelOn

Parameters:
Returns: Command

Also cancel the run when `cancellationToken` fires (in addition to any verb token). This binds the token to the **completion** verbs — `RunAsync`/`Output*`/`ExitCodeAsync`/`ProbeAsync`/`ParseAsync`/`FirstLineAsync`: they drive the child to completion, so they watch the token for the whole run and turn a fired token into `ProcessError.Cancelled`. It does **not** reach a live `StartAsync`/`SpawnAsync` handle. On that path the verb's own token is checked exactly once, before the actual spawn (an already-cancelled token short-circuits to `ProcessError.Cancelled` and starts nothing); once the child is running, neither this `CancelOn` token nor the token passed to `StartAsync` is tracked. A live handle is caller-driven — cancel or reap it yourself: dispose it, call its `Kill`, or register your own callback on the token that calls `Kill`.

cancellationToken : CancellationToken
Returns: Command

this.ConfiguredTimeout

Full Usage: this.ConfiguredTimeout

Returns: TimeSpan option

The configured run timeout, if any.

Returns: TimeSpan option

this.CreateNoWindow

Full Usage: this.CreateNoWindow

Returns: Command

Windows: run the child with `CREATE_NO_WINDOW`, so a console child spawned from a GUI app does not flash a console window. No effect on Unix.

Returns: Command

this.CurrentDir

Full Usage: this.CurrentDir

Parameters:
    directory : string

Returns: Command

Set the working directory for the run. `directory` must not contain an embedded NUL (`'\000'`) — see `CommandConfig.rejectEmbeddedNul`.

directory : string
Returns: Command

this.Encoding

Full Usage: this.Encoding

Parameters:
Returns: Command

Decode both captured streams with `encoding`.

encoding : Encoding
Returns: Command

this.Env

Full Usage: this.Env

Parameters:
    key : string
    value : string

Returns: Command

Set an environment variable for the child. `key` must be non-empty, must not contain `=`, and neither `key` nor `value` may contain an embedded NUL (`'\000'`) — all rejected with `ArgumentException` (either would corrupt the child's environment block, or let it diverge from what was requested).

key : string
value : string
Returns: Command

this.EnvClear

Full Usage: this.EnvClear

Returns: Command

Start the child's environment empty instead of inheriting the parent's.

Returns: Command

this.EnvRemove

Full Usage: this.EnvRemove

Parameters:
    key : string

Returns: Command

Remove an inherited environment variable from the child. `key` must be non-empty and must not contain `=` (same rule as `Env`).

key : string
Returns: Command

this.Gid

Full Usage: this.Gid

Parameters:
    gid : int

Returns: Command

Run the child under this Unix group id (`setgid`) — see `Uid` for the mechanism, platform notes, and privilege requirement. `setgid` is applied before any `setuid`, so the two compose into a correct privilege drop. `gid` must be non-negative.

gid : int
Returns: Command

this.Groups

Full Usage: this.Groups

Parameters:
    gids : int seq

Returns: Command

Set the child's Unix **supplementary groups**, *replacing* the inherited set — the missing third leg of a correct privilege drop, next to `Uid`/`Gid`. A bare `Uid`/`Gid`/`User` drop *clears* the parent's supplementary groups (`setpriv --clear-groups`) so the child never keeps root's; pass the target user's groups here to grant them back (e.g. a service user's `docker`/`video`/`adm` membership), or `[]` to keep the cleared default explicitly. The gids are applied verbatim — they need not name existing `/etc/group` entries. Because it rides the same `setpriv` helper as the uid/gid drop (mapped to `setpriv --groups`), it is meaningful only **alongside a `Uid` or `Gid` drop**: `Groups` set without either is refused at spawn with `ProcessError.Spawn` rather than silently ignored (never a silent no-op). **Unix-only:** on Windows (no equivalent) a set value fails the spawn with `ProcessError.Unsupported`, exactly like `Uid`/`Gid`. Every gid must be non-negative — rejected with `ArgumentOutOfRangeException` at the builder boundary, naming the offending element by index (`Groups[2]`).

gids : int seq
Returns: Command

this.IdleTimeout

Full Usage: this.IdleTimeout

Parameters:
Returns: Command

Kill the run when it produces **no output** — on neither stdout nor stderr — for `duration`, reporting the result as `Outcome.TimedOut`. Every chunk of output resets the deadline, so a run that keeps streaming stays alive; one that hangs after going quiet is killed. This is distinct from `Timeout`, which bounds the *total* run length regardless of output: the two are independent and may both be set, each firing on its own condition. Idle activity is measured at byte granularity across every verb (buffered capture, streaming, raw bytes, and the drained `WaitAsync`/`ProfileAsync`), so even a run whose output is discarded — or a single long newline-free blob — counts as active. A negative `duration` is rejected (`ArgumentOutOfRangeException`, matching `Timeout`); one larger than ~24.8 days is treated as no idle deadline. Honours `TimeoutGrace` (a graceful stop, then a hard kill) exactly as `Timeout`.

duration : TimeSpan
Returns: Command

this.InheritStdin

Full Usage: this.InheritStdin

Returns: Command

Hand the child the parent process's **own standard input** directly — inherited, with no pipe and no feeder — for interactive/console programs that read from the terminal (an editor launched by `git commit`, a tool that prompts the user, a pipe from the parent's own stdin). This is the stdin analogue of `StdioMode.Inherit` for stdout/stderr. Because there is no stdin pipe, it is incompatible with the pipe-based stdin knobs and rejected together with them at the builder boundary (`ArgumentException`, in either chaining order): a feeder source (`Stdin`) and `KeepStdinOpen`. For the same reason `RunningProcess.TakeStdin` yields `None` for an inherited-stdin child (there is no interactive pipe to hand out). The capture/streaming verbs are unaffected — only the child's stdin wiring changes. Repeatable: a retry or a supervisor restart re-inherits the parent's stdin, so `InheritStdin` is never refused by the one-shot-source retry guard.

Returns: Command

this.KeepStdinOpen

Full Usage: this.KeepStdinOpen

Returns: Command

Keep the child's stdin pipe open after the source is exhausted (for interactive writing via `RunningProcess.TakeStdin`). Rejected (`ArgumentException`) when `InheritStdin` is already set — an inherited stdin has no pipe to keep open.

Returns: Command

this.LineTerminator

Full Usage: this.LineTerminator

Parameters:
Returns: Command

Frame **both** captured/streamed streams' lines with `terminator`. See `StdoutLineTerminator` for what the line framing governs (and what it leaves byte-exact).

terminator : LineTerminator
Returns: Command

this.Logger

Full Usage: this.Logger

Parameters:
Returns: Command

Emit structured lifecycle events (spawn / exit / timeout / retry) to `logger`. The program name and non-secret facts only — **argv and environment are never logged**.

logger : ILogger
Returns: Command

this.MergeStderr

Full Usage: this.MergeStderr

Returns: Command

Merge the child's standard **error** into its standard **output** at the OS level — the library equivalent of a shell `2>&1`. The native spawn points the child's stderr at the very same pipe/handle as its stdout (POSIX `dup2` of fd 2 onto stdout's target; Windows shares one handle across `STARTUPINFO.hStdOutput`/`hStdError`), so the two streams interleave **honestly, byte for byte** on the single stdout stream — the real terminal-order `2>&1` view that the post-hoc `ProcessResult.Combined` (a concatenation of two *separately* captured streams) cannot reproduce. It works uniformly for the buffering verbs, the streaming verbs (`StdoutLinesAsync`/ `OutputEventsAsync`), and pipeline stages. The default is off (separate stdout/stderr, unchanged). **There is then no separate stderr stream, and the API reflects that honestly** (never a silent downgrade): `ProcessResult.Stderr` is always empty, the streamed stderr stream is absent, and `OutputEventsAsync` emits only `OutputEvent.Stdout` events — the stderr lines already live, in order, in the stdout byte stream. Because the merge removes the separate stream, the separate-stderr **observation** knobs are rejected at the builder boundary with an `ArgumentException` (in either chaining order) rather than silently never firing: `StderrTee` and `OnStderrLine` cannot be combined with `MergeStderr`. The remaining stderr knobs are documented **no-ops** under merge — the merged bytes follow stdout's settings: `StderrEncoding` (the merged stream decodes with `StdoutEncoding`), `StderrLineTerminator` (framed with `StdoutLineTerminator`), and the `Stderr` `StdioMode` (stderr follows stdout's destination). These are not rejected because `Encoding()` and `LineTerminator()` set the stdout+stderr pair together, so rejecting them would make those pair setters conflict with `MergeStderr`. Inside a `Pipeline`, `MergeStderr` is allowed only on the **last** stage — its stdout is the pipeline's captured output, so a `2>&1` there captures the final stage's merged output. Setting it on any earlier stage is rejected (`ArgumentException`) the moment the stage stops being last: a pipeline wires each stage's stdout into the next stage's stdin, so merging an intermediate stage's stderr would inject it into the downstream stage's input data.

Returns: Command

this.OkCodes

Full Usage: this.OkCodes

Parameters:
    codes : int seq

Returns: Command

Replace the set of exit codes treated as success (the default is `{0}`) — this is what `ProcessResult.IsSuccess`, `ensureSuccess`, and the `RunAsync` verbs check. The codes *replace* the default rather than adding to it, so pass `[0; 3]` to accept both `0` and `3`. An empty set is a **no-op** — the previously configured codes are kept (it never resets the accepted set), so it can't accidentally clear a caller's `[0; 3]` down to nothing.

codes : int seq
Returns: Command

this.OnStderrLine

Full Usage: this.OnStderrLine

Parameters:
Returns: Command

Invoke `handler` for each captured stderr line, as it is pumped. Rejected (`ArgumentException`) together with `MergeStderr`, which folds stderr into stdout at the OS level, leaving no separate stderr stream for the handler to observe.

handler : Action<string>
Returns: Command

this.OnStdoutLine

Full Usage: this.OnStdoutLine

Parameters:
Returns: Command

Invoke `handler` for each captured stdout line, as it is pumped.

handler : Action<string>
Returns: Command

this.OutputBuffer

Full Usage: this.OutputBuffer

Parameters:
Returns: Command

Bound the in-memory backlog of captured lines.

policy : OutputBufferPolicy
Returns: Command

this.Priority

Full Usage: this.Priority

Parameters:
Returns: Command

Launch the child — and the process tree it spawns — at a lower (or higher) CPU-scheduling `priority`: a Windows priority class set at process creation, or a Unix `nice` value applied via `setpriority`. Supported on both platforms (never `ProcessError.Unsupported`); the default (unset) leaves the OS default. Raising priority above the inherited level on Unix (`Priority.High`/`Priority.AboveNormal`) needs privilege — without it the spawn fails with `ProcessError.Spawn` rather than silently running lower. See `Priority`.

priority : Priority
Returns: Command

this.Program

Full Usage: this.Program

Returns: string

The program to run.

Returns: string

this.Retry

Full Usage: this.Retry

Parameters:
Returns: Command

Run the command up to `maxAttempts` times **in total** (the initial run plus up to `maxAttempts - 1` retries), waiting `delay` between attempts, while `shouldRetry` returns true for the error. `maxAttempts` of `0` or `1` both mean a single run — a command always runs at least once.

maxAttempts : int
delay : TimeSpan
shouldRetry : Func<ProcessError, bool>
Returns: Command

this.RetryNever

Full Usage: this.RetryNever

Returns: Command

Explicitly disable retrying for this command, overriding any `Retry` policy already on it — including one inherited from a `CliClient.WithDefaults` template. Distinct from never having called `Retry` at all: an unset `Retry` still accepts a client's default, `RetryNever` refuses it. The command always runs exactly once. A later `Retry(...)` call in the same chain re-opts back in (the last call wins).

Returns: Command

this.Setsid

Full Usage: this.Setsid

Returns: Command

Detach the child into a **new session** (`setsid()`): its own session and process group, with no controlling terminal. **Unix-only:** on Windows a requested detach fails the spawn with `ProcessError.Unsupported`. `setsid()` makes the child a new process-group leader (pgid == pid), so the kill-on-drop group teardown (`killpg`) still reaches the whole session — containment is preserved; the new session simply replaces the group's default `POSIX_SPAWN_SETPGROUP` for this command. A `setsid()` the OS refuses fails the spawn with `ProcessError.Spawn`.

Returns: Command

this.Stderr

Full Usage: this.Stderr

Parameters:
Returns: Command

Set how the child's standard error is connected (default `Piped`).

mode : StdioMode
Returns: Command

this.StderrEncoding

Full Usage: this.StderrEncoding

Parameters:
Returns: Command

Decode captured stderr with `encoding` (default UTF-8).

encoding : Encoding
Returns: Command

this.StderrLineTerminator

Full Usage: this.StderrLineTerminator

Parameters:
Returns: Command

Frame captured/streamed **stderr** lines with `terminator` (default `LineTerminator.Lf`). See `StdoutLineTerminator`; the stdout framing is left untouched.

terminator : LineTerminator
Returns: Command

this.StderrTee

Full Usage: this.StderrTee

Parameters:
Returns: Command

Copy raw captured stderr bytes to `sink` (a tee), in addition to capture. Rejected (`ArgumentException`) together with `MergeStderr`, which folds stderr into stdout at the OS level, leaving no separate stderr stream to tee.

sink : Stream
Returns: Command

this.Stdin

Full Usage: this.Stdin

Parameters:
Returns: Command

Feed the child's standard input from `source`. Rejected (`ArgumentException`) when `InheritStdin` is already set — the inherited stdin has no pipe for a feeder source to write into.

source : Stdin
Returns: Command

this.Stdout

Full Usage: this.Stdout

Parameters:
Returns: Command

Set how the child's standard output is connected (default `Piped`).

mode : StdioMode
Returns: Command

this.StdoutEncoding

Full Usage: this.StdoutEncoding

Parameters:
Returns: Command

Decode captured stdout with `encoding` (default UTF-8).

encoding : Encoding
Returns: Command

this.StdoutLineTerminator

Full Usage: this.StdoutLineTerminator

Parameters:
Returns: Command

Frame captured/streamed **stdout** lines with `terminator` (default `LineTerminator.Lf` — split on `\n`). Pass `LineTerminator.Cr`/`Any` to split carriage-return progress output on a bare `\r`. Affects only the line-pumped path (streaming, per-line handlers, `OutputStringAsync`); the raw `OutputBytesAsync` bytes and the tees stay byte-exact.

terminator : LineTerminator
Returns: Command

this.StdoutTee

Full Usage: this.StdoutTee

Parameters:
Returns: Command

Copy raw captured stdout bytes to `sink` (a tee), in addition to capture.

sink : Stream
Returns: Command

this.StreamBuffer

Full Usage: this.StreamBuffer

Parameters:
Returns: Command

Opt in to a bounded/backpressure channel for the streaming verbs (`StdoutLinesAsync`/ `OutputEventsAsync`/`WaitForLineAsync`). Unset (the default) keeps the unbounded streaming channel ProcessKit has always used. See [Streaming](../../docs/streaming.md) for the backpressure deadlock footgun before opting in to `StreamFullMode.Backpressure`.

policy : StreamBufferPolicy
Returns: Command

this.Timeout

Full Usage: this.Timeout

Parameters:
Returns: Command

Kill the run after `duration`, reporting the result as `Outcome.TimedOut`. A negative `duration` is rejected; one larger than ~24.8 days is treated as no timeout.

duration : TimeSpan
Returns: Command

this.TimeoutGrace

Full Usage: this.TimeoutGrace

Parameters:
Returns: Command

On timeout, terminate gracefully (SIGTERM) and force-kill only if still alive after `grace`. On Windows this degrades to the atomic Job kill. A negative `grace` is rejected (`ArgumentOutOfRangeException`), matching `Timeout`.

grace : TimeSpan
Returns: Command

this.Uid

Full Usage: this.Uid

Parameters:
    uid : int

Returns: Command

Run the child under this Unix user id (`setuid`). **Unix-only:** on Windows (which has no equivalent) a requested uid fails the spawn with `ProcessError.Unsupported` rather than being silently ignored. Because `posix_spawn` has no uid attribute, a command with a uid (or `Gid`) is spawned through the `setpriv` helper (util-linux), which drops the gid/uid and clears the supplementary groups before `exec`ing the real program in place. Dropping to another user is **root-only** (`euid == 0`): a non-root caller asking for a different uid fails the spawn with `ProcessError.Spawn` (never a child that kept the parent's uid) — including one holding `CAP_SETUID`/`CAP_SETGID`, which the up-front check conservatively refuses rather than probes — as does a host with no `setpriv` (mainstream Linux has it; macOS/BSD do not). `uid` must be non-negative (rejected with `ArgumentOutOfRangeException` at the builder boundary). Pair with `Gid` (or `User`) for a full drop.

uid : int
Returns: Command

this.Umask

Full Usage: this.Umask

Parameters:
    mask : int

Returns: Command

Set the child's Unix file-mode creation mask (`umask(2)`), controlling the default permissions of files it creates — pass the value you would give the `umask` shell builtin (e.g. `0o022`). Only the low permission bits are meaningful, as with the syscall itself. **Unix-only:** on Windows (which has no equivalent) a set mask fails the spawn with `ProcessError.Unsupported` rather than being silently ignored. The default (unset) leaves the inherited umask untouched. `mask` must be within `0..0o7777` (the meaningful permission-bit range); outside it an `ArgumentOutOfRangeException` is thrown at the builder boundary rather than being handed to `umask(2)` as-is.

mask : int
Returns: Command

this.UncheckedInPipe

Full Usage: this.UncheckedInPipe

Returns: Command

Inside a pipeline, do not let this stage's non-zero exit fail the pipeline (it is still reported in the stage outcomes). Outside a pipeline this flag has no effect.

Returns: Command

this.User

Full Usage: this.User

Parameters:
    uid : int
    gid : int

Returns: Command

Run the child under this Unix user **and** group id — the common privilege-drop pair, equivalent to `.Gid(gid).Uid(uid)`. See `Uid` for the mechanism, ordering (`setgid` before `setuid`), supplementary-group clearing, platform notes, and privilege requirement. Both ids must be non-negative.

uid : int
gid : int
Returns: Command

this.WindowsCtrlSignals

Full Usage: this.WindowsCtrlSignals

Returns: Command

Windows: spawn the child as its own console process group (`CREATE_NEW_PROCESS_GROUP`), so that `ProcessGroup.Signal(Signal.Int)` / `Signal.Term` can deliver it a best-effort console **CTRL+BREAK** — the closest Windows analogue to a graceful `SIGINT`/`SIGTERM` — instead of the hard atomic Job-Object kill, giving a console child a chance to clean up. **Best-effort and console-only:** the event reaches only a console child that shares the caller's console. A child given its own or hidden console (via `CreateNoWindow`), or a parent that has no console at all, cannot receive it — the send then fails honestly with `ProcessError.Unsupported` rather than a silent downgrade — and even on a successful send delivery is not guaranteed (the child may install its own console handler). `Signal.Kill` is unaffected (always the atomic Job kill), and this has no effect on Unix, where signals reach the child's process group regardless. Note that `CREATE_NEW_PROCESS_GROUP` also disables the child's default CTRL+C handling, which is why the soft signal is delivered as CTRL+BREAK rather than CTRL+C.

Returns: Command

this.WorkingDirectory

Full Usage: this.WorkingDirectory

Returns: string option

The working directory, when overridden.

Returns: string option

Type something to start searching.