Reverse-chronological record of shipped work — features, fixes, and chores. Newest first.
- Added the llame vision document and linked it from agent context, clarifying the platform bets, current focus, emerging directions, and near-term non-goals; bumped the default OpenAI model to
gpt-5.4-miniand added telemetry pricing for that default. - Added test CI (#70): a GitHub Actions workflow gates every PR (and pushes to
master) onturbo run lint,turbo run build, the api unit suite, andapps/api/scripts/rls-test.sh— the cross-tenant RLS proof and HTTP e2e against a throwaway Postgres, same script as local. Actions are SHA-pinned,permissions: contents: read, actionlint + zizmor clean. Standing up root lint surfaced thatpackages/ui's lint had been silently broken forever (noeslintdevDependency) — fixed, along with the three warnings it had been hiding.
- Added per-chat deep links for the web chat (#77):
/chat/[id]now server-loads persisted history throughapps/api, sidebar chat rows navigate to stable chat URLs, New Chat resets to/with a fresh draft id, and SSR history reads are bounded by a short timeout instead of waiting indefinitely on a stalled API.
- Upgraded the Vercel AI SDK off its pre-stable beta line:
ai5.0.0-beta.12 → 6.0.217,@ai-sdk/react→ 3.0.219 (apps/web),@ai-sdk/openai→ 3.0.79 (apps/api), staged through v5-stable and v6 with@ai-sdk/codemodfor the v6 hop. Stopped at v6 rather than v7:ai@7.0.0dropped CommonJS support entirely (ESM-only, norequireexport condition), whichapps/api's NestJS/CommonJS build can't consume without a module-system migration — deferred to whenever the durable-run worker (#50) is built, since that's a new process that can reasonably start as ESM.apps/api'sContextBuildernow delivers the chat's system prompt viastreamText's nativesystemparam instead of arole: 'system'entry inmessages(the AI SDK warns on the latter as of v6, and v7 rejects it outright). - Refreshed the
packages/uishadcn/ui kit to current upstream: migrated all primitives from the individual@radix-ui/react-*packages to the unifiedradix-uipackage, re-pulled the latest component source (newButtonxs/icon-*sizes anddata-variant/data-size, flatter default surfaces), and bumpedlucide-react0.475 → 1.x. No design-token changes —globals.cssstays monochrome. - Added shadcn staple components to
@workspace/ui:badge,tabs,switch,spinner,toggle,toggle-group, andalert-dialog. - Fixed the collapsed-sidebar user avatar squashing into a vertical rectangle: the trigger now uses
SidebarMenuButton size="lg"(which zeroes padding when collapsed) instead of a manualh-12, so the 8×8 avatar stays square in icon mode. - Replaced the hand-rolled
<kbd>shortcut hints in the sidebar with@workspace/ui's officialKbdcomponent, surfaced both inline (on hover, expanded) and in the collapsed-state tooltip — using the samehas-data-[slot=kbd]flex-gap idiom shadcn applies onButton, sinceTooltipContentdoesn't ship it by default. - Added per-assistant-turn telemetry in
apps/api(#56): assistant messages now persist token usage including cached input tokens and reasoning tokens, model/provider, latency, finish reason/status, and best-effortcostUsd; completed turns emit a structured pino trace keyed by chat/message ids without message content. - First message now creates the chat in one call (#86):
POST /api/v1/chats/:id/messagesupserts the chat for a client-supplied id before streaming (idempotentcreateIfAbsent, mirroring the user-message upsert). The id is routing/idempotency only — the owner stays server-derived, and a cross-tenant id collision returns 404 (no hijack, no existence leak), proven by RLS-integration and e2e tests. Eliminates the empty-chat orphan left behind when a first send failed (e.g. the 402 no-model-key case, which now persists nothing).apps/webdrops the create-then-stream machinery (thequeuedMessage/queuedChatIdqueue and the remount-on-activeChatIddance): it mints the chat id up front and keys the session by it, so adopting the id on first send streams without a remount. Dropped the now-unusedPOST /api/v1/chatsempty-chat endpoint — chats are created exclusively by their first message. - Added Playwright browser E2E coverage for the auth cutover (#79): the Playwright harness starts a throwaway Docker Postgres, applies migrations, starts
apps/api+apps/web, reuses worker-scoped authenticated storage state, and verifies login success/failure, callback redirect safety, no-cookie redirects, logout, and revoked-session redirect behavior. - Completed the
apps/webthin-client cutover (#63): removed its database, NextAuth adapter/JWT, and the LangGraph chat/models routes — the browser now callsapps/apidirectly atNEXT_PUBLIC_API_URLfor/auth/v1(login/register/logout) and/api/v1(chats + streaming). Layered auth-state (middleware cookie-presence gate → authoritative api guard → client401interceptor;GET /auth/v1/meas source of truth), with one shared 401 handler across the ky client and the AI SDK chat transport. Added config-driven CORS allowlist + session-cookieDomainonapps/api. - Added the
apps/apisingle-model streaming chat loop (#55): guardedPOST /api/v1/chats/:id/messages, server-authoritative context, idempotent client message ids, AI SDK UI-message SSE streaming, assistant persistence with usage, and abort/cross-tenant/fail-fast e2e coverage.
- Shipped the v0.1 multi-tenant chat foundation (#53, #59):
chats/messagesschema (AI SDK v5role+parts, sender-attributed) with a monotonicseqordering key, achat_visibilityenum, and a deterministic, cache-awareContextBuilder. - Row-Level Security
ENABLEd andFORCEd onchats/messages, engaged per request viaTenantDbService.runAs(transaction-localapp.current_user_id); cross-tenant isolation proven against real Postgres (apps/api/scripts/rls-test.sh). - Local dev database via docker-compose (
pnpm db:up/db:migrate/db:studio/db:psql/db:reset), provisioning a non-superuser app role so RLS is exercised as in production. - Added the
apps/api/auth/v1surface (#60): register, login, current user, and revocable server-side session resources backed by opaque tokens hashed at rest. - Security: re-exposed chat HTTP endpoints under
/api/v1only behind verified sessions, soTenantDbService.runAsis fed by trusted auth context instead of client-suppliedownerUserId.
- Authored the product specification (SPEC.md) and refined it to v0.3: single TypeScript stack, Postgres-first architecture, corrected single-
SKILL.mdskill format — verified via a multi-reviewer pass. - Added hierarchical
CLAUDE.mdcontext files (root +apps/web,apps/api,packages/ui). - Pinned Next.js to 15.5.19 for stable Node middleware; documented OpenAI/Anthropic API keys in
.env.example.
- Dependency updates (Next.js, axios).
- Moved the database out of the Next.js app into the NestJS API.
- Scaffolded the NestJS API app.
- Chat error display;
AlertUI component.
- Experimented with multi-agent / expert-supervision orchestration.
- Persist and fetch user chats via the API/DB.
- Agent supervisor/orchestrator and ReAct agent for chat.
- Added Sentry.
- User info in the sidebar.
- Theme switch and font-family setting (incl. OpenDyslexic), with server-side cookie persistence.
- Model preview card in the selector; upgraded AI SDK to beta.
- Per-message model selection; styled messages, auto-scroll container, and message components; dropped the completions PoC.
- Stateless chat PoC; test chat + completions APIs; message-input, code-block, and markdown components.
- Models API + query; PoC conversation tree; fixed the auth DB connection in middleware.
- Core chat UI shell: sidebar (mock chats/projects), model selector, and shadcn UI kit (dialog, popover, command, dropdown, sidebar).
- React Query wiring; simple auth/register pages.
- Project bootstrapped (shadcn/ui monorepo); Sonner toaster.