.codebuddy/skills/openui-forge-anthropic/SKILL.md
OpenUI generative UI with Anthropic Claude SDK backend. Stream conversion to OpenAI NDJSON format.
npx skillsauth add OthmanAdi/openui-forge openui-forge-anthropicInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Build generative UI apps with OpenUI + Anthropic Claude. Converts Anthropic streaming events to OpenAI-compatible NDJSON.
ANTHROPIC_API_KEY environment variable setnpm install @openuidev/react-ui @openuidev/react-headless @openuidev/react-lang lucide-react zod @anthropic-ai/sdk
app/layout.tsx:import "@openuidev/react-ui/components.css";
import "@openuidev/react-ui/styles/index.css";
npm run dev and testapp/api/chat/route.tsThe backend streams from Anthropic and converts each event into OpenAI-compatible NDJSON chunks that openAIReadableStreamAdapter expects.
import { openuiLibrary } from "@openuidev/react-ui";
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
export async function POST(req: Request) {
const { messages } = await req.json();
const systemPrompt = openuiLibrary.prompt({
preamble: "You are a helpful assistant that generates interactive UIs.",
additionalRules: ["Always use Stack as root when combining multiple components."],
});
const stream = client.messages.stream({
model: "claude-sonnet-4-20250514",
max_tokens: 4096,
system: systemPrompt,
messages,
});
const encoder = new TextEncoder();
const readableStream = new ReadableStream({
async start(controller) {
const id = `chatcmpl-${Date.now()}`;
for await (const event of stream) {
if (
event.type === "content_block_delta" &&
event.delta.type === "text_delta"
) {
const chunk = {
id,
object: "chat.completion.chunk",
choices: [
{
index: 0,
delta: { content: event.delta.text },
finish_reason: null,
},
],
};
controller.enqueue(
encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`)
);
}
}
const done = {
id,
object: "chat.completion.chunk",
choices: [{ index: 0, delta: {}, finish_reason: "stop" }],
};
controller.enqueue(encoder.encode(`data: ${JSON.stringify(done)}\n\n`));
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
controller.close();
},
});
return new Response(readableStream, {
headers: { "Content-Type": "text/event-stream" },
});
}
app/chat/page.tsx"use client";
import { FullScreen } from "@openuidev/react-ui";
import { openuiLibrary } from "@openuidev/react-ui";
import {
openAIReadableStreamAdapter,
openAIMessageFormat,
} from "@openuidev/react-headless";
export default function ChatPage() {
return (
<FullScreen
componentLibrary={openuiLibrary}
adapter={openAIReadableStreamAdapter}
messageFormat={openAIMessageFormat}
apiUrl="/api/chat"
/>
);
}
import { defineComponent } from "@openuidev/react-lang";
import { z } from "zod";
export const StatusCard = defineComponent({
name: "StatusCard",
description: "Displays a status with label and color indicator",
props: z.object({
label: z.string().describe("Status label text"),
status: z.enum(["ok", "warning", "error"]).describe("Current status level"),
}),
component: ({ props }) => {
const colors = { ok: "#22c55e", warning: "#eab308", error: "#ef4444" };
return (
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
<span style={{ width: 10, height: 10, borderRadius: "50%", background: colors[props.status] }} />
<span>{props.label}</span>
</div>
);
},
});
npx @openuidev/cli generate ./src/lib/library.ts --out src/generated/system-prompt.txt
Or at runtime: openuiLibrary.prompt({ preamble: "...", additionalRules: [...] }).
ANTHROPIC_API_KEY is set in .env.localcontent_block_delta events to OpenAI NDJSON chunksfinish_reason: "stop" and ends with data: [DONE]openAIReadableStreamAdapter and openAIMessageFormatcomponentLibrary prop passed to FullScreen| Error | Cause | Fix |
|-------|-------|-----|
| 401 from Anthropic | Missing or invalid API key | Set ANTHROPIC_API_KEY in .env.local |
| Stream hangs | Missing [DONE] sentinel or controller.close() | Ensure final chunk and [DONE] are sent |
| Garbled output | Not wrapping in data: ... SSE format | Each chunk must be data: {json}\n\n |
| Components render as text | Library not passed to FullScreen | Add componentLibrary prop |
| max_tokens required | Anthropic API requires explicit max_tokens | Always set max_tokens (e.g., 4096) |
development
Build generative UI with OpenUI — any LLM provider, any backend language. Scaffold, integrate, validate.
data-ai
使用 OpenUI 构建生成式 UI 应用 — 支持任意 LLM 提供商、任意后端语言。脚手架、集成、验证。
tools
OpenUI generative UI with Vercel AI SDK. streamText, toUIMessageStreamResponse, and tools support.
development
OpenUI generative UI with Rust Axum backend. Async SSE streaming with reqwest and async-stream.