# 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 is a native process permission, outside the WASI sandbox. Only trusted extensions and executables should receive it. Path declarations validate listed files, but cannot constrain arbitrary behavior of a native program. FFmpeg is selected by the video extension; the host has no media-specific logic. ## Syntax The manifest declares `"permissions": ["process", "fs_read", "fs_write"]`. 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; requires `fs_read`. | | `write_paths` | Array[String] | No | [] | Project-relative outputs, existing parent; requires `fs_write`. | | `cleanup_paths` | Array[String] | No | [] | Caller-owned empty ordinary files reserved with create-new semantics; removed after failure, cancellation or timeout and process reaping; requires `fs_write`. | | `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. Process and requested filesystem permissions must also be enabled by the running BT process. ## 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.