Your First UAPI App In Rust
This walkthrough is the shortest current path from "I know Rust" to "I ran a
Krate Phase 2 app." It uses the real Rust SDK, the real manifest commands, and
the current krate run path.
Phase 2 is still pre-alpha, so this guide uses the repo workspace directly. The
future version will start with cargo add krate.
What You Build
A tiny CLI app that:
- reads one file path from app arguments
- reads that file through Krate
fs - writes the text through Krate
stdout - declares its permissions in
manifest.toml
That is enough to touch the core Phase 2 loop:
Rust app -> Krate SDK -> UAPI import -> UCap check -> host adapter
1. Check Your Tools
From the repo root:
cargo run -p krate-cli -- doctor
For this walkthrough, you need:
- Rust installed
wasm32-wasip1installedcargo-componentinstalled
If cargo-component is missing:
cargo install cargo-component --locked --version 0.21.1
2. Start From The Cat Sample
The current Rust SDK is local, so the easiest first app is the existing sample:
apps/krate-cat/
The core code is intentionally plain:
#![allow(unused)] fn main() { use krate::{ fs, io::{args, stdio, streams::OutputStreamExt}, Guest, }; struct Component; impl Guest for Component { fn run() -> i32 { let Some(path) = args::first() else { let _ = stdio::stderr().write_line("usage: krate-cat <file>"); return 64; }; match fs::read_to_string(&path) { Ok(text) => { let _ = stdio::stdout().write_text(&text); 0 } Err(err) => { let _ = stdio::stderr().write_line(&format!("{err:?}")); 5 } } } } krate::export!(Component); }
The important part is what it does not do. It does not call std::fs, std::env,
or direct WASI imports. It asks Krate for arguments, file access, stdout, and
stderr.
3. Build The Component
From the repo root:
cargo build -p krate-cli
scripts/build-krate-cat-component.sh
The script prints a component path like:
apps/krate-cat/target/wasm32-wasip1/release/krate_cat.wasm
4. Generate A Manifest
Use the CLI to create a starter manifest:
cargo run -p krate-cli -- manifest init \
--id dev.krate.cat \
--name krate-cat \
--entry target/wasm32-wasip1/release/krate_cat.wasm \
--cap io.args \
--cap io.stdout \
--cap io.stderr \
--cap 'fs.read:./fixtures/**' \
--output apps/krate-cat/manifest.toml \
--force
This writes valid TOML and checks every capability string before it writes.
5. Explain The Manifest
Before running the app, inspect what it asks for:
cargo run -p krate-cli -- manifest explain apps/krate-cat/manifest.toml
You should see that io.args, io.stdout, and io.stderr are default grants.
You should also see that fs.read:./fixtures/** needs a launch grant.
If you want the same explanation as structured data, use JSON:
cargo run -p krate-cli -- manifest explain \
--format json \
apps/krate-cat/manifest.toml
The check and capability table commands can print JSON too, which is useful when you start wiring your own CI scripts.
That is the Phase 2 permission model in simple form:
low-risk app plumbing -> default grant
host file/network access -> explicit launch grant
If you want a local record of the grants used for a run, add:
--log-grants krate-grants.log
For scripts, use JSON Lines. Krate writes one audit record per line:
--log-grants krate-grants.jsonl --log-grants-format jsonl
If you want a script-readable preview before the component starts, use:
--dump-caps --dump-caps-format json
6. Run It
Create a test file:
mkdir -p apps/krate-cat/fixtures
printf 'hello from Krate\n' > apps/krate-cat/fixtures/hello.txt
Run with the sample manifest:
cd apps/krate-cat
../../target/debug/krate run \
--manifest manifest.toml \
--auto-grant \
target/wasm32-wasip1/release/krate_cat.wasm \
-- ./fixtures/hello.txt
cd ../..
Expected output:
hello from Krate
7. See The Denial Path
Run without granting the file capability:
cd apps/krate-cat
printf '' | ../../target/debug/krate run \
--manifest manifest.toml \
target/wasm32-wasip1/release/krate_cat.wasm \
-- ./fixtures/hello.txt
cd ../..
In a non-interactive shell, Krate exits before starting the component and prints the missing required capability.
That is the behavior we want. The runtime should refuse the app before native file access happens.
8. What To Change For Your Own App
Start by changing:
apps/krate-cat/src/lib.rsapps/krate-cat/Cargo.tomlapps/krate-cat/manifest.toml
Then rebuild and rerun. As the SDK gets published, this flow will move from a repo-local sample to a fresh project outside the Krate tree.
Current Limits
- The SDK is local to the repo and still draft.
- The manifest is unsigned.
- Grants are session-only.
- Cross-host sample proof is still running through CI, not through a released installer.
Even with those limits, this is now the core shape of a Krate CLI app.