# Native background processes for WASI extensions ## Function The optional Rust SDK `host-process` feature exposes `bt_extension_sdk::host_process::request(json)` to extension implementations. It starts native programs using argument arrays and returns immediately. Polling returns bounded output and state without waiting for process completion. This requires the updated BT host; older 1.1.4 binaries do not provide the import. This host capability runs outside the WASI sandbox and is available uniformly to extensions when the BT build includes it. Native programs inherit the authority of the operating-system account. Path declarations validate listed files for ownership and cleanup, but cannot constrain arbitrary native-program behavior. Installing an extension therefore means trusting its code. FFmpeg is selected by the video extension; the host has no media-specific logic. ## Syntax No manifest permission declaration is required. The SDK imports `bts_host.process_request(i32, i32, i32, i32) -> i32` with UTF-8 JSON requests and `{ok: value}` or `{error: message}` response envelopes. The SDK unwraps the envelope into `Result`. This is an extension-author API; BT applications normally use [video jobs](/en/docs/extensions/video). ## Request fields | Field | Type | Required | Default | Range / meaning | |---|---|---|---|---| | `op` | String | Yes | None | `spawn`, `poll`, `cancel`, `close`. | | `program` | String | For spawn | None | Nonempty executable path or PATH name; no implicit shell. | | `args` | Array[String] | For spawn | None | At most 256 arguments; all request JSON at most 64 KiB. | | `timeout_ms` | Int | No | 60000 | 1–300000; includes startup and automatically enforced by the worker. | | `read_paths` | Array[String] | No | [] | Existing project-relative paths retained as task ownership metadata. | | `write_paths` | Array[String] | No | [] | Project-relative outputs with an existing parent. | | `cleanup_paths` | Array[String] | No | [] | Caller-owned empty ordinary files reserved with create-new semantics; removed after failure, cancellation or timeout and process reaping. | | `id` | Int | Except spawn | None | Existing positive task ID in this extension instance. | | `discard_output` | Bool | No | false | For close only: atomically arrange deletion of owned `cleanup_paths`, even if the worker just succeeded. Ordinary close retains successful output. | Listed paths reject parent traversal and canonical paths outside the project root. The executable's working directory is the project root. Native execution retains the operating-system account's authority. The optional process-wide BT policy must allow process execution and filesystem use for requests listing paths. ## Return value `spawn` returns `{id: Int}`. `close` removes the handle immediately and returns `{closed: true}`; cancellation and process reaping continue in the worker. Poll and cancel return these fields: | Field | Type | Present | Default | Meaning / range | |---|---|---|---|---| | `state` | String | Always | None | `queued`, `running`, `succeeded`, `failed`, `cancelled`, `timed_out`. | | `stdout`, `stderr` | String | Always | Empty | Last 1 MiB of each stream; invalid UTF-8 uses replacement characters. | | `stdout_truncated`, `stderr_truncated` | Bool | Always | false | Earlier bytes exceeded the retained tail. | | `exit_code` | Int or JSON null | Always | null | Process exit code when available; null while running or without a numeric code. | | `elapsed_ms` | Int | Always | 0 | Milliseconds since submission; frozen at terminal state. | ## BT example ```bt source = video('@/clip.mp4', {}) job = source.frame('@/frame.png', 0.5) state = job.status() // Output: a queued, probing, running or terminal job state print state job.cancel() job.close() source.close() ``` ## Resource and platform notes Each instance allows four active processes and 32 retained handles; the host process allows 32 active processes across instances. Full capacity rejects new jobs immediately. Closing a running handle does not free its active reservation until the worker has reaped its process. There is no unbounded waiting queue. Each stream retains at most 1 MiB; the WASM SDK reuses a 16 MiB response buffer to cover JSON escaping. Closing all handles releases their output storage. Windows uses hidden child processes and a private kill-on-close Job Object; Unix uses a separate process group for normal cancellation. Native programs must not deliberately escape their process group/job. Abrupt Unix host termination does not guarantee descendant cleanup. Windows x64 is exercised locally; Unix code requires validation on its target. Dropping a store requests cancellation of its children. Successful outputs remain available after close. Web request scripts already run in BT's bounded blocking pool. Media commands run in dedicated bounded workers; applications poll once per request rather than sleeping in a request. No extra work is added to unrelated VM instructions.