Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/dallay/corvus/llms.txt

Use this file to discover all available pages before exploring further.

RuntimeAdapter Trait

The RuntimeAdapter trait abstracts platform differences, enabling the same agent code to run on native, Docker, WASM, edge, and embedded environments. Source: src/runtime/traits.rs:5-32

Trait Definition

use std::path::{Path, PathBuf};
use tokio::process::Command;

pub trait RuntimeAdapter: Send + Sync {
    /// Human-readable runtime name
    fn name(&self) -> &str;
    
    /// Whether this runtime supports shell access
    fn has_shell_access(&self) -> bool;
    
    /// Whether this runtime supports filesystem access
    fn has_filesystem_access(&self) -> bool;
    
    /// Base storage path for this runtime
    fn storage_path(&self) -> PathBuf;
    
    /// Whether long-running processes (gateway, heartbeat) are supported
    fn supports_long_running(&self) -> bool;
    
    /// Maximum memory budget in bytes (0 = unlimited)
    fn memory_budget(&self) -> u64 {
        0
    }
    
    /// Build a shell command process for this runtime
    fn build_shell_command(
        &self,
        command: &str,
        workspace_dir: &Path,
    ) -> anyhow::Result<Command>;
}

Built-in Runtimes

From src/runtime/mod.rs:
RuntimeFileStatusUse Case
Nativenative.rs✅ StableLocal development, servers
Dockerdocker.rs✅ StableSandboxed execution
WASMwasm.rs🚧 PlannedEdge, browsers

Native Runtime

From src/runtime/native.rs:6-31:
pub struct NativeRuntime;

impl NativeRuntime {
    pub fn new() -> Self {
        Self
    }
}

impl RuntimeAdapter for NativeRuntime {
    fn name(&self) -> &str {
        "native"
    }
    
    fn has_shell_access(&self) -> bool {
        true
    }
    
    fn has_filesystem_access(&self) -> bool {
        true
    }
    
    fn storage_path(&self) -> PathBuf {
        dirs::home_dir()
            .unwrap_or_else(|| PathBuf::from("/tmp"))
            .join(".corvus")
    }
    
    fn supports_long_running(&self) -> bool {
        true
    }
    
    fn build_shell_command(
        &self,
        command: &str,
        workspace_dir: &Path,
    ) -> anyhow::Result<Command> {
        let mut cmd = Command::new("sh");
        cmd.arg("-c")
           .arg(command)
           .current_dir(workspace_dir);
        Ok(cmd)
    }
}

Docker Runtime

From src/runtime/docker.rs:15-184:
pub struct DockerRuntime {
    image: String,
    network: String,
    memory_limit_mb: Option<u32>,
    cpu_limit: Option<f32>,
    read_only_rootfs: bool,
    mount_workspace: bool,
}

impl DockerRuntime {
    pub fn new(config: &DockerRuntimeConfig) -> Self {
        Self {
            image: config.image.clone(),
            network: config.network.clone(),
            memory_limit_mb: config.memory_limit_mb,
            cpu_limit: config.cpu_limit,
            read_only_rootfs: config.read_only_rootfs,
            mount_workspace: config.mount_workspace,
        }
    }
}

impl RuntimeAdapter for DockerRuntime {
    fn name(&self) -> &str {
        "docker"
    }
    
    fn has_shell_access(&self) -> bool {
        true
    }
    
    fn has_filesystem_access(&self) -> bool {
        self.mount_workspace
    }
    
    fn storage_path(&self) -> PathBuf {
        PathBuf::from("/workspace")
    }
    
    fn supports_long_running(&self) -> bool {
        false  // containers are ephemeral
    }
    
    fn memory_budget(&self) -> u64 {
        self.memory_limit_mb
            .map(|mb| mb as u64 * 1024 * 1024)
            .unwrap_or(0)
    }
    
