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.Arg0

Full Usage: this.Arg0

Parameters:
    arg0 : string

Returns: Command

Override the child's **`argv[0]`** independently of the executable that is actually launched (`Program`) — the mechanism behind multicall binaries such as BusyBox/Toybox (which dispatch on their own `argv[0]`) and the login-shell convention of a leading `-` (`-bash`). Only the argument vector the child observes changes: `Program` alone still drives PATH/`PreferLocal` resolution, preflight, spawn diagnostics (`ProcessError`), and containment — exactly as if `Arg0` had never been called. Repeated calls are last-write-wins, like every other builder knob. `arg0` must be non-empty and must not contain an embedded NUL (`'\000'`) — both rejected with `ArgumentException` at the builder boundary rather than reaching the native layer, where an empty or NUL-truncated value could let the observed `argv[0]` silently diverge from what was requested. **Unix-only**, applied on the POSIX spawn path by handing the native layer a distinct `argv[0]` separate from the file `posix_spawnp` resolves and executes. **Windows** has no separate `argv[0]` contract (`CreateProcessW` takes one raw command line, not an argv array with an independent first element), so a set value fails the spawn there with `ProcessError.Unsupported`, never a silent fallback to `Program`. It is likewise refused with `ProcessError.Unsupported` — at spawn time, on POSIX — when combined with a knob that routes the launch through a helper which must re-`exec` the target BY NAME and has no CLI seam of its own for a distinct `argv[0]`: a `Uid`/`Gid`/`Groups`/ `KillOnParentDeath` privilege/parent-death drop (the `setpriv` helper), `Pty` (the `setsid --ctty` helper), a run under `ProcessGroup`'s Linux cgroup backend (the `/bin/sh` migration launcher), or a `ResourceLimits.CpuTimeMax` run on the POSIX process-group mechanism (the `/bin/sh` `RLIMIT_CPU` shim). Honouring the override there would mean either handing it to the WRONG process (the helper's own `argv[0]`, silently discarding what was actually requested) or inventing a new native shim — this library does neither; it refuses loudly instead. A lone `Setsid` (no privilege drop) does not route through any such helper, so it composes with `Arg0` normally.

arg0 : 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 ordinary arguments followed by any Windows raw fragments, in their respective append order. Raw fragments are opaque values for test doubles and cassette matching; they are not portable argv elements and a real POSIX spawn rejects them.

Returns: IReadOnlyList<string>

this.CancelGrace

Full Usage: this.CancelGrace

Parameters:
Returns: Command

Make a **cancellation** graceful: when the token that cancels this run fires, its tree is sent `CancelSignal` (default `Signal.Term`), given up to `grace` to leave on its own, and only then hard-killed — the cancellation mirror of `TimeoutGrace`, for the "one shared token, cancelled on Ctrl-C" shutdown pattern where every child would otherwise be killed outright. **Opt-in, and off by default.** Without it a cancellation hard-kills the tree at once, exactly as before. It applies to every cancellation source a run has — the verb's own `CancellationToken`, this command's `CancelOn` (including one inherited from `CliClient.WithDefaults`), `Pipeline.CancelOn` (set it on stage 0, which owns the pipeline-wide control configuration), and a `Supervisor` incarnation's cancellation — and to buffered and streamed completion verbs alike. The streamed one, `FirstLineAsync`, therefore waits for the ladder to conclude before it answers `Cancelled` — returning is what reaps its tree, so answering sooner would collapse the very window this knob opens. The wait is bounded by `grace`; without this knob it answers immediately, as before. **The outcome does not change: a cancelled run is still always an error.** Every consuming path still reports `ProcessError.Cancelled`, whether the child left on the soft signal or was killed after the grace; only the manner of the goodbye becomes gentler, so a child that must flush state, remove a pidfile, or finish a transaction gets the chance to. **Independent of `Timeout`/`TimeoutGrace`/`StopSignal`,** whose behaviour is untouched: a deadline that expires still uses `TimeoutGrace`/`StopSignal` (or hard-kills when unset), and neither pair gap-fills the other. It needs no `Timeout` of its own. **Scope, like the rest of cancellation:** a run that owns its group tears down the whole tree; a run sharing a `ProcessGroup` reaches only its own direct child (the documented shared-group teardown gap). On **Windows** the soft tier is the documented best-effort one — a `WM_CLOSE` to a windowed child plus a CTRL+BREAK to a child started with `WindowsCtrlSignals()` — and the hard kill still lands when the grace elapses; a non-default `CancelSignal` is refused at spawn rather than silently downgraded. A negative `grace` is rejected (`ArgumentOutOfRangeException`), matching `TimeoutGrace`; `TimeSpan.Zero` escalates immediately.

grace : TimeSpan
Returns: Command

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`. The teardown is an **immediate hard kill** by default; add `CancelGrace` (and optionally `CancelSignal`) to route it through a soft signal → grace → hard kill ladder instead. The outcome is unchanged either way — a cancelled run is always `ProcessError.Cancelled`.

cancellationToken : CancellationToken
Returns: Command

this.CancelSignal

Full Usage: this.CancelSignal

Parameters:
Returns: Command

Choose the soft signal that opens a `CancelGrace` window. The default is `Signal.Term`, exactly like `StopSignal`'s. Deliberately independent of `StopSignal`: a command may want a different farewell for "the caller changed its mind" than for "the deadline expired", and neither knob gap-fills the other. Inert without `CancelGrace` — there is no soft tier to send it on. Windows refuses a non-default value at spawn with `ProcessError.Unsupported` (it cannot faithfully represent an arbitrary POSIX signal), exactly as `StopSignal` does, never a silent downgrade to the hard kill.

signal : Signal
Returns: Command

this.CapturePolicy

Full Usage: this.CapturePolicy

Parameters:
Returns: Command

Shape every decoded line on its way into the in-memory capture backlog — the redaction-at-capture seam. `policy.OnCapture` runs before a line is retained, so what it returns is what `ProcessResult.Stdout`/`Stderr` and `Finished.Stderr` carry; a policy that throws or returns `null` fails **closed** (that line is retained empty, never raw). It shapes the retained backlog **only**. The per-line handlers (`OnStdoutLine`/`OnStderrLine`), the tees (`StdoutTee`/`StderrTee`), the streaming verbs and a raw byte capture (`OutputBytesAsync`'s stdout) all keep seeing the unshaped line — see `ICapturePolicy` for the whole boundary and why it is drawn there. A command carrying one cannot be used as a `Pipeline` stage (`Pipe` rejects it with an `ArgumentException`: a pipeline captures raw bytes only, so the seam would have nothing to shape). Unset (the default) retains exactly what the child wrote. Composes with `OutputBuffer`, which decides how much of the shaped output survives; the last `CapturePolicy` call in a chain wins.

policy : ICapturePolicy
Returns: Command

this.ConfiguredCapturePolicyName

Full Usage: this.ConfiguredCapturePolicyName

Returns: string option

The `ICapturePolicy.Name` of the policy configured with `CapturePolicy`, or `None` when none is set — the introspection point that keeps a configured policy visible (in a test assertion, a diagnostic dump) instead of an anonymous callback. Deliberately the *name* rather than the policy itself: a name is safe to print, a policy object is not something a diagnostic should hand out.

Returns: string option

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

Encode text stdin and decode both captured streams with `encoding`. For a legacy Windows console program — one whose non-ASCII input and output use a code page rather than UTF-8 — use `ConsoleEncoding()`, which resolves the right code page for the current host and applies it here.

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.ExtraFd

Full Usage: this.ExtraFd

Parameters:
    targetFd : int

Returns: Command

Add a POSIX full-duplex channel at child file descriptor `targetFd` (3 or greater). After `StartAsync`, claim the parent side once with `RunningProcess.TakeExtraFd(targetFd)`. Windows reports `ProcessError.Unsupported`; pipelines, detached launches, and test doubles reject the setting rather than silently dropping it.

targetFd : int
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) — and it inherits that helper's trusted-directory resolution, so a host carrying `setpriv` only on its `PATH` refuses this drop too (see `Uid`). **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 output discarded by a parent-side verb — or a single long newline-free blob — still counts as active. At least one effective parent-side output stream is required: combining this with only `Null`, `Inherit`, or direct file destinations is rejected with `ArgumentException` in either chaining order; a PTY's merged master stream is observable. 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`. `Pty` is rejected too (either chaining order): a pseudo-terminal gives the child its own pty slave/ConPTY input as stdin, leaving nothing for the parent's own standard input to attach to. 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.IoPriority

Full Usage: this.IoPriority

Parameters:
Returns: Command

Set the **Linux I/O-scheduling priority** of the child — and of the tree it spawns — so that background disk work yields to the interactive users of the same device. A separate axis from the CPU-scheduling `Priority` above and not a substitute for it: that one decides how much *processor* the child gets, this one how its *block-device* requests are ordered. Build the value with `IoPriority.Idle` / `IoPriority.BestEffort level` / `IoPriority.RealTime level`, which validate the level at construction; the default (unset) leaves the inherited I/O priority untouched. Last write wins, like every other builder knob. **How far it reaches, and when it takes effect.** The kernel copies the spawning task's I/O priority into the child when the child is created and it survives every `exec`, so the priority is in force for the child's very FIRST block-device request — before its program runs — and is inherited by every descendant the child later forks. There is no spawn-then-apply window here (the one the CPU `Priority` axis documents for its post-spawn `setpriority`), and no helper binary is involved, so it composes unchanged with a `Uid`/`Gid` drop, a `Pty`, a cgroup-contained group, a `Command.Rlimit` set, and `Command.Arg0` alike. **Linux-only, and honestly so.** `ioprio_set(2)` is a Linux system call with no Win32 or POSIX equivalent, so a spawn carrying an I/O priority fails with `ProcessError.Unsupported` on **Windows, macOS, and the BSDs** rather than running the child at the inherited priority as if the request had been honoured. `Command.LaunchDetached` refuses it on the same terms — that verb deliberately gives up ownership of the child, and this is an owner-applied setting. **Privilege.** `Idle` and `BestEffort` need none. `RealTime` needs `CAP_SYS_ADMIN` (Linux ≥ 5.14 accepts `CAP_SYS_NICE` too); without it the kernel refuses the request and the spawn fails with `ProcessError.Spawn` — never a silent downgrade to best-effort. A kernel or sandbox with no `ioprio_set` at all (a seccomp filter returning `ENOSYS`) is a typed `ProcessError.Unsupported`. **What it does not promise.** The class and level are recorded on the child unconditionally, but whether they change the *order requests are served in* is the block device's I/O scheduler's decision: Linux honours I/O priorities under **BFQ** (and the historical CFQ), while `mq-deadline`, `kyber`, and `none` — the common defaults for NVMe — largely ignore them. This knob asks the kernel for a priority; it cannot promise a scheduler that acts on it. See `IoPriority`.

priority : IoPriority
Returns: Command

this.KeepStdinOpen

Full Usage: this.KeepStdinOpen

Returns: Command

Keep the child's stdin pipe open after the source (if any) is exhausted, for interactive writing via `RunningProcess.TakeStdin`. Works both with **no** source (the pipe is interactive from the start — `TakeStdin` is available immediately) and **with** a `Command.Stdin(source)` (the source is fed first, the pipe is left open afterwards, and `TakeStdin` becomes available once that feed has finished — so the source and the interactive writer never write the pipe concurrently). Rejected (`ArgumentException`) when `InheritStdin` is already set — an inherited stdin has no pipe to keep open. **Take the writer before driving the handle to completion.** The kept-open pipe has exactly one owner, and `TakeStdin`/`TakeStdinAsync` is not its only claimant: a verb that runs the handle to completion while the writer is still untaken ends the child's input itself (`OutputStringAsync`/ `OutputBytesAsync`/`WaitAsync`/`ProfileAsync`, a `WaitAnyAsync`/`WaitAllAsync`/`StopAsync` that is the handle's first consumer, and the verbs that never hand out a `RunningProcess` at all — `RunAsync`/ `ExitCodeAsync`/`ProbeAsync`/`ParseAsync`/`OutputJsonAsync`/`FirstLineAsync`). That is what keeps a child reading stdin to EOF from hanging such a verb, and it is one-way: `TakeStdin` afterwards answers `None`. A writer already taken stays the caller's — no verb closes a handle it gave away.

Returns: Command

this.KillOnParentDeath

Full Usage: this.KillOnParentDeath

Returns: Command
 Opt in to reaping this child when the **parent process dies suddenly** — a SIGKILL, a crash, or a
 Windows `TerminateProcess` — the one case the deterministic kill-on-drop tree guarantee cannot
 cover, because it relies on a `Dispose`/`DisposeAsync` (or the finalizer) that a hard-killed parent
 never runs. Off by default; setting it changes nothing unless the parent actually dies unexpectedly.

 **What the platform actually guarantees differs — query it with `KillOnParentDeathScope`.**

 - **Windows — the whole tree, already, with no extra action.** Every child ProcessKit starts lives
   in a Job Object created with `KILL_ON_JOB_CLOSE`, and the parent process owns the only handle to
   that Job. When the parent dies for *any* reason the kernel closes its handles during process
   rundown; closing the last Job handle terminates every process in the Job. So the guarantee holds
   tree-wide and unconditionally — this method is a documented no-op on Windows, not a silent one.
 - **Linux — the direct child only.** The child is armed with `PR_SET_PDEATHSIG(SIGKILL)` via the
   `setpriv --pdeathsig` helper (util-linux) on the ordinary `posix_spawn` path, so it is killed when
   its parent dies. A parent that dies in the instant *before* that arming — where the signal would
   otherwise bind to the reaper that adopted the orphan, and the child would run on — is covered too:
   immediately after arming, and before the target program runs, the child checks (through `/bin/sh`,
   pinned by absolute path) that its parent is still the exact process that spawned it, and
   `SIGKILL`s itself instead of running the program when it is not. **Known limits (not silent):**
   the parent-death signal is **not inherited** across
   a `fork`, so a **grandchild** the child spawns is *not* covered — with the child's parent gone
   nothing reaps its cgroup/pgroup. The kernel also **resets** `PR_SET_PDEATHSIG` when the child
   `execve`s a **set-uid/set-gid** image, so for a `sudo`-like child the signal only holds up to that
   `exec`. And because the signal is delivered when the **spawning thread** (not merely the process)
   exits, and ProcessKit spawns on a thread-pool thread that .NET may retire while the process lives,
   the reap is best-effort: it can fire early if that thread is reclaimed. The helper is loaded only
   from a trusted system directory (`/usr/bin`, `/bin`, `/usr/sbin`, `/sbin`) and launched by
   absolute path, never resolved on `PATH` — see `Uid` for why. Where no trusted directory holds
   `setpriv` — a minimal image, or a non-FHS layout such as NixOS/Guix that keeps it only on the
   `PATH` — the spawn fails with a typed `ProcessError.Spawn` naming the helper, never a silently
   un-armed child. The `/bin/sh` that runs the parent check is a host requirement in the same way:
   it is taken from that absolute path rather than `PATH`, and a host that has no shell there also
   fails the spawn with a typed `ProcessError.Spawn` — never a child armed but left running with
   the pre-arm window open.
 - **macOS/BSD — unsupported.** There is no `PR_SET_PDEATHSIG` analog, so a set value fails the spawn
   with `ProcessError.Unsupported` rather than pretending the cleanup will happen.
Returns: Command

this.KillOnParentDeathScope

Full Usage: this.KillOnParentDeathScope

Returns: KillOnParentDeathScope

The **scope** of `KillOnParentDeath` cleanup the current platform actually guarantees — `WholeTree` (Windows Job Object), `DirectChildOnly` (Linux `PR_SET_PDEATHSIG`), or `Nothing` (macOS/BSD). Fixed per platform and **independent of whether `KillOnParentDeath()` was called**: this reports what the OS *can* do, the same honest-report principle as `ProcessGroup.Mechanism`.

Returns: KillOnParentDeathScope

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 has no meaningful semantics — no exit could ever count as success — so it is rejected at the builder boundary with `ArgumentException`, matching every other builder knob that fails loud on an invalid value rather than silently keeping the previous codes. Pass at least one code.

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`) when stderr is `Null`, `Inherit`, redirected with `StderrToFile`, or folded into stdout with `MergeStderr`, because those configurations leave no separate parent-side stderr stream.

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. Rejected (`ArgumentException`) when stdout is `Null`, `Inherit`, or redirected with `StdoutToFile`, because those destinations leave no parent-side stdout stream for the handler to observe.

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.PreferLocal

Full Usage: this.PreferLocal

Parameters:
    directory : string

Returns: Command

Add `directory` to a priority search list consulted **before** `PATH` when resolving this command's **bare-name** program: the prefer-local directories are searched first, in the order they were added, and only then the inherited `PATH`. The canonical use is preferring a project-local tool — `node_modules/.bin`, `.venv/bin`, `tools/`, a binary next to the solution — over a global one of the same name, without hand-building the path and losing cross-platform executable resolution. The lookup in each directory is the SAME `PATHEXT`-aware (Windows) / executable-bit (POSIX) probe the `PATH` walk itself uses, so a Windows `.cmd`/`.bat` shim resolves — and launches through `cmd.exe /d /c` — exactly as it would on `PATH`, and a POSIX file without an executable bit is skipped just the same. A **relative** `directory` resolves against this command's `CurrentDir` when one is set (so a project-relative `tools/` anchors to where the child will actually run, not the parent's current directory); otherwise it resolves against the process's current directory. A prefer-local match is ALWAYS handed to the OS as its resolved **absolute** path, whatever its extension — the OS never searches these directories on its own. Only a **bare name** is affected: a path-form program (`./tool`, `/usr/bin/tool`, `C:\tools\tool.exe`) is launched directly and ignores prefer-local, exactly as it ignores `PATH`. `Exec.which` is deliberately unchanged — it answers "is this installed on the host", a preflight question, whereas prefer-local is a launch concern. `directory` must not contain an embedded NUL (`'\000'`). Repeatable: each call appends one more directory to the end of the priority list.

directory : string
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.Pty

Full Usage: this.Pty

Parameters:
    cols : int
    rows : int

Returns: Command

Run the child under a pseudo-terminal with the given initial geometry (echo on). `cols` and `rows` must each be at least 1 (rejected with `ArgumentOutOfRangeException`). See `Command.Pty(PtyConfig)`.

cols : int
rows : int
Returns: Command

this.Pty

Full Usage: this.Pty

Returns: Command

Run the child under a pseudo-terminal with the default 80×24 geometry (echo on). See `Command.Pty(PtyConfig)`.

Returns: Command

this.Pty

Full Usage: this.Pty

Parameters:
Returns: Command

Run the child under an opt-in **pseudo-terminal (PTY)** with `pty`'s initial geometry and flags: the child gets a real controlling terminal (`isatty` true) on a **single merged stdout+stderr stream**, for tools that demand a tty — an interactive `ssh`/`sudo` password prompt, a credential helper, a TUI, or a progress bar that switches to "dumb" line-buffered output when it detects a pipe. A PTY is never implicit; the default (this method unset) is byte-identical to a plain pipe run. **One merged stream.** A tty is a single bidirectional device, so under a PTY the child's stdout and stderr are physically one stream: `ProcessResult.Stderr` is empty and `OutputEventsAsync` emits only `OutputEvent.Stdout` events. Because there is no separate stderr, the separate-stderr observation knobs are rejected at the builder boundary (`ArgumentException`, in either chaining order): `StderrTee` and `OnStderrLine`. `Setsid` is likewise rejected — it detaches the child into a new session with **no** controlling tty, contradicting a PTY's controlling pseudo-terminal. `InheritStdin` is rejected too (either chaining order): a PTY gives the child its own pty slave/ConPTY input as stdin, so there is no way to also hand it the parent's own standard input. Inside a `Pipeline` a PTY is allowed only as a standalone run or the **last** stage (its merged output would otherwise be injected into the downstream stage's stdin). **Platform support (typed, never a silent downgrade).** Windows: ConPTY, needing Windows 10 1809+; an older host fails the spawn with `ProcessError.Unsupported "Pty (needs Windows 10 1809+ / ConPTY)"`. POSIX: a real controlling pty via `openpty` + the `setsid --ctty` helper (util-linux), which — like the `setpriv` helper behind `Uid` — is loaded only from a trusted system directory (`/usr/bin`, `/bin`, `/usr/sbin`, `/sbin`) and launched by absolute path, never resolved on `PATH`. A host with `setsid` in none of those directories (a non-FHS layout such as NixOS/Guix, *even with `setsid` on its `PATH`*) or without the pty devfs (macOS/BSD) fails with `ProcessError.Unsupported`, never a socketpair silently pretending to be a tty. **Secret-safety.** A terminal echoes typed input into its captured output by default — see `PtyConfig` for the echo footgun and the `Echo` flag. argv/env values and any PTY credentials are never logged or traced.

pty : PtyConfig
Returns: Command

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 — while a negative value is rejected with `ArgumentOutOfRangeException`. A negative `delay` is rejected; delays beyond the maximum armable timer interval are clamped when the retry runs. If `shouldRetry` throws, the current attempt is terminal and the consuming verb returns `ProcessError.RetryPredicate` with the original `ProcessError` in `Original`; the callback exception never escapes as a raw task fault and no further attempt runs.

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

this.RetryBackoff

Full Usage: this.RetryBackoff

Parameters:
Returns: Command

Run the command up to `maxAttempts` times in total, using exponential backoff before each retry: `baseDelay × factor^n` (starting at `n = 0`), capped at `maxDelay` before optional jitter multiplies it by a random factor in `[0.5, 1.5)`. A negative `maxAttempts` is rejected with `ArgumentOutOfRangeException`; `0` and `1` both mean a single run. All delays must be non-negative; `factor` must be finite and at least `1.0`. Retry timers use the command's `TimeProvider`. If `shouldRetry` throws, the current attempt is terminal and the consuming verb returns `ProcessError.RetryPredicate` with the original `ProcessError` in `Original`; the callback exception never escapes as a raw task fault and no further attempt runs.

maxAttempts : int
baseDelay : TimeSpan
factor : float
maxDelay : TimeSpan
jitter : bool
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`/`RetryBackoff` at all: an unset policy still accepts a client's default, `RetryNever` refuses it. The command always runs exactly once. A later retry-policy call in the same chain re-opts back in (the last call wins).

Returns: Command

this.Rlimit

Full Usage: this.Rlimit

Parameters:
Returns: Command

Cap one Unix **per-process** resource for the child (`setrlimit(2)`): `soft` is the value in force, `hard` the ceiling the child may raise its own soft value back up to. Both are in the resource's own native unit — bytes, seconds, or a count, as `RlimitResource` documents. The cap is applied before the child's program starts and is inherited INDIVIDUALLY by each descendant (each gets its own copy of the cap, not a shared budget); a descendant may lower its own limits further, and may raise its soft value again as far as the inherited hard value. That makes this a robustness bound, not a containment boundary — the whole-tree caps of `ProcessGroupOptions`/`ResourceLimits` are the boundary, and the two compose. Calls for DIFFERENT resources accumulate; repeating the same resource replaces the earlier pair in place (last write wins), like every other builder knob. `soft` and `hard` must be non-negative and `soft` must not exceed `hard` — both rejected with `ArgumentOutOfRangeException` here at the builder boundary rather than deep in a native call. There is deliberately no "unlimited" value: this knob exists to LOWER what the child inherited, and raising a hard limit above the inherited one needs privilege (see the refusal note below). **Precedence with the whole-tree `ResourceLimits.CpuTimeMax`.** Both target CPU time when a `Rlimit(RlimitResource.Cpu, ...)` runs inside a group that also sets `CpuTimeMax`. Neither wins by position: the STRICTER of the two is applied on each of the soft and hard values (the smaller number), so adding one can only ever tighten the effective cap, never relax the other. They are applied ONCE, together, by the same pre-exec step, so the looser value can never silently overwrite the tighter one on the way to the child. **Unix-only, and honestly so.** On **Windows** there is no `setrlimit` analogue, so a spawn carrying any rlimit fails with `ProcessError.Unsupported` — never a child running uncapped. On **POSIX** the limits are applied by the util-linux `prlimit` helper, which sets them on itself and then `exec`s the real program in place (same pid, so containment, `Priority`, and a PTY are all unaffected). Like `setpriv` and `setsid --ctty`, that helper is loaded only from a trusted system directory (`/usr/bin`, `/bin`, `/usr/sbin`, `/sbin`) and never from `PATH`; a host holding it in none of them — macOS/BSD, which have no util-linux, or a minimal image — fails the spawn with `ProcessError.ResourceLimit` rather than dropping the caps. A limit the kernel itself refuses (raising a hard limit above the inherited one without privilege) fails the helper before it `exec`s anything, so the child never runs with the cap silently unapplied; the helper's message reaches the run's stderr. Because the helper `exec`s the target BY NAME it has no seam for a distinct `argv[0]`, so combining this with `Command.Arg0` is refused at spawn with `ProcessError.Unsupported` — exactly as `Arg0` is refused alongside the `setpriv`/`setsid --ctty`/`CpuTimeMax` shims, and for the same reason: the override would otherwise land on the helper's own `argv[0]` instead of the program that was actually asked for.

resource : RlimitResource
soft : int64
hard : int64
Returns: Command

this.Rlimits

Full Usage: this.Rlimits

Returns: IReadOnlyList<Rlimit>

The per-process Unix rlimits configured through `Command.Rlimit`, in the order they were added (at most one entry per resource), or an empty list when none were — so a config-driven caller can read back exactly what it asked for, and a diagnostic can report it. A fresh list each read, so a caller can never mutate a command's limits through it.

Returns: IReadOnlyList<Rlimit>

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`). Also clears any prior `StderrToFile` redirect — the last destination in a chain wins (see `Stdout`).

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`) when stderr is `Null`, `Inherit`, redirected with `StderrToFile`, or folded into stdout with `MergeStderr`, because those configurations leave no separate parent-side stream.

sink : Stream
Returns: Command

this.StderrToFile

Full Usage: this.StderrToFile

Parameters:
    path : string

Returns: Command

Redirect the child's standard error straight to the file at `path`, creating it (truncating an existing one). Shorthand for `StderrToFile(path, append = false)` — see that overload.

path : string
Returns: Command

this.StderrToFile

Full Usage: this.StderrToFile

Parameters:
    path : string
    append : bool

Returns: Command

Redirect the child's standard **error** straight to the file at `path`, at the OS level — the stderr mirror of `StdoutToFile`. The child is handed the open file as its stderr handle/fd on the spawn, with no parent pump, so the file outlives the parent. `append = false` creates/truncates, `true` appends. There is then no parent-side stderr stream (`ProcessResult.Stderr` empty, `OnStderrLine` never fires, `OutputEvent.Stderr` never produced), so `StderrTee`, `OnStderrLine`, `MergeStderr`, and `Pty` are rejected at the builder boundary (in either chaining order). Redirecting stderr to a file while capturing stdout normally — or redirecting both streams with `StdoutToFile` — is supported. See `StdoutToFile` for the full contract.

path : string
append : bool
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. A **one-shot** source (`Stdin.FromStream`/`FromLines`/`FromAsyncLines`) feeds at most ONE incarnation: the launch that creates a child takes it before spawning, so a second consumer — a later run, a concurrent one, another verb or runner — is refused with `ProcessError.Unsupported` before any child of its own exists, rather than being handed the exhausted remains. That holds whatever drives the command and whether or not it carries a `Retry` policy: a decorator that calls its inner runner twice with the same command, or a command a runner kept and started afterwards, is a second consumer like any other. A launch that produced no child leaves the source intact for the next one. The repeatable sources (`Stdin.FromString`/`FromBytes`/`FromFile`/`Stdin.Empty`) feed every run.

source : Stdin
Returns: Command

this.StdinEncoding

Full Usage: this.StdinEncoding

Parameters:
Returns: Command

Encode text sent to the child's stdin with `encoding` (default UTF-8). This affects `Stdin.FromString`/`FromLines`/`FromAsyncLines` and `ProcessStdin.WriteLineAsync`; raw `Stdin.FromBytes` and `ProcessStdin.WriteAsync` remain byte-exact.

encoding : Encoding
Returns: Command

this.Stdout

Full Usage: this.Stdout

Parameters:
Returns: Command

Set how the child's standard output is connected (default `Piped`). This is a stdout *destination* setter, so it also clears any prior `StdoutToFile` redirect — the last destination in a chain wins.

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. Rejected (`ArgumentException`) when stdout is `Null`, `Inherit`, or redirected with `StdoutToFile`, because those destinations leave no parent-side stdout stream to tee.

sink : Stream
Returns: Command

this.StdoutToFile

Full Usage: this.StdoutToFile

Parameters:
    path : string

Returns: Command

Redirect the child's standard output straight to the file at `path`, creating it (truncating an existing one). Shorthand for `StdoutToFile(path, append = false)` — see that overload.

path : string
Returns: Command

this.StdoutToFile

Full Usage: this.StdoutToFile

Parameters:
    path : string
    append : bool

Returns: Command

Redirect the child's standard **output** straight to the file at `path`, at the OS level — the child is handed the open file as its stdout handle/fd ON THE SPAWN (Windows: an inheritable file handle in `STARTUPINFO`; POSIX: a file fd via a `posix_spawn` file action), with **zero** copying through the parent and **no** parent pump. The file therefore keeps growing even after the parent process (or a pump that would have drained a pipe) is gone — ideal for a long-lived service's log under a `Supervisor`. `append = false` creates the file (truncating an existing one); `append = true` appends to it. `path` must be non-null and must not contain an embedded NUL (`'\000'`); a bad path (missing directory, permission denied) fails the spawn with `ProcessError.Spawn`, not here. **There is then no parent-side stdout stream** — `ProcessResult.Stdout` is empty, the streaming stdout verbs yield nothing, and `OutputEvent.Stdout` is never produced, exactly as for `StdioMode.Null`/`Inherit` (the child's stdout does not reach the parent at all). Because of that, the knobs that need a parent-side stdout stream are rejected at the builder boundary with an `ArgumentException` (in either chaining order): `StdoutTee` and `OnStdoutLine`. `MergeStderr` is rejected too (it folds stderr into the stdout stream the parent observes, which is absent here), as is `Pty` (a pseudo-terminal replaces the child's stdio with one terminal device). What is **allowed** and useful: redirect stdout to a file while capturing stderr the ordinary way (`ProcessResult.Stderr`, `OnStderrLine`, `StderrTee`, the stderr streaming verbs all still work), or redirect **both** streams to files with `StderrToFile`. As a stdout destination this overrides — and is overridden by — a later `Stdout(mode)` in the same chain (the last destination wins).

path : string
append : bool
Returns: Command

this.StopSignal

Full Usage: this.StopSignal

Parameters:
Returns: Command

Choose the soft signal sent by graceful stop paths before they escalate to a hard kill. The default is `Signal.Term`. Windows refuses non-default values at spawn because it cannot faithfully represent arbitrary POSIX signals; its existing WM_CLOSE/CTRL+BREAK mechanisms remain available through the documented Windows control APIs.

signal : Signal
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`) and `ContentLengthSession.FramesAsync` — which honours only the two lossless full modes and refuses `DropOldest`/`DropNewest`, since a dropped protocol frame is corruption its consumer could never detect. It is inapplicable to `PtySession`, whose window and transcript have their own character bounds. Unset (the default) keeps the unbounded streaming channel ProcessKit has always used. See Streaming for the backpressure deadlock footgun before opting in to `StreamFullMode.Backpressure`.

policy : StreamBufferPolicy
Returns: Command

this.TimeProvider

Full Usage: this.TimeProvider

Parameters:
Returns: Command

Use `timeProvider` for retry delays, readiness probes, `PtySession` pattern deadlines, and supervision. The default is `TimeProvider.System`; supplying a deterministic provider makes those time-dependent paths testable without changing process-wide time.

timeProvider : TimeProvider
Returns: Command

this.Timeout

Full Usage: this.Timeout

Parameters:
Returns: Command

Kill the run after `duration`, reporting the result as `Outcome.TimedOut`. The deadline bounds the run's total wall time and is measured from the **spawn**, so a live `StartAsync` handle collected later gets only what is left of it, and one already past its deadline is killed as soon as it is collected — after at most a quarter-second settle window, itself never longer than `duration`, in which an exit the child had already made can still surface. That window is why a child that finished on its own inside the deadline still reports its real outcome, however little of the budget was left when the collecting verb arrived. A fired deadline always reports this configured `duration`. 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, send the configured `StopSignal` and force-kill only if still alive after `grace`. On Windows the default signal uses the documented best-effort soft phase before the Job kill; non-default stop signals are refused at spawn. 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. **Where the helper comes from.** `setpriv` performs the drop while still running with the parent's (usually root) credentials, so it is never resolved on `PATH`: it is loaded only from a fixed list of trusted system directories — `/usr/bin`, `/bin`, `/usr/sbin`, `/sbin`, in that order — and launched by the absolute path of the match. A host that holds `setpriv` in **none** of them fails the spawn with the same typed `ProcessError.Spawn`, *even when `setpriv` is present on the `PATH`*: mainstream Linux installs it in a trusted directory (Debian/Ubuntu and Fedora in `/usr/bin`, Alpine's `util-linux` in `/bin`), a non-FHS layout such as NixOS or Guix does not, and macOS/BSD have no util-linux at all. `Command.PreferLocal` never applies to the helper either — it substitutes your own target program. See `docs/hardening.md`, "Where the Unix helper binaries come from". `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: register the child leader for targeted console signalling, 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. Regular children get `CREATE_NEW_PROCESS_GROUP` through this option. ConPTY children always receive that flag for isolation, regardless of this option, and Windows consequently disables their default CTRL+C handling: sending U+0003 through ConPTY input does not interrupt the child. For ConPTY, this option only registers the leader for targeted CTRL+BREAK; it does not control creation of the process group.

Returns: Command

this.WindowsIntegrityLevel

Full Usage: this.WindowsIntegrityLevel

Parameters:
Returns: Command

Lower the child's **mandatory integrity level** to `level` (Windows), by labelling the token it is started with (`SetTokenInformation(TokenIntegrityLevel, ...)` on a duplicated primary token, spawned via `CreateProcessAsUser`). Windows' no-write-up policy then denies the child write access to anything labelled above that level — the user's own files, `HKCU`, and the windows of medium-integrity processes — regardless of the DACL that would otherwise allow it. Integrity is a *separate axis* from privileges: use `WindowsRestrictedToken` to take away what the child may **do**, and this to take away what it may **write to**. Both compose onto one token when set together. Only lowering is offered (`WindowsIntegrityLevel.Medium`/`Low`/ `Untrusted`) — Windows refuses to raise a token's integrity, so a "higher" variant could only ever fail the spawn. The child's already-open handles are unaffected: the stdio pipes ProcessKit hands it were opened by the parent and their access check has already happened, so a `Low`-integrity child still writes its output back normally. **Windows-only**, with the same honest `ProcessError.Unsupported` on POSIX and the same builder-boundary conflicts as `WindowsRestrictedToken`.

level : WindowsIntegrityLevel
Returns: Command

this.WindowsRawArg

Full Usage: this.WindowsRawArg

Parameters:
    fragment : string

Returns: Command

Append a Windows command-line fragment verbatim after all ordinarily quoted arguments. Raw fragments retain their own insertion order, but ordinary `Arg`/`Args` values always precede them, regardless of builder-call order. This is an explicit escape hatch for programs with non-MSVCRT parsers; never place untrusted input in `fragment`. POSIX spawn returns typed `Unsupported`, and an automatically resolved `.cmd`/`.bat` target is refused (invoke `cmd.exe` explicitly when needed).

fragment : string
Returns: Command

this.WindowsRestrictedToken

Full Usage: this.WindowsRestrictedToken

Returns: Command

Run the child with a **restricted token**: a copy of this process's own primary token created with `CreateRestrictedToken(DISABLE_MAX_PRIVILEGE)`, which strips every privilege the caller holds except the always-present `SeChangeNotifyPrivilege`. The child is then started with `CreateProcessAsUser` under that token. It keeps the caller's *identity* (same user, same SIDs, same file ACLs apply) but loses the ability to do the privileged things that identity could — debug another process, load a driver, take ownership, shut the machine down, impersonate. This is the Windows half of the hardening story whose Unix half is `Uid`/`Gid`/`Groups`; combine it with `WindowsIntegrityLevel` (which restricts what the child may *write to*, orthogonally to what it may *do*) and with the containing group's `ProcessGroupOptions` resource limits and `WindowsUiRestrictions` for the full perimeter — see the hardening guide. **Windows-only:** on POSIX a set value fails the spawn with `ProcessError.Unsupported`, never a silent no-op — the mirror image of `Uid`/`Setsid` failing on Windows. Rejected at the builder boundary in combination with `Pty` (a ConPTY run spawns through a different call that does not carry the token) and with the Unix-only `Uid`/`Gid`/`Groups`/`Umask`/`Setsid` family (a command carrying both halves could not run on *any* host). Elevation is unaffected: a restricted token cannot gain rights, only lose them, so this never turns into a privilege *escalation* path.

Returns: Command

this.WorkingDirectory

Full Usage: this.WorkingDirectory

Returns: string option

The working directory, when overridden.

Returns: string option

Type something to start searching.