# generate-crate > Generate a complete Rust WASM crate from an Intermediate Representation (IR) file, following QWASR SDK patterns for stateless, provider-based WASM components running on wasmtime. - Author: Andrew Weston - Repository: augentic/plugins - Version: 20260202193921 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-06 - Source: https://github.com/augentic/plugins - Web: https://mule.run/skillshub/@@augentic/plugins~generate-crate:20260202193921 --- --- name: generate-crate description: Generate Rust WASM crate from IR following QWASR SDK patterns with provider-based dependency injection. argument-hint: [ir-path] [typescript-source] [rust-crate-output] --- # Generate Crate Skill ## Overview Generate a complete Rust WASM crate from an Intermediate Representation (IR) file, following QWASR SDK patterns for stateless, provider-based WASM components running on wasmtime. --- ## Arguments 1. **IR Path** (`$ARGUMENTS[0]`): Path to the IR file (from analyse-codebase skill) 2. **TypeScript Source** (`$ARGUMENTS[1]`): Path to original TypeScript source (for reference) 3. **Rust Crate Output** (`$ARGUMENTS[2]`): Output path for the Rust crate (e.g., `./crates/my_component`) --- ## Required Permissions ⚠️ **RECOMMENDED**: For seamless execution, request `required_permissions: ["all"]` on the first Shell command to enable cargo operations and file generation without interruption. --- ## Prerequisites - IR file generated by `analyse-codebase` skill - Reference documents are embedded in `references/` directory (no external dependencies required) --- ## Required Reference Documents (Embedded) **All essential patterns are embedded in the `references/` directory** alongside this skill. Read these documents before generating code: 1. `references/handler-trait.md` - Handler trait implementation patterns and examples 2. `references/provider-traits.md` - Provider trait composition and dependency injection 3. `references/wasm32.md` - WebAssembly constraints and forbidden APIs 4. `references/guardrails.md` - Hard rules and enforceable guardrails for QWASR migrations 5. `references/http-handler.md` - Complete working example demonstrating handler patterns ### Usage Instructions **Before generating any code**, read all reference documents to understand: - QWASR SDK patterns and API surface - Provider-based dependency injection - WASM32 constraints and compatibility requirements - Handler trait implementation patterns - Error handling and type safety conventions The embedded reference documents are the **primary source** and contain all necessary patterns for standard migrations. ### Optional: Fetching Latest Versions For the absolute latest versions, you can optionally fetch from the source repository: ```bash # Using gh CLI gh api repos/augentic/context/contents/supportingDocs/handler-trait-patterns.md --jq '.content' | base64 -d gh api repos/augentic/context/contents/supportingDocs/provider-composition.md --jq '.content' | base64 -d gh api repos/augentic/context/contents/supportingDocs/wasm32-constraints.md --jq '.content' | base64 -d gh api repos/augentic/context/contents/supportingDocs/guardrails.md --jq '.content' | base64 -d # Or using git clone git clone --depth 1 https://github.com/augentic/context.git /tmp/augentic-context ``` **Note:** The embedded reference documents are sufficient for all standard migrations. --- ## Section 1: TODO Markers (Mandatory) Any functionality that cannot be fully implemented MUST be marked: ```rust // TODO: // Reason: ``` Use for: - Missing WASI capabilities (sleep, timers) - Incomplete IR specification - Ambiguous requirements - Platform limitations (threading, blocking I/O) --- ## Section 2: WASI Handler Patterns (Embedded) ### Handler Trait (Exact Definition) ```rust use qwasr_sdk::api::{Context, Reply}; pub trait Handler

