command-group

Rust extension trait that spawns child processes in a process group or Windows job object so you can control them as a unit.

Library
Cargo
v5.0.1
44stars
Apache-2.0 OR MIT

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
23/100Needs Attention
Development Activity0
Maintenance0
Community24
Maturity56
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
80/100Excellent
Architecture80
Code Quality78
Innovation82
Learning Curve80

command-group is a small Rust crate that extends the standard library’s std::process::Command (and, optionally, Tokio’s async Command) with the ability to spawn a child inside its own process group on Unix or a job object on Windows. This lets you wait on, signal, and kill an entire tree of descendant processes as a single unit, rather than leaking orphaned grandchildren when you terminate a shell or wrapper command.

The library exposes ergonomic group_spawn, group_output, and builder methods through the CommandGroup and AsyncCommandGroup traits, plus a UnixChildExt trait for sending POSIX signals. Note that the project is deprecated in favour of its successor, process-wrap, but remains widely used and downloaded across the Rust ecosystem.

What You Get

  • A CommandGroup extension trait adding group_spawn, group, and group_output to std::process::Command.
  • An AsyncCommandGroup trait providing the same ergonomics for Tokio’s async Command behind the with-tokio feature.
  • Cross-platform process-group semantics: POSIX process groups on Unix and job objects on Windows, from one API.
  • A UnixChildExt trait for sending signals (SIGTERM, SIGKILL, etc.) to a child or its entire group on Unix.
  • A CommandGroupBuilder for setting group-specific flags not available on the plain Command type.

Common Use Cases

  • Killing an entire subprocess tree when terminating a wrapper command like watch, sh -c, or a build runner.
  • Building file watchers, task runners, or supervisors that must clean up every descendant process on shutdown.
  • Gracefully signalling a group of processes with SIGTERM before escalating to SIGKILL.
  • Managing long-running daemons spawned from async Tokio code without leaking orphaned children.

Under The Hood

Architecture

The crate is organised into parallel stdlib and tokio module trees (src/stdlib.rs, src/tokio.rs), each further split into platform-specific unix.rs and windows.rs implementations plus a child submodule wrapping the spawned handle. The public surface is a set of extension traits (CommandGroup, AsyncCommandGroup) re-exported from lib.rs, which delegate to a shared CommandGroupBuilder (src/builder.rs); the builder ultimately calls into the OS layer to place the child in a POSIX process group (via nix) or a Windows job object (via winapi). An ErasedChild type in each tree abstracts over the spawned handle so callers get uniform wait/kill semantics.

Tech Stack

Written in Rust (edition 2021, MSRV 1.68.0) with essentially no mandatory runtime dependencies. Unix builds pull in nix (fs, poll, signal features) and Windows builds pull in winapi (job object and process-thread APIs); the optional with-tokio feature adds async-trait and tokio. Platform selection is handled entirely through cfg(unix) / cfg(windows) target-specific dependency tables in Cargo.toml.

Code Quality

The crate enforces #![warn(missing_docs)] and ships extensive doc comments with runnable examples on every trait method. There is a dedicated tests/ directory with separate suites per platform and runtime (stdlib_unix.rs, stdlib_windows.rs, tokio_unix.rs, tokio_windows.rs) and six runnable examples under examples/. Code is cleanly factored along platform and runtime boundaries, and rustfmt configuration is checked in.

API Design

The public API is deliberately minimal and mirrors the familiar Command builder pattern: you simply swap .spawn() for .group_spawn() or .output() for .group_output(), keeping migration friction near zero. Async support reuses the exact same method names behind a feature flag, and Unix signalling is exposed through a focused UnixChildExt trait. Naming is consistent and discoverable, and the extensive rustdoc plus examples make onboarding straightforward.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search