Running Commands
The agent provides structured command execution inside sandboxes. Unlike console-based approaches, you get proper exit codes, separated stdout/stderr, and no terminal parsing.
Basic Execution
Connect to the agent and run commands:
let vm = capsa::sandbox()
.build()
.await?;
let agent = vm.agent().await?;
let result = agent.exec("echo").arg("hello").run().await?;
println!("stdout: {}", result.stdout);
println!("stderr: {}", result.stderr);
println!("exit_code: {}", result.exit_code);Direct vs Shell Execution
Commands are executed directly without a shell. For shell features (pipes, redirects, variable expansion), use /bin/sh -c:
// Direct execution (safer, faster)
agent.exec("ls").args(["-la", "/mnt"]).run().await?;
// Shell execution (when you need shell features)
agent.exec("/bin/sh").args(["-c", "ls *.txt | grep foo"]).run().await?;Environment Variables
Pass environment variables with .env():
let result = agent.exec("/bin/sh")
.args(["-c", "echo $API_KEY"])
.env("API_KEY", "secret123")
.env("DEBUG", "1")
.run()
.await?;
assert_eq!(result.stdout.trim(), "secret123");Exit Codes
Check the exit code to determine success:
let result = agent.exec("test").args(["-f", "/etc/passwd"]).run().await?;
if result.exit_code == 0 {
println!("File exists");
} else {
println!("File not found");
}Error Handling
Commands that fail to execute return an error. Commands that execute but return non-zero are not errors:
// This succeeds (command runs, even though it exits with error)
let result = agent.exec("false").run().await?;
assert_eq!(result.exit_code, 1);
// This fails (command doesn't exist)
let result = agent.exec("/nonexistent/binary").run().await;
assert!(result.is_err());Capturing Output
Stdout and stderr are captured separately:
let result = agent.exec("/bin/sh")
.args(["-c", "echo stdout_data && echo stderr_data >&2"])
.run()
.await?;
println!("stdout: {}", result.stdout); // "stdout_data\n"
println!("stderr: {}", result.stderr); // "stderr_data\n"Long-Running Commands
For background processes, use spawn():
// Spawn a background process
agent.spawn("sleep").arg("60").run().await?;
// Check if a process is running
let result = agent.exec("pgrep").arg("sleep").run().await?;
if result.exit_code == 0 {
println!("Sleep is running: {}", result.stdout.trim());
}Complex Commands
Use shell for complex operations:
// Pipelines
let result = agent.exec("/bin/sh")
.args(["-c", "find /tmp -type f | wc -l"])
.run()
.await?;
// Conditionals
let result = agent.exec("/bin/sh")
.args(["-c", "test -f /tmp/config.json && cat /tmp/config.json || echo '{}'"])
.run()
.await?;
// Multiple commands
let result = agent.exec("/bin/sh")
.args(["-c", "cd /project && cargo build && cargo test"])
.run()
.await?;System Information
Query system details with agent.info():
let info = agent.info().await?;
println!("Kernel: {}", info.kernel_version);
println!("Hostname: {}", info.hostname);
println!("CPUs: {}", info.cpus);
println!("Memory: {} bytes", info.memory_bytes);Clean Shutdown
Always shut down cleanly when done:
// Run your commands...
// Then shut down
vm.shutdown().await?;This signals the sandbox to terminate gracefully, waiting up to 30 seconds for clean shutdown before force-killing.
Complete Example
use capsa::AccessMode;
async fn run_tests_in_sandbox() -> capsa::Result<()> {
// Create sandbox with project directory
let vm = capsa::sandbox()
.cpus(4)
.memory_mb(2048)
.share("./my-project", "/project", AccessMode::ReadOnly)
.build()
.await?;
// Connect to agent
let agent = vm.agent().await?;
// Run tests
let result = agent.exec("/bin/sh")
.args(["-c", "cd /project && cargo test 2>&1"])
.run()
.await?;
// Check results
if result.exit_code == 0 {
println!("All tests passed!");
} else {
eprintln!("Tests failed:\n{}", result.stdout);
}
// Clean up
vm.shutdown().await?;
Ok(())
}Next Steps
- Working with Files - File operations and shared directories
- Network Security - Configure network policies