silk/child_process
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc.
Portable blocking child execution from structured byte arguments to fully captured output.
When to use
Build a ProcessRequest when one executable should run directly. This API is not a shell:
spaces, quotes, and metacharacters in an argument remain data and are never parsed as command
syntax.
Details
Requests preserve NUL-free argument and environment-entry bytes in insertion order. The
environment begins empty, and the working directory is inherited unless requestWithin
selects one. Child standard input is closed. ChildProcess.execute blocks until termination and
owns complete stdout and stderr captures in ProcessOutcome. A nonzero exit is outcome data.
ProcessError is reserved for failing to spawn, wait, or capture; it carries a stable
portable reason and may retain a provider code. Execution also reports OutOfMemoryError when
captured output cannot be owned.
Gotchas
An argument, environment name, or environment value must not contain NUL. The request uses NUL as its entry separator, and a native provider cannot preserve an embedded NUL as data.
Examples
Handle a nonzero child exit as outcome data
import silk.bytes { Bytes }
import silk.child_process { ChildProcess, ProcessError, ProcessOutcome, ProcessRequest }
import silk.allocator { Allocator, OutOfMemoryError }
import silk.effect { Effect }
import silk.filesystem { Path, FileError }
import silk.option { Option }
struct Completed {}
effect fn execute(self: &mut Completed, request: &ProcessRequest) -> ProcessOutcome
! ProcessError | OutOfMemoryError
? &mut Allocator {
return ChildProcess.exited(7, Bytes.make(), Bytes.make())
}
impl ChildProcess for Completed {
execute: Completed.execute
}
effect fn program() -> i32
! FileError | OutOfMemoryError | ProcessError {
let mut allocator = Allocator.systemAllocatorProvider()
let mut provider = Completed {}
let path = run Path.make("/tool")
|> Effect.provideMut<Allocator>(&mut allocator)
let request = run ChildProcess.request(&path)
|> Effect.provideMut<Allocator>(&mut allocator)
let outcome = run ChildProcess.submit(&request)
|> Effect.provideMut<ChildProcess>(&mut provider)
|> Effect.provideMut<Allocator>(&mut allocator)
return match move ChildProcess.exitCode(&outcome) {
Option<i32>.Some {value} => 35 + value
Option<i32>.None => 1
}
}
effect fn recover(error: FileError | OutOfMemoryError | ProcessError) -> i32 {
return 0
}
pub fn main() -> i32 {
return run Effect.catchAll(program(), recover)
}Import as ChildProcess with import silk.child_process { ChildProcess }.
Public declarations: 8.
ProcessOperation
pub struct ProcessOperationA provider-reported execution stage for one ProcessError.
Field code
pub code: i32The stable numeric code for the provider-reported execution stage.
ProcessReason
pub struct ProcessReasonA portable recovery category for one ProcessError.
Field code
pub code: i32The stable numeric code for the portable recovery category.
ProcessError
pub struct ProcessErrorA typed failure to start, wait for, or capture one child process.
Details
operation identifies the provider-reported stage. reason gives a portable recovery category.
Use providerCode when diagnostics also need a provider-defined numeric code.
A child that exits with a nonzero code produces ProcessOutcome data instead of this error.
Field operation
pub operation: ProcessOperationThe execution stage reported by the provider.
Field reason
pub reason: ProcessReasonThe portable category that callers can use for recovery.
ProcessRequest
pub struct ProcessRequestOne owned child-process request with ordered arguments and an explicit environment.
Details
Arguments and environment entries are exact platform bytes rather than checked text, so a value received from the platform can be handed to a child unchanged. Entries are retained in the order they were added, and the environment starts empty: a child sees no variable that this request did not name.
Gotchas
Argument, environment-name, and environment-value bytes must not contain NUL. NUL separates entries in the provider request format.
Exited
pub struct ExitedA completed child process that returned an exit code and two owned captures.
Field code
pub code: i32The code the child returned. Any value, including a nonzero one, is ordinary data.
Field output
pub output: BytesThe complete captured standard output, owned by this outcome.
Field errors
pub errors: BytesThe complete captured standard error, owned by this outcome.
Signaled
pub struct SignaledA completed child process that a signal terminated, with two owned captures.
Field signal
pub signal: i32The platform signal number that terminated the child.
Field output
pub output: BytesThe complete captured standard output, owned by this outcome.
Field errors
pub errors: BytesThe complete captured standard error, owned by this outcome.
ProcessOutcome
pub struct ProcessOutcomeOne completed child execution, represented as an exit or signal termination.
Details
An exit code and a terminating signal are distinct members rather than one integer, so a caller can never read a signal number as though it were an exit code.
Field value
pub value: silk/child_process.Exited | silk/child_process.SignaledThe completed outcome.
ChildProcess
pub service ChildProcessA portable blocking child-process service with complete output capture.
Details
execute closes child standard input and blocks until termination. The returned outcome owns
complete standard-output and standard-error captures. A nonzero exit code is outcome data.
A start, wait, or capture failure produces ProcessError. Owning either capture can also
produce OutOfMemoryError. The operation needs exclusive provider and allocator requirements.
Operation execute
effect<'life0> fn execute<'life0>(request: &'life0 silk/child_process.ProcessRequest) -> ProcessOutcome ! ProcessError | OutOfMemoryError ? &mut ChildProcess | &mut AllocatorRuns one request to termination and returns owned captures of both output streams.
Details
This operation blocks and closes the child's standard input. A nonzero exit code returns on
the success channel. Start, wait, and capture failures produce ProcessError.
Associated function ChildProcess.spawnOperation
pub fn spawnOperation() -> ProcessOperationReturns the stage for preparing and starting the child process.
Associated function ChildProcess.waitOperation
pub fn waitOperation() -> ProcessOperationReturns the stage for waiting until the child process terminates.
Associated function ChildProcess.captureOperation
pub fn captureOperation() -> ProcessOperationReturns the stage for copying the completed output and error streams.
Associated function ChildProcess.operationCode
pub fn operationCode(operation: ProcessOperation) -> i32Returns the stable numeric code for an execution stage.
Associated function ChildProcess.notFound
pub fn notFound() -> ProcessReasonReturns the reason used when no executable exists at the requested path.
Associated function ChildProcess.permissionDenied
pub fn permissionDenied() -> ProcessReasonReturns the reason used when the provider denies access to the requested executable.
Associated function ChildProcess.invalidRequest
pub fn invalidRequest() -> ProcessReasonReturns the reason used when the provider cannot present the request to its process boundary.
Associated function ChildProcess.noSpace
pub fn noSpace() -> ProcessReasonReturns the reason used when process setup or captured output exhausts provider storage.
Associated function ChildProcess.unsupported
pub fn unsupported() -> ProcessReasonReturns the reason used when the provider does not support the requested process operation.
Associated function ChildProcess.other
pub fn other() -> ProcessReasonReturns the reason used when no other portable recovery category applies.
Associated function ChildProcess.reasonCode
pub fn reasonCode(reason: ProcessReason) -> i32Returns the stable numeric code for a portable recovery category.
Associated function ChildProcess.failure
pub fn failure(operation: ProcessOperation, reason: ProcessReason) -> ProcessErrorCreates a process failure without a provider-defined numeric code.
Associated function ChildProcess.failureWithCode
pub fn failureWithCode(operation: ProcessOperation, reason: ProcessReason, code: i32) -> ProcessErrorCreates a process failure with a provider-defined numeric code for diagnostics.
Associated function ChildProcess.providerCode
pub fn providerCode<'life0>(error: &'life0 silk/child_process.ProcessError) -> silk/option.Option<i32>Returns the provider-defined numeric code, or None when the failure has no such code.
Associated function ChildProcess.request
pub effect<'life0> fn request<'life0>(program: &'life0 silk/filesystem.Path) -> ProcessRequest ! OutOfMemoryError ? &mut AllocatorCreates a request for program with no arguments, an empty environment, and the caller's
own working directory.
Associated function ChildProcess.requestWithin
pub effect<'env> fn requestWithin<'life0: 'env, 'life1: 'env, 'env>(program: &'life0 silk/filesystem.Path, directory: &'life1 silk/filesystem.Path) -> ProcessRequest ! OutOfMemoryError ? &mut AllocatorCreates a request that runs program in directory instead of the caller's
working directory.
Associated function ChildProcess.addArgument
pub effect<'env> fn addArgument<'life0: 'env, 'life1: 'env, 'env>(self: &'life0 mut silk/child_process.ProcessRequest, value: &'life1 [u8]) -> () ! OutOfMemoryError ? &mut AllocatorAppends one NUL-free byte argument after all arguments already in the request.
Details
The request copies value and preserves argument order.
Gotchas
value must not contain NUL. NUL is the entry separator used by process providers.
If allocation fails, do not reuse self; it can contain an incomplete argument entry.
Associated function ChildProcess.setVariable
pub effect<'env> fn setVariable<'life0: 'env, 'life1: 'env, 'life2: 'env, 'env>(self: &'life0 mut silk/child_process.ProcessRequest, name: &'life1 [u8], value: &'life2 [u8]) -> () ! OutOfMemoryError ? &mut AllocatorAppends one NUL-free environment entry as name, =, and value bytes.
Details
The request starts with an empty environment and preserves insertion order. This function does not read or merge the caller's environment.
Gotchas
name and value must not contain NUL. The request builder does not validate environment-name
grammar beyond this provider-format requirement.
If allocation fails, do not reuse self; it can contain an incomplete environment entry.
Associated function ChildProcess.program
pub fn program<'life0>(self: &'life0 silk/child_process.ProcessRequest) -> &'life0 [u8]Borrows the executable path bytes for the lifetime of the request borrow.
Associated function ChildProcess.arguments
pub fn arguments<'life0>(self: &'life0 silk/child_process.ProcessRequest) -> &'life0 [u8]Borrows all ordered arguments as one block of NUL-terminated entries.
Associated function ChildProcess.argumentCount
pub fn argumentCount<'life0>(self: &'life0 silk/child_process.ProcessRequest) -> usizeReturns the number of calls to addArgument that completed successfully.
Associated function ChildProcess.environment
pub fn environment<'life0>(self: &'life0 silk/child_process.ProcessRequest) -> &'life0 [u8]Borrows the explicit environment as one block of NUL-terminated name=value entries.
Associated function ChildProcess.environmentCount
pub fn environmentCount<'life0>(self: &'life0 silk/child_process.ProcessRequest) -> usizeReturns the number of calls to setVariable that completed successfully.
Associated function ChildProcess.workingDirectory
pub fn workingDirectory<'life0>(self: &'life0 silk/child_process.ProcessRequest) -> &'life0 [u8]Borrows the selected working-directory bytes, or an empty view when the child inherits one.
Associated function ChildProcess.hasWorkingDirectory
pub fn hasWorkingDirectory<'life0>(self: &'life0 silk/child_process.ProcessRequest) -> boolReports whether the request selects a working directory instead of inheriting one.
Associated function ChildProcess.exited
pub fn exited(code: i32, output: Bytes, errors: Bytes) -> ProcessOutcomeCreates an exited outcome that owns output and errors.
Associated function ChildProcess.signaled
pub fn signaled(signal: i32, output: Bytes, errors: Bytes) -> ProcessOutcomeCreates a signaled outcome that owns output and errors.
Associated function ChildProcess.isSignaled
pub fn isSignaled<'life0>(outcome: &'life0 silk/child_process.ProcessOutcome) -> boolReports whether a signal terminated the child instead of an exit code.
Associated function ChildProcess.exitCode
pub fn exitCode<'life0>(outcome: &'life0 silk/child_process.ProcessOutcome) -> silk/option.Option<i32>Returns the exit code, or None when a signal terminated the child.
Associated function ChildProcess.terminatingSignal
pub fn terminatingSignal<'life0>(outcome: &'life0 silk/child_process.ProcessOutcome) -> silk/option.Option<i32>Returns the terminating signal number, or None when the child returned an exit code.
Associated function ChildProcess.outputBytes
pub fn outputBytes<'life0>(outcome: &'life0 silk/child_process.ProcessOutcome) -> &'life0 [u8]Borrows the complete captured standard output without consuming the outcome.
Associated function ChildProcess.errorBytes
pub fn errorBytes<'life0>(outcome: &'life0 silk/child_process.ProcessOutcome) -> &'life0 [u8]Borrows the complete captured standard error without consuming the outcome.
Associated function ChildProcess.submit
pub effect<'life0> fn submit<'life0>(request: &'life0 silk/child_process.ProcessRequest) -> ProcessOutcome ! ProcessError | OutOfMemoryError ? &mut ChildProcess | &mut AllocatorRuns the active ChildProcess provider for one request.
Details
This wrapper preserves the service contract: it blocks, closes child input, and returns complete owned captures. It requires exclusive child-process and allocator providers.