: Sized { type Input; type Output; type Error; fn from_input(input: Self::Input) -> Self; async fn handle(self, ctx: Context<'_, P>) -> Result, Self::Error>; } ``` ### Handler Implementation Pattern ```rust use qwasr_sdk::{api::Context, Config, HttpRequest, Publisher, Identity, Result, Reply}; impl

Handler

for MyRequest where P: Config + HttpRequest + Publisher + Identity, { type Input = MyInputType; type Output = MyOutputType; type Error = qwasr_sdk::Error; fn from_input(input: Self::Input) -> Self { Self { /* fields from input */ } } async fn handle(self, ctx: Context<'_, P>) -> Result> { // Access provider via ctx.provider // Access owner via ctx.owner let result = internal_logic(ctx.provider, &self).await?; Ok(result.into()) } } ``` ### Key Rules - Implement `Handler` directly on the request type `T` (not wrapper types) - Handler trait requires: `type Input`, `type Output`, `type Error`, `fn from_input`, `async fn handle` - Use `Context<'_, P>` to access provider and owner - Return `Reply` wrapped responses using `.into()` - Internal logic must be in a separate async fn from the trait impl --- ## Section 3: QWASR SDK API Surface (Authoritative) Use these exact identifiers. Do not hallucinate other methods. ### Provider Traits (Methods) | Trait | Method | Signature | | ------- | -------- | ----------- | | `Publisher` | `send` | `async fn send(&self, topic: &str, message: &Message) -> Result<()>` | | `HttpRequest` | `fetch` | `async fn fetch(&self, request: http::Request) -> Result>` | | `Identity` | `access_token` | `async fn access_token(&self, identity: String) -> Result` | | `StateStore` | `get` | `async fn get(&self, key: &str) -> Result>>` | | `StateStore` | `set` | `async fn set(&self, key: &str, value: &[u8], ttl_secs: Option) -> Result<()>` | | `StateStore` | `delete` | `async fn delete(&self, key: &str) -> Result<()>` | | `Config` | `get` | `async fn get(&self, key: &str) -> Result` | ### Message Construction ```rust use qwasr_sdk::Message; let message = Message::new(&payload_bytes); ``` ### Required Imports ```rust use qwasr_sdk::{Config, HttpRequest, Identity, Publisher, StateStore, Message, Error, Result}; use qwasr_sdk::api::{Context, Reply}; ``` **NEVER**: redefine, wrap, implement, or shadow any qwasr-sdk provider trait. --- ## Section 4: External I/O Mapping (1-to-1) All external I/O must map exactly to provider trait methods. No batching, retries, or additional calls. ### HTTP Mapping | TypeScript | Rust | | ----------- | ----------- | | `fetch`, `axios.get/post`, `got` | `HttpRequest::fetch()` | ```rust // Build request let request = http::Request::builder() .method("GET") .uri(&url) .header(AUTHORIZATION, format!("Bearer {token}")) .body(Empty::::new())?; // Execute let response = HttpRequest::fetch(provider, request).await?; ``` ### Messaging Mapping | TypeScript | Rust | | ----------- | ----------- | | `producer.send`, `producer.sendBatch` | `Publisher::send()` | ### StateStore Mapping | TypeScript | Rust | | ----------- | ----------- | | `redis.get` | `StateStore::get()` | | `redis.set` | `StateStore::set()` | | `redis.del` | `StateStore::delete()` | ### Identity Mapping | TypeScript | Rust | | ----------- | ----------- | | Azure AD token acquisition | `Identity::access_token(identity_string)` | **CRITICAL**: If ANY HTTP call requires auth: 1. Include `Identity` in handler bounds 2. Fetch identity string from Config 3. Call `Identity::access_token()` before HTTP request 4. Add token as Authorization header ```rust let identity = Config::get(provider, "AZURE_IDENTITY").await?; let token = Identity::access_token(provider, identity).await?; ``` ### XML Parsing (Mandatory for XML inputs) Use `quick-xml` with serde, NOT manual string extraction: ```rust #[derive(Debug, Clone, Deserialize)] pub struct MessagePayload { #[serde(rename(deserialize = "xmlFieldName"))] pub field_name: Option, } let parsed: MessagePayload = quick_xml::de::from_reader(xml_bytes.as_slice())?; ``` --- ## Section 5: Dependency Injection ### Provider Bounds (Minimal and Local) Each function should require only the capability traits it uses: ```rust pub async fn process_message

(provider: &P, input: &Input) -> Result where P: Config + HttpRequest + Publisher, { // ... } ``` ### Rules - Every I/O function accepts generic `provider: &P` with required trait bounds - Never construct host-side types (Client, Config, Producer, Redis) - Never create new I/O abstractions - All state must be contextual and explicit (no caching/memoization) --- ## Section 6: No Host Dependencies The generated code MUST NOT use or import: - `reqwest`, `hyper` (HTTP clients) - `redis` crates - `kafka` clients - `jwt` libraries - OAuth client libraries All I/O flows through WASI provider traits only. --- ## Section 7: Implementation Requirements ### Cargo.toml ```toml [package] name = "component_name" version = "0.1.0" edition = "2021" [dependencies] qwasr-sdk.workspace = true common.workspace = true anyhow = "1.0" thiserror = "2.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" chrono = { version = "0.4", features = ["serde"] } tracing = "0.1" quick-xml = { version = "0.37", features = ["serialize"] } [dev-dependencies] augentic-test.workspace = true tokio = { version = "1", features = ["rt", "macros"] } ``` ### Module Structure ```text $ARGUMENTS[2]/ ├── Cargo.toml ├── src/ │ ├── lib.rs # Public API, module declarations │ ├── error.rs # Error types with thiserror │ ├── types.rs # Input/output structures │ ├── handlers.rs # Handler implementations │ └── transform.rs # Business logic functions ├── Migration.md # Required doc ├── Architecture.md # Required doc └── .env.example # Required doc ``` ### Output Structure Fidelity Preserve exact nesting from IR/TypeScript: ```rust // CORRECT - nested structs pub struct OutputEvent { pub received_at: DateTime, pub event_type: EventType, pub message_data: MessageData, // Nested pub remote_data: RemoteData, // Nested } pub struct MessageData { pub timestamp: DateTime, } // WRONG - flattened pub struct FlatEvent { pub timestamp: DateTime, // Should be in message_data pub external_id: String, // Should be in remote_data } ``` ### Strong Typing - Replace string literals with enums - Use newtypes for IDs, tokens, coordinates - Encode state machines with enums + match ### Error Handling ```rust use thiserror::Error; use qwasr_sdk::{bad_request, Error as SdkError}; #[derive(Error, Debug)] pub enum ComponentError { #[error("{0}")] InvalidInput(String), #[error("Parse error: {0}")] ParseError(String), } impl From for SdkError { fn from(e: ComponentError) -> Self { match e { ComponentError::InvalidInput(msg) => bad_request!("invalid_input", msg), ComponentError::ParseError(msg) => bad_request!("parse_error", msg), } } } ``` --- ## Section 8: Statelessness (Strict) WASM components must be fully stateless: - **NO** `OnceCell`, `static mut`, global caches - **NO** global `HashMap`/`BTreeMap`/`IndexMap` - **NO** background tasks, threads, async work outliving handlers - **NO** memoization or caching - **NO** `LazyLock`, `lazy_static!` All state flows through function parameters or provider trait calls. **Config Access Pattern**: ```rust // WRONG - static config static CONFIG: LazyLock = LazyLock::new(|| load_config()); // CORRECT - provider-based let api_url = Config::get(provider, "API_URL").await?; ``` --- ## Section 9: Hard Rules - Implement all logic exactly as defined in IR - Do not simplify behavior or hallucinate functionality - Do not remove or alter error flows - Respect provider trait usage strictly - Ask for clarification if ambiguity appears - Generated code must comply with WASM single-threaded semantics - Only emit `tracing::debug!` logs unless IR explicitly requires higher levels --- ## Section 10: Output Hygiene Do NOT emit: - `target/`, `Cargo.lock` - `.fingerprint/`, `incremental/` - `*.rlib`, `*.rmeta`, `*.d` - Compiled wasm, component, or binary output Only emit: `.rs` source files, `Cargo.toml`, and the 3 required docs. --- ## Section 11: Required Output Documents Generate EXACTLY these three files after code generation: ### Migration.md 2-3 paragraphs covering: - Key transformation decisions (TS → Rust mapping) - Areas of uncertainty requiring human review - Critical design choices made ### Architecture.md 2-3 paragraphs explaining: - Component behavior and data flows - Error handling and provider integration - How WASM constraints are satisfied ### .env.example ```bash # Required environment variables API_URL=https://api.example.com AZURE_IDENTITY=my-identity-name OUTPUT_TOPIC=events-topic ``` --- ## Section 12: Verification Checklist (Mandatory) Before completing, verify ALL: ### Provider Traits - [ ] If any HTTP call requires auth, `Identity` is in handler bounds - [ ] All provider traits used are imported from `qwasr_sdk` - [ ] Handler bounds include ALL required traits ### API Response Handling - [ ] Every HTTP response parsing matches IR-documented shape exactly - [ ] No invented response structures - [ ] Response error cases are handled ### Output Structure - [ ] Output event nesting matches IR/TS exactly (nested structs) - [ ] Field names match expected JSON serialization - [ ] Coordinate types match IR (f64 vs f32) ### XML Parsing - [ ] Uses `quick-xml` with serde, NOT manual string extraction - [ ] All XML element names have serde rename attributes - [ ] Integer enums use `serde_repr` ### TODO Markers - [ ] Every incomplete implementation has a TODO marker - [ ] TODO format: `// TODO: ` followed by `// Reason: ` ### Timing/Publication - [ ] If IR shows repeated publication, implemented or marked TODO - [ ] If IR shows delays/sleeps, marked TODO with WASI reason ### Error Model - [ ] Errors are typed enums, not flat structs - [ ] `From for qwasr_sdk::Error` is implemented ### Statelessness - [ ] Zero instances of: `static mut`, `OnceCell`, `LazyLock`, `lazy_static!` - [ ] Zero instances of: `std::fs`, `std::net`, `std::thread`, `std::env` - [ ] All I/O routed through provider traits ### Files Generated - [ ] At least 3 `.rs` source files exist - [ ] `Cargo.toml` exists with correct dependencies - [ ] `Migration.md`, `Architecture.md`, `.env.example` exist - [ ] No build artifacts --- ## Process Summary 1. Read IR from `$ARGUMENTS[0]` 2. (Optional) Fetch latest patterns using `gh` CLI or git clone if needed 3. Generate `Cargo.toml` with workspace dependencies 4. Generate `src/error.rs` with typed error enum 5. Generate `src/types.rs` with input/output structures 6. Generate `src/handlers.rs` with Handler implementations 7. Generate `src/transform.rs` with business logic 8. Generate `src/lib.rs` with module declarations and exports 9. Generate `Migration.md`, `Architecture.md`, `.env.example` 10. Run verification checklist 11. Output crate to `$ARGUMENTS[2]` --- ## Examples Detailed examples are available in the `references/examples/` directory: 1. [01-simple-http-handler.md](references/examples/01-simple-http-handler.md) - Generate Rust crate from IR for simple HTTP API handler 2. [02-complex-service-with-authentication-and-pubsub.md](references/examples/02-complex-service-with-authentication-and-pubsub.md) - Service with Azure AD auth and Kafka publishing 3. [03-service-with-incomplete-implementation-todos.md](references/examples/03-service-with-incomplete-implementation-todos.md) - Handling operations not supported by WASI 4. [04-xml-parsing-service.md](references/examples/04-xml-parsing-service.md) - Generate crate for XML message parsing 5. [05-error-recovery-invalid-ir.md](references/examples/05-error-recovery-invalid-ir.md) - Recovering from malformed or incomplete IR Each example includes: - Scenario description - Input parameters - IR content - Execution commands - Expected output - Result explanation See the examples directory for complete details. --- ## Important Notes - The generated code targets `wasm32-wasip1` or `wasm32-wasip2` - All I/O is asynchronous via provider traits - No blocking operations allowed - Handler invocations are stateless and independent - Test incrementally with `cargo check` during generation