Install
$ agentstack add skill-othmanadi-openui-forge-openui-forge-rust ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
OpenUI Forge — Rust
Build generative UI apps with a React frontend + Rust Axum backend. Async SSE streaming to OpenAI-compatible NDJSON.
Activation Triggers
- "openui rust", "openui axum", "openui rust backend"
- "generative ui rust", "rust streaming ui backend"
Prerequisites
- Node.js >= 22 (24 LTS recommended) + React >= 18.3.1 (19+ recommended) (frontend)
- Rust >= 1.75 with Cargo (backend)
OPENAI_API_KEYenvironment variable set
Quick Start
- Create the React frontend and install OpenUI deps:
npm install @openuidev/react-ui @openuidev/react-headless @openuidev/react-lang lucide-react zod
- Generate the system prompt:
npx @openuidev/cli generate ./src/lib/library.ts --out backend/system-prompt.txt
- Create the Rust backend (see Full Code below)
- Run:
cargo runon:3001, frontend on:3000
Full Code
Backend: backend/Cargo.toml
[package]
name = "openui-backend"
version = "0.1.0"
edition = "2021"
[dependencies]
axum = "0.8"
http = "1"
tokio = { version = "1", features = ["full"] }
reqwest = { version = "0.13", features = ["json", "stream"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
async-stream = "0.3"
futures = "0.3"
tower-http = { version = "0.6", features = ["cors"] }
dotenvy = "0.15"
Backend: backend/src/main.rs
use axum::{
extract::{Json, State},
response::sse::{Event, Sse},
routing::post,
Router,
};
use futures::stream::Stream;
use http::HeaderValue;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::{convert::Infallible, fs, net::SocketAddr, sync::Arc};
use tower_http::cors::{Any, CorsLayer};
#[derive(Deserialize)]
struct ChatRequest {
messages: Vec,
}
#[derive(Serialize, Deserialize, Clone)]
struct Message {
role: String,
content: String,
}
#[derive(Clone)]
struct AppState {
system_prompt: String,
}
#[tokio::main]
async fn main() {
dotenvy::dotenv().ok();
let system_prompt = fs::read_to_string("system-prompt.txt")
.expect("system-prompt.txt not found");
let state = Arc::new(AppState { system_prompt });
let cors = CorsLayer::new()
.allow_origin("http://localhost:3000".parse::().unwrap())
.allow_methods([http::Method::POST])
.allow_headers(Any);
let app = Router::new()
.route("/api/chat", post(chat_handler))
.layer(cors)
.with_state(state);
let addr = SocketAddr::from(([0, 0, 0, 0], 3001));
println!("Rust backend listening on {addr}");
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}
async fn chat_handler(
State(state): State>,
Json(req): Json,
) -> Sse>> {
let mut messages = vec![Message { role: "system".into(), content: state.system_prompt.clone() }];
messages.extend(req.messages);
let api_key = std::env::var("OPENAI_API_KEY").expect("OPENAI_API_KEY not set");
let client = Client::new();
let stream = async_stream::stream! {
let resp = client
.post("https://api.openai.com/v1/chat/completions")
.bearer_auth(&api_key)
.json(&serde_json::json!({
"model": std::env::var("OPENAI_MODEL").unwrap_or_else(|_| "gpt-5.5".into()),
"stream": true,
"messages": messages,
}))
.send()
.await;
if let Ok(resp) = resp {
let mut bytes_stream = resp.bytes_stream();
use futures::StreamExt;
let mut buffer = String::new();
while let Some(Ok(chunk)) = bytes_stream.next().await {
buffer.push_str(&String::from_utf8_lossy(&chunk));
while let Some(pos) = buffer.find("\n\n") {
let line = buffer[..pos].to_string();
buffer = buffer[pos + 2..].to_string();
if line.starts_with("data: ") {
yield Ok(Event::default().data(&line[6..]));
}
}
}
}
};
Sse::new(stream)
}
Frontend: app/chat/page.tsx
"use client";
import { FullScreen } from "@openuidev/react-ui";
import { openuiChatLibrary } from "@openuidev/react-ui/genui-lib";
import {
openAIAdapter,
openAIMessageFormat,
} from "@openuidev/react-headless";
export default function ChatPage() {
return (
);
}
> The Rust backend re-emits SSE via Axum's Sse response (Axum wraps each Event::default().data(...) with the data: prefix). Pair it with openAIAdapter() on the frontend. openAIReadableStreamAdapter() is for NDJSON and will silently produce no output here.
System Prompt Generation
npx @openuidev/cli generate ./src/lib/library.ts --out backend/system-prompt.txt
Validation Checklist
- [ ]
system-prompt.txtexists in the Rust backend directory - [ ]
OPENAI_API_KEYis set in environment or.env - [ ] CORS layer allows the frontend origin
- [ ] SSE events forward OpenAI stream chunks correctly
- [ ] Buffer parsing handles partial SSE lines across chunk boundaries
- [ ] Frontend
apiUrlpoints tohttp://localhost:3001/api/chat - [ ] Frontend uses
streamProtocol={openAIAdapter()}andopenAIMessageFormat - [ ]
componentLibrary={openuiChatLibrary}prop passed toFullScreen - [ ] CSS import in root layout (
@openuidev/react-ui/components.css)
Error Patterns
| Error | Cause | Fix | |-------|-------|-----| | system-prompt.txt not found | File missing | Run CLI generate command | | CORS blocked | Origin not in CorsLayer | Update .allow_origin() | | Partial SSE events | Chunk boundary splitting | Buffer and split on \n\n boundaries (handled in code) | | Compile error on http::HeaderValue | Missing http crate | Add http = "1" to Cargo.toml (already in the example) or import from axum::http | | static_mut_refs warning on static mut | Rust 2024 deprecates raw static mut access | Use OnceLock or carry state in State> (this example uses the latter) | | Connection reset | Tokio runtime panic | Check .await on all async calls, verify features = ["full"] |
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: OthmanAdi
- Source: OthmanAdi/openui-forge
- License: MIT
- Homepage: https://spruce-prism-8yya.here.now/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.