components
npx machina-cli add skill andrmaz/spec-driven-architecture/components --openclawTambo Components
Two component types: generative (AI creates on-demand) and interactable (pre-placed, AI updates).
Quick Start
// Generative: AI creates when needed
const components: TamboComponent[] = [
{
name: "WeatherCard",
component: WeatherCard,
description: "Shows weather. Use when user asks about weather.",
propsSchema: z.object({ city: z.string(), temp: z.number() }),
},
];
<TamboProvider components={components}>
<App />
</TamboProvider>;
Generative Components
AI dynamically selects and renders these in response to user messages.
import { TamboProvider, TamboComponent } from "@tambo-ai/react";
import { z } from "zod";
const WeatherCardSchema = z.object({
city: z.string().describe("City name"),
temperature: z.number().describe("Temperature in Celsius"),
condition: z.string().describe("Weather condition"),
});
const components: TamboComponent[] = [
{
name: "WeatherCard",
component: WeatherCard,
description:
"Displays weather for a city. Use when user asks about weather.",
propsSchema: WeatherCardSchema,
},
];
<TamboProvider apiKey={apiKey} components={components}>
<App />
</TamboProvider>;
Rendering Generative Components
Use ComponentRenderer to render AI-generated components in your message list:
import { ComponentRenderer } from "@tambo-ai/react";
function Message({
message,
threadId,
}: {
message: TamboMessage;
threadId: string;
}) {
return (
<div>
{message.content.map((block) => {
switch (block.type) {
case "text":
return <p key={block.type}>{block.text}</p>;
case "component":
return (
<ComponentRenderer
key={block.id}
content={block}
threadId={threadId}
messageId={message.id}
/>
);
default:
return null;
}
})}
</div>
);
}
Generative Key Points
- propsSchema: Zod object with
.describe()on each field - description: Tells AI when to use the component
- Streaming: Props start
undefined, make them optional or handle gracefully - Use
z.infer<typeof Schema>for TypeScript props type
Interactable Components
Pre-place in your UI; AI can observe and update props via natural language.
import { withTamboInteractable } from "@tambo-ai/react";
import { z } from "zod";
const NoteSchema = z.object({
title: z.string().describe("Note title"),
content: z.string().describe("Note content"),
color: z.enum(["white", "yellow", "blue"]).optional(),
});
function Note({ title, content, color = "white" }: Props) {
return (
<div style={{ backgroundColor: color }}>
<h3>{title}</h3>
<p>{content}</p>
</div>
);
}
export const InteractableNote = withTamboInteractable(Note, {
componentName: "Note",
description: "A note with editable title, content, and color",
propsSchema: NoteSchema,
});
Interactable How It Works
- Auto-registration: Component registers when mounted
- Context sending: Current props automatically visible to AI
- Tool registration: Update tools registered automatically
- Bidirectional: User edits and AI updates both work
When to Use Each
| Generative | Interactable |
|---|---|
| AI creates on-demand | You pre-place in UI |
| One-time render | Persistent across session |
| Props generated once | AI can update props |
| Chat responses, dashboards | Settings, forms, task boards |
Source
git clone https://github.com/andrmaz/spec-driven-architecture/blob/develop/.agents/skills/components/SKILL.mdView on GitHub Overview
Tambo Components lets you define two component types: generative, AI creates on demand, and interactable, pre-placed components AI can update. Use it when defining components or wiring TamboComponent, withTamboInteractable, and propsSchema so AI can render or adjust components reliably.
How This Skill Works
Developers declare an array of TamboComponent items with a name, component, description, and a propsSchema. Wrap your app in a TamboProvider and use ComponentRenderer to render generative components inside messages; for interactable components, wrap with withTamboInteractable to enable auto-registration and AI updates. The schema and descriptions guide AI behavior and prop validation.
When to Use It
- Generative: AI creates components on demand when responding to user messages.
- Generative: Use for one-time renders like chat responses or dashboards.
- Generative: Props are generated on the fly and may start undefined during streaming.
- Interactable: Pre-place components in the UI so AI can observe and update their props.
- Interactable: Maintain persistence across a session for settings or forms.
Quick Start
- Step 1: Define an array of TamboComponent with name, component, description and a propsSchema.
- Step 2: Wrap your app with <TamboProvider components={components}>.
- Step 3: Use ComponentRenderer to render generative components inside messages or rely on withTamboInteractable for updates.
Best Practices
- Define a precise propsSchema with zod and describe on each field.
- Provide a clear description to tell AI when to use the component.
- Design streaming friendly props by allowing undefined values initially.
- Use z.infer<typeof Schema> to derive TypeScript types for safety.
- For interactables, rely on auto-registration and enable bidirectional updates.
Example Use Cases
- WeatherCard generative example used to show weather on demand in chat.
- Interactable Note pre-placed UI component with editable title, content, and color.
- Weather dashboard that includes a generative component to answer weather questions.
- Using ComponentRenderer to render AI-generated components inside a message list.
- Auto-registered interactable notes with AI updating props via natural language.