AI charting agents for developers.

Turn messy prompts into trustworthy data stories.

Skip months of prompt tuning and chart infrastructure. Graphy’s specialised agents validate, refine and orchestrate every step from prompt to production-ready chart.

Skip months of prompt tuning and chart infrastructure. Graphy’s specialised agents validate, refine and orchestrate every step from prompt to production-ready chart.

# install the sdk
npm i @graphysdk/agents-sdk
# then, in your code
await ai.generateGraph({ config, userPrompt })
# install the sdk
npm i @graphysdk/agents-sdk
# then, in your code
await ai.generateGraph({ config, userPrompt })

Free for non-commercial use. Contact us for commercial licensing.

Six agents designed for data storytelling.

Graphy's purpose-built agents work together to Extract, Suggest, Mutate, Generate, Annotate and Narrate, transforming messy data and natural-language prompts into production-ready charts. Arithmetic and validation run in Graphy’s deterministic engine; models handle only the judgement calls.

Agents as one animationthe chart is a mount slot · GraphyAgents.registerChart(state, fn)
Speed
Playback

transactions.csv1,247 rows
chart types suggestedline wins
transactions.csvone bar per transaction
grouped by month, amount summed13 monthly totals

Choose specific agents for the task at hand.

Use the full workflow or call only the agents your product needs.

Use case 1 of 3

Export data to chart

A PDF lands in your inbox with the numbers buried in it. Four agents turn it into something you can read.

ExtractSuggestMutateGenerateAnnotateNarrate
Use case 1 of 3

Export data to chart

A PDF lands in your inbox with the numbers buried in it. Four agents turn it into something you can read.

ExtractSuggestMutateGenerateAnnotateNarrate
Turn the support review into a chartsupport-review-q2.pdf
Pulled the table out of the documentextractFromProse()
980 ticket rows, schema inferred from the page
Scored three ways of showing itgenerateSuggestions()
column, donut, stacked — column wins: the finding is one category against five
Built the chartgenerateGraph()
validated and themed before it rendered
Titled itgenerateNarrative()
states the finding rather than describing the axes

Billing generates more tickets than every other category combined.

BillingSignupAPILatencyBugsOther0200400600512141118967439
Use case 2 of 3

Clean a messy export

980 raw rows nobody can read. One agent reshapes them into the six that answer the question.

ExtractSuggestMutateGenerateAnnotateNarrate
Group these by category and total themtickets.csv
Read the exportextractFromProse()
980 rows, 4 columns, types inferred
Grouped by category and summedgenerateMutation()
the maths runs in the engine — the model never returns a number
Data diff
980 rows → 6 rows after grouping by category
COLUMNBEFOREAFTER
ticketstringdropped
categorystringdim.
openeddatedropped
resolvednumbersum
categoryticketssharemedian
Billing51252%41m
Signup14114%18m
API11812%63m
Latency9610%55m
Bugs748%96m
Other394%22m
Use case 3 of 3

Explain a chart you already have

The chart exists. What it is missing is the mark that points at what changed — and the sentence that says why it matters.

ExtractSuggestMutateGenerateAnnotateNarrate
Mark what changed and give it a titleweekly-active-users · 12 weeks
Called out the release weekgenerateAnnotations()
a comment pinned to the observation, not a floating label
Wrote the titlegenerateNarrative()
states what changed rather than describing the axes

Weekly active users stepped up after the W7 release.

W1W2W3W4W5W6W7W8W9W10W11W1201k2k3k
Use case 1 of 3

Export data to chart

A PDF lands in your inbox with the numbers buried in it. Four agents turn it into something you can read.

ExtractSuggestMutateGenerateAnnotateNarrate
Use case 1 of 3

Export data to chart

A PDF lands in your inbox with the numbers buried in it. Four agents turn it into something you can read.

ExtractSuggestMutateGenerateAnnotateNarrate
Turn the support review into a chartsupport-review-q2.pdf
Pulled the table out of the documentextractFromProse()
980 ticket rows, schema inferred from the page
Scored three ways of showing itgenerateSuggestions()
column, donut, stacked — column wins: the finding is one category against five
Built the chartgenerateGraph()
validated and themed before it rendered
Titled itgenerateNarrative()
states the finding rather than describing the axes

Billing generates more tickets than every other category combined.

BillingSignupAPILatencyBugsOther0200400600512141118967439
Use case 2 of 3

Clean a messy export

980 raw rows nobody can read. One agent reshapes them into the six that answer the question.

