Skip to content

BuildNot yet confirmed elsewhere1 publisher3 min readPublished

The chart the model never draws: emit a spec, not a picture

LiveReview's Livi has the LLM write Vega-Lite JSON, then stitches real query results in with Go code, so one definition renders as a browser graph and a flat Slack PNG.

The Engineer · Build desk

How we use AISend a correction

What happened

  • LiveReview built Livi, a chat bot that answers questions about its accumulated code review data with charts rather than paragraphs of hedging.
  • The post says the tempting, wrong idea is to have the LLM generate an image, and that even if you got an image-generating model to draw a bar chart you would have no way to verify the numbers on it are real, because you would be trusting a model that hallucinates plausible-sounding review counts to also render them faithfully.
  • The approach LiveReview uses is that the LLM writes Vega-Lite, a JSON grammar for describing charts declaratively; the post says every serious LLM-charting integration eventually converges on this.
  • The example spec given in the post is: mark "bar", with encoding x = field "month" of type temporal and y = field "review_count" of type quantitative; the post states that is the entire chart.
  • Vega-Lite does the actual drawing, and the LLM's job shrinks to filling in a well-defined schema.

Why it matters

LiveReview has published how its analytics chatbot, Livi, produces charts from review data: the language model writes a Vega-Lite specification, and the company's own Go code inserts the real query results into `data.values` before anything is rendered [1][3][7]. That ordering is the whole design, and it is the part worth copying, because it moves the failure surface from "the picture is wrong" to "the object does not conform".

The alternative the post rejects is having the model produce an image. According to the author, even if you got an image model to draw a bar chart, you would have no way to verify that the numbers on it are real [2]. That is the correct objection. A rendered PNG is an opaque artefact: there is no field to check, no type to reject, no diff against the result set. A Vega-Lite document is the opposite. It is JSON with a grammar, so `mark: bar`, an x encoding on a temporal `month` field, and a y encoding on a quantitative `review_count` field is the entire chart [3][4]. Vega-Lite does the drawing [5].

The consequence is a narrower job for the model. LiveReview's framing is that the LLM is filling in a well-defined schema, and that models are better at choosing between `mark: bar` and `mark: line` than at hallucinating 600 pixels of a correct y-axis [5][6]. The stronger property is the data split: the model writes SQL, LiveReview executes it, and the result set is stitched in by their code, so the model has presentation latitude and no authority over the values [7]. It is also why one definition can serve two renderers, a live interactive graph in the browser and a flat PNG in a Slack thread [8].

The rest of the pipeline exists because the SQL half is where the real risk sits. There are two SQL-writing steps rather than one: the first estimates how many rows the answer has, so the system can decide whether a chart is appropriate or whether the user should get a CSV instead, and the second fetches the data and specifies how to draw it [9]. Nobody wants a bar chart with 4,000 bars [10]. Every generated query goes through a guard that rejects anything not read-only, checks each table against a denylist, and looks for the shape of a tenant-isolation bypass, including constant-versus-constant comparisons and a bare `OR TRUE` [11]. The failure the author names is `org_id = 1 OR 1 = 1` [12]. The model also sees only a narrowed slice of the schema, because there are 58 tables and counting, covering reviews, pull requests, AI comments and review feedback, and dumping all of them into every prompt is both expensive and a good way to confuse the model about which `created_at` belongs to which table [13][14].

One gap in the published account: the excerpt describes validation for the generated SQL, but no equivalent validation step for the generated chart specification [15]. Vega-Lite has a published schema, so that check is available; it is just not described here. If you build this pattern, the guard on the spec is not optional, because a syntactically valid document can still reference a field the result set does not contain.

What to watch: whether the two-step row-count probe survives contact with expensive queries, and whether the SQL guard's denylist approach holds as the table count keeps rising past 58 [9][11][14].

Clarity's read

What the record supports and how the coverage leans. The claims behind it follow.

Reality

Evidence34
Adoption12
Hype gap+18
Incentives74
Confidence38
Why these scores

Claim ledger

Ranked by verification strength, evidence, and original report placement.

  1. [1]

    LiveReview built Livi, a chat bot that answers questions about its accumulated code review data with charts rather than paragraphs of hedging.

    ReportedSupportedSource: LiveReview post on dev.toView cited source
  2. [2]

    The post says the tempting, wrong idea is to have the LLM generate an image, and that even if you got an image-generating model to draw a bar chart you would have no way to verify the numbers on it are real, because you would be trusting a model that hallucinates plausible-sounding review counts to also render them faithfully.

    ReportedSupportedSource: LiveReview post on dev.toView cited source
  3. [3]

    The approach LiveReview uses is that the LLM writes Vega-Lite, a JSON grammar for describing charts declaratively; the post says every serious LLM-charting integration eventually converges on this.

    ReportedSupportedSource: LiveReview post on dev.toView cited source

Sources

1 independent publisher whose own reporting we read for this story.

  1. dev.to

    1 article · August 16, 2026

    How We Got an LLM to Draw Charts Without Ever Touching a Pixel

Share your take

Let Clarity write the post for you.

Signed-in readers get a short post drafted on this story in the register they choose — narrative, analytical, or a direct position — editable to the last word before it goes anywhere. The share buttons at the top of this story work without an account.

Topics and entities

Follow any of these and your For You feed starts watching them — no settings page required.

Topics

  • Schema context selection for promptsFollow
  • Text-to-SQL pipelinesFollow
  • LLM-generated chart specificationsFollow
  • Multi-tenant guardrails for AI data accessFollow
  • AI code review analyticsFollow
Loading related stories