Dashboards from a sentence, in 3 minutes
Agent tooling that rebuilds a Tableau view from live SQL, on the mined estate
The mining project put every workbook's structure into the knowledge base. This is one of the things that unlocks: an agent that rebuilds a dashboard view from live SQL and hands back a link, instead of hand-typing HTML into a reply and inventing the numbers.
- 4 days → 3 min
- Median time to a working view
- 10k → 300
- Model output tokens per rendered view
- 3,000+
- Mined workbooks the tooling can build from
- 15
- Features scoped with named owners
Context
The point of the first project was getting every workbook’s structure into the knowledge base. Not screenshots and not prose about the dashboards, but the shelves, the filters, the parameters with their allowable values, the color encodings, the display format strings, and the warehouse table each view actually reads.
Once that existed, the useful question was what an agent could do with it that it could not do before. Rebuilding a view is one answer. It is not the only one, and it was never the reason the mining project existed. It is the answer that proves the rest: if the agent can reconstruct a dashboard from what was mined, then what was mined is complete enough to answer almost anything else about it.
The problem
The first attempt failed instructively. Asked to recreate a heatmap, the agent did the obvious thing and wrote the HTML and CSS into its reply. That cost about 10,000 output tokens, took minutes, hit the response cap partway through the table, and, because nobody can hand-type five hundred cells, it invented the numbers. One run spent sixteen minutes and timed out.
Every part of that is bad, but only one part is dangerous. A truncated page is visibly broken and gets thrown away. A complete page with plausible wrong numbers gets used.
A dashboard request is also underspecified by nature. “Power utilization by site for last quarter” does not say which utilization definition is meant, which table is authoritative, or what level of detail the view aggregates to. So the answer could not be text-to-SQL either.
Why three minutes is a different thing from four days
Capacity questions arrive faster than a BI team can build views for them. At four days per dashboard the planner either waits past the decision or decides without the view, and the second happens more often. That is the actual cost, and it is not the four days. It is the commitments made on a worse picture because the better picture was not ready in time. In a supply chain placing multi-month orders against a forecast, that difference compounds.
Three minutes changes the category of the artifact. A view stops being something you request and revisit next week and becomes something produced during the conversation. Questions nobody would have opened a four-day ticket for start getting asked, which is where most of the value showed up.
The bigger structural win is who is in the loop. A dashboard used to require a BI engineer for the whole build, which made every request compete for one scarce, expensive queue. Now the planner who has the question writes the prompt, and the BI engineer is needed for the cases that are genuinely hard rather than for the routine ninety percent. That is a better use of the BI engineer, not a smaller need for one.
Speed on its own would not have been enough. A number is only usable in a planning review if someone can say where it came from, so every cell tracing to a real warehouse row matters more than the three minutes does.
What I built
The surface this plugs into. The renderer is one tool on an agent that already had the pieces that make a question answerable: retrieval over the curated knowledge base, cross-account query access to Redshift and Athena, table description and per-column statistics so a table can be sized before it is hit, and date resolution so “last quarter” becomes a real range against the planning calendar. Requests also arrive with the miner’s fleet-importance ranking already injected, before the model runs, so retrieval prefers the dashboards that actually get opened.
What was missing was any route to the mined structure, and any way to produce a rendered view without the model typing it. Those are the two gaps I built into.
Four tools over the mined estate
Resolve the name. The mining run publishes a fleet ranking with one row per workbook on the server, including the fields that reconstruct where its mined documents live. That makes it the only complete name-to-location map either side of the pipeline publishes, and it is regenerated by the same run that mines the content, so the two cannot drift apart. A dashboard somebody names in a sentence becomes an exact key.
Fetch the build spec, not prose about it. Every parameter with its datatype, current value, and allowable values, which is the domain a rebuilt control has to offer and which no other source states. Every filter on the view, per worksheet, with its type and its current values. The warehouse tables behind it, with engine and host, so the query can be written and the table can be sized before it is hit.
Fetch the facts retrieval structurally cannot reach. This is the part that justifies tools over search at all. The knowledge base indexes the curated corpus only, so the agent’s own retrieval tool never sees a mined document, and the curator does not carry the miner’s freshness block across. When a dashboard’s content was last revised, when its extract last refreshed, how often each view is opened: mined, correct, and invisible to search. Those get fetched by exact key instead of hoped for from a query.
Read the view itself. With the key resolved, the mined document for that specific view comes back by direct fetch, and it names the visualization type, the row and column shelves, the color and text encodings, and the filters. The mined worksheet image can come back too, which means the original is available to compare against rather than described from memory. This is the step that makes the render call possible, and it only exists because the mining project captured shelves and encodings rather than a screenshot and a paragraph.
The renderer, which is where the actual fix is
The model no longer writes the page. It produces one query, plus a mapping of which result column plays which role: row labels, column headers, the value in each cell, optionally a status. The tool runs the query, pivots the result, builds the grid and its interaction in code, uploads the page, and returns a link. Output cost falls from ten thousand tokens to a few hundred, and every cell traces to a real row because no cell was ever typed.
The invariants are the interesting part
- Any result column the model does not map to a role becomes a dropdown filter on the page, which is exactly how a Tableau filter shelf behaves. The mined spec already lists the view’s filter dimensions, so the model includes them as plain columns and the filtering is free.
- The workbook’s own format string and its own hex colors pass straight through from the mined documents. That removes the two guesses that get a recreation wrong: whether to rescale the units, and how many decimals to show.
- Rendering is refused unless every cell accounts for exactly one row. The model adds a
count to its own
GROUP BYand passes that column; if any cell counts more than one, the tool will not render. This exists because it happened. Several measures were being summed into a single cell and inflated a grid about sevenfold, and it looked completely fine. A wrong number that renders beautifully is the failure worth engineering against, and a count is a cheap way to make it impossible. - The SQL goes through the same query tools a direct question uses, so the existing preflight hook validates it identically. There is no second validation path to drift out of sync. The same applies to the per-tool call caps and the timeout backstop: a render is subject to the limits every other tool is.
- The query has to pin a snapshot date. These tables hold many snapshots of the same grid, so a query without a date predicate both scans far more than it needs to and silently mixes snapshots into one cell. The date-resolution tools exist so the model can look the real snapshot up instead of guessing at one.
- Grids past four hundred rows or a hundred and twenty columns are rejected with a reason, because a grid that size means the query was not aggregated to the view’s level of detail. Cheaper to say so than to render a forty-megabyte page.
Color is never allowed to carry meaning alone. Status red and green sit only about four ΔE apart under deuteranopia, so every cell also shows its value, a shape glyph, and an optional texture, and the legend pairs swatch with glyph with label.
What comes out is a draft. A person opens it, checks it, and decides whether it becomes anything. That was a deliberate limit rather than a missing feature: the tool is allowed to be wrong as long as being wrong stays cheap and visible.
To decide what to build I analyzed legacy dashboard usage in Redshift and worked the findings through with planning, infra and BI stakeholders. That produced 15 high-value features with named owners, which is why the tooling targeted the requests people actually made.
The hard part
Deciding what the model should not do. The instinct with a capable model is to let it produce the artifact. Every gain here came from taking the artifact away from it and leaving it only the part it is good at: reading a mined spec and writing one correct query. The model chooses, the code constructs, and anything that could be made deterministic was.
The agent was never the bottleneck. The definitions were. I spent a while tuning the things that look like the problem: how much context to retrieve, how granular each tool should be. All of it helped a little. What moved the output was going back to the mined data and getting the structure right. A generator grounded in a definition inherits that definition, mistakes included. Two views disagreeing about what “utilization” means is not an agent problem. It is a data problem, and you cannot fix it from downstream with a better prompt.
Outcome
Four days down to a median of about three minutes, and a view whose every cell traces to a row in the warehouse.
The part I would argue matters more: rebuilding a dashboard is one capability out of a set, not a feature that had to be built specially. Mined structure is composable. Freshness, ownership, usage, lineage, parameter domains, exact colors, all reachable by key, and “recreate this view” becomes one thing to ask of them. That is the argument for mining structure instead of screenshots, and it is the argument the first project was really making.
Where it goes next
Today the tooling rebuilds views that already exist, which is the version that could be checked against a known-correct original. Generating a genuinely new dashboard is the same path pointed at a different query: the model already writes arbitrary SQL and maps result columns onto roles, so nothing about the machinery has to change. What has to be earned is trust, and the honest way to earn it was to be provably right about dashboards someone could verify first.
What I’d do differently
Version the generated specs from the start, and treat every output as a draft carrying its provenance. The first two questions anyone asked were “what changed?” and “why that table?”, both far easier to answer if you design for them up front.