# 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 ```bash 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: ```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` 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::()` 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 ` | Install from registry | | `list` | List installed tools | | `search ` | Search registries | | `info ` | Show metadata | | `verify ` | Verify hash vs manifest | | `update ` | Update (keeps old for rollback) | | `remove ` | Remove tool or version | | `permissions [show\|revoke]` | Manage perms | | `revoke ` | Revoke specific cap | | `audit` | List all granted perms | | `registry [add\|list\|remove]` | Manage registries | | `hash ` | SHA-256 hash | Global flags: `--home`, `--json` ### Runtime - Embed Wasmtime as lib, not binary - Fresh `wasmtime::Engine` per execution - Caps -> WASI perms: ```rust 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`: ```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 ```bash 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 ```bash 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 -- ` - 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 ```bash cargo install --path crates/cli wasmbox registry add https://qstorage.quilibrium.com/wasmbox ``` ### Workflow 1. `wasmbox list --json` -> installed tools 2. `wasmbox search --json` -> search 3. `wasmbox install --allow-all` -> install 4. `wasmbox info --json` -> usage 5. `echo 'input' | wasmbox run -- ` ### 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 ```bash 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