What we shipped. In public, in order, in detail.
Every entry below is a merged pull request. We pull straight from git history — no marketing pass, no rewriting. The latest 60 are listed.
60 ships
- May 17[#218]fix/share
drop mobile gate on share links — render canvas directly
Misread the original HILLA-467 brief. The gate was meant for the auth'd /projects/[id] (where editing is genuinely broken on mobile), NOT share links. Share recipients want to actually see the canv…
- May 17[#217]feat/ai
real "Why this plan?" explanations (HILLA-512)
Replaces the static / deterministic content in the "Why this plan?" modal with a real AI call that returns structured rationale.
- May 17[#216]feat/marketing
/manifesto + /security pages (HILLA-462, HILLA-463)
Two new public marketing pages in the (marketing) route group (cream-only by convention).
- May 17[#215]feat/mobile
cheap viewport gate for canvas + share routes (HILLA-467)
HILLA-467 Option A — the 1-day cheap-insurance branch.
- May 17[#214]fix/theme
keep marketing routes cream-only when user has dark pref
User with dark mode saved sees marketing pages (/, /pricing, /docs, etc.) rendered dark.
- May 17[#213]fix/canvas
polish bucket — Saved mount, image cancel, palette polish, onboarding flag, offline, drag-to-size, eraser
Seven canvas polish / feature-gap fixes bundled together.
- May 17[#212]perf/canvas
viewport virtualization + code-split heavy panels (HILLA-471)
The 150-card test fixture was taking ~3.7s to LCP on M-series hardware — 6× over the <600 ms acceptance bar.
- May 17[#206]feat/auth
migrate Supabase client to createBrowserClient, re-enable SSR middleware (HILLA-449)
Closes the loop opened by PR #190 / PR #195.
- May 17[#211]fix/toast
match Hilla design system — flat, sharp-edged, theme-aware
Sonner toasts were rendering with default shadcn defaults — rounded corners, drop shadow, hardcoded theme="light" that never flipped in dark mode.
- May 17[#210]fix/canvas/modals
preview-QA bug pass — 6 bugs
Six bugs surfaced during preview-deploy QA.
- May 17[#209]fix/dark-mode
cleanup of missed hardcoded literals — 7 reported + sweep
Cleanup pass on dark-mode regressions left over after PR #199.
- May 17[#208]chore/perf
seed 150-card fixture for large-board perf testing (HILLA-471)
Seeds a synthetic 150-card / 8-widget / 50-edge / 120-task project so React Flow rendering performance can be profiled with React DevTools, and ships a reproducible script + JSON + SQL fixture so t…
- May 17[#207]fix/canvas-palette
remove Pan tool, free H for History, add Shape kinds popover
Three small canvas tool palette fixes:
- May 17[#205]fix/cross-cutting
validation + error-handling pass (9 issues)
Batch fix sweep across nine Linear issues — silent failures, missing validations, hardcoded values, and small UX gaps.
- May 17[#204]fix/canvas-panels
surface-bug pass — 8 issues
Tight surface-bug pass across canvas panels and onboarding.
- May 17[#203]fix/modals
bug-fix pass — 8 issues (share/export/digest/standup)
Tight bug-fix pass over four modal/dialog files in src/components/workspace/.
- May 17[#202]fix/canvas-palette
polish pass — 9 issues (HILLA-490, 498, 499, 500, 501, 502, 505, 506, 507)
Polish pass on the left canvas tool palette — fixes 9 small papercuts around dark-mode contrast, accessibility, and pencil-stroke quality.
- May 17[#201]fix/quality
react-doctor sweep — score 45 → 83
🤖 Generated with Claude Code
- May 17[#199]fix/app
make app surfaces dark-mode aware
- May 16[#198]fix/canvas
document-level contextmenu blocker — kill browser menu for good
Yesterday's wrapper fallback (#197) didn't fully kill the browser context menu — React Flow's preventDefault didn't always propagate to the wrapper, and some right-click targets landed outside the…
- May 16[#197]fix/canvas
defensive contextmenu fallback so browser menu never shows
Right-clicking on certain canvas areas was triggering Chrome's native menu (Save As, Print, Inspect, ...) instead of Hilla's pane context menu.
- May 16[#196]fix/canvas + share
multi-task selection works + share view stays light
Two bugs from yesterday.
- May 16[#195]revert/middleware
disable SSR auth — caused login redirect loop
PR #190 broke login. The app's Supabase client uses @supabase/supabase-js (localStorage session), but the middleware uses @supabase/ssr (cookie session). After successful login the middleware's get…
- May 16[#194]feat
share-link CTA polish + pricing PAYG section & credit calculator
Two scope-tight marketing/UX polish wins, one per commit.
- May 16[#193]feat/canvas
drag-snap — align to other cards + 24px grid
While dragging a card on the canvas, snap to the X coordinate of other cards in the same scope (column alignment) and the Y coordinate of cards in the same row band.
- May 16[#192]perf/ai-proxy
race orchestrator against 10s soft deadline on long briefs
| Branch | When | Logged path |
- May 16[#191]feat/canvas
multi-card selection + bulk delete
Selecting more than one card on the canvas previously did nothing visible.
- May 16[#190]feat/auth
enable server-side route protection in middleware (PLAY-449)
Pre-PLAY-449 the middleware was a no-op and protection relied entirely on client-side AuthContext.
- May 16[#189]feat/polar
grandfathering map for legacy subscribers (PLAY-450)
Adds infrastructure so existing subscribers on deprecated pricing tiers don't lose entitlements when their next subscription event fires.
- May 16[#188]refactor
remove @ts-nocheck from 7 core files (PLAY-447)
Removes the @ts-nocheck escape hatch from every remaining file in PLAY-447's list.
- May 16[#187]fix/useai
harden stream-timeout error path + error path audit (PLAY-454)
Audited every error path in useAI.ts. Findings (none silent):
- May 16[#186]chore/services
delete dead vercelApi.ts (PLAY-448)
src/services/vercelApi.ts was the legacy direct-from-browser Vercel client.
- May 16[#185]fix/pricing
derive credits + price from PRODUCT_CREDIT_MAP (PLAY-453)
Pricing page hardcoded credit amounts and dollar prices in the PLANS array, while checkout / webhook code read them from PRODUCT_CREDIT_MAP.
- May 16[#184]chore/ui
dedupe EmptyState components (PLAY-455)
Two EmptyState components existed:
- May 16[#183]fix/widgets
Supabase widget — accept projectRef as config override
Widget showed '—' / +0 / +0 even when status said CONNECTED.
- May 16[#182]feat/ai
canvas diff awareness — surface board changes since last AI turn
The chat AI was reasoning against a stale snapshot of the board: any manual edits, MCP writes, or realtime collaborator changes made between AI turns were invisible.
- May 16[#181]feat/chat
hide plan-style selectors when board already has content
PlanSettingsStrip is plan-intake UI, not chat UI.
- May 16[#180]feat/seo
proper meta + JSON-LD on home and pricing
Home was inheriting the root layout's generic metadata.
- May 16[#179]feat/share
clearer permission UI in the share modal
Two changes to make the share affordances less ambiguous:
- May 16[#178]feat/settings
surface PAYG overflow in CreditPanel — toggle, cap, usage
PAYG overflow was wired up in the backend but never surfaced in the UI.
- May 16[#177]feat/widgets
Plausible Analytics widget (privacy-first)
Follows the Supabase widget pattern from #176:
- May 16[#176]feat/widgets
Supabase widget — live auth user count + new signups
Adds an end-to-end working Supabase widget.
- May 16[#175]feat/settings
credit usage breakdown — 30-day spend by action type
Settings → Billing now has a 'Usage breakdown' section between Credits & Plan and Usage History:
- May 16[#174]feat/cli
align CLI with K2.6 / wandb/fp4 + human-readable error messages
1. CLI's AI engine now matches the in-app stack — kimi-k2.5 swapped for kimi-k2.6 in ALLOWED_MODELS, and fetchOpenRouter injects the same provider:{only:['wandb/fp4'],allow_fallbacks:false} + reaso…
- May 16[#173]chore/ai-proxy
clean up two lint warnings from PR #166 + #172
Trivial cleanup — unused err binding in orchestrator catch (parse-failure path no longer references it) and an unused eslint-disable directive in ThinkStripper.push().
- May 16[#172]perf/ai-proxy
skip orchestrator on simple briefs (~16s faster plan-gen)
The orchestrator runs sequentially for ~16s before the 6 parallel category agents fire.
- May 16[#171]perf/ai-proxy
server-side cap on chat history depth
Cap conversation history at the server: keep ALL system-role messages (summary breadcrumbs) + last 12 non-system messages.
- May 16[#170]perf/ai-proxy
trim BOARD_TOOLS descriptions (~33% smaller)
BOARD_TOOLS schema was 27k chars (~6.8k tokens) shipped on every chat call.
- May 16[#169]perf/ai
compress BOARD STATE in client serializer (~70% smaller)
Drops three pieces of the BOARD STATE block the chat AI sees:
- May 16[#168]
sec: identity guardrails in system prompt + generic 'Hilla AI' badge in chat UI
The AI was happily naming its underlying model, provider, routing layer, and infra (\"I'm Kimi K2.6 via wandb/fp4 on OpenRouter\", \"check the model field in your ai-proxy logs\").
- May 16[#167]fix/ai-proxy
emit ThinkStripper tail BEFORE [DONE] to stop truncation
PR #166 introduced a truncation regression: every K2.6 message lost its last 1-6 chars mid-word.
- May 16[#166]fix/ai-proxy
strip Kimi K2.6 <think> tags from chat stream
K2.6 emits its chain-of-thought as inline \<think>...</think>\ blocks inside the regular content field, ignoring \reasoning:{enabled:false}\ (which only suppresses the structured reasoning field).
- May 15[#165]perf/ai-proxy
chat on K2.6 + context-aware tool injection
1. MODEL_PRIMARY → moonshotai/kimi-k2.6. Chat path moves from Sonnet 4.6 to K2.6 via wandb/fp4 (same pin/no-reasoning routing as plan-gen). Sonnet 4.5 stays as the status-code fallback (404/429/5xx…
- May 15[#164]perf/ai-proxy
trim chat system prompt — 33k → 11k chars
Per-chat input was running 14-16k tokens because BASE_SYSTEM_PROMPT carried 5 verbose few-shot examples (~7k tokens), dominated by a 5k-token \generate_plan\ demo that the chat path never actually…
- May 15[#163]perf/ai-proxy
clarification-question phase on K2.6 too
Chat, board edits, and MCP tool use stay on Sonnet 4.6.
- May 15[#162]perf/ai-proxy
plan-gen on Kimi K2.6 pinned to wandb/fp4
🤖 Generated with Claude Code
- May 15[#161]fix/ai-proxy
Haiku 4.5 for plan generation — Kimi keeps hanging
K2.5 (and K2.6) on OpenRouter's throughput-sort keep landing on hung providers.
- May 15[#160]fix/ai-proxy
plan-gen survives orchestrator timeouts (graceful fallback)
\[ai-proxy] Stream error: TimeoutError: Signal timed out.\ — fired exactly 60s after orchestrator_start.
- May 15[#159]fix/ai-proxy
K2.6 burns budget on reasoning — revert plan models to K2.5
K2.6 on OpenRouter ships with thinking enabled by default.
- May 15[#158]fix/ai-proxy
revert streaming, run all plan models on Kimi K2.6
Two changes in one PR because they ship together:
Build in public
Velocity is the only honest signal. If you want to see how the sausage gets made — the roadmap, the bugs, the perf wins — keep this page bookmarked.
Try it →