Skip to content
Back to skills

Openui Forge Anthropic

ASecurity

OpenUI generative UI with Anthropic Claude SDK backend. Stream conversion to OpenAI NDJSON format.

  • 22 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 27, 2026
developmenttypescriptbashreactnextjsnodeapifrontendbackend

Works with

  • cli
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned May 27, 2026

npx -y skills add OthmanAdi/openui-forge --skill openui-forge-anthropic --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Openui Forge Anthropic?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Openui Forge Anthropic
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/othmanadi-openui-forge-anthropic/badge)](https://www.skillsdirectory.com/skills/othmanadi-openui-forge-anthropic)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: openui-forge-anthropic
description: OpenUI generative UI with Anthropic Claude SDK backend. Stream conversion to OpenAI NDJSON format.
version: 1.0.0
author: OthmanAdi
---

# OpenUI Forge — Anthropic

Build generative UI apps with OpenUI + Anthropic Claude. Converts Anthropic streaming events to OpenAI-compatible NDJSON.

## Activation Triggers

- "openui anthropic", "openui claude", "openui sonnet"
- "generative ui claude", "claude streaming ui"

## Prerequisites

- Node.js >= 18, React >= 18.3.1 (19+ recommended)
- `ANTHROPIC_API_KEY` environment variable set
- Next.js project (App Router recommended)

## Quick Start

1. Install dependencies:
```bash
npm install @openuidev/react-ui @openuidev/react-headless @openuidev/react-lang lucide-react zod @anthropic-ai/sdk
```
2. Add the CSS import to `app/layout.tsx`:
```tsx
import "@openuidev/react-ui/components.css";
```
3. Create the API route and frontend page below
4. Run `npm run dev` and test

## Full Code

### Backend: `app/api/chat/route.ts`

The backend streams from Anthropic and converts each event into OpenAI-compatible SSE chunks that `openAIAdapter()` expects (`data: {json}\n\n` lines, terminated by `data: [DONE]`).

```typescript
import { openuiChatLibrary } from "@openuidev/react-ui/genui-lib";
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

export async function POST(req: Request) {
  const { messages } = await req.json();

  const systemPrompt = openuiChatLibrary.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: process.env.ANTHROPIC_MODEL ?? "claude-sonnet-4-6",
    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" },
  });
}
```

### Frontend: `app/chat/page.tsx`

```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 (
    <FullScreen
      componentLibrary={openuiChatLibrary}
      streamProtocol={openAIAdapter()}
      messageFormat={openAIMessageFormat}
      apiUrl="/api/chat"
    />
  );
}
```

> The 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.

## Component Creation

```tsx
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>
    );
  },
});
```

## System Prompt Generation

```bash
npx @openuidev/cli generate ./src/lib/library.ts --out src/generated/system-prompt.txt
```

Or at runtime: `openuiChatLibrary.prompt({ preamble: "...", additionalRules: [...] })`.

## Validation Checklist

- [ ] `ANTHROPIC_API_KEY` is set in `.env.local`
- [ ] CSS import present in root layout
- [ ] Backend converts Anthropic `content_block_delta` events to OpenAI-compatible SSE chunks
- [ ] Final chunk has `finish_reason: "stop"` and ends with `data: [DONE]`
- [ ] Frontend uses `streamProtocol={openAIAdapter()}` and `openAIMessageFormat`
- [ ] `componentLibrary={openuiChatLibrary}` prop passed to `FullScreen`

## Error Patterns

| 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={openuiChatLibrary}` prop |
| Nothing renders, no error | Used `openAIReadableStreamAdapter()` (NDJSON) on SSE stream, or `adapter=` prop (silently ignored) | Use `streamProtocol={openAIAdapter()}` |
| `max_tokens` required | Anthropic API requires explicit max_tokens | Always set `max_tokens` (e.g., 4096) |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.