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---5
6# ChatGPT Apps Builder
7
8Complete workflow for building, testing, and deploying ChatGPT Apps from concept to production.
9
10## Commands
11
12- `/chatgpt-apps new` - Create a new ChatGPT App
13- `/chatgpt-apps add-tool` - Add an MCP tool to your app
14- `/chatgpt-apps add-widget` - Add a widget to your app
15- `/chatgpt-apps add-auth` - Configure authentication
16- `/chatgpt-apps add-database` - Set up database
17- `/chatgpt-apps validate` - Validate your app
18- `/chatgpt-apps test` - Run tests
19- `/chatgpt-apps deploy` - Deploy to production
20- `/chatgpt-apps resume` - Resume working on an app
21
22---
23
24## Table of Contents
25
261. [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)
36
37---
38
39## 1. Create New App
40
41**Purpose:** Create a new ChatGPT App from concept to working code.
42
43### Workflow
44
45#### Phase 1: Conceptualization
46
471. **Ask for the app idea**
48 "What ChatGPT App would you like to build? Describe what it does and the problem it solves."
49
502. **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?
54
553. **Check for Anti-Patterns**
56 - Static website content display
57 - Complex multi-step workflows requiring external tabs
58 - Duplicating ChatGPT's native capabilities
59 - Ads or upsells
60
614. **Define Use Cases**
62 Create 3-5 primary use cases with user stories.
63
64#### Phase 2: Design
65
661. **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)
72
732. **Widget Design**
74 For each widget:
75 - `id` - unique identifier (kebab-case)
76 - `name` - display name
77 - `description` - what it shows
78 - `mockData` - sample data for preview
79
803. **Data Model**
81 Design entities and relationships.
82
834. **Auth Requirements**
84 - Single-user (no auth needed)
85 - Multi-user (Auth0 or Supabase Auth)
86
87#### Phase 3: Implementation
88
89Generate complete application with this structure:
90
91```
92{app-name}/
93├── package.json
94├── tsconfig.server.json
95├── setup.sh
96├── START.sh
97├── .env.example
98├── .gitignore
99└── server/
100 └── index.ts
101```
102
103**Critical Requirements:**
104- `Server` class from `@modelcontextprotocol/sdk/server/index.js`
105- `StreamableHTTPServerTransport` for session management
106- Widget URIs: `ui://widget/{widget-id}.html`
107- Widget MIME type: `text/html+skybridge`
108- `structuredContent` in tool responses
109- `_meta` with `openai/outputTemplate` on tools
110
111#### Phase 4: Testing
112- Run setup: `./setup.sh`
113- Start dev: `./START.sh --dev`
114- Preview widgets: `http://localhost:3000/preview`
115- Test MCP connection
116
117#### Phase 5: Deployment
118- Generate Dockerfile and render.yaml
119- Deploy to Render
120- Configure ChatGPT connector
121
122---
123
124## 2. Add MCP Tool
125
126**Purpose:** Add a new MCP tool to your ChatGPT App.
127
128### Workflow
129
1301. **Gather Information**
131 - What does this tool do?
132 - What inputs does it need?
133 - What does it return?
134
1352. **Classify Tool Type**
136 - **Query** (readOnlyHint: true) - Fetches data
137 - **Mutation** (destructiveHint: false) - Creates/updates data
138 - **Destructive** (destructiveHint: true) - Deletes data
139 - **Widget** - Returns UI content
140 - **External** (openWorldHint: true) - Calls external APIs
141
1423. **Design Input Schema**
143 Create Zod schema with appropriate types and descriptions.
144
1454. **Generate Tool Handler**
146 Use `chatgpt-mcp-generator` agent to create:
147 - Tool handler in `server/tools/`
148 - Zod schema export
149 - Type exports
150 - Database queries (if needed)
151
1525. **Register Tool**
153 Update `server/index.ts` with metadata:
154 ```typescript
155 {
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 widget
161 }
162 }
163 ```
164
1656. **Update State**
166 Add tool to `.chatgpt-app/state.json`.
167
168### Tool Naming
169Use kebab-case: `list-items`, `create-task`, `show-recipe-detail`
170
171### Annotations Guide
172
173| 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 |
179
180---
181
182## 3. Add Widget
183
184**Purpose:** Add inline HTML widgets with HTML/CSS/JS and Apps SDK integration.
185
186### 5 Widget Patterns
187
1881. **Card Grid** - Multiple items in grid
1892. **Stats Dashboard** - Key metrics display
1903. **Table** - Tabular data
1914. **Bar Chart** - Simple visualizations
1925. **Detail Widget** - Single item details
193
194### Workflow
195
1961. **Gather Information**
197 - Widget purpose and data
198 - Visual design (cards, table, chart, etc.)
199 - Interactivity needs
200
2012. **Define Data Shape**
202 Document expected structure with TypeScript interface.
203
2043. **Add Widget Config**
205 ```typescript
206 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 ```
218
2194. **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)
225
2265. **Create/Update Tool**
227 Link tool to widget via `widgetId`.
228
2296. **Test Widget**
230 Preview at `/preview/{widget-id}` with mock data.
231
232### Widget HTML Structure
233
234```javascript
235(function() {
236 let rendered = false;
237
238 function render(data) {
239 if (rendered || !data) return;
240 rendered = true;
241 // Render logic
242 }
243
244 function tryRender() {
245 if (window.PREVIEW_DATA) { render(window.PREVIEW_DATA); return; }
246 if (window.openai?.toolOutput) { render(window.openai.toolOutput); }
247 }
248
249 window.addEventListener('openai:set_globals', tryRender);
250
251 const poll = setInterval(() => {
252 if (window.openai?.toolOutput || window.PREVIEW_DATA) {
253 tryRender();
254 clearInterval(poll);
255 }
256 }, 100);
257 setTimeout(() => clearInterval(poll), 10000);
258
259 tryRender();
260})();
261```
262
263---
264
265## 4. Add Authentication
266
267**Purpose:** Configure authentication using Auth0 or Supabase Auth.
268
269### When to Add
270- Multiple users
271- Persistent private data per user
272- User-specific API credentials
273
274### Providers
275
276**Auth0:**
277- Enterprise-grade
278- OAuth 2.1, PKCE flow
279- Social logins (Google, GitHub, etc.)
280
281**Supabase Auth:**
282- Simpler setup
283- Email/password default
284- Integrates with Supabase database
285
286### Workflow
287
2881. **Choose Provider**
289 Ask user preference based on needs.
290
2912. **Guide Setup**
292 - **Auth0:** Create application, configure callback URLs, get credentials
293 - **Supabase:** Already configured with database setup
294
2953. **Generate Auth Code**
296 Use `chatgpt-auth-generator` agent to create:
297 - Session management middleware
298 - User subject extraction
299 - Token validation
300
3014. **Update Server**
302 Add auth middleware to protect routes.
303
3045. **Update Environment**
305 ```bash
306 # Auth0
307 AUTH0_DOMAIN=your-tenant.auth0.com
308 AUTH0_CLIENT_ID=...
309 AUTH0_CLIENT_SECRET=...
310
311 # Supabase (from database setup)
312 SUPABASE_URL=...
313 SUPABASE_ANON_KEY=...
314 ```
315
3166. **Test**
317 Verify login flow and user isolation.
318
319---
320
321## 5. Add Database
322
323**Purpose:** Configure PostgreSQL database using Supabase.
324
325### When to Add
326- Persistent user data
327- Multi-entity relationships
328- Query/filter capabilities
329
330### Workflow
331
3321. **Check Supabase Setup**
333 Verify account and project exist.
334
3352. **Gather Credentials**
336 - Project URL
337 - Anon key (public)
338 - Service role key (server-side)
339
3403. **Define Entities**
341 For each entity, specify:
342 - Fields and types
343 - Relationships
344 - Indexes
345
3464. **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 isolation
353
3545. **Setup Connection Pool**
355 ```typescript
356 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 ```
363
3646. **Apply Migrations**
365 Run SQL in Supabase dashboard or via migration tool.
366
367### Query Pattern
368
369Always filter by `user_subject`:
370
371```typescript
372const { data } = await supabase
373 .from('tasks')
374 .select('*')
375 .eq('user_subject', userSubject);
376```
377
378---
379
380## 6. Generate Golden Prompts
381
382**Purpose:** Generate test prompts to validate ChatGPT correctly invokes tools.
383
384### Why Important
385- Measure precision/recall
386- Enable iteration
387- Post-launch monitoring
388
389### 3 Categories
390
3911. **Direct Prompts** - Explicit tool invocation
392 - "Show me my task list"
393 - "Create a new task called..."
394
3952. **Indirect Prompts** - Outcome-based, ChatGPT should infer tool
396 - "What do I need to do today?"
397 - "Help me organize my work"
398
3993. **Negative Prompts** - Should NOT trigger tool
400 - "What is a task?"
401 - "Tell me about project management"
402
403### Workflow
404
4051. **Analyze Tools**
406 Review each tool's purpose and inputs.
407
4082. **Generate Prompts**
409 For each tool, create:
410 - 5+ direct prompts
411 - 5+ indirect prompts
412 - 3+ negative prompts
413 - 2+ edge case prompts
414
4153. **Best Practices**
416 - Tool descriptions start with "Use this when..."
417 - State limitations clearly
418 - Include examples in descriptions
419
4204. **Save Output**
421 Write to `.chatgpt-app/golden-prompts.json`:
422 ```json
423 {
424 "toolName": {
425 "direct": ["prompt1", "prompt2"],
426 "indirect": ["prompt1", "prompt2"],
427 "negative": ["prompt1", "prompt2"],
428 "edge": ["prompt1", "prompt2"]
429 }
430 }
431 ```
432
433---
434
435## 7. Validate App
436
437**Purpose:** Validation suite before deployment.
438
439### 10 Validation Checks
440
4411. **Required Files**
442 - package.json
443 - tsconfig.server.json
444 - setup.sh (executable)
445 - START.sh (executable)
446 - server/index.ts
447 - .env.example
448
4492. **Server Implementation**
450 - Uses `Server` from MCP SDK
451 - Has `StreamableHTTPServerTransport`
452 - Session management with Map
453 - Correct request handlers
454
4553. **Widget Configuration**
456 - `widgets` array exists
457 - Each has id, name, description, templateUri, mockData
458 - URIs match pattern `ui://widget/{id}.html`
459
4604. **Tool Response Format**
461 - Returns `structuredContent` (not just `content`)
462 - Widget tools have `_meta` with `openai/outputTemplate`
463
4645. **Resource Handler Format**
465 - MIME type: `text/html+skybridge`
466 - Returns `_meta` with serialization and CSP
467
4686. **Widget HTML Structure**
469 - Preview mode support
470 - Event listeners for Apps SDK
471 - Polling fallback
472 - Render guard
473
4747. **Endpoint Existence**
475 - `/health` - Health check
476 - `/preview` - Widget index
477 - `/preview/:widgetId` - Widget preview
478 - `/mcp` - MCP endpoint
479
4808. **Package.json Scripts**
481 - Has `build:server`
482 - Has `start` with HTTP_MODE=true
483 - Has `dev` with watch mode
484 - NO web build scripts (web/, ui/, client/)
485
4869. **Annotation Validation**
487 - readOnlyHint set correctly
488 - destructiveHint for delete operations
489 - openWorldHint for external APIs
490
49110. **Database Validation** (if enabled)
492 - Tables have required fields
493 - user_subject indexed
494 - RLS policies enabled
495
496### Common Errors
497
498| 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 |
505
506**Critical:** Check file existence FIRST before other validations!
507
508---
509
510## 8. Test App
511
512**Purpose:** Run automated tests using MCP Inspector and golden prompts.
513
514### 4 Test Categories
515
5161. **MCP Protocol**
517 - Server starts without errors
518 - Handles initialize
519 - Lists tools correctly
520 - Lists resources correctly
521
5222. **Schema Validation**
523 - Tool schemas are valid Zod
524 - Required fields marked
525 - Types match implementation
526
5273. **Widget Tests**
528 - All widgets render in preview mode
529 - Mock data loads correctly
530 - No console errors
531
5324. **Golden Prompt Tests**
533 - Direct prompts trigger correct tools
534 - Indirect prompts work as expected
535 - Negative prompts don't trigger tools
536
537### Workflow
538
5391. **Start Server in Test Mode**
540 ```bash
541 HTTP_MODE=true NODE_ENV=test npm run dev
542 ```
543
5442. **Run MCP Inspector**
545 Test protocol compliance:
546 - Initialize connection
547 - List tools
548 - Call each tool with valid inputs
549 - Check responses
550
5513. **Schema Validation**
552 Verify schemas compile and match implementation.
553
5544. **Golden Prompt Tests**
555 Use ChatGPT to test prompts:
556 - Record which tool was called
557 - Compare to expected tool
558 - Calculate precision/recall
559
5605. **Generate Report**
561 ```json
562 {
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 ```
574
575### Fixing Failures
576
577For each failure, explain:
578- What failed
579- Why it failed
580- How to fix (with code example)
581
582---
583
584## 9. Deploy App
585
586**Purpose:** Deploy ChatGPT App to Render with PostgreSQL and health checks.
587
588### Prerequisites
589
590- ✅ Validation passed
591- ✅ Tests passed
592- ✅ Git repository clean
593- ✅ Environment variables ready
594
595### Workflow
596
5971. **Pre-flight Check**
598 - Run validation
599 - Run tests
600 - Check database connection (if enabled)
601
6022. **Generate render.yaml**
603 ```yaml
604 services:
605 - type: web
606 name: {app-name}
607 runtime: docker
608 plan: free
609 healthCheckPath: /health
610 envVars:
611 - key: PORT
612 value: 3000
613 - key: HTTP_MODE
614 value: true
615 - key: NODE_ENV
616 value: production
617 - key: WIDGET_DOMAIN
618 generateValue: true
619 # Add auth/database vars if needed
620 ```
621
6223. **Generate Dockerfile**
623 ```dockerfile
624 FROM node:20-slim
625 WORKDIR /app
626 COPY package*.json ./
627 RUN npm ci --only=production
628 COPY dist ./dist
629 EXPOSE 3000
630 CMD ["node", "dist/server/index.js"]
631 ```
632
6334. **Deploy**
634 **Option A: Automated (if Render MCP available)**
635 Use Render MCP agent to deploy.
636
637 **Option B: Manual**
638 - Push to GitHub
639 - Connect repo in Render dashboard
640 - Set environment variables
641 - Deploy
642
6435. **Verify Deployment**
644 - Health check: `https://{app}.onrender.com/health`
645 - MCP endpoint: `https://{app}.onrender.com/mcp`
646 - Tool discovery works
647 - Widgets render
648
6496. **Configure ChatGPT Connector**
650 - URL: `https://{app}.onrender.com/mcp`
651 - Test in ChatGPT
652
653---
654
655## 10. Resume App
656
657**Purpose:** Resume building an in-progress ChatGPT App.
658
659### Workflow
660
6611. **Load State**
662 Read `.chatgpt-app/state.json`:
663 ```json
664 {
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": false
673 }
674 ```
675
6762. **Display Progress**
677 Show current status:
678 - App name
679 - Current phase
680 - Completed items (tools, widgets)
681 - Pending items (auth, validation, deployment)
682
6833. **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?"
704
7054. **Continue Work**
706 Based on user's choice, invoke the appropriate workflow section.
707
708---
709
710## Best Practices
711
7121. **Always save state** after each major step
7132. **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 workflow
7176. **Explain trade-offs** when offering choices (Auth0 vs Supabase, etc.)
7187. **Show examples** when introducing new concepts
719
720---
721
722## State Management
723
724The `.chatgpt-app/state.json` file tracks progress:
725
726```json
727{
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" | null
736 },
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```
749
750---
751
752## Command Reference
753
754```bash
755# Setup
756./setup.sh
757
758# Development
759./START.sh --dev # Dev mode with watch
760./START.sh --preview # Open preview in browser
761./START.sh --stdio # STDIO mode (testing)
762./START.sh # Production mode
763
764# Testing
765npm run validate # Type checking
766curl http://localhost:3000/health
767
768# Deployment
769git push origin main # Trigger Render deploy
770```
771
772---
773
774## Getting Started
775
776When the user invokes any chatgpt-app command:
777
7781. Check if `.chatgpt-app/state.json` exists
7792. If yes → use **Resume App** workflow
7803. If no → use **Create New App** workflow
781
782Always guide users through the natural progression:
783**Concept → Implementation → Testing → Deployment**