Install
openclaw skills install chatgpt-appsComplete ChatGPT Apps builder - Create, design, implement, test, and deploy ChatGPT Apps with MCP servers, widgets, auth, database integration, and automated deployment
openclaw skills install chatgpt-appsComplete workflow for building, testing, and deploying ChatGPT Apps from concept to production.
/chatgpt-apps new - Create a new ChatGPT App/chatgpt-apps add-tool - Add an MCP tool to your app/chatgpt-apps add-widget - Add a widget to your app/chatgpt-apps add-auth - Configure authentication/chatgpt-apps add-database - Set up database/chatgpt-apps validate - Validate your app/chatgpt-apps test - Run tests/chatgpt-apps deploy - Deploy to production/chatgpt-apps resume - Resume working on an appPurpose: Create a new ChatGPT App from concept to working code.
Ask for the app idea "What ChatGPT App would you like to build? Describe what it does and the problem it solves."
Analyze against UX Principles
Check for Anti-Patterns
Define Use Cases Create 3-5 primary use cases with user stories.
Tool Topology
Widget Design For each widget:
id - unique identifier (kebab-case)name - display namedescription - what it showsmockData - sample data for previewData Model Design entities and relationships.
Auth Requirements
Generate complete application with this structure:
{app-name}/
├── package.json
├── tsconfig.server.json
├── setup.sh
├── START.sh
├── .env.example
├── .gitignore
└── server/
└── index.ts
Critical Requirements:
Server class from @modelcontextprotocol/sdk/server/index.jsStreamableHTTPServerTransport for session managementui://widget/{widget-id}.htmltext/html+skybridgestructuredContent in tool responses_meta with openai/outputTemplate on tools./setup.sh./START.sh --devhttp://localhost:3000/previewPurpose: Add a new MCP tool to your ChatGPT App.
Gather Information
Classify Tool Type
Design Input Schema Create Zod schema with appropriate types and descriptions.
Generate Tool Handler
Use chatgpt-mcp-generator agent to create:
server/tools/Register Tool
Update server/index.ts with metadata:
{
name: "my-tool",
_meta: {
"openai/toolInvocation/invoking": "Loading...",
"openai/toolInvocation/invoked": "Done",
"openai/outputTemplate": "ui://widget/my-widget.html", // if widget
}
}
Update State
Add tool to .chatgpt-app/state.json.
Use kebab-case: list-items, create-task, show-recipe-detail
| Scenario | readOnlyHint | destructiveHint | openWorldHint |
|---|---|---|---|
| List/Get | true | false | false |
| Create/Update | false | false | false |
| Delete | false | true | false |
| External API | varies | varies | true |
Purpose: Add inline HTML widgets with HTML/CSS/JS and Apps SDK integration.
Gather Information
Define Data Shape Document expected structure with TypeScript interface.
Add Widget Config
const widgets: WidgetConfig[] = [
{
id: "my-widget",
name: "My Widget",
description: "Displays data",
templateUri: "ui://widget/my-widget.html",
invoking: "Loading...",
invoked: "Ready",
mockData: { /* sample */ },
},
];
Add Widget HTML Generate HTML with:
window.PREVIEW_DATA)window.openai.toolOutput)openai:set_globals)Create/Update Tool
Link tool to widget via widgetId.
Test Widget
Preview at /preview/{widget-id} with mock data.
(function() {
let rendered = false;
function render(data) {
if (rendered || !data) return;
rendered = true;
// Render logic
}
function tryRender() {
if (window.PREVIEW_DATA) { render(window.PREVIEW_DATA); return; }
if (window.openai?.toolOutput) { render(window.openai.toolOutput); }
}
window.addEventListener('openai:set_globals', tryRender);
const poll = setInterval(() => {
if (window.openai?.toolOutput || window.PREVIEW_DATA) {
tryRender();
clearInterval(poll);
}
}, 100);
setTimeout(() => clearInterval(poll), 10000);
tryRender();
})();
Purpose: Configure authentication using Auth0 or Supabase Auth.
Auth0:
Supabase Auth:
Choose Provider Ask user preference based on needs.
Guide Setup
Generate Auth Code
Use chatgpt-auth-generator agent to create:
Update Server Add auth middleware to protect routes.
Update Environment
# Auth0
AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_CLIENT_ID=...
AUTH0_CLIENT_SECRET=...
# Supabase (from database setup)
SUPABASE_URL=...
SUPABASE_ANON_KEY=...
Test Verify login flow and user isolation.
Purpose: Configure PostgreSQL database using Supabase.
Check Supabase Setup Verify account and project exist.
Gather Credentials
Define Entities For each entity, specify:
Generate Schema
Use chatgpt-database-generator agent to create SQL with:
id (UUID primary key)user_subject (varchar, indexed)created_at (timestamptz)updated_at (timestamptz)Setup Connection Pool
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!
);
Apply Migrations Run SQL in Supabase dashboard or via migration tool.
Always filter by user_subject:
const { data } = await supabase
.from('tasks')
.select('*')
.eq('user_subject', userSubject);
Purpose: Generate test prompts to validate ChatGPT correctly invokes tools.
Direct Prompts - Explicit tool invocation
Indirect Prompts - Outcome-based, ChatGPT should infer tool
Negative Prompts - Should NOT trigger tool
Analyze Tools Review each tool's purpose and inputs.
Generate Prompts For each tool, create:
Best Practices
Save Output
Write to .chatgpt-app/golden-prompts.json:
{
"toolName": {
"direct": ["prompt1", "prompt2"],
"indirect": ["prompt1", "prompt2"],
"negative": ["prompt1", "prompt2"],
"edge": ["prompt1", "prompt2"]
}
}
Purpose: Validation suite before deployment.
Required Files
Server Implementation
Server from MCP SDKStreamableHTTPServerTransportWidget Configuration
widgets array existsui://widget/{id}.htmlTool Response Format
structuredContent (not just content)_meta with openai/outputTemplateResource Handler Format
text/html+skybridge_meta with serialization and CSPWidget HTML Structure
Endpoint Existence
/health - Health check/preview - Widget index/preview/:widgetId - Widget preview/mcp - MCP endpointPackage.json Scripts
build:serverstart with HTTP_MODE=truedev with watch modeAnnotation Validation
Database Validation (if enabled)
| Error | Fix |
|---|---|
| Missing structuredContent | Add to tool response |
| Wrong widget URI | Use ui://widget/{id}.html |
| No session management | Add Map<string, Transport> |
| Missing _meta | Add to tool definition and response |
| Wrong MIME type | Use text/html+skybridge |
Critical: Check file existence FIRST before other validations!
Purpose: Run automated tests using MCP Inspector and golden prompts.
MCP Protocol
Schema Validation
Widget Tests
Golden Prompt Tests
Start Server in Test Mode
HTTP_MODE=true NODE_ENV=test npm run dev
Run MCP Inspector Test protocol compliance:
Schema Validation Verify schemas compile and match implementation.
Golden Prompt Tests Use ChatGPT to test prompts:
Generate Report
{
"passed": 42,
"failed": 3,
"categories": {
"mcp": "✅",
"schema": "✅",
"widgets": "✅",
"prompts": "⚠️ 3 failures"
},
"timing": "2.3s"
}
For each failure, explain:
Purpose: Deploy ChatGPT App to Render with PostgreSQL and health checks.
Pre-flight Check
Generate render.yaml
services:
- type: web
name: {app-name}
runtime: docker
plan: free
healthCheckPath: /health
envVars:
- key: PORT
value: 3000
- key: HTTP_MODE
value: true
- key: NODE_ENV
value: production
- key: WIDGET_DOMAIN
generateValue: true
# Add auth/database vars if needed
Generate Dockerfile
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist ./dist
EXPOSE 3000
CMD ["node", "dist/server/index.js"]
Deploy Option A: Automated (if Render MCP available) Use Render MCP agent to deploy.
Option B: Manual
Verify Deployment
https://{app}.onrender.com/healthhttps://{app}.onrender.com/mcpConfigure ChatGPT Connector
https://{app}.onrender.com/mcpPurpose: Resume building an in-progress ChatGPT App.
Load State
Read .chatgpt-app/state.json:
{
"appName": "My Task Manager",
"phase": "Implementation",
"tools": ["list-tasks", "create-task"],
"widgets": ["task-list"],
"auth": false,
"database": true,
"validated": false,
"deployed": false
}
Display Progress Show current status:
Offer Next Steps Based on phase:
Concept Phase:
Implementation Phase:
Testing Phase:
Deployment Phase:
Continue Work Based on user's choice, invoke the appropriate workflow section.
The .chatgpt-app/state.json file tracks progress:
{
"appName": "string",
"description": "string",
"phase": "Concept" | "Implementation" | "Testing" | "Deployment",
"tools": ["tool-name"],
"widgets": ["widget-id"],
"auth": {
"enabled": boolean,
"provider": "auth0" | "supabase" | null
},
"database": {
"enabled": boolean,
"entities": ["entity-name"]
},
"validated": boolean,
"tested": boolean,
"deployed": boolean,
"deploymentUrl": "string | null",
"goldenPromptsGenerated": boolean,
"lastUpdated": "ISO timestamp"
}
# Setup
./setup.sh
# Development
./START.sh --dev # Dev mode with watch
./START.sh --preview # Open preview in browser
./START.sh --stdio # STDIO mode (testing)
./START.sh # Production mode
# Testing
npm run validate # Type checking
curl http://localhost:3000/health
# Deployment
git push origin main # Trigger Render deploy
When the user invokes any chatgpt-app command:
.chatgpt-app/state.json existsAlways guide users through the natural progression: Concept → Implementation → Testing → Deployment