    fn build_shell_command(
        &self,
        command: &str,
        workspace_dir: &Path,
    ) -> anyhow::Result<Command> {
        let mut cmd = Command::new("docker");
        cmd.arg("run")
           .arg("--rm")
           .arg("--network").arg(&self.network);
        
        // Resource limits
        if let Some(mb) = self.memory_limit_mb {
            cmd.arg("--memory").arg(format!("{}m", mb));
        }
        if let Some(cpu) = self.cpu_limit {
            cmd.arg("--cpus").arg(format!("{}", cpu));
        }
        
        // Security
        if self.read_only_rootfs {
            cmd.arg("--read-only");
        }
        
        // Mount workspace
        if self.mount_workspace {
            cmd.arg("-v")
               .arg(format!("{}:/workspace", workspace_dir.display()));
        }
        
        // Execute command
        cmd.arg(&self.image)
           .arg("sh")
           .arg("-c")
           .arg(command);
        
        Ok(cmd)
    }
}

Configuration

Native (Default)

[runtime]
kind = "native"

Docker

[runtime]
kind = "docker"

[runtime.docker]
image = "alpine:3.20"
network = "none"              # isolated
memory_limit_mb = 512
cpu_limit = 1.0
read_only_rootfs = true       # prevent writes to container
mount_workspace = true

Custom Runtime Implementation

use corvus::runtime::RuntimeAdapter;
use std::path::{Path, PathBuf};
use tokio::process::Command;

pub struct EdgeRuntime {
    storage: PathBuf,
}

impl RuntimeAdapter for EdgeRuntime {
    fn name(&self) -> &str {
        "edge"
    }
    
    fn has_shell_access(&self) -> bool {
        false  // no shell on edge
    }
    
    fn has_filesystem_access(&self) -> bool {
        true  // limited KV storage
    }
    
    fn storage_path(&self) -> PathBuf {
        self.storage.clone()
    }
    
    fn supports_long_running(&self) -> bool {
        true  // edge functions are long-lived
    }
    
    fn memory_budget(&self) -> u64 {
        128 * 1024 * 1024  // 128MB
    }
    
    fn build_shell_command(
        &self,
        _command: &str,
        _workspace_dir: &Path,
    ) -> anyhow::Result<Command> {
        Err(anyhow::anyhow!("Shell not supported on edge runtime"))
    }
}

Tool Integration

Tools query runtime capabilities:
impl Tool for ShellTool {
    async fn execute(&self, args: Value) -> anyhow::Result<ToolResult> {
        if !self.runtime.has_shell_access() {
            return Ok(ToolResult {
                success: false,
                error: Some("Shell not supported in this runtime".into()),
                ..Default::default()
            });
        }
        
        let mut cmd = self.runtime.build_shell_command(
            command,
            &self.security.workspace_dir,
        )?;
        
        // Execute...
    }
}

Registration

From src/runtime/mod.rs:41-66:
pub fn create_runtime(config: &RuntimeConfig) -> anyhow::Result<Arc<dyn RuntimeAdapter>> {
    match config.kind.as_str() {
        "native" => Ok(Arc::new(NativeRuntime::new())),
        "docker" => Ok(Arc::new(DockerRuntime::new(&config.docker))),
        "wasm" => Err(anyhow::anyhow!("WASM runtime not yet implemented")),
        other => Err(anyhow::anyhow!("Unknown runtime kind: {}", other)),
    }
}

Best Practices

Use Docker runtime for untrusted code execution
Implement memory_budget() to enable resource-aware tool selection
Always validate has_shell_access() and has_filesystem_access() before using tools

Future Runtimes

WASM (Planned)

pub struct WasmRuntime {
    memory_pages: u32,
}

impl RuntimeAdapter for WasmRuntime {
    fn has_shell_access(&self) -> bool { false }
    fn has_filesystem_access(&self) -> bool { false }
    fn memory_budget(&self) -> u64 { self.memory_pages as u64 * 65536 }
}

Embedded (Raspberry Pi, ESP32)

pub struct EmbeddedRuntime {
    flash_size: u64,
}

impl RuntimeAdapter for EmbeddedRuntime {
    fn has_shell_access(&self) -> bool { false }
    fn storage_path(&self) -> PathBuf { PathBuf::from("/flash") }
    fn memory_budget(&self) -> u64 { 512 * 1024 }  // 512KB RAM
}

Build docs developers (and LLMs) love