A sandboxed shell execution engine using WebAssembly.
Named after the conch shell from Lord of the Flies — "whoever holds the conch gets to speak."
Conch provides secure shell execution in a WASM sandbox using wasmtime. It wraps brush, a bash-compatible shell written in Rust, and provides a hybrid virtual filesystem that combines:
- VFS storage: In-memory or custom storage for orchestrator-controlled paths
- Real filesystem: cap-std secured mounts for host directory access
- Full bash compatibility via brush-core
- Secure sandboxing — WASM isolation with capability-based filesystem access
- Hybrid VFS — combine virtual storage with real filesystem mounts
- Resource limits — CPU time, memory, output size
- Multiple APIs — high-level
ShellAPI or low-levelComponentShellExecutor - MCP server — integrate with AI assistants via Model Context Protocol
- FFI bindings — C ABI for Go integration (via purego, no CGO required)
Add to your Cargo.toml:
[dependencies]
conch = { version = "0.1", features = ["embedded-shell"] }use conch::{Shell, ResourceLimits};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a shell with default settings (VFS at /scratch)
let shell = Shell::builder().build()?;
// Write data to VFS
shell.vfs().write("/scratch/input.txt", b"hello world").await?;
// Execute commands
let result = shell.execute(
"cat /scratch/input.txt | wc -w",
&ResourceLimits::default(),
).await?;
println!("Output: {}", String::from_utf8_lossy(&result.stdout));
println!("Exit code: {}", result.exit_code);
Ok(())
}use conch::{Shell, Mount, ResourceLimits};
let shell = Shell::builder()
// Mount host directory as read-only
.mount("/project", "/home/user/code", Mount::readonly())
// Mount output directory as read-write
.mount("/output", "/tmp/agent-output", Mount::readwrite())
.build()?;
let result = shell.execute(
"grep -r 'TODO' /project/src > /output/todos.txt",
&ResourceLimits::default(),
).await?;conch/
├── crates/
│ ├── conch/ # Host library (Shell API, executor, FFI)
│ ├── conch-shell/ # Brush-based shell (compiles to WASM)
│ ├── conch-mcp/ # MCP server for AI assistants
│ └── conch-cli/ # CLI test harness
├── examples/ # Usage examples
├── tests/go/ # Go FFI integration tests
└── mise.toml # Task definitions
The Shell struct provides a high-level interface with builder pattern:
use conch::{Shell, Mount, DirPerms, FilePerms};
let shell = Shell::builder()
// Custom VFS paths
.vfs_path("/data", DirPerms::all(), FilePerms::all())
.vfs_path("/config", DirPerms::READ, FilePerms::READ)
// Real filesystem mounts
.mount("/src", "./src", Mount::readonly())
.build()?;For simple execution without VFS:
use conch::{Conch, ResourceLimits};
let conch = Conch::embedded(4)?; // max 4 concurrent executions
let result = conch.execute("echo hello | cat", ResourceLimits::default()).await?;For maximum control over the WASM runtime:
use conch::ComponentShellExecutor;
let executor = ComponentShellExecutor::embedded()?;
let result = executor.execute("echo hello", &limits).await?;Conch includes an MCP server for AI assistant integration:
# Build and run
cargo build -p conch-mcp --release
./target/release/conch-mcpConfigure in Claude Desktop:
{
"mcpServers": {
"conch": {
"command": "/path/to/conch-mcp"
}
}
}- Rust 1.90+ (1.92 recommended)
- mise for task running (optional but recommended)
# Install dependencies and build
mise install
mise run build
# Build the WASM shell module
mise run wasm-build
# Build with embedded shell (for deployment)
mise run build-embedded
# Run tests
mise run test-all./target/debug/conch-cli -c "echo hello | cat"
./target/debug/conch-cli script.shConch also provides JavaScript/TypeScript bindings for browsers and Node.js via the @bsull/conch npm package:
import { execute } from '@bsull/conch';
import { setFileData, updateFile, fromPaths } from '@bsull/conch/vfs';
// Set up the virtual filesystem
setFileData(fromPaths({
'/data/input.txt': 'hello world',
}));
// Execute shell commands
execute('cat /data/input.txt'); // prints: hello world
// Update files dynamically (works even after execute())
updateFile('/data/input.txt', 'updated content');
execute('cat /data/input.txt'); // prints: updated contentWorks out of the box in both browsers and Node.js 19+ with the same sandboxed VFS behavior—no configuration required.
See js/conch-shell/README.md for full documentation.
The library exposes a C FFI callable from Go using purego:
import "github.com/yourorg/conch/tests/go"
executor, _ := conch.NewExecutorEmbedded()
defer executor.Close()
result, _ := executor.Execute("echo hello | grep hello")
fmt.Println(string(result.Stdout)) // "hello\n"The shell includes these utilities:
- Core: echo, printf, test, true, false, exit
- Text: cat, head, tail, wc, grep, sort, uniq
- Data: jq (JSON processing)
- Standard brush builtins: cd, pwd, export, etc.
use conch::ResourceLimits;
use std::time::Duration;
let limits = ResourceLimits {
max_cpu_ms: 5000, // 5 seconds CPU time
max_memory_bytes: 64 * 1024 * 1024, // 64 MB memory
max_output_bytes: 1024 * 1024, // 1 MB output
timeout: Duration::from_secs(30), // 30 second wall clock
};Apache-2.0