ExtractSuggestMutateGenerateAnnotateNarrate
Group these by category and total themtickets.csv
Read the exportextractFromProse()
980 rows, 4 columns, types inferred
Grouped by category and summedgenerateMutation()
the maths runs in the engine — the model never returns a number
Data diff
980 rows → 6 rows after grouping by category
COLUMNBEFOREAFTER
ticketstringdropped
categorystringdim.
openeddatedropped
resolvednumbersum
categoryticketssharemedian
Billing51252%41m
Signup14114%18m
API11812%63m
Latency9610%55m
Bugs748%96m
Other394%22m
Use case 3 of 3

Explain a chart you already have

The chart exists. What it is missing is the mark that points at what changed — and the sentence that says why it matters.

ExtractSuggestMutateGenerateAnnotateNarrate
Mark what changed and give it a titleweekly-active-users · 12 weeks
Called out the release weekgenerateAnnotations()
a comment pinned to the observation, not a floating label
Wrote the titlegenerateNarrative()
states what changed rather than describing the axes

Weekly active users stepped up after the W7 release.

W1W2W3W4W5W6W7W8W9W10W11W1201k2k3k
Use case 1 of 3

Export data to chart

A PDF lands in your inbox with the numbers buried in it. Four agents turn it into something you can read.

ExtractSuggestMutateGenerateAnnotateNarrate
Use case 1 of 3

Export data to chart

A PDF lands in your inbox with the numbers buried in it. Four agents turn it into something you can read.

ExtractSuggestMutateGenerateAnnotateNarrate
Turn the support review into a chartsupport-review-q2.pdf
Pulled the table out of the documentextractFromProse()
980 ticket rows, schema inferred from the page
Scored three ways of showing itgenerateSuggestions()
column, donut, stacked — column wins: the finding is one category against five
Built the chartgenerateGraph()
validated and themed before it rendered
Titled itgenerateNarrative()
states the finding rather than describing the axes

Billing generates more tickets than every other category combined.

BillingSignupAPILatencyBugsOther0200400600512141118967439
Use case 2 of 3

Clean a messy export

980 raw rows nobody can read. One agent reshapes them into the six that answer the question.

ExtractSuggestMutateGenerateAnnotateNarrate
Group these by category and total themtickets.csv
Read the exportextractFromProse()
980 rows, 4 columns, types inferred
Grouped by category and summedgenerateMutation()
the maths runs in the engine — the model never returns a number
Data diff
980 rows → 6 rows after grouping by category
COLUMNBEFOREAFTER
ticketstringdropped
categorystringdim.
openeddatedropped
resolvednumbersum
categoryticketssharemedian
Billing51252%41m
Signup14114%18m
API11812%63m
Latency9610%55m
Bugs748%96m
Other394%22m
Use case 3 of 3

Explain a chart you already have

The chart exists. What it is missing is the mark that points at what changed — and the sentence that says why it matters.

ExtractSuggestMutateGenerateAnnotateNarrate
Mark what changed and give it a titleweekly-active-users · 12 weeks
Called out the release weekgenerateAnnotations()
a comment pinned to the observation, not a floating label
Wrote the titlegenerateNarrative()
states what changed rather than describing the axes

Weekly active users stepped up after the W7 release.

W1W2W3W4W5W6W7W8W9W10W11W1201k2k3k
Use case 1 of 3

Export data to chart

A PDF lands in your inbox with the numbers buried in it. Four agents turn it into something you can read.

ExtractSuggestMutateGenerateAnnotateNarrate
Use case 1 of 3

Export data to chart

A PDF lands in your inbox with the numbers buried in it. Four agents turn it into something you can read.

ExtractSuggestMutateGenerateAnnotateNarrate
Turn the support review into a chartsupport-review-q2.pdf
Pulled the table out of the documentextractFromProse()
980 ticket rows, schema inferred from the page
Scored three ways of showing itgenerateSuggestions()
column, donut, stacked — column wins: the finding is one category against five
Built the chartgenerateGraph()
validated and themed before it rendered
Titled itgenerateNarrative()
states the finding rather than describing the axes

Billing generates more tickets than every other category combined.

BillingSignupAPILatencyBugsOther0200400600512141118967439
Use case 2 of 3

Clean a messy export

980 raw rows nobody can read. One agent reshapes them into the six that answer the question.

