ChatGPT Apps Builder
Complete workflow for building, testing, and deploying ChatGPT Apps from concept to production.
Commands
/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 app
Table of Contents
- Create New App
- Add MCP Tool
- Add Widget
- Add Authentication
- Add Database
- Generate Golden Prompts
- Validate App
- Test App
- Deploy App
- Resume App
1. Create New App
Purpose: Create a new ChatGPT App from concept to working code.
Workflow
Phase 1: Conceptualization
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
- Conversational Leverage: What can users accomplish through natural language?
- Native Fit: How does this integrate with ChatGPT's conversational flow?
- Composability: Can tools work independently and combine with other apps?
Check for Anti-Patterns
- Static website content display
- Complex multi-step workflows requiring external tabs
- Duplicating ChatGPT's native capabilities
- Ads or upsells
Define Use Cases
Create 3-5 primary use cases with user stories.
Phase 2: Design
Tool Topology
- Query tools (readOnlyHint: true)
- Mutation tools (destructiveHint: false)
- Destructive tools (destructiveHint: true)
- Widget tools (return UI with _meta)
- External API tools (openWorldHint: true)
Widget Design
For each widget:
id - unique identifier (kebab-case)
name - display name
description - what it shows
mockData - sample data for preview
Data Model
Design entities and relationships.
Auth Requirements
- Single-user (no auth needed)
- Multi-user (Auth0 or Supabase Auth)
Phase 3: Implementation
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.js
StreamableHTTPServerTransport for session management
- Widget URIs:
ui://widget/{widget-id}.html
- Widget MIME type:
text/html+skybridge
structuredContent in tool responses
_meta with openai/outputTemplate on tools
Phase 4: Testing
- Run setup:
./setup.sh
- Start dev:
./START.sh --dev
- Preview widgets:
http://localhost:3000/preview
- Test MCP connection
Phase 5: Deployment
- Generate Dockerfile and render.yaml
- Deploy to Render
- Configure ChatGPT connector
2. Add MCP Tool
Purpose: Add a new MCP tool to your ChatGPT App.
Workflow
Gather Information
- What does this tool do?
- What inputs does it need?
- What does it return?
Classify Tool Type
- Query (readOnlyHint: true) - Fetches data
- Mutation (destructiveHint: false) - Creates/updates data
- Destructive (destructiveHint: true) - Deletes data
- Widget - Returns UI content
- External (openWorldHint: true) - Calls external APIs
Design Input Schema
Create Zod schema with appropriate types and descriptions.
Generate Tool Handler
Use chatgpt-mcp-generator agent to create:
- Tool handler in
server/tools/
- Zod schema export
- Type exports
- Database queries (if needed)
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.
Tool Naming
Use kebab-case: list-items, create-task, show-recipe-detail
Annotations Guide
| Scenario |
readOnlyHint |
destructiveHint |
openWorldHint |
| List/Get |
true |
false |
false |
| Create/Update |
false |
false |
false |
| Delete |
false |
true |
false |
| External API |
varies |
varies |
true |
3. Add Widget
Purpose: Add inline HTML widgets with HTML/CSS/JS and Apps SDK integration.
5 Widget Patterns
- Card Grid - Multiple items in grid
- Stats Dashboard - Key metrics display
- Table - Tabular data
- Bar Chart - Simple visualizations
- Detail Widget - Single item details
Workflow
Gather Information
- Widget purpose and data
- Visual design (cards, table, chart, etc.)
- Interactivity needs
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:
- Preview mode support (
window.PREVIEW_DATA)
- OpenAI Apps SDK integration (
window.openai.toolOutput)
- Event listeners (
openai:set_globals)
- Polling fallback (100ms, 10s timeout)
Create/Update Tool
Link tool to widget via widgetId.
Test Widget
Preview at /preview/{widget-id} with mock data.
Widget HTML Structure
(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();
})();
4. Add Authentication
Purpose: Configure authentication using Auth0 or Supabase Auth.
When to Add
- Multiple users
- Persistent private data per user
- User-specific API credentials
Providers
Auth0:
- Enterprise-grade
- OAuth 2.1, PKCE flow
- Social logins (Google, GitHub, etc.)
Supabase Auth:
- Simpler setup
- Email/password default
- Integrates with Supabase database
Workflow
Choose Provider
Ask user preference based on needs.
Guide Setup
- Auth0: Create application, configure callback URLs, get credentials
- Supabase: Already configured with database setup
Generate Auth Code
Use chatgpt-auth-generator agent to create:
- Session management middleware
- User subject extraction
- Token validation
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.
5. Add Database
Purpose: Configure PostgreSQL database using Supabase.
When to Add
- Persistent user data
- Multi-entity relationships
- Query/filter capabilities
Workflow
Check Supabase Setup
Verify account and project exist.
Gather Credentials
- Project URL
- Anon key (public)
- Service role key (server-side)
Define Entities
For each entity, specify:
- Fields and types
- Relationships
- Indexes
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)
- RLS policies for user isolation
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.
Query Pattern
Always filter by user_subject:
const { data } = await supabase
.from('tasks')
.select('*')
.eq('user_subject', userSubject);
6. Generate Golden Prompts
Purpose: Generate test prompts to validate ChatGPT correctly invokes tools.
Why Important
- Measure precision/recall
- Enable iteration
- Post-launch monitoring
3 Categories
Direct Prompts - Explicit tool invocation
- "Show me my task list"
- "Create a new task called..."
Indirect Prompts - Outcome-based, ChatGPT should infer tool
- "What do I need to do today?"
- "Help me organize my work"
Negative Prompts - Should NOT trigger tool
- "What is a task?"
- "Tell me about project management"
Workflow
Analyze Tools
Review each tool's purpose and inputs.
Generate Prompts
For each tool, create:
- 5+ direct prompts
- 5+ indirect prompts
- 3+ negative prompts
- 2+ edge case prompts
Best Practices
- Tool descriptions start with "Use this when..."
- State limitations clearly
- Include examples in descriptions
Save Output
Write to .chatgpt-app/golden-prompts.json:
{
"toolName": {
"direct": ["prompt1", "prompt2"],
"indirect": ["prompt1", "prompt2"],
"negative": ["prompt1", "prompt2"],
"edge": ["prompt1", "prompt2"]
}
}
7. Validate App
Purpose: Validation suite before deployment.
10 Validation Checks
Required Files
- package.json
- tsconfig.server.json
- setup.sh (executable)
- START.sh (executable)
- server/index.ts
- .env.example
Server Implementation
- Uses
Server from MCP SDK
- Has
StreamableHTTPServerTransport
- Session management with Map
- Correct request handlers
Widget Configuration
widgets array exists
- Each has id, name, description, templateUri, mockData
- URIs match pattern
ui://widget/{id}.html
Tool Response Format
- Returns
structuredContent (not just content)
- Widget tools have
_meta with openai/outputTemplate
Resource Handler Format
- MIME type:
text/html+skybridge
- Returns
_meta with serialization and CSP
Widget HTML Structure
- Preview mode support
- Event listeners for Apps SDK
- Polling fallback
- Render guard
Endpoint Existence
/health - Health check
/preview - Widget index
/preview/:widgetId - Widget preview
/mcp - MCP endpoint
Package.json Scripts
- Has
build:server
- Has
start with HTTP_MODE=true
- Has
dev with watch mode
- NO web build scripts (web/, ui/, client/)
Annotation Validation
- readOnlyHint set correctly
- destructiveHint for delete operations
- openWorldHint for external APIs
Database Validation (if enabled)
- Tables have required fields
- user_subject indexed
- RLS policies enabled
Common Errors
| 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!
8. Test App
Purpose: Run automated tests using MCP Inspector and golden prompts.
4 Test Categories
MCP Protocol
- Server starts without errors
- Handles initialize
- Lists tools correctly
- Lists resources correctly
Schema Validation
- Tool schemas are valid Zod
- Required fields marked
- Types match implementation
Widget Tests
- All widgets render in preview mode
- Mock data loads correctly
- No console errors
Golden Prompt Tests
- Direct prompts trigger correct tools
- Indirect prompts work as expected
- Negative prompts don't trigger tools
Workflow
Start Server in Test Mode
HTTP_MODE=true NODE_ENV=test npm run dev
Run MCP Inspector
Test protocol compliance:
- Initialize connection
- List tools
- Call each tool with valid inputs
- Check responses
Schema Validation
Verify schemas compile and match implementation.
Golden Prompt Tests
Use ChatGPT to test prompts:
- Record which tool was called
- Compare to expected tool
- Calculate precision/recall
Generate Report
{
"passed": 42,
"failed": 3,
"categories": {
"mcp": "✅",
"schema": "✅",
"widgets": "✅",
"prompts": "⚠️ 3 failures"
},
"timing": "2.3s"
}
Fixing Failures
For each failure, explain:
- What failed
- Why it failed
- How to fix (with code example)
9. Deploy App
Purpose: Deploy ChatGPT App to Render with PostgreSQL and health checks.
Prerequisites
- ✅ Validation passed
- ✅ Tests passed
- ✅ Git repository clean
- ✅ Environment variables ready
Workflow
Pre-flight Check
- Run validation
- Run tests
- Check database connection (if enabled)
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
- Push to GitHub
- Connect repo in Render dashboard
- Set environment variables
- Deploy
Verify Deployment
- Health check:
https://{app}.onrender.com/health
- MCP endpoint:
https://{app}.onrender.com/mcp
- Tool discovery works
- Widgets render
Configure ChatGPT Connector
- URL:
https://{app}.onrender.com/mcp
- Test in ChatGPT
10. Resume App
Purpose: Resume building an in-progress ChatGPT App.
Workflow
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:
- App name
- Current phase
- Completed items (tools, widgets)
- Pending items (auth, validation, deployment)
Offer Next Steps
Based on phase:
Concept Phase:
- "Let's design the tools and widgets"
- "Shall we start implementation?"
Implementation Phase:
- "Add another tool?"
- "Add a widget?"
- "Set up authentication?"
- "Set up database?"
Testing Phase:
- "Generate golden prompts?"
- "Run validation?"
- "Run tests?"
Deployment Phase:
- "Deploy to Render?"
- "Configure ChatGPT connector?"
Continue Work
Based on user's choice, invoke the appropriate workflow section.
Best Practices
- Always save state after each major step
- Validate before moving forward (especially before deployment)
- Use agents for code generation (chatgpt-mcp-generator, chatgpt-auth-generator, etc.)
- Test at every phase (preview widgets, test tools, run golden prompts)
- Keep it conversational - guide the user naturally through the workflow
- Explain trade-offs when offering choices (Auth0 vs Supabase, etc.)
- Show examples when introducing new concepts
State Management
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"
}
Command Reference
# 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
Getting Started
When the user invokes any chatgpt-app command:
- Check if
.chatgpt-app/state.json exists
- If yes → use Resume App workflow
- If no → use Create New App workflow
Always guide users through the natural progression:
Concept → Implementation → Testing → Deployment
1---2name: chatgpt-apps3description: Complete ChatGPT Apps builder - Create, design, implement, test, and deploy ChatGPT Apps with MCP servers, widgets, auth, database integration, and automated deployment4---56# ChatGPT Apps Builder78Complete workflow for building, testing, and deploying ChatGPT Apps from concept to production.910## Commands1112- `/chatgpt-apps new` - Create a new ChatGPT App13- `/chatgpt-apps add-tool` - Add an MCP tool to your app14- `/chatgpt-apps add-widget` - Add a widget to your app15- `/chatgpt-apps add-auth` - Configure authentication16- `/chatgpt-apps add-database` - Set up database17- `/chatgpt-apps validate` - Validate your app18- `/chatgpt-apps test` - Run tests19- `/chatgpt-apps deploy` - Deploy to production20- `/chatgpt-apps resume` - Resume working on an app2122---2324## Table of Contents25261. [Create New App](#1-create-new-app)272. [Add MCP Tool](#2-add-mcp-tool)283. [Add Widget](#3-add-widget)294. [Add Authentication](#4-add-authentication)305. [Add Database](#5-add-database)316. [Generate Golden Prompts](#6-generate-golden-prompts)327. [Validate App](#7-validate-app)338. [Test App](#8-test-app)349. [Deploy App](#9-deploy-app)3510. [Resume App](#10-resume-app)3637---3839## 1. Create New App4041**Purpose:** Create a new ChatGPT App from concept to working code.4243### Workflow4445#### Phase 1: Conceptualization46471. **Ask for the app idea**48 "What ChatGPT App would you like to build? Describe what it does and the problem it solves."49502. **Analyze against UX Principles**51 - **Conversational Leverage**: What can users accomplish through natural language?52 - **Native Fit**: How does this integrate with ChatGPT's conversational flow?53 - **Composability**: Can tools work independently and combine with other apps?54553. **Check for Anti-Patterns**56 - Static website content display57 - Complex multi-step workflows requiring external tabs58 - Duplicating ChatGPT's native capabilities59 - Ads or upsells60614. **Define Use Cases**62 Create 3-5 primary use cases with user stories.6364#### Phase 2: Design65661. **Tool Topology**67 - Query tools (readOnlyHint: true)68 - Mutation tools (destructiveHint: false)69 - Destructive tools (destructiveHint: true)70 - Widget tools (return UI with _meta)71 - External API tools (openWorldHint: true)72732. **Widget Design**74 For each widget:75 - `id` - unique identifier (kebab-case)76 - `name` - display name77 - `description` - what it shows78 - `mockData` - sample data for preview79803. **Data Model**81 Design entities and relationships.82834. **Auth Requirements**84 - Single-user (no auth needed)85 - Multi-user (Auth0 or Supabase Auth)8687#### Phase 3: Implementation8889Generate complete application with this structure:9091```92{app-name}/93├── package.json94├── tsconfig.server.json95├── setup.sh96├── START.sh97├── .env.example98├── .gitignore99└── server/100 └── index.ts101```102103**Critical Requirements:**104- `Server` class from `@modelcontextprotocol/sdk/server/index.js`105- `StreamableHTTPServerTransport` for session management106- Widget URIs: `ui://widget/{widget-id}.html`107- Widget MIME type: `text/html+skybridge`108- `structuredContent` in tool responses109- `_meta` with `openai/outputTemplate` on tools110111#### Phase 4: Testing112- Run setup: `./setup.sh`113- Start dev: `./START.sh --dev`114- Preview widgets: `http://localhost:3000/preview`115- Test MCP connection116117#### Phase 5: Deployment118- Generate Dockerfile and render.yaml119- Deploy to Render120- Configure ChatGPT connector121122---123124## 2. Add MCP Tool125126**Purpose:** Add a new MCP tool to your ChatGPT App.127128### Workflow1291301. **Gather Information**131 - What does this tool do?132 - What inputs does it need?133 - What does it return?1341352. **Classify Tool Type**136 - **Query** (readOnlyHint: true) - Fetches data137 - **Mutation** (destructiveHint: false) - Creates/updates data138 - **Destructive** (destructiveHint: true) - Deletes data139 - **Widget** - Returns UI content140 - **External** (openWorldHint: true) - Calls external APIs1411423. **Design Input Schema**143 Create Zod schema with appropriate types and descriptions.1441454. **Generate Tool Handler**146 Use `chatgpt-mcp-generator` agent to create:147 - Tool handler in `server/tools/`148 - Zod schema export149 - Type exports150 - Database queries (if needed)1511525. **Register Tool**153 Update `server/index.ts` with metadata:154 ```typescript155 {156 name: "my-tool",157 _meta: {158 "openai/toolInvocation/invoking": "Loading...",159 "openai/toolInvocation/invoked": "Done",160 "openai/outputTemplate": "ui://widget/my-widget.html", // if widget161 }162 }163 ```1641656. **Update State**166 Add tool to `.chatgpt-app/state.json`.167168### Tool Naming169Use kebab-case: `list-items`, `create-task`, `show-recipe-detail`170171### Annotations Guide172173| Scenario | readOnlyHint | destructiveHint | openWorldHint |174|----------|--------------|-----------------|---------------|175| List/Get | true | false | false |176| Create/Update | false | false | false |177| Delete | false | true | false |178| External API | varies | varies | true |179180---181182## 3. Add Widget183184**Purpose:** Add inline HTML widgets with HTML/CSS/JS and Apps SDK integration.185186### 5 Widget Patterns1871881. **Card Grid** - Multiple items in grid1892. **Stats Dashboard** - Key metrics display1903. **Table** - Tabular data1914. **Bar Chart** - Simple visualizations1925. **Detail Widget** - Single item details193194### Workflow1951961. **Gather Information**197 - Widget purpose and data198 - Visual design (cards, table, chart, etc.)199 - Interactivity needs2002012. **Define Data Shape**202 Document expected structure with TypeScript interface.2032043. **Add Widget Config**205 ```typescript206 const widgets: WidgetConfig[] = [207 {208 id: "my-widget",209 name: "My Widget",210 description: "Displays data",211 templateUri: "ui://widget/my-widget.html",212 invoking: "Loading...",213 invoked: "Ready",214 mockData: { /* sample */ },215 },216 ];217 ```2182194. **Add Widget HTML**220 Generate HTML with:221 - Preview mode support (`window.PREVIEW_DATA`)222 - OpenAI Apps SDK integration (`window.openai.toolOutput`)223 - Event listeners (`openai:set_globals`)224 - Polling fallback (100ms, 10s timeout)2252265. **Create/Update Tool**227 Link tool to widget via `widgetId`.2282296. **Test Widget**230 Preview at `/preview/{widget-id}` with mock data.231232### Widget HTML Structure233234```javascript235(function() {236 let rendered = false;237238 function render(data) {239 if (rendered || !data) return;240 rendered = true;241 // Render logic242 }243244 function tryRender() {245 if (window.PREVIEW_DATA) { render(window.PREVIEW_DATA); return; }246 if (window.openai?.toolOutput) { render(window.openai.toolOutput); }247 }248249 window.addEventListener('openai:set_globals', tryRender);250251 const poll = setInterval(() => {252 if (window.openai?.toolOutput || window.PREVIEW_DATA) {253 tryRender();254 clearInterval(poll);255 }256 }, 100);257 setTimeout(() => clearInterval(poll), 10000);258259 tryRender();260})();261```262263---264265## 4. Add Authentication266267**Purpose:** Configure authentication using Auth0 or Supabase Auth.268269### When to Add270- Multiple users271- Persistent private data per user272- User-specific API credentials273274### Providers275276**Auth0:**277- Enterprise-grade278- OAuth 2.1, PKCE flow279- Social logins (Google, GitHub, etc.)280281**Supabase Auth:**282- Simpler setup283- Email/password default284- Integrates with Supabase database285286### Workflow2872881. **Choose Provider**289 Ask user preference based on needs.2902912. **Guide Setup**292 - **Auth0:** Create application, configure callback URLs, get credentials293 - **Supabase:** Already configured with database setup2942953. **Generate Auth Code**296 Use `chatgpt-auth-generator` agent to create:297 - Session management middleware298 - User subject extraction299 - Token validation3003014. **Update Server**302 Add auth middleware to protect routes.3033045. **Update Environment**305 ```bash306 # Auth0307 AUTH0_DOMAIN=your-tenant.auth0.com308 AUTH0_CLIENT_ID=...309 AUTH0_CLIENT_SECRET=...310 311 # Supabase (from database setup)312 SUPABASE_URL=...313 SUPABASE_ANON_KEY=...314 ```3153166. **Test**317 Verify login flow and user isolation.318319---320321## 5. Add Database322323**Purpose:** Configure PostgreSQL database using Supabase.324325### When to Add326- Persistent user data327- Multi-entity relationships328- Query/filter capabilities329330### Workflow3313321. **Check Supabase Setup**333 Verify account and project exist.3343352. **Gather Credentials**336 - Project URL337 - Anon key (public)338 - Service role key (server-side)3393403. **Define Entities**341 For each entity, specify:342 - Fields and types343 - Relationships344 - Indexes3453464. **Generate Schema**347 Use `chatgpt-database-generator` agent to create SQL with:348 - `id` (UUID primary key)349 - `user_subject` (varchar, indexed)350 - `created_at` (timestamptz)351 - `updated_at` (timestamptz)352 - RLS policies for user isolation3533545. **Setup Connection Pool**355 ```typescript356 import { createClient } from '@supabase/supabase-js';357 358 const supabase = createClient(359 process.env.SUPABASE_URL!,360 process.env.SUPABASE_SERVICE_ROLE_KEY!361 );362 ```3633646. **Apply Migrations**365 Run SQL in Supabase dashboard or via migration tool.366367### Query Pattern368369Always filter by `user_subject`:370371```typescript372const { data } = await supabase373 .from('tasks')374 .select('*')375 .eq('user_subject', userSubject);376```377378---379380## 6. Generate Golden Prompts381382**Purpose:** Generate test prompts to validate ChatGPT correctly invokes tools.383384### Why Important385- Measure precision/recall386- Enable iteration387- Post-launch monitoring388389### 3 Categories3903911. **Direct Prompts** - Explicit tool invocation392 - "Show me my task list"393 - "Create a new task called..."3943952. **Indirect Prompts** - Outcome-based, ChatGPT should infer tool396 - "What do I need to do today?"397 - "Help me organize my work"3983993. **Negative Prompts** - Should NOT trigger tool400 - "What is a task?"401 - "Tell me about project management"402403### Workflow4044051. **Analyze Tools**406 Review each tool's purpose and inputs.4074082. **Generate Prompts**409 For each tool, create:410 - 5+ direct prompts411 - 5+ indirect prompts412 - 3+ negative prompts413 - 2+ edge case prompts4144153. **Best Practices**416 - Tool descriptions start with "Use this when..."417 - State limitations clearly418 - Include examples in descriptions4194204. **Save Output**421 Write to `.chatgpt-app/golden-prompts.json`:422 ```json423 {424 "toolName": {425 "direct": ["prompt1", "prompt2"],426 "indirect": ["prompt1", "prompt2"],427 "negative": ["prompt1", "prompt2"],428 "edge": ["prompt1", "prompt2"]429 }430 }431 ```432433---434435## 7. Validate App436437**Purpose:** Validation suite before deployment.438439### 10 Validation Checks4404411. **Required Files**442 - package.json443 - tsconfig.server.json444 - setup.sh (executable)445 - START.sh (executable)446 - server/index.ts447 - .env.example4484492. **Server Implementation**450 - Uses `Server` from MCP SDK451 - Has `StreamableHTTPServerTransport`452 - Session management with Map453 - Correct request handlers4544553. **Widget Configuration**456 - `widgets` array exists457 - Each has id, name, description, templateUri, mockData458 - URIs match pattern `ui://widget/{id}.html`4594604. **Tool Response Format**461 - Returns `structuredContent` (not just `content`)462 - Widget tools have `_meta` with `openai/outputTemplate`4634645. **Resource Handler Format**465 - MIME type: `text/html+skybridge`466 - Returns `_meta` with serialization and CSP4674686. **Widget HTML Structure**469 - Preview mode support470 - Event listeners for Apps SDK471 - Polling fallback472 - Render guard4734747. **Endpoint Existence**475 - `/health` - Health check476 - `/preview` - Widget index477 - `/preview/:widgetId` - Widget preview478 - `/mcp` - MCP endpoint4794808. **Package.json Scripts**481 - Has `build:server`482 - Has `start` with HTTP_MODE=true483 - Has `dev` with watch mode484 - NO web build scripts (web/, ui/, client/)4854869. **Annotation Validation**487 - readOnlyHint set correctly488 - destructiveHint for delete operations489 - openWorldHint for external APIs49049110. **Database Validation** (if enabled)492 - Tables have required fields493 - user_subject indexed494 - RLS policies enabled495496### Common Errors497498| Error | Fix |499|-------|-----|500| Missing structuredContent | Add to tool response |501| Wrong widget URI | Use ui://widget/{id}.html |502| No session management | Add Map<string, Transport> |503| Missing _meta | Add to tool definition and response |504| Wrong MIME type | Use text/html+skybridge |505506**Critical:** Check file existence FIRST before other validations!507508---509510## 8. Test App511512**Purpose:** Run automated tests using MCP Inspector and golden prompts.513514### 4 Test Categories5155161. **MCP Protocol**517 - Server starts without errors518 - Handles initialize519 - Lists tools correctly520 - Lists resources correctly5215222. **Schema Validation**523 - Tool schemas are valid Zod524 - Required fields marked525 - Types match implementation5265273. **Widget Tests**528 - All widgets render in preview mode529 - Mock data loads correctly530 - No console errors5315324. **Golden Prompt Tests**533 - Direct prompts trigger correct tools534 - Indirect prompts work as expected535 - Negative prompts don't trigger tools536537### Workflow5385391. **Start Server in Test Mode**540 ```bash541 HTTP_MODE=true NODE_ENV=test npm run dev542 ```5435442. **Run MCP Inspector**545 Test protocol compliance:546 - Initialize connection547 - List tools548 - Call each tool with valid inputs549 - Check responses5505513. **Schema Validation**552 Verify schemas compile and match implementation.5535544. **Golden Prompt Tests**555 Use ChatGPT to test prompts:556 - Record which tool was called557 - Compare to expected tool558 - Calculate precision/recall5595605. **Generate Report**561 ```json562 {563 "passed": 42,564 "failed": 3,565 "categories": {566 "mcp": "✅",567 "schema": "✅",568 "widgets": "✅",569 "prompts": "⚠️ 3 failures"570 },571 "timing": "2.3s"572 }573 ```574575### Fixing Failures576577For each failure, explain:578- What failed579- Why it failed580- How to fix (with code example)581582---583584## 9. Deploy App585586**Purpose:** Deploy ChatGPT App to Render with PostgreSQL and health checks.587588### Prerequisites589590- ✅ Validation passed591- ✅ Tests passed592- ✅ Git repository clean593- ✅ Environment variables ready594595### Workflow5965971. **Pre-flight Check**598 - Run validation599 - Run tests600 - Check database connection (if enabled)6016022. **Generate render.yaml**603 ```yaml604 services:605 - type: web606 name: {app-name}607 runtime: docker608 plan: free609 healthCheckPath: /health610 envVars:611 - key: PORT612 value: 3000613 - key: HTTP_MODE614 value: true615 - key: NODE_ENV616 value: production617 - key: WIDGET_DOMAIN618 generateValue: true619 # Add auth/database vars if needed620 ```6216223. **Generate Dockerfile**623 ```dockerfile624 FROM node:20-slim625 WORKDIR /app626 COPY package*.json ./627 RUN npm ci --only=production628 COPY dist ./dist629 EXPOSE 3000630 CMD ["node", "dist/server/index.js"]631 ```6326334. **Deploy**634 **Option A: Automated (if Render MCP available)**635 Use Render MCP agent to deploy.636 637 **Option B: Manual**638 - Push to GitHub639 - Connect repo in Render dashboard640 - Set environment variables641 - Deploy6426435. **Verify Deployment**644 - Health check: `https://{app}.onrender.com/health`645 - MCP endpoint: `https://{app}.onrender.com/mcp`646 - Tool discovery works647 - Widgets render6486496. **Configure ChatGPT Connector**650 - URL: `https://{app}.onrender.com/mcp`651 - Test in ChatGPT652653---654655## 10. Resume App656657**Purpose:** Resume building an in-progress ChatGPT App.658659### Workflow6606611. **Load State**662 Read `.chatgpt-app/state.json`:663 ```json664 {665 "appName": "My Task Manager",666 "phase": "Implementation",667 "tools": ["list-tasks", "create-task"],668 "widgets": ["task-list"],669 "auth": false,670 "database": true,671 "validated": false,672 "deployed": false673 }674 ```6756762. **Display Progress**677 Show current status:678 - App name679 - Current phase680 - Completed items (tools, widgets)681 - Pending items (auth, validation, deployment)6826833. **Offer Next Steps**684 Based on phase:685 686 **Concept Phase:**687 - "Let's design the tools and widgets"688 - "Shall we start implementation?"689 690 **Implementation Phase:**691 - "Add another tool?"692 - "Add a widget?"693 - "Set up authentication?"694 - "Set up database?"695 696 **Testing Phase:**697 - "Generate golden prompts?"698 - "Run validation?"699 - "Run tests?"700 701 **Deployment Phase:**702 - "Deploy to Render?"703 - "Configure ChatGPT connector?"7047054. **Continue Work**706 Based on user's choice, invoke the appropriate workflow section.707708---709710## Best Practices7117121. **Always save state** after each major step7132. **Validate before moving forward** (especially before deployment)7143. **Use agents for code generation** (chatgpt-mcp-generator, chatgpt-auth-generator, etc.)7154. **Test at every phase** (preview widgets, test tools, run golden prompts)7165. **Keep it conversational** - guide the user naturally through the workflow7176. **Explain trade-offs** when offering choices (Auth0 vs Supabase, etc.)7187. **Show examples** when introducing new concepts719720---721722## State Management723724The `.chatgpt-app/state.json` file tracks progress:725726```json727{728 "appName": "string",729 "description": "string",730 "phase": "Concept" | "Implementation" | "Testing" | "Deployment",731 "tools": ["tool-name"],732 "widgets": ["widget-id"],733 "auth": {734 "enabled": boolean,735 "provider": "auth0" | "supabase" | null736 },737 "database": {738 "enabled": boolean,739 "entities": ["entity-name"]740 },741 "validated": boolean,742 "tested": boolean,743 "deployed": boolean,744 "deploymentUrl": "string | null",745 "goldenPromptsGenerated": boolean,746 "lastUpdated": "ISO timestamp"747}748```749750---751752## Command Reference753754```bash755# Setup756./setup.sh757758# Development759./START.sh --dev # Dev mode with watch760./START.sh --preview # Open preview in browser761./START.sh --stdio # STDIO mode (testing)762./START.sh # Production mode763764# Testing765npm run validate # Type checking766curl http://localhost:3000/health767768# Deployment769git push origin main # Trigger Render deploy770```771772---773774## Getting Started775776When the user invokes any chatgpt-app command:7777781. Check if `.chatgpt-app/state.json` exists7792. If yes → use **Resume App** workflow7803. If no → use **Create New App** workflow781782Always guide users through the natural progression:783**Concept → Implementation → Testing → Deployment**