Tambo building-with-tambo
Integrates Tambo into existing React apps — detects tech stack, installs @tambo-ai/react, wires TamboProvider, registers components with Zod schemas, and sets up tools/context. Use when adding AI-powered generative UI to an existing codebase. Triggers on "add Tambo", "integrate Tambo", "add AI chat to my app", "add generative UI", or when the user has an existing React/Next.js/Vite project and wants to add AI-powered components. For brand-new projects, use generative-ui instead.
git clone https://github.com/tambo-ai/tambo
T=$(mktemp -d) && git clone --depth=1 https://github.com/tambo-ai/tambo "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/tambo/skills/building-with-tambo" ~/.claude/skills/tambo-ai-tambo-building-with-tambo && rm -rf "$T"
plugins/tambo/skills/building-with-tambo/SKILL.mdBuilding with Tambo
Detect tech stack and integrate Tambo while preserving existing patterns.
Reference Guides
Load these when you reach the relevant step or need deeper implementation details:
- Components - Load at Step 5. Generative vs interactable components, propsSchema, ComponentRenderer.
- Component Rendering - Streaming props, loading states, persistent state. Load when building custom message rendering.
- Threads and Input - Load when building custom chat UI. useTambo(), useTamboThreadInput(), userKey/userToken auth, suggestions, voice.
- Tools and Context - Load when wiring host app APIs. defineTool(), MCP servers, contextHelpers.
- CLI Reference - Load at Step 6.
component library,tambo add
flags, non-interactive mode.tambo init - Skills - Mention as a next step after setup. Project-scoped agent skills via CLI and dashboard.
- Add Components to Registry - Load when registering existing app components. Analyzes props, generates Zod schemas, writes descriptions.
Shared references (components, rendering, threads, tools/context, CLI, skills) are duplicated into generative-ui so each skill works independently.
add-components-to-registry is unique to this skill.
Workflow
- Detect tech stack - Analyze package.json, lock files, project structure, monorepo layout
- Confirm with user - Present findings, ask about preferences
- Install dependencies - Add @tambo-ai/react and zod using the project's package manager
- Create provider setup - Wire TamboProvider with apiKey, userKey, components
- Create component registry - Set up lib/tambo.ts
- Add chat UI - Install pre-built Tambo components via CLI, set up path aliases and globals.css
Step 1: Detect Tech Stack
Check these files to understand the project:
# Key files to read package.json # Dependencies, scripts, AND package manager tsconfig.json # TypeScript config, path aliases next.config.* # Next.js vite.config.* # Vite tailwind.config.* # Tailwind CSS postcss.config.* # PostCSS src/index.* or app/ # Entry points yarn.lock / pnpm-lock.yaml / package-lock.json # Which package manager
Detection Checklist
| Technology | Detection |
|---|---|
| Next.js | in dependencies, exists |
| Vite | in devDependencies, exists |
| Create React App | in dependencies |
| TypeScript | in deps, exists |
| Tailwind | in deps, config file exists |
| Plain CSS | No Tailwind, CSS files in src/ |
| Zod | in dependencies |
| Other validation | , , in deps |
Package Manager Detection
Always detect and use the project's package manager. Do not assume npm.
| Lock file | Manager | Install command |
|---|---|---|
| npm | |
| Yarn | |
| pnpm | |
For monorepos, install in the correct workspace:
- Yarn:
yarn workspace <app-name> add @tambo-ai/react - pnpm:
pnpm --filter <app-name> add @tambo-ai/react - npm:
npm install @tambo-ai/react -w <app-name>
Monorepo Detection
Check for monorepo indicators:
field in rootworkspacespackage.jsonpnpm-workspace.yaml
orturbo.jsonnx.json- Multiple
files inpackage.json
orapps/packages/
If monorepo detected, identify which package is the web app that will use Tambo (usually in
apps/web, apps/frontend, or similar).
Global Keyboard Shortcuts Detection
Check if the app captures keyboard events globally (common in drawing tools, editors, IDEs). Look for:
in the codebasedocument.addEventListener("keydown", ...)- Canvas-based apps (Excalidraw, Figma-like, code editors)
- Keyboard shortcut libraries (hotkeys-js, mousetrap, etc.)
If found, the Tambo chat UI wrapper must stop event propagation (see Step 6).
Step 2: Confirm with User
Present findings including the package manager and any special concerns:
I detected your project uses: - Framework: Next.js 14 (App Router) - Package manager: Yarn - Styling: Tailwind CSS - Validation: No Zod (will need to add) - TypeScript: Yes - Monorepo: No - Global keyboard shortcuts: No Should I: 1. Install Tambo with these settings? 2. Use plain CSS instead of Tailwind for Tambo components? 3. Something else?
Step 3: Install Dependencies
Use the project's package manager (detected in Step 1):
# npm npm install @tambo-ai/react npm install zod # if no Zod installed # yarn yarn add @tambo-ai/react yarn add zod # pnpm pnpm add @tambo-ai/react pnpm add zod # Monorepo (install in the correct workspace) yarn workspace <app-name> add @tambo-ai/react zod pnpm --filter <app-name> add @tambo-ai/react zod npm install @tambo-ai/react zod -w <app-name>
Step 4: Create Provider Setup
Next.js App Router
// app/providers.tsx "use client"; import { TamboProvider } from "@tambo-ai/react"; import { components } from "@/lib/tambo"; export function Providers({ children }: { children: React.ReactNode }) { return ( <TamboProvider apiKey={process.env.NEXT_PUBLIC_TAMBO_API_KEY} userKey="default-user" components={components} > {children} </TamboProvider> ); }
IMPORTANT:
userKey is required for authentication. Without it, message submission fails at runtime with "authentication is not ready." Note: userKey is typed as optional in TypeScript (userKey?: string), so the compiler won't catch this — the failure is purely at runtime. In production, use a real user identifier (e.g., session ID, user ID from your auth system). For development/demo, a static string such as "default-user" works.
// app/layout.tsx import { Providers } from "./providers"; export default function RootLayout({ children }) { return ( <html> <body> <Providers>{children}</Providers> </body> </html> ); }
Next.js Pages Router
// pages/_app.tsx import { TamboProvider } from "@tambo-ai/react"; import { components } from "@/lib/tambo"; export default function App({ Component, pageProps }) { return ( <TamboProvider apiKey={process.env.NEXT_PUBLIC_TAMBO_API_KEY} userKey="default-user" components={components} > <Component {...pageProps} /> </TamboProvider> ); }
Vite / CRA
// src/main.tsx import { TamboProvider } from "@tambo-ai/react"; import { components } from "./lib/tambo"; import App from "./App"; ReactDOM.createRoot(document.getElementById("root")!).render( <TamboProvider apiKey={import.meta.env.VITE_TAMBO_API_KEY} userKey="default-user" components={components} > <App /> </TamboProvider>, );
Step 5: Create Component Registry
// lib/tambo.ts (or src/lib/tambo.ts) import { TamboComponent } from "@tambo-ai/react"; export const components: TamboComponent[] = [ // Components will be registered here ];
Step 6: Add Chat UI
Pick the right chat layout for the app:
| Component | Best for | How it renders |
|---|---|---|
| Overlaying on top of existing UI (drawing tools, simple apps) | Fixed-position floating panel, bottom-right corner, toggle open/close |
| Apps with sidebar layouts (dashboards, admin panels, SaaS apps) | Side panel with thread history, resizable |
| Dedicated chat pages or full-screen chat experiences | Full-height thread with all features |
Choose based on the app's layout. If there's a sidebar or dashboard layout, use
panel. If the chat should float over existing content, use collapsible. If the whole page is the chat, use full.
npx tambo add message-thread-panel --yes # Or: npx tambo add message-thread-collapsible --yes # Or: npx tambo add message-thread-full --yes # With other package managers: # yarn dlx tambo add <component> --yes # pnpm dlx tambo add <component> --yes
After tambo add
, complete the setup:
tambo add-
CSS setup —
adds Tailwind directives and CSS variables to your project's CSS entry file. The file it modifies depends on the framework:tambo add- Next.js:
(orapp/globals.css
) — already imported in layout by default.src/app/globals.css - Vite:
(orsrc/index.css
) — already imported inindex.css
by default.main.tsx
If your entry file already imports a CSS file,
modifies that file in place. No new import is needed.tambo add - Next.js:
-
Path alias — Tambo components use
imports. Check if the project's tsconfig already has@/
in its@/*
. Many Next.js projects created withpaths
have this, but not all (e.g., Cal.com usescreate-next-app
and~/*
instead).@components/*If
is missing, add it to the app tsconfig (@/*
when present, otherwisetsconfig.app.json
):tsconfig.json{ "compilerOptions": { "paths": { "@/*": ["./src/*"] } } }If the project has no
directory and components land in the project root, usesrc/
instead of["./*"]
. Check where["./src/*"]
placed the components to determine the correct path.tambo addFor Vite projects, also add the alias to
:vite.config.ts// vite.config.ts import path from "path"; export default defineConfig({ resolve: { alias: { "@": path.resolve(__dirname, "src"), }, }, });
Keyboard Event Isolation
Critical for apps with global keyboard shortcuts (drawing tools, editors, terminal-like apps). Without this, typing in the Tambo chat input triggers the host app's shortcuts.
Wrap the Tambo chat UI in a div that stops keyboard event propagation:
<div onKeyDown={(e) => e.stopPropagation()} onKeyUp={(e) => e.stopPropagation()} > {/* Use whichever component you installed */} <MessageThreadCollapsible />{" "} {/* or <MessageThreadPanel /> or <MessageThreadFull /> */} </div>
Z-Index for Full-Screen Apps
Apps with full-screen canvases or overlays may render on top of the Tambo chat. The
MessageThreadCollapsible component uses position: fixed, but the host app's canvas may have a higher stacking context. Wrap with a fixed container that sits above everything:
<div style={{ position: "fixed", inset: 0, zIndex: 9999, pointerEvents: "none" }} > <div style={{ pointerEvents: "auto" }}> {/* Use whichever component you installed */} <MessageThreadCollapsible />{" "} {/* or <MessageThreadPanel /> or <MessageThreadFull /> */} </div> </div>
The outer div creates a stacking context above the canvas, while
pointerEvents: none/auto ensures only the chat panel is clickable — the rest of the screen passes clicks through to the canvas.
You can combine keyboard isolation and z-index in one wrapper.
Adapting to Existing Patterns
No Tailwind? Use Plain CSS
If the project doesn't use Tailwind,
tambo add will install Tailwind v4 via PostCSS alongside the existing styling. This is additive — it won't break existing CSS/SCSS. The Tambo components use Tailwind, but the rest of your app keeps its styling.
If you'd prefer to avoid Tailwind entirely:
# Skip --yes flag to customize styling during add npx tambo add message-thread-full # Select "CSS Modules" or "Plain CSS" when prompted
Existing Validation Library?
If using Yup/Joi instead of Zod, user can either:
- Add Zod just for Tambo schemas (recommended - small addition)
- Convert schemas (more work, not recommended)
Monorepo?
Run commands from the web app package, not the monorepo root.
Run
npx tambo init --project-name=<app-name> from the web app directory. This opens the browser for authentication and polls until the user completes auth (up to 15 minutes). Use a long timeout. Once auth completes, the CLI creates the project and writes the API key to .env.local.
Monorepo gotchas:
- Env vars:
createstambo init
in the current directory. Vite loads env from.env.local
(checkenvDir
). Ensure the env file is where Vite looks for it.vite.config.* - Dependency hoisting: Some package managers hoist deps to the monorepo root. If Vite can't resolve a Tambo dependency, install it at the root level too (e.g.,
).yarn add -W @tambo-ai/react - Path aliases: Vite resolves from the
directory. Thevite.config.*
alias must resolve to the correct@/
directory within the workspace, not the monorepo root.src/
Environment Variables
npx tambo init --project-name=<name> opens the browser and polls until the user authenticates (up to 15 minutes). Use a long timeout. Once auth completes, it creates the project and writes .env.local.
If manual setup is needed (monorepo, read-only filesystem), add the appropriate variable:
| Framework | Variable |
|---|---|
| Next.js | |
| Vite | |
| CRA | |
Verification
After setup, verify by creating a simple test:
import { useTambo } from "@tambo-ai/react"; function TestComponent() { const { thread, isIdle } = useTambo(); console.log("Tambo connected:", isIdle); return <div>Tambo is set up!</div>; }
Reporting Bugs & Feedback
If you encounter any of these while helping a user, suggest filing a GitHub issue:
- A bug in
,@tambo-ai/react
, or the@tambo-ai/client
CLItambo - Documentation that contradicts actual behavior
- Missing or misleading instructions in this skill
Issue Template
Use this template when drafting an issue for
tambo-ai/tambo:
**Title:** [Short description of the problem] **Expected behavior** What should happen. **Actual behavior** What happens instead, including any error messages or stack traces. **Repro steps** 1. Run `npx tambo create-app ...` (or whatever command) 2. Add this code: ```tsx // minimal code that reproduces the issue ``` 3. Observe the error **Environment** - `@tambo-ai/react` version: - `@tambo-ai/client` version: - Framework (Next.js / Vite / CRA) and version: - Node.js version: - OS: **Additional context** Link to relevant docs or skill file path if applicable.
Security: Redact API keys, tokens, and any customer data before including logs or code snippets in the issue.
Suggesting an Issue to the User
When you hit a problem that looks like a Tambo bug, say something like:
This looks like a bug in
. Want me to open a GitHub issue on@tambo-ai/reactwith the repro steps and environment details?tambo-ai/tambo
Always wait for the user to confirm before filing.