Inside openai/openai-chatkit-starter-app: The Chat Starter That Makes the Backend a Boundary

A deep dive into OpenAI’s reference app, where one path hosts the whole conversation and the other turns the server into a secure session broker.

11 min read • View on GitHub • More from openai

A browser window hands a sealed envelope across a security desk into a locked back office. The image shows that the frontend can start a chat session without ever holding the real OpenAI key, which is the core security idea in this starter.
The starter’s central idea is a trust boundary, not a chat bubble.
Key Takeaways

The backend is the boundary

Most chat starters begin with the UI. This repo starts with permissions. In managed mode, the browser asks the backend for a session, and the backend swaps its own credentials for a short-lived `client_secret`; in self-hosted mode, the same server owns history, streaming, and agent execution.

The repo teaches two architectures at once: a thin session broker and a full self-hosted chat server.

Two modes, one chat surface

That split gives the repo its useful weirdness. It is one codebase that teaches both the thin-proxy version and the full-server version of ChatKit. If you are deciding how much of the stack to own, the contrast is the point.

DimensionManaged ChatKitSelf-hosted ChatKit
Backend roleAuthenticates the user and exchanges a server key for a short-lived `client_secret`.Owns the chat loop, persistence, and the streamed response.
State ownershipOpenAI-hosted workflow state does most of the work.Threads, items, attachments, and cursors live in app code.
CustomizationFastest path to a working product surface.Most room for custom storage, agent logic, and integrations.
Best fitTeams that want less plumbing and more product surface.Teams that need to shape the conversation stack themselves.

The important trade-off is not convenience versus control in the abstract. It is where you want intelligence, state, and responsibility to live. If the session secret is short-lived and server-generated, the frontend becomes safer by default. If the conversation store lives in your app, you gain flexibility but you also inherit the durability problem.

How the self-hosted path actually responds

Under the hood, `StarterChatServer` does the interesting work. It loads the conversation from the store, turns history into agent input with `simple_to_agent_input`, and passes that into `Runner.run_streamed`. FastAPI only handles the transport layer, wrapping the stream as Server-Sent Events so the UI can render incremental output instead of waiting for a full response.

That separation is deliberate. `main.py` stays thin, and the React layer stays focused on rendering and state. The result is a backend you could swap without rewriting the whole chat surface, which is exactly what a starter should teach.

Why the store looks boring on purpose

The memorable file is `memory_store.py`, because it looks unremarkable until you notice what it encodes. ChatKit’s state is not one blob. It is threads, items, attachments, cursors, and `has_more` flags. A demo store that understands pagination is not pretending conversations fit on one screen.

A close-up of a card catalog with narrow drawers, paper slips, and index tabs arranged like a conversation archive. The scene explains that ChatKit state is a navigable timeline of threads, items, and attachments, not one opaque message blob.
The store’s simplicity hides a precise data model.

That is the real lesson. State is not one blob, it is a navigable timeline. Once you have attachments and cursors, your app is already thinking like a product, not a prompt toy.

What this starter replaces

If you built this from scratch, you would be writing glue code across session auth, streaming, message persistence, rerenders, and the edge cases that show up once conversations get long. ChatKit Starter App replaces that plumbing while keeping the agent logic visible. It is closer to a production scaffold than a design kit.

The piece most frontend teams will love is ChatKit — an embeddable, production‑grade chat surface that handles streaming, history, and UI polish so you don’t have to build a chat from scratch.

Doran Gao, Creator of TheOneQuote.app · Doran Gao on Medium

That is the real competition. Not another bubble component, but the hours you would otherwise spend on the invisible parts of chat. The starter’s job is to make the hard parts boring so the product team can focus on the parts users actually notice.

Who built it, and why that matters

This is an official OpenAI reference app, with maintainers such as `seratch`, `katia-openai`, and `lukas-openai` in the contributor list. That matters because the repo is opinionated in the right way. It teaches the current shape of ChatKit, not a generic pattern detached from the platform. If you want the shortest path from agent workflow to a functioning product shell, this is a strong map of the territory.