Flatpak-style launcher for sandboxed WebAssembly tools. Install, verify, and run .wasm binaries with explicit capability grants. Single binary, local-first, zero telemetry. wasmbox.orbiter.website
wasm rust wasmbox
wasmbox-cli AGENTS-comp.md
11 kB
Markdown
at dev

AGENTS-comp.md #

Project Overview #

WasmBox = Flatpak-style launcher for sandboxed .wasm tools. Single binary, local-first, no telemetry. Users discover, install, verify, run .wasm tools with explicit capability grants.

Architecture #

wasmbox/
  crates/
    cli/            CLI binary (clap). Entry point
      tests/        Integration tests (wiremock, 27 tests)
    runtime/        Wasmtime wrapper. Loads .wasm, enforces caps, executes
    registry/       Registry client. Fetches manifests + binaries over HTTPS
    permissions/    Cap manager. Prompts, stores, revokes per-tool grants
    verify/         Hash verification (SHA-256, constant-time)
    manifest/       wasmbox.toml parsing + validation
    shared/         Types shared across crates
    server/         Local HTTP server for web UI (v0.2+)
    dashboard/      Leptos web dashboard (v0.3+)
  tests/
    fixtures/       Test .wasm binaries (hello.wasm, echo.wasm)
  deny.toml         cargo-deny config
  Cargo.toml        Workspace root

Tech Stack #

  • Rust 1.94+ (MSRV 1.94)
  • Wasmtime 42 (wasm32-wasip2, embedded as lib)
  • clap (derive API)
  • reqwest (rustls, no OpenSSL)
  • sha2, subtle, toml, serde
  • ed25519-dalek (optional, not impl)
  • wiremock + tempfile (testing)
  • Leptos 0.8 (dashboard, v0.3+)
  • Fermyon Spin (v0.4+)

Build Commands #

rustup target add wasm32-wasip2
cargo build --release -p wasmbox-cli
cargo test --workspace
cargo install --path crates/cli
rustup target add wasm32-unknown-unknown && cargo install trunk
cd crates/dashboard && trunk build --release

Compilation Targets #

Crate Target Purpose
cli native wasmbox binary
runtime native Embeds Wasmtime
registry native HTTPS fetches
permissions native ~/.wasmbox/permissions.toml
verify native SHA-256 + Ed25519
manifest native + wasm32 Parses wasmbox.toml
shared native + wasm32 Shared types
dashboard wasm32-unknown-unknown Leptos UI

Code Quality #

Dead Code #

Deny dead_code, unused_imports, unused_variables, unused_mut in workspace Cargo.toml:

[workspace.lints.rust]
dead_code = "deny"
unused_imports = "deny"
unused_variables = "deny"
unused_mut = "deny"

Apply via [lints] workspace = true in each crate. #[allow(dead_code)] only in test modules.

Code Style #

Rust #

  • thiserror for lib crates, anyhow only in cli crate
  • impl Into<String> > String in fn signatures
  • Public types in shared derive Serialize, Deserialize, Clone, Debug
  • Gate platform-specific code with #[cfg(target_arch = "wasm32")] / #[cfg(not(target_arch = "wasm32"))]
  • No unwrap() in lib code. Use ?
  • Functions > 40 lines -> split
  • Prefer array_windows::<N>() over windows(N) when N is const
  • TOML v1.1: multiline inline tables + trailing commas OK

CLI #

  • Derive API for all commands + args
  • --json flag on every command
  • colored crate, respects NO_COLOR
  • Exit codes: 0 success, 1 error, 2 perm denied, 3 verification failed
  • User-facing msgs -> stderr. Tool output -> stdout
Command Description
run [name|--file path] Run tool (--sandbox, --allow, --allow-all)
install <name> Install from registry
list List installed tools
search <query> Search registries
info <name> Show metadata
verify <name> Verify hash vs manifest
update <name> Update (keeps old for rollback)
remove <name[@version]> Remove tool or version
permissions <name> [show|revoke] Manage perms
revoke <name> <capability> Revoke specific cap
audit List all granted perms
registry [add|list|remove] Manage registries
hash <file> SHA-256 hash

