Highlights
- Live reports Built from a chat, current on every view no snapshots, in production
- Sandbox & bridge Hosting HTML the agent wrote, safely host-held credentials, read-only calls
- Design context Shell, tokens and taste for the agent so reports look like they belong
- A pattern that spread The report canvas became the template briefings, routine previews, chat artifacts
Backstory
It started with insights
- Strive AI could already turn a chat into a shareable insight doc: blocks you pick, plus AI summaries.
- It still lives on as
/share-insights. But reports wanted more: live data, big volumes, and a story you get in one scan.
Visibility vs. ad spendSend to Slack
The bet
Let the model write HTML
- Every new report layout meant another schema and another UI tool. Some reports can’t be written as JSON at all.
- So for reports we dropped schemas, and let the agent write what it knows best.
Strive chat
tool call → our renderer
one HTML file → a sandboxed canvas
Design call · naming
Two ways to share, one product
- We couldn’t drop insights. Snapshots with AI summaries, on a schedule, and customers liked them.
- So I named the two apart, and gave reports a studio and a home of their own.
/share-insights · insight doc
- A snapshot of one moment in a chat
- The chat’s blocks, plus AI summaries
- Re-run on a schedule for a fresh copy
&
Report Studio · live reportlive
- A dashboard on your connected data
- Agent-written HTML, laid out your way
- Its own Reports page, linked to chat
Security
Untrusted HTML, trusted data
- The report runs in a sandboxed iframe: no cookies, no storage, no direct line to our API.
- It asks the host for data. The host checks every message, holds the credentials, and only runs read-only calls.
- Report · sandbox the HTML the agent wrote
- Host · Strive app holds the session
- Your data ads, analytics, CRM, warehouse
- Report → Host 1query(…) · id 7 asks, holding no keys
- Host 2Three checks source · origin · shape
- Host → Your data 3call as the user host picks the credential · read-only
- Your data → Host 4rows
- Host → Report 5result · id 7 only the answer to its own question
Design context
From a stylesheet to a little taste
- I first wrote 650 lines of CSS for the agent to learn. It didn’t scale, and fought the point of dropping schemas.
- Now it’s a little taste plus Tailwind, which models already write fluently, and brand context pulled in at onboarding.
Scale
Live, not heavy
- Loading every row on page load froze the tab on big accounts.
- Now reports load what you see first, and query the rest on demand, paginated on both ends.
Before · everything at once
- Every row fetched on page load
- The tab stalls on big accounts
- Heavy pages break
vs
Now · progressive loadinglazy
- What you see loads first
- Queries run as you scroll or switch tabs
- Paginated on client and server
Shipping it
Build apart, then fold in
- v1 was its own chat, to keep report rules out of the main prompt and experiment undisturbed. The price: a separate history.
- v2 made it a skill in the main chat, with the report in a canvas beside the thread. One chat, one history.
v1 · its own chat
- Report rules kept out of the main prompt
- Free to experiment without touching core chat
- Trade-off: a separate agent and history
v2 · a skill in the main chat
- A skill the main chat picks up when the intent is a report
- The report opens in a canvas beside the thread
- One chat, one history
Design call · canvas
Loud canvas, quiet controls
- Sync you can see. Chat and sandbox stay in step, and every stage says what’s happening: written to the sandbox, rendering, or why it’s slow. The canvas paints smoothly, with no flicker on a rewrite.
- Controls that don’t overwhelm. A resize handle with a generous hit area, and sensible default and max widths. Distinct icons for the main actions, with split buttons tucking secondary ones like export away. Lovable’s clean side panel was the bar.
1
2
3
4
- Every stage, said out loud. Reading the data, validating queries, writing, then live.
- A handle you can’t miss. A generous hit area, a sensible default and a max width.
- Code or preview. One toggle, never a new screen.
- Distinct icons for the main moves. Open in Reports, full screen, collapse the panel.
Misses & lessons
What the first reports taught us
-
MissWrote 650 lines of CSS for the agent to learn.
LessonGive it taste, not a stylesheet. Extend what models already write, like Tailwind.
-
MissLoaded every row on page load. Big accounts froze the tab.
LessonLive should never mean heavy. Load what’s on screen, fetch the rest on demand.
-
MissEarly reports looked vibe-coded: four KPI cards in a row.
LessonBrand context and emphasis rules make a report look like yours.
-
MissExported multi-page reports in one go.
LessonSnapshot page by page, and put a hard cap on the size.
A dashboard shows you numbers someone else chose. This builds the report you asked for, and keeps it alive.
Deep dive · ~10 min read
Building live reports inside Strive: the story of Strive Studio
The backstory, the naming call, the bet on HTML, and everything that broke at scale.
Read the full story