Repository F# setup
open System
open System.IO
open System.Threading
open System.Threading.Tasks
open Axial
open Axial.Console
open Axial.FileSystem
open Axial.PlatformService
open Axial.ProcessProcesses
Axial.Process lets a command-line program start an external command without giving up typed failures, cancellation,
or cleanup. You describe the command first, choose what happens to its input and output, then run it.
A script
For a small command-line program, describe commands, connect them, choose where output goes, then call run:
Show page setup
// Setup for the checked examples on this page.
open System
open System.IO
open System.Threading
open System.Threading.Tasks
open Axial
open Axial.Console
open Axial.FileSystem
open Axial.PlatformService
open Axial.Process
/// Fails the docs test when an example's result differs from the value shown.
let shouldEqual expected actual =
if actual <> expected then failwithf "Expected %A but got %A" expected actual// The examples on this page start real processes with the live service.
let host : ProcessHostEnvironment =
{ Process = Process.live Clock.live FileSystem.live Console.live
Console = Console.live }
let stdoutOf (workflow: Flow<ProcessHostEnvironment, ProcessError, ProcessResult>) : string =
match Flow.run host workflow with
| Exit.Success result -> result.StdOut
| Exit.Failure cause -> failwithf "%A" cause
host: ProcessHostEnvironmentAxial.Process.ProcessHostEnvironmentThe live environment used by <c>Process.run</c> at a command-line host boundary. Application workflows normally use their own environment record and <c>Process.runWith</c>.
Process: IProcessAxial.Process.ProcessModulelive: IClock -> IFileSystem -> IConsole -> IProcessCreates a live process service using an explicit clock for transcript timestamps and durations.
Axial.PlatformService.ClockHelpers for the clock service.
live: IClockCreates a live clock backed by and a monotonic timer.
Axial.FileSystem.FileSystemModulelive: IFileSystemCreates a live file-system service backed by , , and .
Axial.Console.ConsoleModulelive: IConsoleCreates a live console service backed by .
Console: IConsolestdoutOf: Flow<ProcessHostEnvironment,ProcessError,ProcessResult> -> stringworkflow: Flow<ProcessHostEnvironment,ProcessError,ProcessResult>Axial.Flow`3Represents a cold workflow that reads an environment, returns a typed result, and is executed explicitly through one of its execution members such as ToTask, ToAsync, or RunSynchronously. The type of the environment dependency. The type of the failure value. The type of the success value.
Axial.Process.ProcessErrorA recoverable process startup, timeout, stage, or I/O failure. Interrupting the workflow is not an error: it terminates the processes and surfaces as <c>Cause.Interrupt</c>.
Axial.Process.ProcessResultThe complete structured transcript returned by a process execution.
stringAn abbreviation for the CLI type . Basic Types
Axial.Flowrun: 'env -> Flow<'env,'error,'value> -> Exit<'value,'error>Runs the workflow and blocks until the final exit is available. The environment used by the workflow. The workflow to run. The final workflow exit. let exit = workflow |> Flow.run environment
Axial.Exit`2Represents the final outcome of a workflow execution. The type of the success value. The type of the domain-specific failure value.
SuccessThe workflow completed successfully.
result: ProcessResultStdOut: stringFailureThe workflow failed due to a specific cause.
cause: Cause<ProcessError>failwithf: Printf.StringFormat<'T,'Result> -> 'TPrint to a string buffer and raise an exception with the given result. Helper printers must return strings. The formatter. The formatted result. See Printf.failwithf (link: ) for examples.
open Axial.Process.DSL // Short pipeline helpers: cwd, env, timeout, =>, capture, run
let recentCommits (repository: string) =
cmd $"git log --oneline -20"
|> cwd repository
|> env "NO_COLOR" "1"
|> timeout (TimeSpan.FromSeconds 5.0)
=> cmd $"head -5"
|> capture
// In a script, finish with `|> run`: it runs the workflow with live services and returns an exit code.
let script () = recentCommits "." |> run
AxialProcessAxial.Process.DSLrecentCommits: string -> Flow<'a,ProcessError,ProcessResult>repository: stringstringAn abbreviation for the CLI type . Basic Types
cmd: FormattableString -> ProcessSpecBuilds a command-line-shaped command while preserving every interpolation hole as one argument.
(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
cwd: string -> ProcessSpec -> ProcessSpecenv: string -> string -> ProcessSpec -> ProcessSpectimeout: TimeSpan -> ProcessSpec -> ProcessSpecSets the maximum execution time for a command or specification. Example: cmd $"service-device" |> timeout (TimeSpan.FromSeconds 30.0) |> capture
System.TimeSpanRepresents a time interval.
FromSeconds: float -> TimeSpanReturns a that represents a specified number of seconds, where the specification is accurate to the nearest millisecond. A number of seconds, accurate to the nearest millisecond. An object that represents . is less than or greater than . -or- is . -or- is . is equal to .
(=>): ^source -> ^destination -> ^resultConnects a typed input, command, specification, or terminal output endpoint.
capture: ProcessSpec -> Flow<'a,ProcessError,ProcessResult>Runs a command or specification and captures stdout and stderr.
script: unit -> intrun: Flow<ProcessHostEnvironment,ProcessError,'a> -> intStarts a process Flow with live services and returns a command-line exit code.
let lines = stdoutOf (recentCommits ".") |> _.Split('\n', StringSplitOptions.RemoveEmptyEntries)
(lines.Length >= 1 && lines.Length <= 5) |> shouldEqual true
lines: string arraystdoutOf: Flow<ProcessHostEnvironment,ProcessError,ProcessResult> -> stringrecentCommits: string -> Flow<'a,ProcessError,ProcessResult>(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
_arg1: stringSplit: char * StringSplitOptions -> string arraySystem.StringSplitOptionsSpecifies whether applicable method overloads include or omit empty substrings from the return value.
RemoveEmptyEntries: StringSplitOptionsThe return value does not include array elements that contain an empty string
Length: intGets the total number of elements in all the dimensions of the . The total number of elements in all the dimensions of the ; zero if there are no elements in the array. The array is multidimensional and contains more than elements.
(>=): 'T -> 'T -> boolStructural greater-than-or-equal The first parameter. The second parameter. The result of the comparison. 5 >= 1 // Evaluates to true 5 >= 5 // Evaluates to true [1; 5] >= [1; 6] // Evaluates to false
(&&): bool -> bool -> boolBinary 'and'. When used as a binary operator the right hand value is evaluated only on demand The first value. The second value. The result of the operation.
(<=): 'T -> 'T -> boolStructural less-than-or-equal comparison The first parameter. The second parameter. The result of the comparison. 5 <= 1 // Evaluates to false 5 <= 5 // Evaluates to true [1; 5] <= [1; 6] // Evaluates to true
shouldEqual: 'a -> 'a -> unitProcess.command (and DSL cmd) preserves each interpolation hole as one native argument. cwd, env, and
timeout return updated command specifications. => connects stdout to the next command's stdin. capture creates
a Flow that retains stdout and stderr; none of those steps starts a child process. The final run starts the Flow
with live clock, filesystem, console, and process services. It returns 0 on success, or writes a redacted error and
returns an appropriate nonzero exit code. Use it at a .NET command-line application's outermost boundary.
For a server, worker, or application Flow, see run a process in an application Flow.
That guide explains the explicit process capability, live wiring, test fakes, and the difference between Process.toFlow
and Flow.run.
Choose how the command communicates
| Need | DSL | Full API | What you receive |
|---|---|---|---|
| Inspect output after the command exits | capture |
Process.capture |
ProcessResult: stdout, stderr, bytes, exit codes, and timing |
| Show output as it arrives | console |
Process.console |
Structured completion data |
| React to output before completion | stream |
Process.stream |
A backpressured stream of output and completion events |
| Send final output elsewhere | writeTo / appendTo |
Process.stdout / Process.stderr |
A configured command |
New process specifications capture stdout and stderr by default. capture makes that choice explicit and replaces a prior output policy. Output capture and destinations explains bounded capture, files, console forwarding, and tees. Streaming output covers long-running commands and incremental handling.
What Axial owns
The process service starts the native topology; Axial owns its lifetime. A timeout or interruption terminates every started stage, including partially started pipelines, before the enclosing Flow finishes. Expected process problems remain ProcessError values instead of becoming unstructured exceptions.

