Something went wrong. Try again.
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
Something went wrong. Try again.
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 #
thiserrorfor lib crates,anyhowonly in cli crateimpl Into<String>>Stringin fn signatures- Public types in
sharedderiveSerialize, 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>()overwindows(N)when N is const - TOML v1.1: multiline inline tables + trailing commas OK
CLI #
- Derive API for all commands + args
--jsonflag on every commandcoloredcrate, respectsNO_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::Engineper 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 updateshows 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.rswith 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 --homeflag 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_stdcrates where possible - Pin exact versions for security-critical deps
- No proc macros except clap + serde derive
- Audit new deps with
cargo auditbefore 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 #
wasmbox list --json-> installed toolswasmbox search <kw> --json-> searchwasmbox install <name> --allow-all-> installwasmbox info <name> --json-> usageecho '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