Repository navigation
Description
User Story
I am implementing a Compute Driver extension. I am porting an internal agent orchestration platform that uses firecracker to openshell.
I want to do that without forking openshell-driver-vm and without re-deriving its guest init, disk layout and boundary formats. The VM driver already boots each VM through a launcher process, however it won't let my custom driver provide a different one.
Problem Statement
VmDriverConfig already has a launcher_bin field that tells the driver which executable to run for each VM. The only obstacle is that the shipped openshell-driver-vm binary hardcodes it to None in its main, so an operator can't set it from outside
VmDriver starts every sandbox VM, and the image-preparation VM, by running a launcher with --internal-run-vm and a fixed flag set. The launcher is VmDriverConfig::launcher_bin. In VmDriver::new_with_extensions, when it is unset the driver uses its own executable (std::env::current_exe()).
Impact / Why This Matters
Without this feature, users are limited to only computes based on libkrun. Another VMM has to fork the driver, or provide a complete reimplementation of the driver against compute_driver.proto.
This is costly - as per #4351, the reimplementation depends on VM internals that aren't a published contract, so every OpenShell bump needs re-qualifying.
The other alternative is forking the whole openshell codebase to patch in the required change.
Proposed Design
Add an operator option to crates/openshell-driver-vm/src/main.rs and pass it through:
/// VM launcher executable the driver runs for every VM. Defaults to this
/// binary. The launcher receives the driver's `--internal-run-vm` flags.
#[arg(long, env = "OPENSHELL_VM_LAUNCHER_BIN")]
launcher_bin: Option<PathBuf>,
launcher_bin: args.launcher_bin.clone(), // was: None
Validate it with the other startup checks, so a bad path fails at driver start rather than on the first sandbox:
if let Some(path) = args.launcher_bin.as_deref()
&& (!path.is_absolute() || !path.is_file())
{
return Err(miette::miette!(
"launcher_bin must be an absolute path to an existing file: {}",
path.display()
));
}
Trust: the value comes from the driver's own command line and environment, which only the operator controls, like --state-dir. A launcher runs as the driver's user, so naming one is as sensitive as choosing which driver binary to run. It isn't reachable from a sandbox spec, the gateway API or the driver protocol.
Compatibility: unset, behavior is unchanged. A launcher must accept the --internal-run-vm and --vm-* flags, and either handle the driver's other --internal-* modes or run the stock driver binary for them.
Acceptance Criteria
- the default is the driver's own executable;
- a set path reaches VmDriverConfig::launcher_bin;
- a relative or missing path is rejected at startup.
Alternatives Considered
- A [openshell.drivers.vm] gateway key. The gateway spawns the VM driver with a fixed argument list, so this adds gateway code and a config field for a driver-local choice. The environment variable also works for an externally run driver.
- Firecracker inside the VM driver (the RFC 0012 / feat(firecracker): prototype host-supervised isolation #2934 direction). This couples the driver to one more VMM; the hook keeps VMMs out of it.
- Publish the guest artifacts as a versioned contract (option (a) in feat: Firecracker compute driver — reuse the VM guest model with jailer, OCI images and full sandbox lifecycle #4351). That answers a broader question and takes more to maintain. This hook needs no new contract, because the launcher flags already exist.
Agent Investigation
#4351 (Firecracker compute driver)
#1907 (external compute driver extension point).
Checklist
- I've reviewed existing issues and the published docs
- This is a design proposal, not a "please build this" request
Activity