vtcode-bash-runner
September 9, 2026 · View on GitHub
Root AGENTS.md | Cross-platform command runner with workspace-safe operations.
Modules
executor CommandExecutor trait + backends | runner BashRunner | policy CommandPolicy + WorkspaceGuardPolicy | pipe async process spawning | process handles | process_group kill/cleanup | background long-running tasks | stream utilities
Rules
CommandExecutortrait = primary abstraction for new backends.CommandPolicytrait = execution gate.WorkspaceGuardPolicyenforces boundaries.- Preserve command shape through admission: direct argv executes without shell reconstruction; shell scripts require explicit validated syntax and never fall back from malformed argv.
- Feature flags:
dry-run,pure-rust,exec-events,serde-errors. process_groupuses safenixwrappers (Pid::from_raw,signal::killpg,setpgidinpre_exec); there is nounsafehere. Unsafe env mutation is centralized invtcode-commons::env_lock, serialized by a process-wide mutex.
Testing
cargo nextest run -p vtcode-bash-runner | pipe tests: cargo nextest run -p vtcode-bash-runner -E 'binary(/pipe_tests/)' | use AllowAllPolicy unless testing policy.
Gotchas
BashRunner::new()canonicalizes root — bails if missing.- Authorization resolves paths freshly; never cache symlink targets across operations. OS sandboxing or bound filesystem handles remain necessary against concurrent replacement.
- Unsafe env mutation (
set_var/remove_var) is centralized invtcode-commons::env_lock, serialized by a process-wide mutex, single-threaded startup only. policycontainment delegates tovtcode_commons::paths::ensure_path_within_workspace—..-traversal paths are rejected (intentionally stricter than the oldstarts_with).- Pipe spooling opts into
SpawnedProcess::reliable_output_rx, a bounded lossless stream; legacy broadcast subscribers must remain independent of that backpressure path. wait_with_outputbounds post-exit draining even when a descendant inherits the pipe; never turn that drain back into an unbounded wait.