A minimal, production-shaped conversational app for the Fountain API. It is a static React app with no backend of its own.
It deliberately includes the boring, easy-to-get-wrong parts:
- Fountain OAuth authorization code + PKCE, with API-key paste as a fallback
- agent selection and conversation creation
- follow-up prompts and interrupt
- server-parsed response, thinking, tool, and error blocks
- authenticated SSE over
fetch(notEventSource),Last-Event-ID, reconnect, and duplicate suppression - transcript restoration and browser-local session state
- useful API errors, responsive layout, light/dark themes, tests, and a static build
After clicking Use this template, make these changes first:
-
Edit
src/config.ts: set the app name, description, OAuth client ID, and storage key. Make the storage key unique so local development apps do not overwrite one another. -
Replace the agent context in
src/App.tsxand the starter copy insrc/styles.css/index.htmlwith the product's actual first workflow. -
Register the OAuth client and browser origin on the Fountain server:
API_CORS_ORIGINS=http://localhost:5173 OAUTH_CLIENTS='[{"id":"fountain-template-chat","name":"Fountain Chat Starter","redirect_uris":["http://localhost:5173/"]}]'The ID must equal
APP.oauthClientId; the redirect URI must match exactly. -
Delete this checklist and describe what your app does.
If OAuth is not registered yet, choose Paste an API key instead.
bun install
bun run devOptional local proxy (useful when developing against a server without the dev origin in CORS yet):
FOUNTAIN_PROXY=http://localhost:4000 bun run devbun test
bun run typecheck
bun run buildThe static build is written to dist/ and can be hosted anywhere. Add the
production origin and redirect URI to Fountain before deploying.
| Concern | File |
|---|---|
| app identity and OAuth client | src/config.ts |
| product flow and UI | src/App.tsx |
| API endpoints and errors | src/api/client.ts |
| Fountain response shapes | src/api/types.ts |
| response/tool rendering | src/lib/blocks.ts |
| OAuth + PKCE | src/lib/oauth.ts |
| authenticated event stream | src/lib/sse.ts |
| local state | src/lib/settings.ts |
| visual system | src/styles.css |
The conversation and events on Fountain are the system of record. Local
storage only remembers credentials and the current IDs. The app asks Fountain
for blocks=true, so it renders the server's runtime-aware parse instead of
parsing provider output itself. The event stream uses a bearer header, which
is why it uses fetch rather than the browser's EventSource API.
MIT