processkit
Child-process management for Rust, in two layers:
- Process groups (
ProcessGroup) — spawn a child as the root of a process tree that is killed as a unit when the group is dropped, using Windows Job Objects, Linux cgroup v2 (with a POSIX process-group fallback) and a POSIX process group on macOS/BSD, so no descendant ever outlives its owner. - Process runner (
Command) — async (tokio) run-and-capture of a child'sstdout/stderrand exit status, built on the group layer, with a mockableProcessRunnerseam for tests.
Async throughout. Errors are structured (Error); a non-zero exit is reported in
the result, not raised, until you call ProcessResult::ensure_success.
Status: feature-complete — process groups, the runner and capture helpers, streaming, interactive stdin, push line-handlers, output-buffer policies, encoding overrides, line counters, and CPU/memory stats. See
CHANGELOG.md.
Install
This crate requires a tokio runtime.
Usage
use ;
async
Async streaming and interactive I/O
The one-shot helpers above buffer the whole output. For long-running or
conversational children, start() returns a live RunningProcess you can
drive asynchronously.
Stream stdout line by line
Process each line as it arrives — no waiting for the child to exit, no buffering
the full output. StreamExt (re-exported from tokio-stream) provides .next():
use ;
async
Streaming does not auto-enforce the command's
timeout: it applies to the run-to-completion helpers (output_string/run/first_line). To bound a manual stream, wrap your loop intokio::time::timeoutand drop the handle (which kills the tree) on elapse.
Interactive stdin — write requests, read responses
Keep stdin open with keep_stdin_open(), take the writer with
standard_input(), then interleave async writes and reads:
use ;
async
Feed stdin from an async stream, react to stdout as it's read
Stdin::from_lines writes each item of any Stream<Item = String> as a line —
back it with a channel, a file tail, or a network source. Pair it with
on_stdout_line / on_stderr_line to handle output inline (the handler runs on
the read pump, in addition to capture):
use ;
use iter; // any `Stream<Item = String>` works
async
Wrapping a CLI tool
CliClient + the cli_client! macro turn a typed wrapper around an external
tool (git, jj, gh, …) into just its parsers — the runner is injectable, so
the wrapper is hermetically testable with a ScriptedRunner (no subprocess):
use ;
use Path;
cli_client!
Testing
License
Licensed under the MIT License.