Summary
The wrap crate unconditionally compiles all four execution backends (docker, tmux, pty, subprocess) and their dependencies. Only the subprocess backend is actively used in production. Gate the other backends behind Cargo feature flags so they are not compiled or installed unless explicitly enabled.
Motivation
- bollard (Docker client) and portable-pty are always compiled even when unused, adding to build times and binary size
- The docker, tmux, and pty backends need revisiting but there is no bandwidth for that now
- Feature-gating makes the supported backend explicit and avoids shipping dead code paths
- Reduces the attack surface of the production binary
Implementation Plan
1. Add features to crates/wrap/Cargo.toml
[features]
default = ["subprocess"]
subprocess = []
tmux = []
docker = ["dep:bollard"]
pty = ["dep:portable-pty"]
Mark bollard and portable-pty as optional:
[dependencies]
bollard = { version = "0.18", optional = true }
portable-pty = { version = "0.9", optional = true }
2. Gate modules in crates/wrap/src/lib.rs
pub mod backend;
pub mod subprocess;
pub mod types;
#[cfg(feature = "docker")]
pub mod docker;
#[cfg(feature = "tmux")]
pub mod tmux;
#[cfg(feature = "pty")]
pub mod pty;
#[cfg(feature = "pty")]
pub mod pty_stream;
3. Gate backend types in crates/wrap/src/types.rs
BackendType enum variants for docker, tmux, and pty should be conditionally compiled. from_env_strict() should return a clear error when a backend is requested but not compiled in:
"Docker backend requested but not compiled. Rebuild with --features docker"
4. Update crates/orchestrator/Cargo.toml
[dependencies]
wrap = { path = "../wrap", features = ["subprocess"] }
[features]
docker = ["wrap/docker"]
tmux = ["wrap/tmux"]
pty = ["wrap/pty"]
5. Gate orchestrator imports and match arms in main.rs
Conditionally import and match on backend types:
#[cfg(feature = "docker")]
use wrap::docker::DockerBackend;
// In the backend match:
#[cfg(feature = "docker")]
BackendType::Docker => { ... }
#[cfg(not(feature = "docker"))]
BackendType::Docker => anyhow::bail!("Docker backend not compiled. Rebuild with --features docker"),
6. Update launchd plists and build scripts
Ensure the production build uses cargo build -p orchestrator (which gets subprocess by default). Document how to enable other backends for development.
7. Update wrap service binary
The wrap service (crates/wrap/src/main.rs) may also reference backends directly. Gate those similarly.
Acceptance Criteria
Summary
The wrap crate unconditionally compiles all four execution backends (docker, tmux, pty, subprocess) and their dependencies. Only the subprocess backend is actively used in production. Gate the other backends behind Cargo feature flags so they are not compiled or installed unless explicitly enabled.
Motivation
Implementation Plan
1. Add features to
crates/wrap/Cargo.tomlMark bollard and portable-pty as optional:
2. Gate modules in
crates/wrap/src/lib.rs3. Gate backend types in
crates/wrap/src/types.rsBackendTypeenum variants for docker, tmux, and pty should be conditionally compiled.from_env_strict()should return a clear error when a backend is requested but not compiled in:4. Update
crates/orchestrator/Cargo.toml5. Gate orchestrator imports and match arms in
main.rsConditionally import and match on backend types:
6. Update launchd plists and build scripts
Ensure the production build uses
cargo build -p orchestrator(which gets subprocess by default). Document how to enable other backends for development.7. Update wrap service binary
The wrap service (
crates/wrap/src/main.rs) may also reference backends directly. Gate those similarly.Acceptance Criteria
cargo build -p orchestratorcompiles only the subprocess backend by defaultbollardandportable-ptyare not compiled unless their feature is enabledAGENTD_BACKENDproduces a clear error messagecargo build -p orchestrator --features dockerenables the Docker backendcargo build -p orchestrator --features tmuxenables the tmux backendcargo build -p orchestrator --features ptyenables the PTY backendcargo test --all-features