Global flags: --home, --json

Runtime #

  • Embed Wasmtime as lib, not binary
  • Fresh wasmtime::Engine per execution
  • Caps -> WASI perms:
    fs cap -> WasiCtxBuilder::preopened_dir()
    network cap -> allowed outbound hosts
    stdin/stdout -> WasiCtxBuilder::stdin()/stdout()
    env vars -> WasiCtxBuilder::env()
    
  • Set resource limits (memory, fuel)
  • Never reuse Store between executions

Permissions #

Stored in ~/.wasmbox/permissions.toml:

[fantasma]
version = "0.1.0"
granted_at = "2026-03-09T10:00:00Z"
stdout = true; stdin = true; network = []; filesystem = []

[crypts]
version = "0.2.0"
filesystem = [{ path = "~/Documents", read = true, write = false }]

Update -> new caps requested -> re-prompt. wasmbox audit prints all perms.

Registry Client #

  • Static HTTPS endpoint, no auth, no cookies
  • reqwest + rustls (no OpenSSL)
  • Cache index 1 hour, re-fetch on search/update
  • Verify TLS certs
  • User-Agent: wasmbox/{version}

Manifest Parsing #

  • wasmbox.toml = source of truth
  • Validate: name (alphanumeric + hyphens), version (semver), hash (hex sha256)
  • Strict parsing (reject unknown fields)
  • Binary hash must match .wasm file hash before execution

Verification #

  • SHA-256 checked before EVERY execution
  • Constant-time comparison (timing attack prevention)
  • Hash fail -> no run, stderr error, exit code 3
  • Optional Ed25519 signature verification

Security #

Zero External Dependencies #

Single static binary. No shared libs, no system services. reqwest + rustls.

Sandboxing #

  • Zero capabilities by default
  • Caps granted per-tool, per-version
  • Wasmtime enforces WASI sandbox
  • Memory: 256MB default, configurable
  • Fuel: prevents infinite loops, configurable

No Telemetry #

No analytics, crash reporting, usage tracking. Plain HTTPS GETs. User-Agent = wasmbox/{version} only.

Update Safety #

  • Never automatic
  • wasmbox update shows old vs new hash before applying
  • Previous versions kept for rollback
  • Cap changes -> re-prompt

Dependency Auditing #

cargo audit && cargo deny check

File Organization #

  • One module per file per crate
  • Public API in lib.rs with explicit re-exports
  • No circular deps
  • Dep direction: cli -> runtime, registry, permissions, verify, manifest, shared
  • shared has zero deps on other wasmbox crates

Testing #

  • Unit tests: #[cfg(test)] modules (17 tests across 5 crates)
  • Integration tests: crates/cli/tests/integration.rs (27 tests)
  • wiremock + tempfile
  • Fixtures: tests/fixtures/hello.wasm, tests/fixtures/echo.wasm
  • --home flag for isolation
  • Exit codes tested: 0, 2, 3
cargo test --workspace
cargo test -p wasmbox-cli --test integration

Dependencies #

  • Minimize count (security tool)
  • Prefer no_std crates where possible
  • Pin exact versions for security-critical deps
  • No proc macros except clap + serde derive
  • Audit new deps with cargo audit before merge

Common Pitfalls #

  • Wasmtime Engine creation expensive. Create once per wasmbox run
  • WASI Preview 2 for wasi:http outbound. Preview 1 only -> fs + stdio
  • reqwest + rustls may fail with unusual CA bundles -> ship webpki-roots
  • Temp dirs in tests -> tempfile crate (RAII)
  • Don't cache compiled modules across versions
  • colored -> respect NO_COLOR + TERM=dumb

