On this page
tecs.io.Process
Streaming child processes.
new starts the child immediately and returns its live standard-stream endpoints. Piped stdin is a Writer; piped stdout and stderr are Reader values. The process owns all three endpoints. Closing one endpoint closes only that pipe; closing the process closes every endpoint, terminates a live child, and reaps it. Buffers and byte views passed to an endpoint remain caller-owned.
Process:communicate is the complete-exchange form for tools and build steps. It feeds stdin while draining stdout and stderr concurrently, so neither output pipe can fill and deadlock the child:
tecs.scoped(function(scope: tecs.Scope)
local child <const> = scope:own(tecs.io.Process.new({
args = {"git", "status", "--porcelain"},
timeoutMs = 2000,
}))
local result, communicateReason = child:communicate()
if result == nil then
error(communicateReason)
end
if result:succeeded() then
print(result.output)
else
io.stderr:write(result.errorOutput)
end
end)Interactive children use the same reader and writer vocabulary as files, buffers, and transforms. Closing stdin sends EOF:
tecs.scoped(function(scope: tecs.Scope)
local child <const> = scope:own(tecs.io.Process.new({
args = {"/bin/cat"}
}))
local written, writeReason = child.stdin:write("one request\n")
if written == nil then
error(writeReason)
end
child.stdin:close()
local reply, readReason = child.stdout:read(4096)
if reply == nil then
error(readReason)
end
print(reply)
end)Frame-driven code uses readAvailable, readAvailableInto, and the matching writer methods. Nil without a reason means an open pipe has no bytes or capacity right now; an empty string or zero means output EOF. These methods make backpressure visible instead of growing an implicit queue. Buffer and byte-view variants avoid constructing Lua strings.
Use "inherit" for a CLI that should share the terminal, "null" to discard a stream, and stderr = "stdout" for one ordered transcript. A nonzero child exit still produces a ready Exit; succeeded performs the separate exit-code check. Spawn failures return nil and a reason. Deadlines and explicit kills set the exit's killed fields.
Module contents
Constructors
| Constructor | Description |
|---|---|
new |
Starts a caller-owned child process with streaming standard I/O. |
Types
| Type | Kind | Description |
|---|---|---|
CommunicateOptions |
record | CommunicateOptions controls a complete duplex exchange. |
ErrorMode |
enum | ErrorMode selects where a child writes standard error. |
Exit |
record | Exit describes how a child stopped. |
InputMode |
enum | InputMode selects where a child reads standard input. |
Options |
record | Options configures a child and its standard streams. |
OutputMode |
enum | OutputMode selects where a child writes standard output. |
Reader |
interface | Reader reads one live child-process output pipe. |
Result |
record | Result contains a completed duplex exchange. |
Writer |
interface | Writer writes one live child-process input pipe. |
Functions
| Function | Kind | Description |
|---|---|---|
communicate |
Instance | Feeds stdin and captures stdout and stderr without pipe deadlock. |
isRunning |
Instance | Returns whether the child has not stopped yet. |
kill |
Instance | Requests that the child terminate. |
Values
| Value | Type | Description |
|---|---|---|
finished |
Future |
Read-only. Settles ready with the exit description after the child stops. |
pid |
integer |
Read-only. Reports the operating-system process identifier. |
stderr |
Reader |
Read-only. Provides standard error when its mode is "pipe", or nil when error output is inherited, discarded, or... |
stdin |
Writer |
Read-only. Provides standard input when its mode is "pipe", or nil when input is inherited or discarded. |
stdout |
Reader |
Read-only. Provides standard output when its mode is "pipe", or nil when output is inherited or discarded. |
Constructors
tecs.io.Process.new Static
Starts a caller-owned child process with streaming standard I/O.
Piped endpoints are nonblocking at their readAvailable and writeAvailable boundaries. The process owns them, while buffers and byte views passed to endpoint methods remain caller-owned.
Arguments
| Name | Type | Description |
|---|---|---|
options |
Options |
The caller supplies the program, arguments, environment, working directory, standard-stream modes, and optional deadline. |
Returns
| Type | Description |
|---|---|
Process |
Returns a caller-owned process when the platform starts it. |
string |
Returns the platform reason when the first return is nil. |
Examples
tecs.scoped(function(scope: tecs.Scope)
local child <const> = scope:own(tecs.io.Process.new({
args = {"git", "status", "--porcelain"},
cwd = tecs.io.Path.new("workspace"),
}))
local result, communicateReason = child:communicate()
assert(result, communicateReason)
end)tecs.scoped(function(scope: tecs.Scope)
local child <const> = scope:own(tecs.io.Process.new({
args = {"git", "rev-parse", "HEAD"},
timeoutMs = 2000,
}))
local result, communicateReason = child:communicate()
assert(result, communicateReason)
assert(result:succeeded())
print(result.output)
end)Types
tecs.io.Process.CommunicateOptions record
CommunicateOptions controls a complete duplex exchange.
record tecs.io.Process.CommunicateOptions
input: string | ByteView
maxOutputBytes: integer
endtecs.io.Process.CommunicateOptions.input field
Caller-writable. Supplies complete standard-input bytes as a string, open Buffer, or open ByteView. Omitted input sends EOF immediately.
tecs.io.Process.CommunicateOptions.input: string | ByteViewtecs.io.Process.CommunicateOptions.maxOutputBytes field
Caller-writable. Limits stdout and stderr together. Defaults to 268,435,456 bytes. Exceeding it forcibly terminates the child and returns a failure.
tecs.io.Process.CommunicateOptions.maxOutputBytes: integertecs.io.Process.ErrorMode enum
ErrorMode selects where a child writes standard error.
enum tecs.io.Process.ErrorMode
"inherit"
"null"
"pipe"
"stdout"
endtecs.io.Process.Exit record
Exit describes how a child stopped.
record tecs.io.Process.Exit
exitCode: integer
killed: boolean
timedOut: boolean
succeeded: function(self): boolean
endtecs.io.Process.Exit.exitCode field
Read-only. Reports the platform exit code, or the platform's best answer after termination.
tecs.io.Process.Exit.killed field
Read-only. Reports whether Tecs requested termination.
tecs.io.Process.Exit.timedOut field
Read-only. Reports whether the configured deadline requested that termination.
tecs.io.Process.Exit:succeeded Instance
Returns whether the child exited normally with code zero.
function tecs.io.Process.Exit.succeeded(self): booleanArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessExit |
The completed exit to inspect. |
Returns
| Type | Description |
|---|---|
boolean |
Returns true only for a normal zero exit. |
tecs.io.Process.InputMode enum
InputMode selects where a child reads standard input.
enum tecs.io.Process.InputMode
"inherit"
"null"
"pipe"
endtecs.io.Process.Options record
Options configures a child and its standard streams.
record tecs.io.Process.Options
args: {string}
cwd: string | Path
env: {string: string}
clearEnv: boolean
stdin: ProcessInputMode
stdout: ProcessOutputMode
stderr: ProcessErrorMode
timeoutMs: integer
endtecs.io.Process.Options.args field
Caller-writable. Supplies the program in args[1] followed by its arguments. A program without a separator resolves through PATH.
tecs.io.Process.Options.cwd field
Caller-writable. Selects the child's working directory as a string or Path, or omits it to inherit the current directory.
tecs.io.Process.Options.env field
Caller-writable. Overlays environment variables on the inherited environment, or supplies the complete environment with clearEnv.
tecs.io.Process.Options.clearEnv field
Caller-writable. Starts with an empty environment when true. Defaults to false.
tecs.io.Process.Options.stdin field
Caller-writable. Selects "pipe", "inherit", or "null" for standard input. Defaults to "pipe".
tecs.io.Process.Options.stdin: ProcessInputModetecs.io.Process.Options.stdout field
Caller-writable. Selects "pipe", "inherit", or "null" for standard output. Defaults to "pipe".
tecs.io.Process.Options.stdout: ProcessOutputModetecs.io.Process.Options.stderr field
Caller-writable. Selects "pipe", "inherit", "null", or "stdout" for standard error. Defaults to "pipe".
tecs.io.Process.Options.stderr: ProcessErrorModetecs.io.Process.Options.timeoutMs field
Caller-writable. Forcibly terminates the child after this many milliseconds, or omits the deadline. The deadline begins when the process is created.
tecs.io.Process.OutputMode enum
OutputMode selects where a child writes standard output.
enum tecs.io.Process.OutputMode
"inherit"
"null"
"pipe"
endtecs.io.Process.Reader interface
Reader reads one live child-process output pipe.
interface tecs.io.Process.Reader is Reader
isClosed: function(self): boolean
isEOF: function(self): boolean
readAvailable: function(self, maxBytes: integer): string, string
readAvailableInto: function(
self, destination: Buffer, offset: integer, maxBytes: integer
): integer, string
endInterfaces
| Interface |
|---|
Reader |
tecs.io.Process.Reader:isClosed Instance
Returns whether this endpoint has been closed.
function tecs.io.Process.Reader.isClosed(self): booleanArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessReader |
The process reader to inspect. |
Returns
| Type | Description |
|---|---|
boolean |
Returns true after close. |
tecs.io.Process.Reader:isEOF Instance
Returns whether the child closed its end and every byte was consumed.
function tecs.io.Process.Reader.isEOF(self): booleanArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessReader |
The process reader to inspect. |
Returns
| Type | Description |
|---|---|
boolean |
Returns true after end of file. |
tecs.io.Process.Reader:readAvailable Instance
Reads immediately available bytes without waiting.
Nil without a reason means the pipe remains open but has no bytes ready. An empty string means end of file.
function tecs.io.Process.Reader.readAvailable(
self, maxBytes: integer
): string, stringArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessReader |
The process reader whose pipe advances. |
maxBytes |
integer |
The caller supplies 1 through 65,536 bytes or omits it for 16,384. |
Returns
| Type | Description |
|---|---|
string |
Returns available bytes, nil when none are ready, or an empty string at end of file. |
string |
Returns a reason only when reading fails. |
Examples
tecs.scoped(function(scope: tecs.Scope)
local child <const> = scope:own(tecs.io.Process.new({
args = {"/bin/sh", "-c", "sleep 1; printf ready"},
}))
local chunk <const>, readReason = child.stdout:readAvailable()
assert(chunk == nil)
assert(readReason == nil)
end)tecs.io.Process.Reader:readAvailableInto Instance
Reads immediately available bytes into reusable storage.
Nil without a reason means no bytes are ready. Zero means end of file.
function tecs.io.Process.Reader.readAvailableInto(
self, destination: Buffer, offset: integer, maxBytes: integer
): integer, stringArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessReader |
The process reader whose pipe advances. |
destination |
Buffer |
The caller supplies an open destination buffer and retains ownership. |
offset |
integer |
The caller supplies a non-negative destination offset or omits it for zero. |
maxBytes |
integer |
The caller supplies 1 through 65,536 bytes or omits it for 16,384. |
Returns
| Type | Description |
|---|---|
integer |
Returns bytes read, nil when none are ready, or zero at end of file. |
string |
Returns a reason only when reading fails. |
tecs.io.Process.Result record
Result contains a completed duplex exchange.
record tecs.io.Process.Result
exit: ProcessExit
output: string
errorOutput: string
succeeded: function(self): boolean
endtecs.io.Process.Result.exit field
Read-only. Contains the child's exit description.
tecs.io.Process.Result.exit: ProcessExittecs.io.Process.Result.output field
Read-only. Contains every captured standard-output byte. It is empty when stdout was inherited or discarded.
tecs.io.Process.Result.errorOutput field
Read-only. Contains every captured standard-error byte. It is empty when stderr was inherited, discarded, or merged into stdout.
tecs.io.Process.Result.errorOutput: stringtecs.io.Process.Result:succeeded Instance
Returns whether the child exited normally with code zero.
function tecs.io.Process.Result.succeeded(self): booleanArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessResult |
The completed exchange to inspect. |
Returns
| Type | Description |
|---|---|
boolean |
Returns true only for a normal zero exit. |
tecs.io.Process.Writer interface
Writer writes one live child-process input pipe.
interface tecs.io.Process.Writer is Writer
isClosed: function(self): boolean
writeAvailable: function(
self, bytes: string, offset: integer, count: integer
): integer, string
writeAvailableFrom: function(
self, source: Buffer, offset: integer, count: integer
): integer, string
writeAvailableView: function(
self, source: ByteView, offset: integer, count: integer
): integer, string
endInterfaces
| Interface |
|---|
Writer |
tecs.io.Process.Writer:isClosed Instance
Returns whether this endpoint has sent EOF or been closed.
function tecs.io.Process.Writer.isClosed(self): booleanArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessWriter |
The process writer to inspect. |
Returns
| Type | Description |
|---|---|
boolean |
Returns true after close. |
tecs.io.Process.Writer:writeAvailable Instance
Writes as many immediately acceptable string bytes as possible.
Nil without a reason means the pipe has no capacity yet.
function tecs.io.Process.Writer.writeAvailable(
self, bytes: string, offset: integer, count: integer
): integer, stringArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessWriter |
The process writer whose pipe advances. |
bytes |
string |
The caller supplies binary bytes including embedded NULs. |
offset |
integer |
The caller supplies a zero-based string offset or omits it for zero. |
count |
integer |
The caller supplies a byte count or omits it for the remainder. |
Returns
| Type | Description |
|---|---|
integer |
Returns bytes accepted, or nil when none fit immediately. |
string |
Returns a reason only when writing fails. |
tecs.io.Process.Writer:writeAvailableFrom Instance
Writes an immediately acceptable buffer prefix without a Lua string.
function tecs.io.Process.Writer.writeAvailableFrom(
self, source: Buffer, offset: integer, count: integer
): integer, stringArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessWriter |
The process writer whose pipe advances. |
source |
Buffer |
The caller supplies an open source buffer and retains ownership. |
offset |
integer |
The caller supplies a zero-based source offset or omits it for zero. |
count |
integer |
The caller supplies a byte count or omits it for the remainder. |
Returns
| Type | Description |
|---|---|
integer |
Returns bytes accepted, or nil when none fit immediately. |
string |
Returns a reason only when writing fails. |
tecs.io.Process.Writer:writeAvailableView Instance
Writes an immediately acceptable immutable-view prefix.
function tecs.io.Process.Writer.writeAvailableView(
self, source: ByteView, offset: integer, count: integer
): integer, stringArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessWriter |
The process writer whose pipe advances. |
source |
ByteView |
The caller supplies an open source view and retains ownership. |
offset |
integer |
The caller supplies a zero-based source offset or omits it for zero. |
count |
integer |
The caller supplies a byte count or omits it for the remainder. |
Returns
| Type | Description |
|---|---|
integer |
Returns bytes accepted, or nil when none fit immediately. |
string |
Returns a reason only when writing fails. |
Functions
tecs.io.Process:communicate Instance
Feeds stdin and captures stdout and stderr without pipe deadlock.
The call blocks the current Lua thread, drains both output pipes while feeding input, closes stdin after the final byte, and returns only after the child exits and both captured pipes reach EOF. Run it in a worker when blocking is inappropriate.
function tecs.io.Process.communicate(
self, options: CommunicateOptions
): Result, stringArguments
| Name | Type | Description |
|---|---|---|
self |
Process |
The open process whose piped endpoints are consumed. |
options |
CommunicateOptions |
The caller supplies complete input and an output limit, or omits both. |
Returns
| Type | Description |
|---|---|
Result |
Returns the complete exchange result. |
string |
Returns a reason when communication fails or exceeds its output limit. |
Examples
tecs.scoped(function(scope: tecs.Scope)
local child <const> = scope:own(tecs.io.Process.new({
args = {"/bin/cat"}
}))
local result, communicateReason = child:communicate({
input = "request bytes\n",
maxOutputBytes = 1024 * 1024,
})
assert(result, communicateReason)
assert(result.output == "request bytes\n")
end)tecs.io.Process:isRunning Instance
Returns whether the child has not stopped yet.
function tecs.io.Process.isRunning(self): booleanArguments
| Name | Type | Description |
|---|---|---|
self |
Process |
The process to inspect. |
Returns
| Type | Description |
|---|---|
boolean |
Returns true while the child remains live. |
tecs.io.Process:kill Instance
Requests that the child terminate.
function tecs.io.Process.kill(self, force: boolean): boolean, stringArguments
| Name | Type | Description |
|---|---|---|
self |
Process |
The process to terminate. |
force |
boolean |
The caller requests an unhandleable termination when true or a graceful request when false or omitted. |
Returns
| Type | Description |
|---|---|
boolean |
Returns whether the request was delivered or the child had already stopped. |
string |
Returns the platform reason when the first return is false. |
Values
tecs.io.Process.finished variable
Read-only. Settles ready with the exit description after the child stops. Canceling this future does not terminate the separately owned process.
tecs.io.Process.pid variable
Read-only. Reports the operating-system process identifier.
tecs.io.Process.pid: integertecs.io.Process.stderr variable
Read-only. Provides standard error when its mode is "pipe", or nil when error output is inherited, discarded, or merged into stdout. The process owns it.
tecs.io.Process.stderr: Readertecs.io.Process.stdin variable
Read-only. Provides standard input when its mode is "pipe", or nil when input is inherited or discarded. The process owns it.
tecs.io.Process.stdin: Writertecs.io.Process.stdout variable
Read-only. Provides standard output when its mode is "pipe", or nil when output is inherited or discarded. The process owns it.
tecs.io.Process.stdout: Reader