Install
openclaw skills install stitch-design-agentSkill for an agent that integrates designs generated by Google Stitch directly into an app under development. Use this skill whenever the agent needs to: authenticate with Google Stitch via an OAuth token, send a design prompt to the Stitch API, retrieve the generated component/design, and automatically integrate it into the active codebase (React, NestJS, etc.). Always trigger when the user mentions "Stitch", "design from Stitch", "integrate UI from Stitch", or "ask Stitch for the design".
openclaw skills install stitch-design-agentAutonomous agent that requests designs from Google Stitch via its API and integrates them into the active project. The full flow is:
OAuth Token → Design Prompt → Stitch API → Generated Code → Project Integration
| Resource | Where to get it |
|---|---|
Google OAuth 2.0 token with cloud-platform scope | Step 2 below |
| Active project (React / NestJS / any stack) | Must already be in the workspace |
STITCH_TOKEN environment variable | .env file or agent secret |
# 1. Redirect the user to the authorization URL
GET https://accounts.google.com/o/oauth2/v2/auth
?client_id=<CLIENT_ID>
&redirect_uri=<REDIRECT_URI>
&response_type=code
&scope=https://www.googleapis.com/auth/cloud-platform
&access_type=offline
# 2. Exchange the authorization code for tokens
POST https://oauth2.googleapis.com/token
grant_type=authorization_code
&code=<CODE>
&client_id=<CLIENT_ID>
&client_secret=<CLIENT_SECRET>
&redirect_uri=<REDIRECT_URI>
# Response:
# { "access_token": "ya29.xxx", "refresh_token": "1//xxx", "expires_in": 3599 }
# Generate a signed JWT with the service account key and exchange it:
POST https://oauth2.googleapis.com/token
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion=<SIGNED_JWT>
The agent must always read the token from the
STITCH_TOKENenvironment variable. Never hardcode tokens in source code.
POST https://stitch.googleapis.com/v1/designs:generate
Authorization: Bearer {STITCH_TOKEN}
Content-Type: application/json
{
"prompt": "<natural language description of the desired design>",
"output_format": "react_component", // "html" | "react_component" | "vue_component"
"theme": {
"primary_color": "#3B82F6",
"font_family": "Inter"
},
"context": {
"framework": "react",
"styling": "tailwind" // "css_modules" | "tailwind" | "styled_components"
}
}
"Create a financial summary card component with:
- Total balance prominently displayed at the top
- Small bar chart showing the last 7 days
- Two action buttons: Income and Expense
- Minimalist style with a soft shadow
- Dark mode compatible"
{
"design_id": "dsgn_abc123",
"component_name": "FinancialSummaryCard",
"code": "import React from 'react';\n\nexport const FinancialSummaryCard = ...",
"assets": [],
"metadata": {
"tokens_used": 840,
"framework": "react"
}
}
// The agent must:
// 1. Extract `response.code` from the Stitch response
// 2. Determine the correct path based on the project structure
const componentName = response.component_name; // e.g. "FinancialSummaryCard"
const targetPath = `src/components/${componentName}.tsx`;
// 3. Write the file
fs.writeFileSync(targetPath, response.code, 'utf-8');
The agent should scan the project to find the most logical integration point:
# Find files that are likely to use the new component
grep -r "Dashboard\|Overview\|Home\|Layout" src/pages --include="*.tsx" -l
// Add to the target file:
import { FinancialSummaryCard } from '../components/FinancialSummaryCard';
// And in the JSX:
<FinancialSummaryCard />
npx tsc --noEmit # Check TypeScript types
npm run lint -- --fix # Auto-fix linting issues
async function stitchDesignFlow(userPrompt: string) {
// Step 1: Read token
const token = process.env.STITCH_TOKEN;
if (!token) throw new Error('STITCH_TOKEN is not configured');
// Step 2: Request design from Stitch
const stitchResponse = await fetch(
'https://stitch.googleapis.com/v1/designs:generate',
{
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
prompt: userPrompt,
output_format: 'react_component',
context: { framework: 'react', styling: 'tailwind' },
}),
}
);
const design = await stitchResponse.json();
// Step 3: Save the component
const filePath = `src/components/${design.component_name}.tsx`;
fs.writeFileSync(filePath, design.code);
// Step 4: Find the integration point
const integrationTarget = await detectIntegrationPoint(design.component_name);
// Step 5: Inject import and JSX
await injectComponent(integrationTarget, design.component_name);
// Step 6: Verify build
execSync('npx tsc --noEmit');
return { filePath, integrationTarget };
}
| Error | Likely cause | Agent action |
|---|---|---|
401 Unauthorized | Token expired or invalid | Ask the user for a new token or refresh automatically |
400 Bad Request | Prompt too vague or invalid payload | Refine the prompt and retry |
429 Too Many Requests | Rate limit reached | Wait 60s and retry |
TypeScript errors | Generated component has incorrect types | Fix types manually or request regeneration |
Import conflicts | Component name already exists in the project | Rename with a _v2 suffix |
# openclaw.config.yml (relevant section)
agents:
stitch-designer:
skill: stitch-design-agent
env:
STITCH_TOKEN: ${secrets.GOOGLE_STITCH_TOKEN}
tools:
- file_write
- file_read
- bash
- web_fetch
triggers:
- "design a component"
- "ask stitch for the design"
- "integrate UI from stitch"
- "generate the view for"
- "create a screen for"
refresh_token to
renew it automatically before retrying.recharts, framer-motion) and run npm install <pkg> before integrating.src/modules/<domain>/components/, not at the src/components/ root.