Lesson 3 of 3 · Building ChatGPT Apps

Planning Your First App

reading10 min

Before writing code, you need to think carefully about tool design. The tools you expose to ChatGPT are not just API endpoints -- they are the vocabulary your app speaks. The model uses tool names, descriptions, and schemas to decide when and how to call them. Bad tool design leads to an app that the model calls incorrectly, at the wrong times, or not at all.

Tool Design Principles

These principles come from real production apps. They are not theoretical -- they are the patterns that survive the App Store review process and produce good user experiences.

Principle 1: One Job Per Tool

Each tool should do exactly one thing. The model decides which tool to call based on the tool's name and description. If a tool does multiple things, the model cannot reliably decide when to use it.

Do

Create separate tools: search_products, get_product_details, add_to_cart, checkout. Each has a clear purpose the model can reason about.

Don't

Create a single do_everything tool with a 'action' parameter that switches between search, details, cart, and checkout. The model will misuse it because the purpose is ambiguous.

Principle 2: Read vs Write Separation

Separate tools that read data from tools that modify data. This is not just good API design -- it matters for the model's decision-making and for user trust:

  • Read tools can be called freely. The model calls them to gather information.
  • Write tools should be called deliberately. The model should confirm with the user before modifying data.

The tool annotations system enforces this:

typescript
{
  name: 'search_products',
  annotations: {
    readOnlyHint: true,    // Safe to call without confirmation
    destructiveHint: false,
  }
}

{
  name: 'delete_item',
  annotations: {
    readOnlyHint: false,
    destructiveHint: true,  // Model will confirm before calling
  }
}

Principle 3: Descriptive Names and Descriptions

The model reads your tool names and descriptions to understand what they do. Write them for the model, not for humans:

typescript
// Good: The model knows exactly when to use this
{
  name: 'search_restaurants_by_location',
  description: 'Search for restaurants near a specific location. Returns a list of restaurants with name, cuisine type, rating, price range, and distance. Use this when the user wants to find places to eat near a specific address or landmark.'
}

// Bad: The model has to guess what this does
{
  name: 'search',
  description: 'Search for things'
}
Write Descriptions for the Model

Include when-to-use guidance in your tool descriptions. Phrases like "Use this when the user wants to..." or "Call this after the user has selected a product" help the model make better decisions about when to invoke your tools.

Principle 4: Schema Everything

Every tool input must have a JSON Schema. Every required field must be marked required. Every field must have a description. The model uses these schemas to extract parameters from user messages:

typescript
{
  name: 'book_restaurant',
  inputSchema: {
    type: 'object',
    required: ['restaurant_id', 'date', 'party_size'],
    properties: {
      restaurant_id: {
        type: 'string',
        description: 'The unique ID of the restaurant (from search results)'
      },
      date: {
        type: 'string',
        format: 'date-time',
        description: 'The desired reservation date and time in ISO 8601 format'
      },
      party_size: {
        type: 'integer',
        minimum: 1,
        maximum: 20,
        description: 'Number of guests'
      },
      special_requests: {
        type: 'string',
        description: 'Optional dietary restrictions or seating preferences'
      }
    }
  }
}

100%

Every tool parameter needs a schema and description -- no exceptions

Planning Your Tool Set

Before writing code, map out your entire tool set on paper. Ask these questions for each tool:

  1. What does it do? (One sentence. If you need two, split into two tools.)
  2. When should the model call it? (Write this into the description.)
  3. What inputs does it need? (Schema every field.)
  4. What does it return? (Structured content with component hints if applicable.)
  5. Is it read or write? (Set annotations accordingly.)
  6. What can go wrong? (Plan error responses.)

Error Design

How your tools report errors matters more than you think. The model reads error messages and uses them to explain what went wrong to the user. Good error messages help the model help the user:

typescript
// Good: The model can explain this to the user and suggest next steps
return {
  content: [{
    type: 'text',
    text: 'No restaurants found within 5 miles of "123 Main St, Springfield". Try expanding the search radius or using a different location.'
  }],
  isError: true
};

// Bad: The model cannot help the user recover
return {
  content: [{
    type: 'text',
    text: 'Error: NOT_FOUND'
  }],
  isError: true
};

beginner

Plan your first app:

  1. Choose a domain you know well (recipes, fitness, music, books, travel)
  2. List 5-8 tools your app would need
  3. For each tool, write: name, one-sentence description, read/write classification
  4. Write the full input schema for your most complex tool
  5. Write one success response and one error response for each tool

Do not write any code yet. This planning step saves more time than it costs.

Concept Card