A simple, well-documented example agent for the Whatever OS platform. Perfect for learning how to build AI agents with the Claude Agent SDK.
- Generates QR codes for URLs, text, and any content
- Displays QR codes in a beautiful UI card
- Demonstrates all core agent concepts with clear documentation
# 1. Install dependencies
npm install
# 2. Copy environment file
cp .env.example .env
# 3. Add your Anthropic API key to .env
# ANTHROPIC_API_KEY=sk-ant-...
# 4. Start the development server
npm run devThe agent runs on http://localhost:3003 by default.
example-agent/
├── app/ # Next.js App Router
│ ├── api/
│ │ ├── process/route.ts # Main message processing endpoint
│ │ ├── health/route.ts # Health check endpoint
│ │ ├── ui/[id]/route.ts # UI data endpoint for iframes
│ │ └── iframe-config/route.ts # Iframe display configuration
│ ├── frames/
│ │ ├── qr-code/page.tsx # QR code iframe page
│ │ ├── lib/fetch-ui-data.ts # Data fetching utility
│ │ └── layout.tsx # Frames layout
│ ├── welcome/page.tsx # Welcome screen
│ └── layout.tsx # Root layout
│
├── components/
│ └── ui-frames/
│ └── qr-frame.tsx # QR code display component
│
├── lib/
│ ├── agent.ts # ⭐ Main agent class
│ ├── tools.ts # ⭐ MCP tools (QR generation)
│ ├── system-prompt.ts # ⭐ System prompt
│ ├── ui-store.ts # UI data storage
│ ├── settings.json # Agent settings
│ └── core/ # Agent framework
│ ├── base-agent.ts # Base agent class
│ ├── orchestrator.ts # Claude SDK integration
│ ├── types.ts # TypeScript types
│ ├── schema-utils.ts # JSON schema helpers
│ └── iframe-config.ts # Iframe config types
│
└── README.md # This file!
Tools are actions the AI can perform. Define them with:
- Name: Unique identifier
- Description: Helps AI understand when to use it
- Schema: Zod schema for input validation
- Handler: Async function that executes the action
import { tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";
const generateQR = tool(
"generate_qr", // Name
"Generate a QR code from text or URL", // Description
{ // Input schema
content: z.string(),
size: z.number().optional().default(300),
},
async ({ content, size }) => { // Handler
const dataUrl = await QRCode.toDataURL(content, { width: size });
return {
content: [{ type: "text", text: JSON.stringify({ dataUrl, content }) }]
};
}
);The system prompt defines the AI's personality and behavior:
const SYSTEM_PROMPT = `You are QR Code Generator, a helpful assistant...
## Your Capabilities
- Generate QR codes for URLs and text
- Customize colors and sizes
## Response Format
Use ui_data with type "qr_code" to display QR codes.
`;The agent class ties everything together:
class ExampleAgent extends BaseAgent {
readonly config = { id: "example", name: "QR Generator", ... };
getMcpServer() { return exampleMcpServer; }
async buildSystemPrompt() { return buildSystemPrompt(); }
getFrameUrl(type: string) { /* Map UI types to iframe URLs */ }
}Rich UI components rendered in iframes:
User asks for QR code
↓
Agent generates QR code using tool
↓
Agent returns ui_data: { type: "qr_code", dataUrl: "...", content: "..." }
↓
UI data stored with unique ID
↓
Platform loads iframe: /frames/qr-code?id=abc123
↓
Iframe fetches data from /api/ui/abc123
↓
Beautiful QR code card displayed!
| Endpoint | Method | Description |
|---|---|---|
/api/process |
POST | Process user messages (main endpoint) |
/api/health |
GET | Health check |
/api/ui/[id] |
GET | Fetch UI data for iframes |
/api/iframe-config |
GET | Get iframe display config |
- Define the tool in
lib/tools.ts:
const myNewTool = tool(
"my_tool",
"Description of what it does",
{ input: z.string() },
async ({ input }) => {
// Do something
return { content: [{ type: "text", text: "result" }] };
}
);
// Add to allTools array
const allTools = [generateQR, myNewTool];- Update the system prompt to mention the new capability
- Create the frame component in
components/ui-frames/ - Create the frame page in
app/frames/my-type/page.tsx - Update
lib/agent.ts:- Add to
EXAMPLE_UI_TYPES - Add properties to
EXAMPLE_UI_PROPERTIES - Add route mapping in
getFrameUrl()
- Add to
Edit lib/system-prompt.ts to change the agent's personality, capabilities, and response format.
| Variable | Description | Default |
|---|---|---|
ANTHROPIC_API_KEY |
Your Anthropic API key | Required |
AGENT_ID |
Agent ID (match platform registration) | example |
PLATFORM_JWKS_URL |
Platform's JWKS endpoint for JWT verification | http://localhost:3000/.well-known/jwks.json |
AGENT_BASE_URL |
Agent's base URL for iframe URLs | http://localhost:3003 |
NEXT_PUBLIC_AGENT_URL |
Public URL for client-side fetches | http://localhost:3003 |
- Deploy to Vercel, Railway, or your hosting provider
- Set environment variables in your hosting dashboard
- Register the agent in the Whatever platform's
agentstable:
INSERT INTO agents (id, name, description, base_url, is_public, price)
VALUES (
'example',
'QR Generator',
'Generate QR codes for URLs and text',
'https://your-agent.vercel.app',
true,
0
);┌─────────────────────┐ ┌─────────────────────┐
│ Whatever Platform │────▶│ Example Agent │
│ (sends messages) │◀────│ (processes them) │
└─────────────────────┘ └─────────────────────┘
│ │
│ ▼
│ ┌─────────────────┐
│ │ Claude Agent │
│ │ SDK │
│ └────────┬────────┘
│ │
│ ▼
│ ┌─────────────────┐
│ │ MCP Tools │
│ │ (generate_qr) │
│ └─────────────────┘
│
▼
┌─────────────────────┐
│ Iframe (QR code) │◀──── Loads UI data from agent
└─────────────────────┘
- Start the agent:
npm run dev - Open
http://localhost:3003/welcometo see the welcome screen - Use the Whatever platform to chat with the agent
- Ask: "Create a QR code for https://example.com"
Try these exercises:
- Add Color Support: Update the QR frame to accept custom colors
- Add WiFi QR Codes: Create a special tool for WiFi credentials
- Add History: Store generated QR codes in a database
Add AGENT_ID=example to your .env file.
Make sure PLATFORM_JWKS_URL points to the running platform.
Check that AGENT_BASE_URL and NEXT_PUBLIC_AGENT_URL are set correctly.
MIT - Feel free to use this as a starting point for your own agents!