I find AI coding tools such as Claude Code incredibly useful, especially when combined with tools like Kaimon.jl. However, I also find that the code they generate is often surprisingly non-idiomatic Julia.
Beyond aesthetics, this has practical consequences. The generated code frequently misses opportunities for classic Julia strengths such as multiple dispatch, leveraging existing package functionality, and introducing concrete types or type information early in the design. Instead, it often produces code that feels more like a direct translation of patterns from Python, JavaScript, or other ecosystems.
How do you deal with this limitation?
Has anyone had success steering these models toward more idiomatic Julia? For example, can we point them at curated examples of “blessed” Julia code, style guides, or particularly well-designed packages that they can learn from and emulate?
In my experience with agentic coding, this is hard to do something about. Ingesting a comprehensive style guide big enough to rid them of Python-isms would take up a good chunk of the context window, which is probably better spent elsewhere.
I recommend two approaches to this:
Put a brief list of instructions addressing only the most annoying tendencies in your AGENTS.md
Have the agent work in small chunks of work and review each chunk. This way, you can steer it better.
One option which I haven’t tried yet, but maybe could work, is to have a review-julia skill, which has this more comprehensive Julia design guide. You can then point a cheaper agent (e.g. gpt-5.6 luna) to review the bigger agent’s work with that skill.
Edit: FWIW, I do a bunch of agentic coding in Python as well and I also find that agents coding Python have some bad design patterns I repeatedly need to rid my code of. An example that I constantly struggle with is that they prefer to defer checks to where data is used instead of where it’s loaded. E.g. they do
def process_element(d: dict[str, int], key: str)
value = d.get(key)
process_1(value)
process_2(value)
if value is None:
raise TypeError("Should not be None")
...
def process_1(value: Union[Int, None]):
if value is None:
raise TypeError("Should not be None")
...
def process_2(value: Union[Int, None]):
if value is None:
raise TypeError("Should not be None")
...
I’ve read that the idea of separating these models into two, one human language trained, and one computer language trained (with a third to translate between the two), often yields worse results than the monolithic human language one. But for this specific aspect, it does sound like a version of Claude that is tuned more towards (for instance) Julia would be ideal… As unlikely as that sounds…
It would be fantastic if people could share their (currently) most successful Julia-idiomatic related agent-instructions and/or Julia review skill.
Aside from asking agents to do some API documentation, help with some macros, and standardising instructions and prompts. I basically hand wrote all of PortfolioOptimisers.jl until Opus 4.8 came out.
I think i did a pretty good job creating an agentic workflow bit by bit that now works incredibly well. I’m adding a ton of features, fixing bugs, improving the user experience, documenting, etc. Here is a step by step guide of what I would do if i were starting from scratch. I had to go back and redo some stuff that in hindsight could have been avoided. However, you should periodically audit your workflow to make improvements as models change or as you get a better idea of what you want your code to do and look like.
It’s important to note that it’s best if you start with a clearly defined skeleton of your standards and code practices. You can use an AI to work with you to refine them. This should be ongoing as the codebase evolves.
Run /grill-with-docs in the bare repo. This will ask you a ton of questions to establish a common lexicon and grammar. This is the CONTEXT.md file, which is going to be the first place an agent looks before asking you questions. I think i might break this up into a map where each section contains only its relevant information as it’s getting long.
Set up a STANDARDS.md. To start with you might want to plop your standards directly, but ideally you want it to be an index of where each standard is defined. This should give the agent instructions on how you want things done. Mine has the files it must run tests on, pointers to how i want docstrings written, code subtyped, tests written, etc.
Set up your CLAUDE/AGENTS.md. This establishes general etiquette and points the agents to the places they need to check out for contextual answers and instructions so they can make high quality additions. It also bounds the etiquette, i had claude ping people without my asking and i find that distasteful.
Matt’s skills (step 1) come with an /improve-codebase-architecture skill. Use it as the basis for creating /improve-codebase-security (security issues), /improve-codebase-maintainability (easier maintenance), /improve-codebase-ergonomics (for user experience improvements). You can also use it to modify /thermo-nuclear-code-quality-review so it generates `html` in the same style, or merge the skills into one (i haven’t tried this yet). You should probably do this after all the above files have been created so they know to use them in case they need.
Set up a code quality CI ratchet. I made one that uses CodeComplexity.jl, another that uses JET.jl, another one that sweeps files and additions to ensure their docs are up to date and their code is correct, another that tracks coverage, another that tracks file size. I will probably turn it into a package, as it’s been really useful for improving code quality in general.
Use the best model you have available for any grilling or research session if the task is complex. Opus 5 works great, but Fable 5.1 makes fewer bone-headed moves/asks fewer dumb questions. It can be very noticeable if the task is complex and/or touches many files.
When making a PR run /improve-codebase-architecture and /thermo-nuclear-code-quality-review (or the merged skill). Fix any issues you agree with, tell it not to relitigate things you need for your codebase or deliberate choices you’ve made. Repeat until it starts finding the same things over and over that maybe you think are worth doing but not just now. Move on to /improve-codebase-security, /improve-codebase-maintenance, and finally /improve-codebase-ergonomics. Each time, run each skill and fix issues until it keeps finding the same things. I used to run them in parallel, but i’ve found that they often find the same issues, and by fixing the one higher in the hierarchy, you end up fixing the ones below it. You should use good models for these. The best you have available if you can, but Opus 5 is really good here as well. You can use lesser models for the implementation. I typically use Opus 5 for everything unless the features or fixes are very complex, sonnet if the fix is easy and well described. You can repeat the entire loop ad infinitum, but that can get boring, burn through tokens, and give diminishing returns. If you are running up to your reset and haven’t hit your token limits, it never hurts to run these on your entire codebase. They are genuinely awesome at improving it, provided you have the set up i’ve described.
It seems that recent discussions on this forum indicate growing interest in two directions for Julia native language models. The first is pretraining a model from scratch in Julia, as explored in the recent and fairly recent threads by @mantzaris. The second is fine-tuning / post training existing models. I believe, this approach has become even more attractive with the new generation of releases. In particular, Qwen3.8-27B and especially Qwen3.8 Flash Next appear to represent a huge step forward in both reliability and efficiency, although I’d maintain that @Palli’s estimates regarding the feasibility of running genuinely useful workloads on 2GB of VRAM or on a mobile device remain somewhat optimistic. Also Qwen models for various reasons look a bit risky, thus, I sustain again that focusing on i.e. Trinity seems to be probably much safer approach as of now and a great opportunity to practice and to set up an infrastructure. As for your proposals, if I understand them correctly: separation, orchestration, and cross-validation, they resemble a bit what I outlined a few weeks or months ago in my posts here about NeuroREPL. It has turned out that related ideas have already been validated in practice. Examples include the Sakana AI models and the self-improving coding harness behind Prime Agent.
The better tool for this is hooks, which let you reject and/or rewrite edits with a regex (e.g. I have one prohibiting concrete types on function arguments to stop it from overtyping).
Note “idiomatic” below, not in the paper, but what it enabled for Fortran porting:
.. Genesis used DeepSeek V4 Flash to build a Rust-based C compiler with about 250k tracked lines; the run lasted over 120 hours, archived over 1,000 agent episodes and incurred only US$44 in model-token charges. The compiler passed the complete c-testsuite and most LLVM and Csmith tests. In a separate compiler world generated with GLM 5.2, development continued after repeated agent replacement while retaining full test performance. Genesis also reimplemented 13 MESA modules with over 100k Fortran lines as a Rust workspace with nearly 90k Rust lines; across six numerical workloads, it achieved median speedups of 1.55–6.87x. These results show that long-horizon software development can be organized around a persistent project rather than a persistent agent. Project Website: this https URL
Costing US$10.64:
rewrite of the core numerical/physics stack of MESA — the original ~462K-LOC Fortran 90/2008 stellar astrophysics suite. This workspace ports the const → utils → math → mtx → interp_1d → interp_2d → num → chem → rates → neu → net → eos → kap module chain into 13 idiomatic Rust crates, mirroring the original module APIs to preserve backwards compatibility, and ships a benchmark harness that proves the port is faster than the original Fortran on every workload (medians of driver-internal timings, gfortran -O3 -march=native vs Rust release lto=fat, codegen-units=1).
Highlights
~67K LOC of pure Rust library code (129 files, 13 crates), #![forbid(unsafe_code)] everywhere — zero unsafe, zero FFI.
~1050 tests green (cargo test --workspace → 1052 passed / 0 failed / 18 ignored), including golden tests ported from the original Fortran test_output files (bit-exact or ~1e-9).
No LAPACK/BLAS FFI ..
Rest is older in chronological order:
So we are down 99% in cost since 6 months ago, then cost 444x making a C compiler (and now 2.8x quicker to make “120 hours”/5 days vs 2 weeks):
Over nearly 2,000 Claude Code sessions and $20,000 in API costs, the agent team produced a 100,000-line compiler that can build Linux 6.9 on x86, ARM, and RISC-V.
The key seems to be 1000/16 = 62x more agents, though only part of the reason, the paper is brand new to me.
This has been a bit U-shaped; c. 2023-early 2025 Julia was catching up to these languages, but since then it’s fallen behind. This is mostly because Julia lacks the static checking used for informed speculative decoding and RLVF (Reinforcement Learning from Verifiable Feedback) in other programming languages. (Unfortunately, JET.jl doesn’t count: it’s slow, not sound, still doesn’t have traits or interfaces, and isn’t included by default so nobody knows about it and the LLMs often don’t think of including it in their tests.)
The other big issue is the long compile and startup times and big runtime, which make the iteration/training process painfully slow. This means you can’t make up for it in sheer quantity of data the way you can in Python (which has both a larger pretraining corpus and a faster feedback loop). Julia is kind of stuck in a “worst of both worlds” situation.
I flagged this back in 2023 when the AI companies started broadcasting their plan going forward was to use RLVF, but it lines up pretty closely with the most common complaints people have had about Julia since it came out in 2014.
I appreciate @dcelisgarza’s post since it’s an actionable venue to solving some of the issues mentioned here. Thank you!
It also highlights the lack of a unified framework to achieve Julia-AI-nirvana. While every project has its own unique needs, a future where we settle on a agent-dev-env (CLAUDE.md, AGENTS.md, skills, CONTEXT.md, STANDARDS.md, etc) that results in idiomatic Julia code sounds promising. Or perhaps we’ll get there via some of the other venues mentioned in this post.
Yes, the workflow provided by @dcelisgarza looks very good. I’m planning to test something similar with Prime Agent this weekend. Also that new mention by @Palli, the one about EvoX Genesis, looks interesting. And thanks for starting this thread. The synthetic generation of idiomatic Julia code appears to be of significant importance those days.
Please see here and here. You can speed up performance by having a draft model propose outputs (speculative decoding); eliminating proposals that would fail to compile improves the draft model’s quality and thus overall performance.
Writing code that errors, fails tests, or doesn’t compile is generally scored negatively by RLVR graders, since it’s a very easy-to-measure reward signal.
…that said, I’m kinda remembering why I stopped hanging around these parts, so have a good day I suppose.