Install
$ agentstack add skill-othmanadi-openui-forge-openui-forge-python ✓ 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 Used
- ✓ 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 — Python
Build generative UI apps with a React frontend + Python FastAPI backend. Streams OpenAI-compatible NDJSON.
Activation Triggers
- "openui python", "openui fastapi", "openui flask"
- "generative ui python", "python streaming ui backend"
Prerequisites
- Node.js >= 22 (24 LTS recommended) + React >= 18.3.1 (19+ recommended) (frontend)
- Python >= 3.10 (backend)
OPENAI_API_KEYorANTHROPIC_API_KEYset
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 from your component library:
npx @openuidev/cli generate ./src/lib/library.ts --out backend/system-prompt.txt
- Set up the Python backend (see Full Code below)
- Run both: frontend on
:3000, backend on:8000
Full Code
Backend: backend/requirements.txt
fastapi>=0.115.0
uvicorn>=0.24.0
openai>=2.0
anthropic>=0.111.0
python-dotenv>=1.0.0
> The Python >= 3.10 floor comes from fastapi/uvicorn/python-dotenv; openai and anthropic themselves need only Python 3.9.
Backend (OpenAI): backend/main.py
import os
from pathlib import Path
from dotenv import load_dotenv
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
from openai import AsyncOpenAI
load_dotenv()
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"],
allow_methods=["POST"],
allow_headers=["*"],
)
# AsyncOpenAI keeps the request from blocking the event loop during streaming.
client = AsyncOpenAI()
SYSTEM_PROMPT = Path("system-prompt.txt").read_text()
@app.post("/api/chat")
async def chat(request: Request):
body = await request.json()
messages = [{"role": "system", "content": SYSTEM_PROMPT}] + body["messages"]
async def generate():
response = await client.chat.completions.create(
model=os.getenv("OPENAI_MODEL", "gpt-5.5"),
stream=True,
messages=messages,
)
async for chunk in response:
data = chunk.model_dump_json()
yield f"data: {data}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(generate(), media_type="text/event-stream")
Backend (Anthropic variant): backend/main_anthropic.py
import os, json, time
from pathlib import Path
from dotenv import load_dotenv
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
from anthropic import AsyncAnthropic
load_dotenv()
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"],
allow_methods=["POST"],
allow_headers=["*"],
)
# AsyncAnthropic mirrors AsyncOpenAI so the stream does not block the loop.
client = AsyncAnthropic()
SYSTEM_PROMPT = Path("system-prompt.txt").read_text()
@app.post("/api/chat")
async def chat(request: Request):
body = await request.json()
stream_id = f"chatcmpl-{int(time.time())}"
async def generate():
async with client.messages.stream(
model=os.getenv("ANTHROPIC_MODEL", "claude-sonnet-4-6"),
max_tokens=4096,
system=SYSTEM_PROMPT,
messages=body["messages"],
) as stream:
async for text in stream.text_stream:
chunk = {"id": stream_id, "object": "chat.completion.chunk",
"choices": [{"index": 0, "delta": {"content": text}, "finish_reason": None}]}
yield f"data: {json.dumps(chunk)}\n\n"
done = {"id": stream_id, "object": "chat.completion.chunk",
"choices": [{"index": 0, "delta": {}, "finish_reason": "stop"}]}
yield f"data: {json.dumps(done)}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(generate(), media_type="text/event-stream")
Frontend: app/chat/page.tsx (or src/Chat.tsx for Vite)
"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 Python backend emits SSE (data: {json}\n\n). Pair it with openAIAdapter() on the frontend. openAIReadableStreamAdapter() is for NDJSON (no data: prefix) and will silently produce no output here.
System Prompt Generation
Generate once, copy to backend directory:
npx @openuidev/cli generate ./src/lib/library.ts --out backend/system-prompt.txt
Regenerate after every component change.
Validation Checklist
- [ ]
system-prompt.txtexists in the backend directory - [ ] CORS allows the frontend origin
- [ ] Backend streams
data: {json}\n\nlines with OpenAI chunk format - [ ] Final chunk has
finish_reason: "stop"followed bydata: [DONE] - [ ] Frontend
apiUrlpoints to the correct backend URL - [ ] Frontend uses
streamProtocol={openAIAdapter()}andopenAIMessageFormat - [ ]
componentLibrary={openuiChatLibrary}prop passed toFullScreen - [ ] CSS import in root layout (
@openuidev/react-ui/components.css) - [ ] Run backend:
uvicorn main:app --reload --port 8000
Error Patterns
| Error | Cause | Fix | |-------|-------|-----| | CORS blocked | Frontend origin not allowed | Add origin to allow_origins list | | Connection refused | Backend not running | Start with uvicorn main:app --port 8000 | | FileNotFoundError | system-prompt.txt missing | Run the CLI generate command | | Stream not rendering | Backend not sending SSE format | Ensure data: prefix and \n\n after each chunk | | 422 Unprocessable Entity | Request body missing messages | Check frontend sends { messages: [...] } |
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.