Teaching LLMs to Write Better Nim
I have been working on a public set of Nim SKILL.md files for coding
assistants:
https://github.com/planetis-m/skills
They are not meant to make an LLM "know Nim" in some grand sense. Each one is a small file that tells the assistant what to pay attention to for a specific kind of work: ownership hooks, API design, tests, C bindings, wrappers, docs, fuzzing, debugging, error handling, and code organization.
The motivation is practical. LLMs can write useful Nim code, but they also drift. They half-remember language rules, invent API names, miss compiler-specific semantics, and produce code that compiles while still being the wrong shape. For a niche language this matters more than usual. There is less training data, fewer examples in the wild, and a lot of the important knowledge lives in compiler behavior, standard library conventions, and the habits of experienced programmers.
A skill file is my attempt to write those habits down in a form an assistant can actually use.
This Is Not "Vibe Coding"
"Vibe coding" usually implies little oversight: ask for software, accept the output, maybe poke it until it runs. That is not what I am doing, or what anyone using these tools seriously is doing. The distinction I care about: the LLM produces code, the programmer owns the design, the compiler, tests, and review decide whether the code is acceptable.
Calling all LLM-assisted code "ethically dubious" or inherently low quality misses the point. Bad code is the responsibility of the person who ships it. The tool can make mistakes, but the author still has to review the result, run the tests, and maintain the code later.
The useful question is not whether using an LLM makes the code legitimate. It is whether we can make LLM-assisted programming more reviewable, more idiomatic, and less wasteful. That is where skill files fit.
The Quantum Error Code Analogy
A video titled "Are SKILL.md files the Quantum Error Codes of Industrial AI?" (Discover AI, April 9, 2026) makes a comparison I found useful. It argues that industry wants reproducibility, risk management, and traceable outputs, while LLMs are probabilistic systems with nonzero hallucination rates. Skill files, tools, scripts, and retrieval systems become a scaffold around that probabilistic core.
The quantum error correction analogy describes what we are trying to do:
we are trying to force a messy space of possible model behavior through a smaller number of checked, named, repeatable patterns.
For coding, I do not need the assistant to be creative about how Nim ownership
hooks work. I need it to classify the ownership model, write the right hook
set, avoid a custom =sink unless there is a real reason, use
=destroy(x: T), and mark =copy as an error for move-only owning types.
There is nothing creative about this. The assistant just has to follow the
pattern, and the pattern is small enough to write down.
The uncomfortable part the video gets right is that the scaffold may be deterministic text, but the model executing it is still probabilistic. A skill file does not make the assistant safe. It gives me another lever for review, and that is how I treat it.
How the Skills Are Built
The repo is organized around a refinement loop:
- extract claims from a draft skill;
- write small Nim tests for the claims that can be checked;
- curate the dataset, marking what is verified, wrong, too broad, or still untested;
- rewrite the skill from the verified material;
- feed benchmark failures and bad assistant outputs back into the loop.
This has not been a fully autonomous process. A lot of the value came from manual argument, and two examples are worth mentioning.
The first is operator precedence for not. It is easy to write
not a or b while meaning not (a or b), or not x < y while meaning
not (x < y). That belongs in the style and testing instructions because it
directly affects generated Nim code, and it is the kind of thing an assistant
will get wrong without being told.
The second is API naming. Invented names such as findIndex and
getOption were removed because they did not match how Nim libraries usually name these
operations. The skills follow Nim's NEP1 naming and
style conventions, so the assistant produces names that Nim programmers
recognize instead of names borrowed from other languages.
Not every fix was a deletion. Some rules were correct in substance but
misleading in wording. A skill said to define < or <= for
comparable types. The or reads as a choice, but Nim derives >
from < and >= from <= independently, so defining only one
leaves the other pair broken.
What the Experiment Showed
I ran a small check with DeepSeek V4 Pro, not a full benchmark. The task was
to write a Nim OwnedBuffer with ownership hooks, compile it, and fix it
until it passed.
The no-skill run was not useless. It produced compiling code and passing tests, and that is the interesting part. The value of the skill was not that it turned a failure into a success. It changed the shape of the code. The skill-guided run avoided unnecessary hook code, used the cleaner destructor signature, guarded empty allocation, and produced tests that matched the actual ownership risks.
Skills do not make the assistant smarter. They reduce the amount of cleanup needed before I can focus my review on design and correctness instead of basic Nim habits.
Why Nim Benefits From This
Nim is a good target for skill files because the mistakes are often specific. Generic "systems language" advice is not enough.
General models tend to blur details that matter in Nim. sink does not mean
"always moved." Hook declaration order matters. assert disappears in danger
mode. foo (1, 2) is not the same call as foo(1, 2). These are not
exotic edge cases. They are the kind of thing that quietly changes what a
program does, and they are easy for a model to get wrong because they look
like details in other languages too.
Idiomatic Nim also depends heavily on standard library shape. Good APIs use
names and contracts Nim programmers recognize: initX for value
constructors, items and pairs for iteration, contains for
membership, and [] for lookup. A skill can steer the assistant away from
invented API surfaces before review has to catch them.
The smaller ecosystem makes this more useful, not less. There is less generic Nim code for a model to imitate, so a short, reviewed instruction can carry a lot of weight. Nim already has reference material. The missing piece for an assistant is a reminder of the rule it is most likely to forget, not a second manual.
What Skill Files Can and Cannot Do
Skill files are useful for procedural knowledge:
- how to structure ownership hooks;
- how to write deterministic Nim tests;
- how to shape a public API;
- how to wrap C handles safely;
- how to run sanitizer checks;
- how to avoid parser-sensitive syntax bugs.
They are much less useful as giant knowledge dumps. If a skill grows without pressure from real failures, it starts to make the assistant worse: more options, more noise, more chances to apply a rare rule in a common case. The Common Mistakes section needs the strictest standard of all. Every entry has to be backed by a real benchmark failure, not a guess at what might go wrong.
There is also a trust limit. A skill file cannot make an LLM deterministic. It cannot prove that generated code is good. It can only bias the assistant toward known-good patterns and make review easier.
That may sound modest, but modest tools are often the ones that survive contact with real programming.
Try Them, Then Complain
The skills are public because this only improves if people use them on real Nim work and report where they fail. The useful reports are concrete: "the assistant still writes this bad ownership hook," "this API rule fights the standard library," "this instruction made the model overfit an edge case." Those reports turn into tests, dataset entries, and better wording.
That is more valuable than arguing in the abstract about whether LLM-assisted code is good or bad. The code still has to compile. The API still has to make sense.
Conclusion
The best use of skill files is not to cage the model until it becomes deterministic. The better use is to move repeated review knowledge out of my head and into a small artifact that can be tested, shared, criticized, and improved. That is why I made the skills public. They do not solve AI coding. They make a certain kind of AI-assisted Nim programming less random.
That is not vibe coding. It is assisted programming, checked by the compiler and review.

Comments
Post a Comment