OS Process ABI v1 (os.process.*)
This document defines the stable bytes encodings used by the standalone-only subprocess builtins.
- Capture APIs (return
ResultBytesV1):os.process.run_capture_v1(req: bytes, caps: bytes) -> bytesos.process.spawn_capture_v1(req: bytes, caps: bytes) -> i32os.process.try_join_capture_v1(handle: i32) -> option_bytesos.process.join_capture_v1(handle: i32) -> bytes
- Streaming spawn (uses the same
ProcReqV1/ProcCapsV1layouts):os.process.spawn_piped_v1(req: bytes, caps: bytes) -> i32
Agents should build requests and caps via:
stdlib/os/0.2.0/modules/std/os/process/req_v1.x07.json(std.os.process.req_v1.*)stdlib/os/0.2.0/modules/std/os/process/caps_v1.x07.json(std.os.process.caps_v1.finish)
Callers must import std.os.process.req_v1 and std.os.process.caps_v1.
Agents should decode results via:
stdlib/os/0.2.0/modules/std/os/process.x07.json(std.os.process.is_err,std.os.process.err_code,std.os.process.resp_*)
Branded stdlib wrappers
The low-level os.process.* builtins accept raw bytes for req/caps and operate on the stable encodings defined below.
The stdlib builders/wrappers use branded bytes to prevent mixing encodings:
std.os.process.req_v1.finish(...) -> bytes@std.os.process.req_v1std.os.process.caps_v1.finish(...) -> bytes@std.os.process.caps_v1
And validators are available for safe casting:
std.os.process.req_v1.validate_v1(v: bytes_view) -> result_i32std.os.process.caps_v1.validate_v1(v: bytes_view) -> result_i32
Conventions
- Little-endian for all multi-byte integers.
u8: 1 byteu32_le: 4 bytes, unsigned, little-endianbytes: raw bytes (no implicit NUL terminator)
Error Codes (err_code: u32_le)
1:POLICY_DENIED2:INVALID_REQUEST3:SPAWN_FAILED4:TIMEOUT5:OUTPUT_LIMIT
Result Bytes (ResultBytesV1) (capture APIs only)
All capture APIs return a single bytes value with this encoding.
ERR
u8 tag = 0
u32_le err_code
u32_le flags (reserved; v1: 0)
OK (ProcRespV1)
u8 tag = 1
u8 ver = 1
u32_le exit_code
u32_le flags
u32_le stdout_len
bytes stdout
u32_le stderr_len
bytes stderr
Spawn Request (ProcReqV1)
u8 ver = 1
u8 flags (v1: MUST be 0)
u32_le argv_count
repeat argv_count:
u32_le arg_len
bytes arg
u32_le env_count
repeat env_count:
u32_le key_len
bytes key
u32_le val_len
bytes val
u32_le cwd_len
bytes cwd
u32_le stdin_len
bytes stdin
Notes:
argv[0]is the executable path. No shell expansion is performed.cwd_len=0means “inherit current working directory”.cwd_len>0sets the child working directory tocwd:run-os:cwdis treated as a path string (no NUL bytes).run-os-sandboxed: requirespolicy.process.allow_cwd=trueand resolvescwdas a safe relative path joined againstpolicy.process.allow_cwd_roots(first root thatchdir()succeeds with is used).
Resource Caps (ProcCapsV1)
u8 ver = 1
u32_le max_stdout_bytes
u32_le max_stderr_bytes
u32_le timeout_ms
u32_le max_total_bytes (0 = max_stdout_bytes + max_stderr_bytes)
Piped API v1 (streaming)
These are standalone-only and operate on a handle returned by os.process.spawn_piped_v1.
os.process.stdout_read_v1(handle: i32, max: i32) -> bytesos.process.stderr_read_v1(handle: i32, max: i32) -> bytesos.process.stdin_write_v1(handle: i32, chunk: bytes) -> i32(1 if accepted, 0 if closed)os.process.stdin_close_v1(handle: i32) -> i32(1 if closed, 0 if already closed)os.process.try_wait_v1(handle: i32) -> i32(1 if exited, 0 otherwise)os.process.join_exit_v1(handle: i32) -> i32(yield boundary; waits until exit)os.process.take_exit_v1(handle: i32) -> i32- returns
exit_codeon success - returns
-err_codefor subprocess errors (err_codetable above) - traps if called before exit or called twice
- returns