"Open the files in your editor. The patterns are right there. Recognizing them in the wild is the test."
The route as a recipe
This tour is the recipe you'd use on any Pippa-style TypeScript frontend — your own project, an open-source app, or any well-typed React codebase. Five files, in order. Each represents a layer; together they cover the whole shape.
The tour route
1. src/types/index.ts — start here. Every shared type lives in this file: identity unions (like BrainName), record shapes (like Conversation, Message), discriminated unions for events. Reading this file is reading what the system is. Note the literal-union pattern for enums-by-convention, the discriminated union for streaming events, and the optional fields in record interfaces.
2. src/lib/api.ts — the API client. Look at how functions like fetchConversations() declare their return types as Promise<Conversation[]>. Notice the type-only imports from ../types. Notice how errors are typed (unknown in catch, narrowed by instanceof Error).
3. src/hooks/useChat.ts — the central chat hook. This is where SSE streaming happens. Look at the reducer state shape (a discriminated union), the action types (another discriminated union), and how useReducer's state and dispatch are typed through.
4. src/App.tsx — the top-level component. State is lifted here; child components receive typed props. The component tree wires together the chat, sidebar, council, admin, and settings areas.
5. src/components/chat/MessageList.tsx (or any leaf component) — notice how Props are typed inline, how the children are rendered, how callbacks are typed.
What to look for
As you read, identify:
- Every literal-union you see (status fields, enum-shaped identifiers).
- Every discriminated union (events, actions, results).
- Every
import type. - Every place narrowing happens via
if,switch, or type predicates. - Every place a generic function signature preserves a type through.
- Every
Promise<T>and what T is.