All skills
alpic-ai avatar

/chatgpt-app-builder

@3340b34
by Alpicalpic-ai/skybridge2.1k stars
140

Guide developers through creating and updating ChatGPT apps. Covers the full lifecycle: brainstorming ideas against UX guidelines, bootstrapping projects, implementing tools/views, debugging, running dev servers, deploying and connecting apps to ChatGPT. Use when a user wants to create or update a ChatGPT app / MCP server for ChatGPT, or use the Skybridge framework.

Use this Skill: https://skilld.dev/gh/alpic-ai/skybridge/chatgpt-app-builder

This session only. Nothing lands on disk.

referencesstate-and-context.md

≈1.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Manage View State and LLM Context

  • View state (useViewState/createStore) persists and is visible to LLM as structured data.
  • data-llm gives LLM context for referential language ("this one").
  • React useState is ephemeral and invisible to LLM.

Decision guide:

Need Use
Persist data, single component useViewState
Persist data, shared across components, complex mutations createStore
Help LLM understand "this one" data-llm
Ephemeral UI only (hover, animation) useState

useViewState

Single component, simple access patterns.

function SeatPicker({ seats }) {
  const [{ selectedSeat }, setState] = useViewState({ selectedSeat: null });

  return (
    <div className="seat-grid">
      {seats.map(seat => (
        <button
          key={seat.id}
          onClick={() => setState((prev) => ({ ...prev, selectedSeat: seat.id }))}
          className={selectedSeat === seat.id ? "selected" : ""}
        >
          {seat.id}
        </button>
      ))}
    </div>
  );
}

Why useViewState: Single component reads selectedSeat to highlight button. View or LLM reads when booking.

createStore

Shared across components, complex mutations. createStore is a thin wrapper around Zustand.

import { createStore } from "skybridge/web";

const useCartStore = createStore<CartState>((set) => ({
  cart: [],
  add: (item) => set((s) => ({ cart: [...s.cart, item] })),
  remove: (id) => set((s) => ({ cart: s.cart.filter(i => i.id !== id) })),
}));

// ProductCard.tsx
function ProductCard({ product }) {
  const add = useCartStore((s) => s.add);
  return <button onClick={() => add(product)}>Add to Cart</button>;
}

// CartSummary.tsx
function CartSummary() {
  const cart = useCartStore((s) => s.cart);
  return <span>{cart.length} items</span>;
}

Why createStore: Cart accessed by multiple components. View or LLM reads items at checkout.

data-llm

Tell the LLM what user is viewing/doing. One-way—view doesn't read it back. These are annotations—don't put complex objects here.

function ProductDetail({ product }) {
  return (
    <div data-llm={`Viewing: ${product.name}, $${product.price}, ${product.inStock ? "in stock" : "out of stock"}`}>
      <h1>{product.name}</h1>
      <p>${product.price}</p>
    </div>
  );
}

Why data-llm: When user asks "Is this one good?" or "Add this to cart", LLM knows what "this" refers to.

Common mistakes

// DON'T: useState is not persisted, LLM can't see it
const [selected, setSelected] = useState(null);

// DO: useViewState persists and LLM sees it
const [{ selected }, setState] = useViewState({ selected: null });
// DON'T: Complex object in data-llm
<div data-llm={JSON.stringify(cart)}>

// DO: Human-readable summary
<div data-llm={`Cart: ${cart.length} items, $${total}`}>

Avoid duplicated model context

Model-visible context accumulates across tool content, structuredContent, persisted view state, and data-llm. Give each channel a distinct role instead of copying the same payload between them:

  • Keep tool content to a short status or summary.
  • Put model-relevant result fields in structuredContent.
  • Persist only UI state that must survive and help the conversation; don't copy the complete tool output into view state.
  • Use data-llm for a concise description of the user's current focus or action, not for data already available to the model.

_meta is different: it is available to the view but not the model, so it can carry additional details or display-only content intentionally omitted from direct model context.

Combined example

Todo list. User checks off tasks, asks "what should I prioritize?"

function TaskList() {
  // PERSIST: All tasks with completed status
  const [{ tasks }, setState] = useViewState({
    tasks: [
      { id: 1, title: "Buy groceries", completed: false },
      { id: 2, title: "Call mom", completed: true },
    ]
  });

  // EPHEMERAL: Task user is viewing — reset on reopen
  const [viewing, setViewing] = useState(null);

  return (
    // CONTEXT: What user is looking at — LLM answers "how should I handle this task?"
    <div data-llm={viewing
      ? `Viewing: "${viewing.title}"`
      : `${tasks.filter(t => !t.completed).length} tasks remaining`
    }>
      {tasks.map(t => (
        <Task
          key={t.id}
          task={t}
          onView={() => setViewing(t)}
          onToggle={() => setState((prev) => ({
            ...prev,
            tasks: prev.tasks.map(task =>
              task.id === t.id ? { ...task, completed: !task.completed } : task
            )
          }))}
        />
      ))}
    </div>
  );
}

Why each?

What API Why
tasks useViewState Persists. Tasks and progress survive reopen.
viewing useState Ephemeral. Current focus resets on reopen.
"Viewing: Buy groceries" data-llm LLM context. Understands "this task" in conversation.

Source: SKILL.md on GitHub

1 alert6d5 checks · Risk SAFE
  • Gen Agent Trust Hub6d

    The skill is a comprehensive development guide for the Skybridge framework, which helps build ChatGPT applications. It is generally safe and follows security best practices, such as documenting CSP and OAuth configurations. It identifies a minor risk of indirect prompt injection as it processes user-provided specification files to guide the development process.

  • Socket6d

    No alerts

  • Snyk6d

    Risk: LOW · No issues

  • Runlayer7mo

    8/23 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 3340b34. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 days ago.

Activeupdated last week

README badge

README badge for alpic-ai/skybridge

Guides developers through the complete lifecycle of building ChatGPT apps—from ideation and project setup through implementation, debugging, and deployment to the ChatGPT Directory. Covers the Skybridge MCP server framework, tool integration, custom UI views, state management, OAuth, and the dual-user model where both the human and ChatGPT LLM interact with the same view.

Generated from the current SKILL.md.

What is a ChatGPT app and how does it work?
A ChatGPT app is a conversational experience that extends ChatGPT through tools and custom UI views, built as an MCP server. The view serves as a shared surface where both the human user and the ChatGPT LLM interact and collaborate.
Do I need a SPEC.md file before building?
Yes. You should read discover.md first to create a SPEC.md that documents your app's requirements and design decisions before implementing anything.
What does this skill cover?
The skill guides the full lifecycle: brainstorming ideas against UX guidelines, bootstrapping projects, implementing tools and views, debugging, running dev servers, deploying via Alpic, and publishing to the ChatGPT Directory.
Does this skill provide API documentation?
Yes. Full API docs are available at https://docs.skybridge.tech/api-reference.md, and the skill includes implementation references for specific tasks like OAuth, state management, and CSP configuration.

Generated from the current SKILL.md. These answers refresh after source changes.