Environment #

  • Dev: cargo run -p wasmbox-cli -- <cmd>
  • Test: cargo test --workspace
  • Release: cargo build --release -p wasmbox-cli
  • CI: cargo clippy --workspace -- -D warnings && cargo test --workspace && cargo audit && cargo deny check
  • Cross-compile: cross build --release --target x86_64-unknown-linux-musl
  • Binary size: ~26MB unstripped, ~20MB stripped (target <20MB)

WasmBox Tools #

Check installed tool FIRST before system commands.

Setup #

cargo install --path crates/cli
wasmbox registry add https://qstorage.quilibrium.com/wasmbox

Workflow #

  1. wasmbox list --json -> installed tools
  2. wasmbox search <kw> --json -> search
  3. wasmbox install <name> --allow-all -> install
  4. wasmbox info <name> --json -> usage
  5. echo 'input' | wasmbox run <name> -- <flags>

Available Tools #

Tool Description Key Flags
compact Strip token waste from code (13 languages) --stats, --tree, --verify HASH, --lang, --keep-debug, --keep-license
jfmt JSON: pretty-print, compact, validate, extract -q path, -k, -v
secretscan Credential scanner (25 secret types) --exit-code
b64 Base64 encode/decode (auto-detect) -e, -d, -u, --raw, --wrap N
errparse HTTP error -> RFC 9457 JSON --oneline, --exit-code, --status-only, --strict
hashit SHA-256/384/512, BLAKE3 --algo, --verify HASH, --raw
epoch Timestamp converter (IANA timezone) --fmt, --relative, --tz, --json, --diff
yamlfmt YAML parse, format, query, convert -q PATH, --to-json, --from-json, --sort
diffsummary Structured diff summaries -c, --files, --stats
worldid-verify World ID ZKP proof-of-humanity Request: QR + deep_link. Verify: validate proofs

Examples #

cat src/main.rs | wasmbox run compact
cat src/main.rs | wasmbox run compact -- --stats
find src/ -name '*.rs' -exec echo '===FILE:{}===' \; -exec cat {} \; | wasmbox run compact -- --tree
cat src/main.rs | wasmbox run compact -- --verify sha256:abc123...
echo '{"a":1}' | wasmbox run jfmt
echo '{"data":{"id":42}}' | wasmbox run jfmt -- -q data.id
cat .env | wasmbox run secretscan
cat config.yml | wasmbox run secretscan | wasmbox run jfmt
cat deploy.yml | wasmbox run secretscan -- --exit-code
echo 'hello world' | wasmbox run b64
echo 'aGVsbG8gd29ybGQK' | wasmbox run b64 -- -d
echo 'data' | wasmbox run b64 -- -u --raw
curl -si https://api.example.com | wasmbox run errparse
curl -si https://api.example.com | wasmbox run errparse -- --oneline
curl -si https://api.example.com | wasmbox run errparse | wasmbox run jfmt -- -q retry_after
echo 'hello' | wasmbox run hashit
cat file.wasm | wasmbox run hashit -- --verify sha256:expected...
cat src/main.py | wasmbox run compact | wasmbox run hashit
echo '1711540800' | wasmbox run epoch
echo '1711540800' | wasmbox run epoch -- --tz Europe/Madrid
curl -s https://api.example.com/user | wasmbox run jfmt -- -q created_at | wasmbox run epoch
cat pod.yaml | wasmbox run yamlfmt -- -q spec.containers.0.image
cat values.yaml | wasmbox run yamlfmt -- --to-json | wasmbox run jfmt -- -q database.host
git diff HEAD~1 | wasmbox run diffsummary
git diff | wasmbox run diffsummary -- --files

Token Efficiency #

  • No boilerplate. Use derive macros (clap, serde, thiserror)
  • Change only affected function/module when editing
  • No file rewrites for small changes -> diffs or targeted edits
  • CLI crate = glue code. Keep thin. Logic in lib crates