flow.js

Inspiration

Personalized, self-optimizing software is normally something only enterprises can afford — a dedicated UX research team watching how people use a product and iterating the interface accordingly. We wanted every developer, not just enterprise budgets, to get that: an agent that behaves like an embedded product team, generating and continuously refining an interface from nothing but the backend capabilities a developer already has.

What it does

flow.js is an adaptive interface runtime. A developer registers what their app can do — data fetchers, actions, shared state, semantic descriptions, and a theme — not a layout. From that, flow.js:

  • Generates an initial dashboard with GPT-5.5, using structured, schema-validated output instead of raw HTML/JSX.
  • Instruments every generated component, capturing real interactions (hovers, focus, clicks, dead ends) alongside Sentry-traced backend latency for the same call.
  • Diagnoses friction, distinguishing "this control is buried" or "these related controls are split apart" from "the backend call is just slow" — so a slow PDF export doesn't get blamed on the UI.
  • Proposes and validates mutations (move, reorder, resize, swap variant, show/hide), rejecting anything that would hide the only control for a required capability, then scores each proposal on benefit, confidence, and evidence against a stable↔experimental threshold you control.
  • Applies changes live, animating the transition, and keeps every version immutable with full history and one-click undo.

Beyond a single user, flow.js also rolls up usage across everyone overnight (via Tiger Data/Timescale continuous aggregates) into one shared next baseline layout — gated behind minimum-evidence thresholds so a quiet day can't force a bad redesign — while each person's personal layout rebases onto that baseline without losing their own preferences.

How we built it

A Next.js/TypeScript monorepo: a framework-agnostic core runtime (capability graph, schema validation, mutation scoring, versioning), a Next.js demo app, and a separate analytics service. GPT-5.5 is called through OpenAI's Responses API with Zod-structured outputs for both generation and optimization reasoning, with a recorded-response fallback so demos survive bad Wi-Fi. Node 24's built-in SQLite stores immutable UI versions (enforced by triggers, not convention). Motion drives the runtime layout animations. Sentry instruments every generated component: tracing wraps each data/action call so we can pair the server-measured latency with a real trace id, and Session Replay attaches a replay id to every telemetry event — together they're what let us tell "the UI is confusing" apart from "the backend is slow" instead of guessing from click counts alone. Tiger Data/Timescale (hypertables, continuous aggregates, percentile sketches) powers the cross-user daily baseline pipeline.

Challenges we ran into

  • Trusting an LLM to modify a live UI is dangerous by default — we had to build a validator that independently rejects unsafe mutations (e.g., ones that would hide a user's only path to a required capability), regardless of what the model proposed.
  • Telling apart "people can't find this" from "the backend is slow" required correlating semantic telemetry with Sentry trace latency, not just counting clicks.
  • Designing the shared-vs-personal layout model: continuous ingestion, idempotent delivery, and a daily job that only ever publishes a new baseline once there's real evidence — without ever rearranging a page someone already has open.
  • Making mutations animate as a legible, continuous transition instead of a layout swap.

Accomplishments that we're proud of

We closed the full loop end-to-end, live: capability registration → AI-generated dashboard → real usage telemetry → friction diagnosis → validated, scored mutation → animated, versioned change → undo — running against a live GPT-5.5 model and a live Tiger Cloud/Timescale service, not mocks. We're especially proud of the safety layer: independent mutation validation, evidence-gated scoring, and immutable version history are what make a self-modifying UI feel trustworthy instead of chaotic.

What's next for flow.js

Multi-tenant auth with per-cohort baselines and real A/B experiments, adapters for more backend frameworks beyond our capability-registration API, retention/compression policies for long-running telemetry, and extending personalization beyond internal dashboards to full customer-facing sites — both per-user layouts and aggregate, population-level optimization.

Built With

Share this project:

Updates

Submission history