ExtractSuggestMutateGenerateAnnotateNarrate
Group these by category and total themtickets.csv
Read the exportextractFromProse()
980 rows, 4 columns, types inferred
Grouped by category and summedgenerateMutation()
the maths runs in the engine — the model never returns a number
Data diff
980 rows → 6 rows after grouping by category
COLUMNBEFOREAFTER
ticketstringdropped
categorystringdim.
openeddatedropped
resolvednumbersum
categoryticketssharemedian
Billing51252%41m
Signup14114%18m
API11812%63m
Latency9610%55m
Bugs748%96m
Other394%22m
Use case 3 of 3

Explain a chart you already have

The chart exists. What it is missing is the mark that points at what changed — and the sentence that says why it matters.

ExtractSuggestMutateGenerateAnnotateNarrate
Mark what changed and give it a titleweekly-active-users · 12 weeks
Called out the release weekgenerateAnnotations()
a comment pinned to the observation, not a floating label
Wrote the titlegenerateNarrative()
states what changed rather than describing the axes

Weekly active users stepped up after the W7 release.

W1W2W3W4W5W6W7W8W9W10W11W1201k2k3k

why graphy agents

why graphy agents

A single model call has to do six jobs at once; read the file, pick the chart, do the arithmetic, draw it, mark what matters, write the title. It does all six at about sixty per cent each, and you can't tell which one it fluffed.

So we split them up. The arithmetic runs in our engine, where it can't be wrong. The chart type is scored by rules, not guessed. Every spec is validated before it renders. What's left for the model is the part where judgement actually helps.

The numbers below are what that's worth.

A single model call has to do six jobs at once — read the file, pick the chart, do the arithmetic, draw it, mark what matters, write the title. It does all six at about sixty per cent each, and you can't tell which one it fluffed.


So we split them up. The arithmetic runs in our engine, where it can't be wrong. The chart type is scored by rules, not guessed. Every spec is validated before it renders. What's left for the model is the part where judgement actually helps.


The numbers below are what that's worth.

benchmarks

Why Graphy's agents beat a raw model call.

Graphy
GPT-5.5
Opus 4.8
Gemini 3.5
Accuracy pass rate
100%
61%
20%
50%
Run success rate
100%
75%
75%
61%
Median speed
11s
37s
5s
42s
Median cost
$0.20
$2.54
$8.85
$0.25
Benchmarked May 2026. We tested Graphy’s mutate-only agent against direct LLM calls (GPT-5.5, Claude Opus 4.8, Gemini 3.5 Flash) on 24 fixed table tasks: 6 operations (sum, count, mean, max, pivot, unpivot) across 4 file sizes (~100 to ~30k rows), each on 3 seeds. Outputs are checked in code against precomputed ground truth (columns, row count, values within tolerance). Pass means 100% correct. No partial credit, no human judges.

Four things we don't let the model decide.

The math

Aggregations run in the engine. The model never returns a number.

The math

Aggregations run in the engine. The model never returns a number.

The math

Aggregations run in the engine. The model never returns a number.

The math

Aggregations run in the engine. The model never returns a number.

The chart type

evaluate() scores every type against your data. Rule-based, no model, zero tokens.

The chart type

evaluate() scores every type against your data. Rule-based, no model, zero tokens.

Your raw rows

The agents work from a schema summary. Your records don't go to the model.

Your raw rows

The agents work from a schema summary. Your records don't go to the model.

Whether it ships

Validated against the schema, and retried on failure before it renders.

Whether it ships

Validated against the schema, and retried on failure before it renders.

Whether it ships

Validated against the schema, and retried on failure before it renders.

Whether it ships

Validated against the schema, and retried on failure before it renders.

FAQ

Questions, answered.

What are Graphy Agents?

Graphy Agents are six purpose-built agents—Extract, Suggest, Mutate, Generate, Annotate and Narrate—that turn messy data and natural-language prompts into production-ready charts.

How are they different from a direct LLM call?

Graphy separates the work into specialist steps. Arithmetic, chart selection and validation run in a deterministic engine, while models handle the judgement calls where they help.

Does my raw data go to the model?

No. The agents work from a schema summary rather than your raw records. Aggregations run in Graphy’s engine.

Can I use only the agents I need?

Yes. Use the complete workflow or call individual agents for extraction, chart suggestions, data mutation, chart generation, annotation or narrative.

How do I get started?

Install the SDK or add Graphy’s skills to your coding agent, then follow the docs to render your first chart. You can try Graphy free before arranging production access.

GET STARTED

Set up Graphy Agents in your project

Get your first AI-generated chart modification working in 5 minutes.

2026 Graphy Technologies Ltd. All rights reserved.

2026 Graphy Technologies Ltd. All rights reserved.

2026 Graphy Technologies Ltd. All rights reserved.

2026 Graphy Technologies Ltd. All rights reserved.