pub struct Competitor {
pub id: &'static str,
pub project: &'static str,
pub repository: &'static str,
pub commit: &'static str,
pub license: &'static str,
pub stars: u32,
pub source_files: u32,
pub registration_sites: u32,
pub scope: &'static [&'static str],
}
pub struct CorpusEntry {
pub id: &'static str,
pub competitors: &'static [&'static str],
pub upstream: &'static [&'static str],
}
pub struct ExcludedClass {
pub id: &'static str,
pub reason: &'static str,
}
pub const SNAPSHOT_DATE: &str = "2026-09-13";
pub const COMPETITORS: &[Competitor] = &[
Competitor {
id: "rust-std-process",
project: "Rust std::process",
repository: "rust-lang/rust",
commit: "24d472027454741e74f8e913755fbc7e03f02af5",
license: "Apache-2.0 OR MIT",
stars: 118_804,
source_files: 39,
registration_sites: 30,
scope: &["library/std/src/process/tests.rs", "tests/ui/process/*.rs"],
},
Competitor {
id: "tokio-process",
project: "Tokio process",
repository: "tokio-rs/tokio",
commit: "6276684c288d8e513410219fa2129c69df41af18",
license: "MIT",
stars: 33_143,
source_files: 9,
registration_sites: 10,
scope: &["tokio/tests/process_*.rs"],
},
Competitor {
id: "async-process",
project: "async-process",
repository: "smol-rs/async-process",
commit: "f4485f156f9294b86a5be37f7236bcf0cf93c76b",
license: "Apache-2.0 OR MIT",
stars: 216,
source_files: 2,
registration_sites: 24,
scope: &["tests/*.rs"],
},
Competitor {
id: "assert-cmd",
project: "assert_cmd",
repository: "assert-rs/assert_cmd",
commit: "a57ef45a33986390be3057c192c6bdbe61b8912d",
license: "Apache-2.0 OR MIT",
stars: 562,
source_files: 4,
registration_sites: 18,
scope: &["tests/**/*.rs (excluding fixture data)"],
},
Competitor {
id: "duct",
project: "duct",
repository: "oconnor663/duct.rs",
commit: "0195544c9d963d94348e8bc94fc60b8519e5516b",
license: "MIT",
stars: 1_043,
source_files: 1,
registration_sites: 39,
scope: &["src/test.rs"],
},
Competitor {
id: "xshell",
project: "xshell",
repository: "matklad/xshell",
commit: "52f71bac326aaac291d07146ea790ad886dd8131",
license: "Apache-2.0 OR MIT",
stars: 834,
source_files: 6,
registration_sites: 60,
scope: &["tests/**/*.rs (excluding tests/data)"],
},
Competitor {
id: "subprocess",
project: "subprocess",
repository: "hniksic/rust-subprocess",
commit: "e8cd8d0c930a790ce29373a8c3ee080dd746b9eb",
license: "Apache-2.0 OR MIT",
stars: 452,
source_files: 9,
registration_sites: 206,
scope: &["src/tests/**/*.rs", "tests/*.rs"],
},
Competitor {
id: "rust-cmd-lib",
project: "rust_cmd_lib",
repository: "rust-shell-script/rust_cmd_lib",
commit: "5a87af574a694fbfd0d4ade0c9b3dadc7cd463f6",
license: "Apache-2.0 OR MIT",
stars: 1_155,
source_files: 1,
registration_sites: 27,
scope: &["tests/*.rs"],
},
Competitor {
id: "run-script",
project: "run_script",
repository: "sagiegurari/run_script",
commit: "a79fdf0e15afca84681e5cf104bc080ceec60954",
license: "Apache-2.0",
stars: 131,
source_files: 7,
registration_sites: 45,
scope: &["src/*_test.rs", "tests/*.rs"],
},
Competitor {
id: "bkt",
project: "bkt",
repository: "dimo414/bkt",
commit: "76c4d24306bd9679ebc6cbacfdb9934ec9ba3be5",
license: "MIT",
stars: 358,
source_files: 3,
registration_sites: 48,
scope: &["src/lib.rs", "tests/*.rs"],
},
Competitor {
id: "rust-shell",
project: "rust-shell",
repository: "google/rust-shell",
commit: "8b1e775b09c133c9bfbfbb9be2e3a2b2f4219682",
license: "Apache-2.0",
stars: 224,
source_files: 4,
registration_sites: 11,
scope: &[
"src/command.rs",
"src/result.rs",
"src/shell_command.rs",
"tests/shell_tests.rs",
],
},
Competitor {
id: "shellfn",
project: "shellfn",
repository: "synek317/shellfn",
commit: "d8e2f39ab6633b388b0f9b47ea62c95dc7ee78ca",
license: "MIT",
stars: 220,
source_files: 1,
registration_sites: 72,
scope: &["tests/tests.rs"],
},
Competitor {
id: "rexpect",
project: "rexpect",
repository: "rust-cli/rexpect",
commit: "4c6a13d3d2c79cd63c8b12821530ec015b34fc71",
license: "Apache-2.0 OR MIT",
stars: 392,
source_files: 3,
registration_sites: 23,
scope: &["src/process.rs", "src/reader.rs", "src/session.rs"],
},
Competitor {
id: "expectrl",
project: "expectrl",
repository: "zhiburt/expectrl",
commit: "a2407de94df0b05dd794f79c57dea7b6f0a86f1f",
license: "MIT",
stars: 215,
source_files: 10,
registration_sites: 118,
scope: &[
"tests/*.rs",
"src/process/unix.rs",
"src/session/async_session.rs",
],
},
];
pub const PORTED_CASES: &[CorpusEntry] = &[
CorpusEntry {
id: "direct-exact-argv",
competitors: &[
"rust-std-process",
"tokio-process",
"async-process",
"assert-cmd",
"duct",
"xshell",
"subprocess",
"rust-cmd-lib",
"run-script",
"bkt",
],
upstream: &[
"library/std/src/process/tests.rs",
"tokio/tests/process_smoke.rs",
"tests/weird-args.rs",
],
},
CorpusEntry {
id: "argument-edge-cases",
competitors: &[
"rust-std-process",
"tokio-process",
"async-process",
"assert-cmd",
"duct",
"xshell",
"subprocess",
"rust-cmd-lib",
"run-script",
"bkt",
],
upstream: &[
"tests/ui/process/process-spawn-with-unicode-params.rs",
"tests/weird-args.rs",
"tests/escape-args.rs",
],
},
CorpusEntry {
id: "safe-template-interpolation",
competitors: &["duct", "xshell", "rust-cmd-lib"],
upstream: &["src/test.rs", "tests/it/main.rs", "tests/run_test.rs"],
},
CorpusEntry {
id: "cwd-string",
competitors: &[
"rust-std-process",
"tokio-process",
"async-process",
"assert-cmd",
"duct",
"xshell",
"subprocess",
"run-script",
"bkt",
],
upstream: &["tests/std.rs", "src/test.rs", "tests/it/main.rs"],
},
CorpusEntry {
id: "environment",
competitors: &[
"rust-std-process",
"tokio-process",
"async-process",
"assert-cmd",
"duct",
"xshell",
"subprocess",
"rust-cmd-lib",
"run-script",
"bkt",
"shellfn",
],
upstream: &[
"tests/ui/process/process-envs.rs",
"tests/std.rs",
"tests/it/env.rs",
],
},
CorpusEntry {
id: "stdout-stderr-separation",
competitors: &[
"rust-std-process",
"tokio-process",
"async-process",
"assert-cmd",
"duct",
"xshell",
"subprocess",
"rust-cmd-lib",
"run-script",
"bkt",
"rust-shell",
"shellfn",
"rexpect",
],
upstream: &[
"tests/std.rs",
"src/test.rs",
"src/tests/communicate.rs",
"tests/cli.rs",
"tests/shell_tests.rs",
"tests/tests.rs",
],
},
CorpusEntry {
id: "newline-preservation",
competitors: &[
"async-process",
"assert-cmd",
"duct",
"xshell",
"subprocess",
"bkt",
"shellfn",
],
upstream: &["tests/std.rs", "src/test.rs", "tests/assert.rs"],
},
CorpusEntry {
id: "unicode-output",
competitors: &[
"rust-std-process",
"async-process",
"assert-cmd",
"subprocess",
"bkt",
"shellfn",
],
upstream: &[
"tests/ui/process/process-spawn-with-unicode-params.rs",
"tests/std.rs",
],
},
CorpusEntry {
id: "large-output",
competitors: &[
"tokio-process",
"async-process",
"duct",
"xshell",
"subprocess",
"bkt",
],
upstream: &[
"tokio/tests/process_smoke.rs",
"tests/std.rs",
"src/test.rs",
],
},
CorpusEntry {
id: "nonzero-exit",
competitors: &[
"rust-std-process",
"tokio-process",
"async-process",
"assert-cmd",
"duct",
"xshell",
"subprocess",
"rust-cmd-lib",
"run-script",
"bkt",
"rust-shell",
"shellfn",
"rexpect",
],
upstream: &[
"tests/ui/process/process-exit.rs",
"tests/std.rs",
"src/test.rs",
],
},
CorpusEntry {
id: "stdin-string",
competitors: &[
"rust-std-process",
"tokio-process",
"async-process",
"assert-cmd",
"duct",
"xshell",
"subprocess",
"rust-cmd-lib",
"run-script",
"rexpect",
],
upstream: &["tests/std.rs", "src/test.rs", "src/tests/communicate.rs"],
},
CorpusEntry {
id: "lazy-execution",
competitors: &[
"tokio-process",
"async-process",
"duct",
"subprocess",
"bkt",
],
upstream: &[
"tokio/tests/process_smoke.rs",
"tests/std.rs",
"src/test.rs",
],
},
CorpusEntry {
id: "concurrent-execution",
competitors: &["tokio-process", "async-process", "duct", "subprocess"],
upstream: &[
"tokio/tests/process_smoke.rs",
"tests/std.rs",
"src/test.rs",
],
},
CorpusEntry {
id: "streamed-before-exit",
competitors: &[
"tokio-process",
"async-process",
"subprocess",
"bkt",
"rexpect",
],
upstream: &[
"tokio/tests/process_smoke.rs",
"tests/std.rs",
"src/reader.rs",
],
},
CorpusEntry {
id: "sync-execution",
competitors: &[
"rust-std-process",
"assert-cmd",
"duct",
"xshell",
"subprocess",
"rust-cmd-lib",
"run-script",
"bkt",
"rust-shell",
"shellfn",
"rexpect",
],
upstream: &[
"library/std/src/process/tests.rs",
"src/test.rs",
"tests/run_test.rs",
],
},
CorpusEntry {
id: "programmatic-pipeline",
competitors: &["duct", "subprocess", "rust-cmd-lib"],
upstream: &["src/test.rs", "src/tests/pipeline.rs", "tests/run_test.rs"],
},
CorpusEntry {
id: "spawn-error-propagation",
competitors: &[
"rust-std-process",
"tokio-process",
"async-process",
"assert-cmd",
"duct",
"xshell",
"subprocess",
"rust-cmd-lib",
"run-script",
"rust-shell",
"shellfn",
"rexpect",
],
upstream: &[
"tests/ui/process/process-spawn-nonexistent.rs",
"tokio/tests/process_smoke.rs",
"tests/std.rs",
],
},
CorpusEntry {
id: "stream-kill",
competitors: &[
"tokio-process",
"async-process",
"duct",
"subprocess",
"bkt",
"rust-shell",
"rexpect",
],
upstream: &[
"tokio/tests/process_kill_after_wait.rs",
"tests/std.rs",
"src/process.rs",
],
},
];
pub const MISSING_FEATURES: &[CorpusEntry] = &[
CorpusEntry {
id: "array-and-splat-interpolation",
competitors: &["xshell", "rust-cmd-lib"],
upstream: &["tests/it/main.rs", "tests/run_test.rs"],
},
CorpusEntry {
id: "non-utf8-arguments-and-environment",
competitors: &[
"rust-std-process",
"tokio-process",
"async-process",
"assert-cmd",
"subprocess",
],
upstream: &["tests/ui/process/env-funky-keys.rs", "tests/weird-args.rs"],
},
CorpusEntry {
id: "binary-input-and-lossless-output",
competitors: &[
"rust-std-process",
"tokio-process",
"async-process",
"assert-cmd",
"duct",
"subprocess",
"rexpect",
],
upstream: &["tests/std.rs", "src/test.rs", "src/tests/communicate.rs"],
},
CorpusEntry {
id: "environment-clear-and-remove",
competitors: &[
"rust-std-process",
"tokio-process",
"async-process",
"assert-cmd",
"duct",
"xshell",
"subprocess",
],
upstream: &[
"tests/ui/process/process-remove-from-env.rs",
"tests/std.rs",
],
},
CorpusEntry {
id: "custom-stdio-and-file-handles",
competitors: &[
"rust-std-process",
"tokio-process",
"async-process",
"assert-cmd",
"duct",
"subprocess",
],
upstream: &[
"library/std/src/process/tests.rs",
"tests/std.rs",
"src/test.rs",
],
},
CorpusEntry {
id: "max-buffer-policy",
competitors: &["subprocess"],
upstream: &["src/tests/communicate.rs"],
},
CorpusEntry {
id: "timeout-option",
competitors: &["assert-cmd", "xshell", "run-script", "rexpect", "expectrl"],
upstream: &["tests/assert.rs", "tests/it/timeout.rs", "src/session.rs"],
},
CorpusEntry {
id: "try-wait-and-shared-child-handle",
competitors: &[
"rust-std-process",
"tokio-process",
"async-process",
"subprocess",
],
upstream: &[
"tests/ui/process/try-wait.rs",
"tokio/tests/process_smoke.rs",
"src/process.rs",
],
},
CorpusEntry {
id: "native-exit-status-and-signal-metadata",
competitors: &[
"rust-std-process",
"tokio-process",
"async-process",
"subprocess",
],
upstream: &["tests/ui/process/signal-exit-status.rs", "tests/std.rs"],
},
CorpusEntry {
id: "expect-and-pty-session",
competitors: &["rexpect", "expectrl"],
upstream: &[
"src/process.rs",
"src/reader.rs",
"src/session.rs",
"tests/expect.rs",
"tests/interact.rs",
],
},
CorpusEntry {
id: "shell-expression-composition-and-redirection",
competitors: &["duct", "xshell", "rust-cmd-lib", "rust-shell"],
upstream: &[
"src/test.rs",
"tests/it/main.rs",
"tests/run_test.rs",
"src/command.rs",
],
},
CorpusEntry {
id: "subprocess-result-caching",
competitors: &["bkt"],
upstream: &["src/lib.rs", "tests/cli.rs", "tests/cwd.rs"],
},
CorpusEntry {
id: "typed-script-return-adapters",
competitors: &["shellfn"],
upstream: &["tests/tests.rs"],
},
];
pub const EXCLUDED_TEST_CLASSES: &[ExcludedClass] = &[
ExcludedClass {
id: "competitor-api-shape",
reason: "Pure constructor, trait, macro, and type-surface checks do not describe command-stream behavior; observable process results are classified by behavior instead.",
},
ExcludedClass {
id: "competitor-internals",
reason: "Mocks and assertions for private executors, parsers, async reactors, and implementation-only errors are not portable.",
},
ExcludedClass {
id: "upstream-runtime-regressions",
reason: "Rust compiler, Tokio runtime, and dependency regressions that do not exercise command-stream belong upstream.",
},
ExcludedClass {
id: "unrelated-utilities",
reason: "Filesystem helpers, assertion formatting, script discovery, and general shell utilities outside process execution are out of scope.",
},
ExcludedClass {
id: "platform-fixture-mechanics",
reason: "Upstream harness setup, compile-fail annotations, snapshots, permissions, and fixture self-tests are infrastructure rather than product behavior.",
},
];
pub fn pinned_source_url(competitor: &Competitor, path: &str) -> String {
format!(
"https://github.com/{}/blob/{}/{}",
competitor.repository, competitor.commit, path
)
}