You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add Julia as anyplot's third language, with Makie.jl (CairoMakie backend for headless PNG rendering) as its first library entry. This is Phase 5 of docs/concepts/library-expansion.md — the second non-Python runtime — and it should reuse and generalize every piece of plumbing we built for R/ggplot2 in #6944 + the follow-ups #6947 / #6961 / #7066.
This is a meta / infrastructure issue, not a spec request. Do not apply the spec-request label — there is no plot type to draft. The work follows the feat(ggplot2): add R/ggplot2 library + multi-language pipeline shape, not the spec-create.yml flow.
Phase 1+2 (JavaScript / Chart.js / D3 / ECharts / Highcharts-JS) is still listed as planned in docs/concepts/library-expansion.md. Adding Julia before JS skips a phase on the roadmap — call this out in the PR description but ship anyway: the multi-language pipeline is already proven on R, and the value of a second non-Python runtime is mostly validating (not blocking) the JS work.
Why Makie.jl
Per docs/concepts/library-expansion.md §5:
| Julia | Makie.jl | ~45 % | Phase 5. Distinct scientific stack; not a wrapper. |
| Julia | Plots.jl | ~40 % | Alternative; pick Makie unless visitor data flips. |
CairoMakie is the right backend for CI — pure-Cairo, headless, no GPU, no GLFW window. PNG/SVG/PDF out of the box. (GLMakie / WGLMakie are interactive backends that we don't need for static gallery rendering.)
Distinct scientific stack — not a thin wrapper around plotly.js or Vega — so it earns its own entry under the "most-used variant" rule in §6.
License: MIT.
Excluded by the rule: Plots.jl is the alternative; we ship Makie unless Plausible data later shows the audience flips. PlotlyJS.jl is a wrapper around plotly.js (already covered via Python Plotly entry).
Reference: how R/ggplot2 was integrated
The relevant PR chain — read these before starting to understand the surface area and the bugs that surfaced after merge:
The big bang. Library + language registry, R runtime in CI, all five workflows made language-aware, frontend syntax-highlighting, tests. 45 files, +1110 / -179.
fix(frontend+api): wire R/ggplot2 into code viewer, libraries page, languages count
get_impl_code accepts ?language=, LIBRARIES array, LIB_ABBREV, languages count in stats, language-aware cache keys. The "always-going-to-need-a-follow-up" PR.
Goal for Julia: roll all four PRs' lessons into one PR (or one PR + one tiny follow-up). Specifically: every if language == "python" / "r" branch must become a generic python | r | julia dispatch, every hardcoded 9 / 10 library count must already use LIBRARIES.length / len(SUPPORTED_LIBRARIES), and the DebugPage / LIB_TO_LANG / ?language= plumbing must be exercised end-to-end before the PR is opened.
Scope
1. Library + language registry (core/constants.py)
LANGUAGES_METADATA: append the Julia entry. Suggested values:
{
"id": "julia",
"name": "Julia",
"file_extension": ".jl",
"runtime_version": "1.11", # confirm against the version we install in CI"documentation_url": "https://julialang.org",
"description": "High-level, high-performance dynamic language for technical computing. Combines the productivity of Python/R with the speed of compiled languages; popular in scientific computing, numerical analysis, and machine learning research.",
},
SUPPORTED_LIBRARIES: add "makie" (alpha-sorted, between letsplot and matplotlib).
LIBRARIES_METADATA: append the Makie entry. Suggested values (verify on first CI run):
{
"id": "makie",
"name": "Makie.jl",
"language_id": "julia",
"version": "0.22", # pin to whatever the Project.toml resolves to"documentation_url": "https://docs.makie.org",
"description": "High-performance, extensible visualization ecosystem for Julia. CairoMakie renders publication-quality static PNG/SVG/PDF; GLMakie/WGLMakie handle interactive use. anyplot uses CairoMakie for the static gallery.",
},
INTERACTIVE_LIBRARIES: leave makie out. CairoMakie produces PNG only — same model as matplotlib / seaborn / plotnine / ggplot2. (GLMakie / WGLMakie are out of scope: they need a display server or a JS runtime.)
2. Julia runtime in CI
New composite action .github/actions/setup-julia/action.yml — mirror of .github/actions/setup-r/action.yml. Steps:
Same reproducibility model as renv.lock: the Manifest.toml is the lockfile; commit both. Document the snapshot expectations in a # Notes / open follow-ups section of the PR description (renv.lock had the same caveat).
System deps: Cairo is bundled in Cairo_jll so apt should not be needed, but mirror the apt fallback from setup-r for libfreetype6-dev / libfontconfig1-dev / libpng-dev to be safe against future runner-image changes.
3. Workflows (extension- and language-aware)
For every file below, the R/ggplot2 PR introduced a case "$LIBRARY" in ggplot2) LANGUAGE=r; EXT=.R ;; *) LANGUAGE=python; EXT=.py ;; esac step. Refactor that into a single shared shell function or a tiny Python helper sourced by all workflows, so adding the next language is a one-line table edit. At minimum, every existing case must grow a makie) LANGUAGE=julia; EXT=.jl ;; arm. Files to update:
.github/workflows/impl-generate.yml — add makie to the librarychoices; add Julia setup step (conditional on language == "julia"); add Julia version detection (julia -e 'print(VERSION)'); add Julia package-version detection for Makie (julia --project=. -e 'using Pkg; println(Pkg.project().dependencies["Makie"].version)' or equivalent).
.github/workflows/impl-repair.yml — same derive-lang step; conditional Julia setup; conditional Python plotting deps suppression for julia branch.
.github/workflows/impl-review.yml — extend the per-library canvas/dpi hint dictionary with a Makie entry (CairoMakie uses save(path, fig; px_per_unit=2) or resolution on Figure); make the header-rewrite step's prepend fallback (added in chore(ggplot2): follow-up Copilot review fixes after #6944 merge #6947) work for .jl files using # comments.
.github/workflows/impl-merge.yml — branch-name parser already derives LANGUAGE + EXT from LIBRARY; just add the makie) arm to the same case statement.
.github/workflows/bulk-generate.yml — add makie to library choices and to ALL_LIBRARIES.
.github/workflows/daily-regen.yml — sanity-check it still works after the matrix grows by one.
4. Prompts
New prompts/library/makie.md — analogous to prompts/library/ggplot2.md. Cover:
File extension .jl, runtime julia (not python).
No workarounds clause (don't shell out to Python / R / matplotlib).
Static PNG only via CairoMakie. NOT_FEASIBLE for primary-interactivity specs.
Theme-adaptive chrome tokens via ENV["ANYPLOT_THEME"] (mirror of the ggplot2 ANYPLOT_THEME switch).
Save canvas: hard rule on output size (mirror of ggplot2 §"Canvas — hard rule, no deviation"). For Makie, save("plot-light.png", fig; px_per_unit=…) plus an explicit Figure(; resolution=(3200, 1800)) (landscape) or (2400, 2400) (square). Pick whichever combo of resolution × px_per_unit lands cleanly on those exact pixel sizes — pre-render gate in impl-review.yml rejects anything off by more than 16 px.
Forbidden patterns (Julia equivalents of the ggplot2 list): no Plots.jl, no shelling out, no display(fig) instead of save(...), no @show, etc.
Header style: # comment block at the top of every .jl file mirroring the Python/R conventions (# Library: Makie.jl 0.22 | Julia 1.11 etc.).
prompts/plot-generator.md — three small edits:
The lead sentence ("Most anyplot libraries are Python … ggplot2 is R") gets extended to mention Makie/Julia.
The "Available environment" block — append the Julia stack alongside Python and R.
The "Forbidden" sections — add a Julia / Makie block mirroring the R / ggplot2 block.
TS-types blocker: the @types/react-syntax-highlighter package didn't declare prism/r and we shipped that gap (see fix(frontend+api): wire R/ggplot2 into code viewer, libraries page, languages count #6961 "Out of scope"). Fix it for Julia in the same PR — either via declare module '…/prism/julia' or by patching the project-local ambient types so we don't carry forward two unresolved TS7016 imports.
components/CodeHighlighter.test.tsx — add a case rendering using CairoMakie under language="julia".
components/LibraryCard.tsx — add a one-line description for makie (mirror of the ggplot2 entry).
components/MastheadRule.tsx — julia: { open: '#=', close: '=#' } is already there. Verify it actually gets used after this change lands.
pages/LibrariesPage.tsx — meta-description string ("Ten plotting libraries across Python and R …") bumps to "Eleven plotting libraries across Python, R, and Julia …".
Tests — every *.test.tsx that hardcoded 9 / 10 or enumerated libraries / languages needs the same bump.
api/routers/specs.py — get_impl_code already accepts ?language= (default "python") since fix(frontend+api): wire R/ggplot2 into code viewer, libraries page, languages count #6961. Don't widen the default to "julia" or change call sites silently — the default-python contract is the BC promise that kept that PR small. Just verify the Julia path works end-to-end.
api/routers/insights.py, api/routers/seo.py, api/mcp/server.py — grep for any hardcoded library/language enumerations and replace with SUPPORTED_LIBRARIES / SUPPORTED_LANGUAGES constant references.
automation/scripts/label_manager.py — after merge, the docs section says to run uv run python -m automation.scripts.label_manager sync once so library:makie, generate:makie, impl:makie:{pending,done,failed} labels appear. Include the same callout in the PR description.
7. Tags / Plausible / SEO
docs/reference/plausible.md — line 305 already lists julia as a future language token (python, future: julia, r, matlab). Promote it from "future" to "current" once this PR lands. No new event types needed: every existing language / library event slot already accepts arbitrary strings.
docs/reference/seo.md §"Adding a New Language" already documents the exact procedure (Library.language = "julia", sitemap auto-picks up /scatter-basic/julia/makie, optional julia.anyplot.ai subdomain). Walk through each step and confirm there's nothing left to wire — and if a julia.anyplot.ai subdomain is on the table, it's a separate small PR (mirror of the python.anyplot.ai nginx block).
docs/reference/tagging-system.md — no schema change needed; tags are language-agnostic. Verify nothing hardcodes "python or r" in narrative text.
8. Tests
tests/unit/core/test_constants.py — TestSupportedLanguages (added in feat(ggplot2): add R/ggplot2 library + multi-language pipeline #6944) gets a Julia assertion. language_id integrity test covers Makie automatically. Bump any explicit length expectations from 10 → 11 libraries and 2 → 3 languages.
tests/unit/api/test_debug.py, test_routers.py, test_stats.py, test_schemas.py — verify all len(SUPPORTED_LIBRARIES) / len(SUPPORTED_LANGUAGES) references still pass without per-library / per-language edits (this is the pattern feat(ggplot2): add R/ggplot2 library + multi-language pipeline #6944 introduced; new tests added since then may have regressed it — fix in place, don't add noqa suppressions).
tests/unit/api/mcp/test_tools.py — same.
Frontend: useCodeFetch.test.ts gains a Julia case (mirror of the ggplot2 case added in fix(frontend+api): wire R/ggplot2 into code viewer, libraries page, languages count #6961 — separate cache keys per language for same library_id, ?language=julia appended for non-python). CodeHighlighter.test.tsx, LibraryCard.test.tsx, ImageCard.test.tsx, DebugPage.test.tsx — Julia row / Julia language string.
9. Documentation
docs/concepts/library-expansion.md — update §1 ("Current state" table grows a Julia row; library count goes from 10 to 11), §8 (Phase 5 status: shipped), §9 (record the decision to ship Makie over Plots.jl). Note the phase-skip vs. the original roadmap (we shipped Julia before JS): one paragraph in §9 explaining why is enough.
docs/reference/repository.md — the plots/{spec}/implementations/ tree gets a julia/ sibling alongside python/ and r/.
docs/reference/style-guide.md — the §3.8 "pipeline story" / "catalogue story" copy ("a thousand examples across ten libraries in two languages") gets bumped to "eleven libraries in three languages". The §1 plot-palette intro ("10 libraries (9 Python + R/ggplot2)") gets bumped similarly.
docs/concepts/vision.md — quick grep for hardcoded counts, update as needed.
agentic/docs/project-guide.md — append a Makie entry to the per-library list (the section that already covers plotnine / lets-plot / ggplot2).
prompts/README.md — library count.
README.md — quick grep for hardcoded library/language counts.
10. Existing R-rollout gaps to not repeat
For each gap the R rollout hit, prove the Julia path doesn't:
Gap (R rollout)
Verify for Julia
/api/specs/scatter-basic/ggplot2/code 404'd because language wasn't piped through (#6961)
Manually curl /api/specs/scatter-basic/makie/code?language=julia after the first Makie impl lands and verify 200.
The Julia branch of the same step uses re.match first, prepends the canonical # header if absent.
@types/react-syntax-highlighter missing prism/r declaration (#6961 "Out of scope")
Don't carry this forward — declare or patch the Julia import in the same PR.
Suggested phasing inside this PR
The R PR landed as a single 45-file commit. That's fine for Julia too, but it's also reasonable to split:
PR A (the big one): constants + workflows + setup-julia action + Project.toml + prompts + tests.
PR B (the frontend wire-up): the changes in §5, gated on PR A having merged so the API actually returns Julia impls.
PR C (cleanup): docs sweep, label sync, GCS bucket structure verification, julia.anyplot.ai subdomain if we want one.
If the team has bandwidth for a single combined PR, prefer that — fewer roundtrips with Copilot review, and the "always-going-to-need-a-follow-up" PR class (#6961) shouldn't be inevitable a second time around.
Acceptance criteria
core/constants.py: SUPPORTED_LANGUAGES = frozenset(["python", "r", "julia"]), SUPPORTED_LIBRARIES contains "makie", both LANGUAGES_METADATA and LIBRARIES_METADATA are extended.
.github/actions/setup-julia/action.yml installs Julia, restores from Project.toml + Manifest.toml, smoke-tests a CairoMakie render.
All five workflows (impl-generate, impl-repair, impl-review, impl-merge, bulk-generate) derive LANGUAGE + EXT from LIBRARY via a shared table, and the table contains a makie → (julia, .jl) row.
prompts/library/makie.md exists and follows the ggplot2-prompt shape (no-workarounds, NOT_FEASIBLE policy, canvas hard rule, ANYPLOT_THEME handling, forbidden patterns, header style).
Frontend renders language="julia" with Julia syntax highlighting and the MastheadRule block-comment tokens (#= … =#) for the masthead are wired up.
gh workflow run impl-generate.yml -f specification_id=scatter-basic -f library=makie produces a passing Julia implementation with plot-light.png + plot-dark.png in GCS.
/scatter-basic/julia/makie loads the code panel (no 404 on /api/specs/scatter-basic/makie/code?language=julia) and the rendered preview, in both light and dark mode.
/debug matrix has a makie column; clicking a Julia cell deep-links to /{spec}/julia/makie, not the python hub.
uv run pytest tests/unit tests/integration is green. Frontend yarn test --run, yarn tsc --noEmit, yarn lint are clean — no @types/react-syntax-highlighter TS7016 carry-forward.
Post-merge: uv run python -m automation.scripts.label_manager sync run once so library:makie, generate:makie, impl:makie:{pending,done,failed} labels exist.
Out of scope (separate issues)
Phase 1+2 (JavaScript family) — Chart.js / D3 / ECharts / Highcharts-JS. Tracked in docs/concepts/library-expansion.md; not blocked by Julia.
Plots.jl as a second Julia library — defer until Plausible data shows Makie traffic and a clear case for a second Julia entry, per the ≥ 3× rule in §6.
GLMakie / WGLMakie interactive backends — out of scope; CairoMakie covers the static gallery, and INTERACTIVE_LIBRARIES intentionally excludes Makie.
julia.anyplot.ai marketing subdomain — small, optional follow-up modeled on the python.anyplot.ai nginx block in app/nginx.conf.
First batch of Makie implementations across existing specs — handled by the regular bulk-generate.yml flow once this PR lands.
Summary
Add Julia as anyplot's third language, with Makie.jl (CairoMakie backend for headless PNG rendering) as its first library entry. This is Phase 5 of
docs/concepts/library-expansion.md— the second non-Python runtime — and it should reuse and generalize every piece of plumbing we built for R/ggplot2 in #6944 + the follow-ups #6947 / #6961 / #7066.This is a meta / infrastructure issue, not a spec request. Do not apply the
spec-requestlabel — there is no plot type to draft. The work follows thefeat(ggplot2): add R/ggplot2 library + multi-language pipelineshape, not thespec-create.ymlflow.Why Makie.jl
Per
docs/concepts/library-expansion.md§5:plotly.jsorVega— so it earns its own entry under the "most-used variant" rule in §6.Plots.jlis the alternative; we ship Makie unless Plausible data later shows the audience flips.PlotlyJS.jlis a wrapper around plotly.js (already covered via Python Plotly entry).Reference: how R/ggplot2 was integrated
The relevant PR chain — read these before starting to understand the surface area and the bugs that surfaced after merge:
feat(ggplot2): add R/ggplot2 library + multi-language pipelinechore(ggplot2): follow-up Copilot review fixes after #6944 mergePlotOfTheDayTerminalrunner-token,plot-generator.mddocstring rule,impl-review.ymlheader rewrite prepend fallback.fix(frontend+api): wire R/ggplot2 into code viewer, libraries page, languages countget_impl_codeaccepts?language=,LIBRARIESarray,LIB_ABBREV,languagescount in stats, language-aware cache keys. The "always-going-to-need-a-follow-up" PR.fix(debug): preserve language in plot links so R/ggplot2 deep-links workDebugPagehardcoded'python',RecentActivitypayload,SpecStatusItemcolumn, coverage formula,LIB_TO_LANGconstant.Goal for Julia: roll all four PRs' lessons into one PR (or one PR + one tiny follow-up). Specifically: every
if language == "python" / "r"branch must become a genericpython | r | juliadispatch, every hardcoded9/10library count must already useLIBRARIES.length/len(SUPPORTED_LIBRARIES), and theDebugPage/LIB_TO_LANG/?language=plumbing must be exercised end-to-end before the PR is opened.Scope
1. Library + language registry (
core/constants.py)SUPPORTED_LANGUAGES: add"julia"→frozenset(["python", "r", "julia"]).LANGUAGES_METADATA: append the Julia entry. Suggested values:{ "id": "julia", "name": "Julia", "file_extension": ".jl", "runtime_version": "1.11", # confirm against the version we install in CI "documentation_url": "https://julialang.org", "description": "High-level, high-performance dynamic language for technical computing. Combines the productivity of Python/R with the speed of compiled languages; popular in scientific computing, numerical analysis, and machine learning research.", },SUPPORTED_LIBRARIES: add"makie"(alpha-sorted, betweenletsplotandmatplotlib).LIBRARIES_METADATA: append the Makie entry. Suggested values (verify on first CI run):{ "id": "makie", "name": "Makie.jl", "language_id": "julia", "version": "0.22", # pin to whatever the Project.toml resolves to "documentation_url": "https://docs.makie.org", "description": "High-performance, extensible visualization ecosystem for Julia. CairoMakie renders publication-quality static PNG/SVG/PDF; GLMakie/WGLMakie handle interactive use. anyplot uses CairoMakie for the static gallery.", },INTERACTIVE_LIBRARIES: leavemakieout. CairoMakie produces PNG only — same model as matplotlib / seaborn / plotnine / ggplot2. (GLMakie / WGLMakie are out of scope: they need a display server or a JS runtime.)2. Julia runtime in CI
.github/actions/setup-julia/action.yml— mirror of.github/actions/setup-r/action.yml. Steps:julia-actions/setup-julia@v2with the pinned major.minor (1.11). Dependabot will SHA-pin on first run (same policy as r-lib actions — see chore(ggplot2): follow-up Copilot review fixes after #6944 merge #6947 §"Deliberately not in this PR").julia-actions/cache@v2to cache the depot — Julia precompilation is slow on cold start.julia --project=. -e 'using Pkg; Pkg.instantiate()'to restore from the committedProject.toml/Manifest.toml.setup-r/action.yml).Project.toml+Manifest.toml(sibling ofrenv.lock):CairoMakie,Makie,DataFrames,CSV,Colors,ColorSchemes,RDatasets(gives usiris,mtcars,diamonds,gapmindercross-language-compatibly),PalmerPenguins,Random,Statistics.renv.lock: theManifest.tomlis the lockfile; commit both. Document the snapshot expectations in a# Notes / open follow-upssection of the PR description (renv.lockhad the same caveat).Cairo_jllso apt should not be needed, but mirror the apt fallback fromsetup-rforlibfreetype6-dev/libfontconfig1-dev/libpng-devto be safe against future runner-image changes.3. Workflows (extension- and language-aware)
For every file below, the R/ggplot2 PR introduced a
case "$LIBRARY" in ggplot2) LANGUAGE=r; EXT=.R ;; *) LANGUAGE=python; EXT=.py ;; esacstep. Refactor that into a single shared shell function or a tiny Python helper sourced by all workflows, so adding the next language is a one-line table edit. At minimum, every existing case must grow amakie) LANGUAGE=julia; EXT=.jl ;;arm. Files to update:.github/workflows/impl-generate.yml— addmakieto thelibrarychoices; add Julia setup step (conditional onlanguage == "julia"); add Julia version detection (julia -e 'print(VERSION)'); add Julia package-version detection for Makie (julia --project=. -e 'using Pkg; println(Pkg.project().dependencies["Makie"].version)'or equivalent)..github/workflows/impl-repair.yml— same derive-lang step; conditional Julia setup; conditional Python plotting deps suppression for julia branch..github/workflows/impl-review.yml— extend the per-library canvas/dpi hint dictionary with a Makie entry (CairoMakie usessave(path, fig; px_per_unit=2)orresolutiononFigure); make the header-rewrite step's prepend fallback (added in chore(ggplot2): follow-up Copilot review fixes after #6944 merge #6947) work for.jlfiles using#comments..github/workflows/impl-merge.yml— branch-name parser already derivesLANGUAGE+EXTfromLIBRARY; just add themakie)arm to the same case statement..github/workflows/bulk-generate.yml— addmakietolibrarychoices and toALL_LIBRARIES..github/workflows/daily-regen.yml— sanity-check it still works after the matrix grows by one.4. Prompts
New
prompts/library/makie.md— analogous toprompts/library/ggplot2.md. Cover:.jl, runtimejulia(notpython).NOT_FEASIBLEfor primary-interactivity specs.using CairoMakie, Makie, DataFrames, Colors, ColorSchemes, Random, Statistics. Optional dataset packages:RDatasets,PalmerPenguins.Random.seed!(42).ENV["ANYPLOT_THEME"](mirror of the ggplot2ANYPLOT_THEMEswitch).save("plot-light.png", fig; px_per_unit=…)plus an explicitFigure(; resolution=(3200, 1800))(landscape) or(2400, 2400)(square). Pick whichever combo ofresolution×px_per_unitlands cleanly on those exact pixel sizes — pre-render gate inimpl-review.ymlrejects anything off by more than 16 px.Plots.jl, no shelling out, nodisplay(fig)instead ofsave(...), no@show, etc.#comment block at the top of every.jlfile mirroring the Python/R conventions (# Library: Makie.jl 0.22 | Julia 1.11etc.).prompts/plot-generator.md— three small edits:Julia / Makieblock mirroring theR / ggplot2block.prompts/quality-evaluator.md+prompts/workflow-prompts/ai-quality-review.md:${EXT}legend (.py | .R | .jl) and the language allow-list ({python, r, julia}).prompts/workflow-prompts/impl-generate-claude.md+impl-repair-claude.md:(language, ext, runner)table grows ajulia | .jl | julia --project=.row.Rscript {LIBRARY}.Rexample pair gets a siblingANYPLOT_THEME=light julia --project=. {LIBRARY}.jl/…=dark …block.prompts/workflow-prompts/impl-similarity-claude.md— the{language}ispython/rmapping in the parenthetical needs a third arm forjulia.5. Frontend (
app/src/)This is the section that took two follow-up PRs to finish for R (#6961, #7066). Get it right in one pass this time.
constants/index.ts:LIBRARIES: insert'makie'in alpha order (betweenletsplotandmatplotlib).LIB_ABBREV: addmakie: 'mk'(ormki— pick whichever the design wants).LIB_TO_LANG: addmakie: 'julia'.LANG_DISPLAY: addjulia: 'Julia'.LANG_EXT: addjulia: 'jl'.components/CodeHighlighter.tsx:juliafromreact-syntax-highlighter/dist/esm/languages/prism/julia.SyntaxHighlighter.registerLanguage('julia', julia).PRISM_LANGUAGEmap:julia: 'julia'.@types/react-syntax-highlighterpackage didn't declareprism/rand we shipped that gap (see fix(frontend+api): wire R/ggplot2 into code viewer, libraries page, languages count #6961 "Out of scope"). Fix it for Julia in the same PR — either viadeclare module '…/prism/julia'or by patching the project-local ambient types so we don't carry forward two unresolved TS7016 imports.components/CodeHighlighter.test.tsx— add a case renderingusing CairoMakieunderlanguage="julia".components/LibraryCard.tsx— add a one-line description formakie(mirror of the ggplot2 entry).components/MastheadRule.tsx—julia: { open: '#=', close: '=#' }is already there. Verify it actually gets used after this change lands.components/PlotOfTheDay.tsx+PlotOfTheDayTerminal.tsx— the runner token (python/Rscript) added in chore(ggplot2): follow-up Copilot review fixes after #6944 merge #6947 grows ajulia --project=.arm. Same for theextswitch.pages/DebugPage.tsx—SpecStatusIteminterface adds amakiecolumn. The matrix gridrepeat(…, 40px)is supposed to useLIBRARIES.length(per fix(debug): preserve language in plot links so R/ggplot2 deep-links work #7066) — verify, don't hardcode11.pages/LibrariesPage.tsx— meta-description string ("Ten plotting libraries across Python and R …") bumps to"Eleven plotting libraries across Python, R, and Julia …".Tests — every
*.test.tsxthat hardcoded9/10or enumerated libraries / languages needs the same bump.6. Backend (
api/+core/)Per the lessons of #6961 / #7066:
api/routers/specs.py—get_impl_codealready accepts?language=(default"python") since fix(frontend+api): wire R/ggplot2 into code viewer, libraries page, languages count #6961. Don't widen the default to"julia"or change call sites silently — the default-python contract is the BC promise that kept that PR small. Just verify the Julia path works end-to-end.api/routers/debug.py—RecentActivitypayload already carrieslanguage_id(fix(debug): preserve language in plot links so R/ggplot2 deep-links work #7066). Addmakieto whatever per-library counters exist.api/routers/libraries.py— verify the new entry appears in/api/librariesonce the seed runs.api/routers/stats.py— thelanguagescount (added in fix(frontend+api): wire R/ggplot2 into code viewer, libraries page, languages count #6961 — bumped from 1 to 2 when ggplot2 landed) should auto-derive fromSUPPORTED_LANGUAGES. Verify it now reports3.api/routers/insights.py,api/routers/seo.py,api/mcp/server.py— grep for any hardcoded library/language enumerations and replace withSUPPORTED_LIBRARIES/SUPPORTED_LANGUAGESconstant references.core/database/models.py—Languagemodel already exists (feat(ggplot2): add R/ggplot2 library + multi-language pipeline #6944). Thelanguage_versioncolumn from migration3a7e1b5c0c4fcovers Julia versions too. No schema change needed.automation/scripts/sync_to_postgres.py— directory traversal already iteratesLANGUAGE_FILE_EXTENSIONS.keys()(per feat(ggplot2): add R/ggplot2 library + multi-language pipeline #6944). Verify it picks upplots/.../implementations/julia/makie.jlautomatically.automation/scripts/label_manager.py— after merge, the docs section says to runuv run python -m automation.scripts.label_manager synconce solibrary:makie,generate:makie,impl:makie:{pending,done,failed}labels appear. Include the same callout in the PR description.7. Tags / Plausible / SEO
docs/reference/plausible.md— line 305 already listsjuliaas a future language token (python, future:julia,r,matlab). Promote it from "future" to "current" once this PR lands. No new event types needed: every existinglanguage/libraryevent slot already accepts arbitrary strings.docs/reference/seo.md§"Adding a New Language" already documents the exact procedure (Library.language = "julia", sitemap auto-picks up/scatter-basic/julia/makie, optionaljulia.anyplot.aisubdomain). Walk through each step and confirm there's nothing left to wire — and if ajulia.anyplot.aisubdomain is on the table, it's a separate small PR (mirror of thepython.anyplot.ainginx block).docs/reference/tagging-system.md— no schema change needed; tags are language-agnostic. Verify nothing hardcodes "python or r" in narrative text.8. Tests
tests/unit/core/test_constants.py—TestSupportedLanguages(added in feat(ggplot2): add R/ggplot2 library + multi-language pipeline #6944) gets a Julia assertion.language_idintegrity test covers Makie automatically. Bump any explicit length expectations from10→11libraries and2→3languages.tests/unit/api/test_debug.py,test_routers.py,test_stats.py,test_schemas.py— verify alllen(SUPPORTED_LIBRARIES)/len(SUPPORTED_LANGUAGES)references still pass without per-library / per-language edits (this is the pattern feat(ggplot2): add R/ggplot2 library + multi-language pipeline #6944 introduced; new tests added since then may have regressed it — fix in place, don't addnoqasuppressions).tests/unit/api/mcp/test_tools.py— same.useCodeFetch.test.tsgains a Julia case (mirror of the ggplot2 case added in fix(frontend+api): wire R/ggplot2 into code viewer, libraries page, languages count #6961 — separate cache keys per language for same library_id,?language=juliaappended for non-python).CodeHighlighter.test.tsx,LibraryCard.test.tsx,ImageCard.test.tsx,DebugPage.test.tsx— Julia row / Julia language string.9. Documentation
docs/concepts/library-expansion.md— update §1 ("Current state" table grows a Julia row; library count goes from 10 to 11), §8 (Phase 5 status:shipped), §9 (record the decision to ship Makie over Plots.jl). Note the phase-skip vs. the original roadmap (we shipped Julia before JS): one paragraph in §9 explaining why is enough.docs/reference/repository.md— theplots/{spec}/implementations/tree gets ajulia/sibling alongsidepython/andr/.docs/reference/style-guide.md— the §3.8 "pipeline story" / "catalogue story" copy ("a thousand examples across ten libraries in two languages") gets bumped to "eleven libraries in three languages". The §1 plot-palette intro ("10 libraries (9 Python + R/ggplot2)") gets bumped similarly.docs/concepts/vision.md— quick grep for hardcoded counts, update as needed.agentic/docs/project-guide.md— append a Makie entry to the per-library list (the section that already covers plotnine / lets-plot / ggplot2).prompts/README.md— library count.README.md— quick grep for hardcoded library/language counts.10. Existing R-rollout gaps to not repeat
For each gap the R rollout hit, prove the Julia path doesn't:
/api/specs/scatter-basic/ggplot2/code404'd becauselanguagewasn't piped through (#6961)curl /api/specs/scatter-basic/makie/code?language=juliaafter the first Makie impl lands and verify 200.LIBRARIESarray silently skipped ggplot2 (#6961)/librariesshows the Makie card; landing strip showslanguages: 3.DebugPagehardcoded'python'when building plot deep links (#7066)/{spec}/julia/makie, not/{spec}/python/makie.RecentActivitypayload missinglanguage_id(#7066)SpecStatusItemmatrix column missing for ggplot2 (#7066)LIBRARIES.lengthsays) without hardcoded edits.9s /* 9/repeat(9, 40px)(#7066)PlotOfTheDayTerminalhardcodedpythonrunner (#6947)julia --project=. plots/.../makie.jl(or whatever runner token is chosen).impl-review.ymlheader rewrite needed prepend fallback (#6947)re.matchfirst, prepends the canonical#header if absent.@types/react-syntax-highlightermissingprism/rdeclaration (#6961 "Out of scope")Suggested phasing inside this PR
The R PR landed as a single 45-file commit. That's fine for Julia too, but it's also reasonable to split:
julia.anyplot.aisubdomain if we want one.If the team has bandwidth for a single combined PR, prefer that — fewer roundtrips with Copilot review, and the "always-going-to-need-a-follow-up" PR class (#6961) shouldn't be inevitable a second time around.
Acceptance criteria
core/constants.py:SUPPORTED_LANGUAGES = frozenset(["python", "r", "julia"]),SUPPORTED_LIBRARIEScontains"makie", bothLANGUAGES_METADATAandLIBRARIES_METADATAare extended..github/actions/setup-julia/action.ymlinstalls Julia, restores fromProject.toml+Manifest.toml, smoke-tests a CairoMakie render.impl-generate,impl-repair,impl-review,impl-merge,bulk-generate) deriveLANGUAGE+EXTfromLIBRARYvia a shared table, and the table contains amakie → (julia, .jl)row.prompts/library/makie.mdexists and follows the ggplot2-prompt shape (no-workarounds, NOT_FEASIBLE policy, canvas hard rule,ANYPLOT_THEMEhandling, forbidden patterns, header style).language="julia"with Julia syntax highlighting and theMastheadRuleblock-comment tokens (#=…=#) for the masthead are wired up.gh workflow run impl-generate.yml -f specification_id=scatter-basic -f library=makieproduces a passing Julia implementation withplot-light.png+plot-dark.pngin GCS./scatter-basic/julia/makieloads the code panel (no 404 on/api/specs/scatter-basic/makie/code?language=julia) and the rendered preview, in both light and dark mode./debugmatrix has amakiecolumn; clicking a Julia cell deep-links to/{spec}/julia/makie, not the python hub./librarieslists Makie;/statsreportslanguages: 3;/sitemap.xmlincludes/{spec}/julia/makieentries.uv run pytest tests/unit tests/integrationis green. Frontendyarn test --run,yarn tsc --noEmit,yarn lintare clean — no@types/react-syntax-highlighterTS7016 carry-forward.docs/concepts/library-expansion.mdPhase 5 row markedshipped; library + language counts updated everywhere they're surfaced.uv run python -m automation.scripts.label_manager syncrun once solibrary:makie,generate:makie,impl:makie:{pending,done,failed}labels exist.Out of scope (separate issues)
docs/concepts/library-expansion.md; not blocked by Julia.≥ 3×rule in §6.INTERACTIVE_LIBRARIESintentionally excludes Makie.julia.anyplot.aimarketing subdomain — small, optional follow-up modeled on thepython.anyplot.ainginx block inapp/nginx.conf.bulk-generate.ymlflow once this PR lands.