Flint: Microsoft Research's Visualization Language for AI Agents
Asking an AI agent to generate a chart in Vega-Lite tends to produce one of two outcomes: a technically valid specification that looks mediocre, or a verbose JSON blob that renders nothing at all. The problem isn't that the model lacks chart knowledge; it's that Vega-Lite was designed for humans who can reason precisely about pixels, axis domains, and color gradients. LLMs can't.
Flint is a visualization intermediate language from Microsoft Research and Renmin University of China's IDEAS Lab that addresses this by separating what the chart means from how it should be rendered. The AI describes meaning in a concise semantic specification; a deterministic compiler handles all the geometric and aesthetic decisions. The output is a correct, polished chart in Vega-Lite, ECharts, Chart.js, Plotly, or Excel-native format. This article covers the design, how to set it up with Claude Code, and where the current limitations are.
The problem with direct chart generation
A typical Vega-Lite specification for a moderately complex chart can run to 100+ lines of JSON. It requires explicit values for axis domains, scale types, padding, color ramps, label formatting, and dozens of other parameters. These are precise, interdependent geometric decisions. A small error in an axis domain or a misplaced bracket breaks the entire spec.
LLMs are probabilistic token predictors. They're well-suited for semantic understanding and pattern recognition, but not for the kind of exact interdependent arithmetic that low-level chart specifications require. This is why AI chart generation success rates hover around 80%, which sounds reasonable until you realize that one in five charts failing is unusable for any real workflow.
The deeper issue is that chart generation is actually two jobs conflated into one:
The meaning job: Looking at a table with columns for Month, Revenue, and Percentage Change and understanding what each column represents. LLMs do this well.
The math job: Translating that understanding into exact axis scales, color palettes, tick formats, and padding. LLMs do this poorly.
Flint separates them.
How Flint works
Step 1: The LLM writes a short Flint spec
Instead of generating a full Vega-Lite specification, the model produces a concise Flint spec, typically around 10 lines of JSON. The spec has two main parts:
semantic_types: The model analyzes the data and assigns a semantic type to each relevant column. Flint ships with over 70 built-in types including QUARTER, PRICE, RANK, PERCENTAGE_CHANGE, PROFIT, YEAR_MONTH, and many others.
chart_spec: The high-level structure of the chart: chartType (e.g., Heatmap, Bar), encodings (which fields map to x, y, and color), and general chartProperties like desired colorScheme.
There are no pixels, no axis domains, no color hex codes. The model's job ends when it has described what the chart means, not how to render it.
Step 2: The Flint compiler generates the full spec
The compiler is a deterministic piece of software that reads the semantic description and makes all the low-level decisions based on data visualization best practices.
When it sees PERCENTAGE_CHANGE, it knows to use a diverging color palette centered on zero with red for negative and blue for positive values. When it sees a PROFIT column, it calculates a sensible axis scale with clean tick marks. When it sees Heatmap, it generates the correct rect marks and encodings.
The output is a complete, correct specification for whichever rendering backend you're using.
Setting up Flint with Claude Code
Flint is a TypeScript library. The MCP server (flint-chart-mcp) makes it available to any agent that supports MCP, including Claude Code.
In your project directory, add Flint as an MCP tool:
This creates a configuration file in your project that makes the render_chart and create_chart_view tools available whenever you're working in that directory.
Place your data file (in this example, signup_data.csv with columns for month, game, and new_users) in the same directory. Then prompt the agent:
The agent identifies the file, generates a ~10-line Flint spec with appropriate semantic types and encodings, calls render_chart, and returns a PNG image directly in the chat.
To make the chart interactive, follow up with:
This opens an interactive panel where you can change the color scheme, adjust sorting, and inspect individual data points by hovering. The agent does the initial work; you handle the fine-tuning.
The semantic layer in action
The real power of the semantic layer is visible when you change a single type annotation. Suppose new_users is actually a month-over-month percentage change rather than an absolute count.
With semantic type Quantity, the compiler produces a sequential color scale (light to dark blue) starting from the data minimum, which is correct for an absolute count.
Change the semantic type to PercentageChange and the compiler makes a completely different set of decisions: it switches to a diverging color scheme (red-white-blue), centers the midpoint on zero, and formats labels and tooltips with a % symbol. The entire visual logic of the chart changes from one word in the spec.
This is the core value of the semantic layer: the model doesn't need to know how to implement a diverging color scale. It only needs to know that the data is a percentage change. The compiler handles the rest.
Flint vs. Vega-Lite
Flint doesn't replace Vega-Lite. It compiles to it. The relationship is similar to a high-level programming language compiling to assembly: Vega-Lite is powerful and explicit but verbose and brittle for machine generation. Flint is concise, focused on intent, and relies on the compiler to handle the details that LLMs should never have been trusted to improvise.
Current limitations
Flint is a Microsoft Research project published in July 2026 and is still in early development.
The chart type coverage is solid for common visualizations but doesn't yet include maps, 3D charts, network graphs, or complex chart layering. Accessibility features are on the roadmap but not yet implemented. The core library is TypeScript/JavaScript only, though a Python port (flint-py) is in preview in the repository and a PyPI package is expected. The compiler also doesn't yet handle all edge cases around high-cardinality data or highly customized layouts that require manual parameter overrides.
That said, the project is already being used internally at Microsoft in their Data Formulator analytics tool, and the pattern it introduces, using a semantic intermediate representation as the contract between LLM and deterministic compiler, is a generalizable approach that's likely to show up across other AI tooling categories as well.
The GitHub repository includes the core flint-chart library, the flint-chart-mcp server, an interactive gallery, and documentation for both the agent workflow and direct library usage. The Microsoft Research blog post covers the design rationale in more depth.