Quick Start
In this guide you will install the qos CLI, scaffold a new Rust edge agent, write a fully functional module that reads and writes from the local Sled DB, broadcasts a Gossipsub message across the P2P mesh, and returns a JSON response — then deploy and monitor it with live tail logs.
#Prerequisites
Make sure you have the following installed before continuing:
- ✓Rust + Cargo≥ 1.78 (stable)
- ✓wasm32 targetrustup target add wasm32-unknown-unknown
- ✓qos CLIInstalled in Step 1 below
Install the CLI
The Q-OS CLI is a single Rust binary that manages your local edge node, handles module signing, and gives you a live window into the running mesh. Install it with a single curl command:
$ curl -sL https://q-os.io/install | bash
> [OK] Detected platform: darwin-arm64
> [OK] Downloading qos-cli v0.1.0...
> [OK] Binary installed to /usr/local/bin/qos
> [OK] Sled state directory initialized at ~/.qos/state/
> [OK] Ed25519 keypair generated at ~/.qos/master.key
> Run 'qos --version' to verify the install.ℹ️ NOTE
Ed25519 keypair at ~/.qos/master.key on first run. This is your module signing identity — keep the private key secure. The public key is embedded in every module you publish.⚠️ WARNING
xattr -d com.apple.quarantine /usr/local/bin/qosInitialize Project
Use qos init to scaffold a new edge agent from the official Rust template. This creates a ready-to-build Cargo project pre-configured with the qos-sdk dependency and a signed module manifest.
$ qos init my-edge-agent --template rust
> [OK] Scaffolding Rust edge agent in ./my-edge-agent/
> [OK] Creating Cargo.toml with wasm32 target config
> [OK] Creating src/lib.rs with qos-sdk boilerplate
> [OK] Creating qos.toml (module manifest)
>
> Your edge agent is ready. Next steps:
> cd my-edge-agent
> qos build --releaseProject Structure
my-edge-agent/
├── Cargo.toml # wasm32 lib target + qos-sdk dependency
├── qos.toml # Module manifest (name, version, public_key)
└── src/
└── lib.rs # Your module logic — the run() entry pointCargo.toml
The scaffolded Cargo.toml sets the crate type to cdylib so Cargo emits a .wasm binary, and includes qos-sdk for safe host ABI access:
[package]
name = "my-edge-agent"
version = "0.1.0"
edition = "2021"
# cdylib emits a .wasm binary the Q-OS runtime can load
[lib]
crate-type = ["cdylib"]
[dependencies]
# qos-sdk provides safe wrappers around the host ABI.
# It is a zero-dependency crate — no std required.
qos-sdk = "0.1"
# serde_json is compiled to WASM for payload serialization
serde_json = { version = "1", default-features = false, features = ["alloc"] }Write the Module
Open src/lib.rs. The snippet below is a complete, production-annotated module demonstrating all four core SDK operations: reading from the Sled DB, incrementing and persisting a counter, broadcasting a Gossipsub message to mesh peers, and returning a structured JSON payload to the caller.
//! my-edge-agent — a Q-OS WASM module
//!
//! Demonstrates the four core SDK operations:
//! 1. Reading persistent state from the node's local Sled DB
//! 2. Incrementing and writing state back
//! 3. Broadcasting a Gossipsub message to all peers on the mesh
//! 4. Returning a structured JSON payload to the caller
use qos_sdk::{
state, // Typed Sled DB wrappers (get / set / delete)
gossip, // libp2p Gossipsub broadcast API
input, // Read the raw input bytes from the caller
output, // Write the response payload back to the host
};
/// Module entry point — called by the Q-OS runtime on every invocation.
#[no_mangle]
pub extern "C" fn run() {
// ── Step 1: Read the caller's JSON payload ─────────────────────────────
let raw = input::read();
let payload: serde_json::Value =
serde_json::from_slice(&raw).unwrap_or(serde_json::Value::Null);
let agent_id = payload["agent_id"]
.as_str()
.unwrap_or("unknown")
.to_string();
// ── Step 2: Read & increment a heartbeat counter from Sled DB ──────────
// state::get returns Option<Vec<u8>>; state::set persists raw bytes.
let counter_key = format!("heartbeat::{agent_id}");
let count: u64 = state::get(&counter_key)
.and_then(|bytes| String::from_utf8(bytes).ok())
.and_then(|s| s.parse().ok())
.unwrap_or(0) + 1;
state::set(&counter_key, count.to_string().as_bytes());
// ── Step 3: Broadcast a Gossipsub message to all mesh peers ────────────
let gossip_msg = serde_json::json!({
"topic": "qos.agents.heartbeat",
"agent_id": agent_id,
"count": count,
"ts": qos_sdk::clock::unix_ms(),
});
gossip::publish("qos.agents.heartbeat", gossip_msg.to_string().as_bytes());
// ── Step 4: Return a JSON response payload ─────────────────────────────
let response = serde_json::json!({
"ok": true,
"agent_id": agent_id,
"count": count,
"message": format!("Heartbeat #{count} recorded and broadcast to mesh."),
});
output::write(response.to_string().as_bytes());
}💡 TIP
state::get, gossip::publish, output::write) compile to a handful of extern "C" calls that the runtime resolves at link time. No networking, no async runtime — just raw speed.ℹ️ NOTE
qos_sdk::clock::unix_ms() reads the host's monotonic clock via host::now_ms() in the ABI. This ensures timestamps are tamper-proof even when the WASM sandbox has no direct access to system time.Deploy & Monitor
Build the module to a signed .qos bundle, deploy it to your running node, then tail the live execution logs to watch each invocation, state mutation, and Gossipsub broadcast in real time:
Build & Deploy
# Build the module to WASM (one-time target setup)
$ rustup target add wasm32-unknown-unknown
# Compile in release mode — optimized, stripped
$ qos build --release
> [OK] Compiling my-edge-agent (wasm32)
> [OK] Module size: 38 KB (stripped)
> [OK] Ed25519 signature applied — hash: a3f9c12...
# Deploy the signed module to your live edge node
$ qos module deploy ./dist/my-edge-agent.qos --name heartbeat-agent
> [MESH] Uploading payload to local node...
> [OK] Module 'heartbeat-agent' registered on node edge-001
> [OK] Invoke via: POST http://localhost:3000/api/v1/invoke/heartbeat-agentMonitor with Live Logs
qos logs --tail streams structured log lines directly from the runtime engine — WASM execution traces, state reads/writes, gossip broadcasts, and peer receipts:
# Stream live execution logs from the edge node
$ qos logs --tail
> 2026-06-26T13:01:04Z INFO qos_runtime Module 'heartbeat-agent' loaded (38 KB)
> 2026-06-26T13:01:05Z INFO qos_wasm run() invoked — agent_id="node-42"
> 2026-06-26T13:01:05Z DEBUG qos_state state::get "heartbeat::node-42" → None (first run)
> 2026-06-26T13:01:05Z DEBUG qos_state state::set "heartbeat::node-42" = "1"
> 2026-06-26T13:01:05Z INFO qos_gossip Published 84 bytes → topic "qos.agents.heartbeat"
> 2026-06-26T13:01:05Z INFO qos_runtime run() → 200 OK (0.6ms)
> 2026-06-26T13:01:06Z INFO qos_mesh Peer edge-002 received gossip — heartbeat::node-42 count=1
# Query current persisted state directly
$ qos state get heartbeat::node-42
> 1💡 TIP
--filter heartbeat-agent to scope logs to a single module. Use --level debug for full WASM frame traces including fuel consumption.Next Steps
Full API surface: state, gossip, input, output, clock, and error types.
How the Rust daemon, Sled store, WASM sandbox, and libp2p mesh interconnect.
How Q-OS keeps state consistent across all peers with zero coordination overhead.
Sign, publish, and earn recurring revenue from your edge agent on the registry.