TLDR; A personal experience of reading, writing and understanding programming languages and navigating the AI agent era. Also there are no sectional partitions since this was one-shotted by me :)
My first exposure to programming was through Python. I followed that up with the usual culprits, C, C#, Javascript/Typescript. Once I started delving deeper, I found myself navigating a dense forest of languages, from Elm, Erlang to Haskell, Ocaml, from lower level x86 assembly to the pinnacle of high-level theorem provers like Lean4 or Coq, from memory safe Rust to the monstrosity that is C ++, to the new ones like Gleam1. Each new language brought forth a different design philosophy, internal working models and syntaxes. And the natural progression ? Writing my own of course !
I had read many a blog on writing parsers, and it was quite fascinating to say the least. I was enthralled by the process of writing a lexer, parser and an emitter, to decide the rules and syntax, and the extent of it’s type systems2. I learned about libraries like Nearley and Lark, and what recursive decent parsers were. I have spend many hours getting an LLM to write the grammar for Nearley3, merrily understanding the near alien looking rules and syntaxes4.
Moving forward from my fascination of all programming languages, we have now entered the agents era, where English is the new programming language. Am I distraught at this development ? Not really. The way I see it, languages were always a point of fascination for me, and I still write code by hand. It’s pure joy ! That is not to say I write all code at a glacial pace. I extensively use agents as the industry demands of me. Designing the architecture and specification also remains interesting, and navigating agents is not an easy task (could I one-shot a client’s requirements ? Nope. Mostly because we both don’t know what they want). So while writing code by hand has become a hobby, and agents have taken it’s place, I was pleasantly surprised to discover that my love for designing languages may actually come in handy !
A Domain Specific Language is a programming language, specialized to a specific application domain
LLMs may have made learning programming language syntax irrelevant56, but they intrinsically invite us to design our own programming language, specific to our problems, through Structured Outputs. It may seem like I have made a leap, but hang on and keep reading !
Structured outputs essentially force a model to output a JSON schema, which enables us to know the shape of the model output in advance, and write deterministic code which can truly leverage the model’s capabilities. Upon learning the fact that a model’s output quality deteriorates when it’s forced to output a specific JSON schema, one might conclude that it’s a net negative, but that is not the case at all:
- First, the recent model capabilities have leaped in raw “intelligence“ 7 which allows them to output the correct JSON most of the times, often with complex reasoning as well
- Second, the real power of deterministic code is an increase in accuracy and reduced token usage, as instead of the Model outputting arbitrary text, we can simply let the model output a JSON, and interpret that through deterministic code. That gives us determinism, robustness and the LLM’s semantic understanding, all at once. It’s the complete package !
Ok Ok. Structured outputs. Great. What’s the point ? And how is this connected to DSLs ? Well … structured outputs are DSLs ! (but one abstraction lower …)
Remembering that every programming language, before being turned to machine code and being executed goes through three phases: Tokenization, Abstract Syntax Tree and then to a lower level language8 (like C or x86, before machine code). Tokenization is simply the compiler separating the string (our code basically) into tokens9, which are then converted into an intermediate representation (IR), also generally known as the Abstract Syntax Tree. Here’s a small example:
If we squint a little, it’s not hard to see that the Abstract Syntax Tree is a simple nested structure, very similar to JSON (in fact it IS exactly similar to JSON). Which means JSON is yet another representation of a programming language ! (Although very verbose) Going back to structured outputs, it simply means that the models are outputting an intermediate representation of a specialized Domain specific language, the domain being whatever task we want the LLM to accomplish. This re-framing allows us to really explore what’s possible with the combination of structured outputs + LLMs, and what guarantees we get by this re-framing of our task and usage of the models.
LLM’s true capabilities exploded once it started giving accurate and correct code (especially Python and React/JS/TS), which allowed them to defer certain pure computational task to scripts or snippets they could conjure, alongside the ability to navigate and interact with systems, giving rise to coding agents themselves. Alas, simply being able to write code did not help it complete tasks, or be more reliable. One major advantage of writing code was that it was deterministic (a fact that made programming a verifiable domain, the exact reason why LLMs are so good at it in the first place !). But when coding agents brought forth with a wave of non-determinism, we started looking for various methods and alternative paths to ensure determinism and good [Agentic] engineering practices. And on this path, did I re-discover the old point mentioned above: there is a way to get determinism, robustness alongside an agent’s semantic understanding10.
So, this all points towards: letting an agent produce DSLs instead of arbitrary code. But why ? What are the advantages ?
- It’s domain specific. Most other programming language are too general, and the model may go on trying longer methods, or write an enormous amounts of code, which can be detrimental if the task is frequent enough. Letting it output a DSL let’s it focus only on the task at hand, and if designed properly, can save it both reasoning and output tokens.
- It’s more efficient. In a lot of cases, there’s generally two levels for code: one where logic exists, and one where execution exists. If we let the agent write at both levels, we are inviting hallucinations, bugs and increase in token costs. Instead, we can write a DSL which carries out only the logical aspect of the task, while write a simple Transpiler which converts the DSL to another “lower“ level language, and execute it deterministically. This also lets the model solely focus on what matters more, which is the logic. Also, in cases of complex logic or longer outputs, letting it emit a textual DSL is much better then JSON through structured outputs as:
- Substantially much less token usage
- The model can reason better when it has to output text, over JSON (as I mentioned earlier, it deteriorates perfomance ).
- It’s safer. As the recent incidents with openAI’s model hacking into Huggingface and various other AI cyber attacks prove, the models are at the level that they can easily exploit their environments or run malicious code. One fix would be to restrict the code that they can write to a constrained language or … a DSL ! Since the language, by design, won’t be as comprehensive and general as the normal programming languages, we can easily write a Transpiler that strictly checks for malicious code in this constrained search space (or, since with smaller DSLs and more powerful LLMs, we can formally prove the DSL’s correctness as well. Making it notjust safe, but mathematically safe.)
Although we must be aware of the caveat of designing overly complex DSLs: we start approaching general purpose languages themselves, and in that case, it’s better to let the model output the language it’s already deeply familiar with. Here, I have mentioned the two disadvantages of using a DSL:
- Designing it involves a trade-off. Sufficiently complex ones would rather be replaced by Python and
- the model is unaware of our DSL, hence it’ll always be slightly worse in writing it (though, again, with current capabilities, I think it matters less).
Before concluding this, I would like to present two examples where I have used DSLs to complete the tasks at hand. Case studies !
The Financial DSL
The use case was simple: use agents to write trading algorithms. This use case had clearly ticked the write checkboxes :
- I wanted a separation of logic (the trading strategy itself)
- From the infrastructure that executes it (and deals with brokers, live ingestion of prices and execution of the logic itself)
Now there was a scenario where I could let it write a subset of python, or let it utilize libraries and the like, but that approach left too much on the table: I am asking the model to keep up with Python versions, importing correct libraries, remembering to perform implicit time management (for inter time-frame trading) and such, whereas I can design a DSL which both hides the execution logic and makes certain things explicit. Here’s a snippet of my DSL below:
A few things to note: the PARAM keyword signifies the external parameters that the user can tune, while the [1min] syntax makes explicit at what time frame will that rule be applied, alongside the easy-to-see BUY and SELL syntax. However, there’s another, better example to showcase my DSL:
This snippet introduces the very commonly used FILTER feature. By allowing the language model to only focus on the logic, I have freed it from the hassle of using numpy logic, or perform other optimizations, which I can focus on, including which array frameworks to best utilize
The Excel DSL
It does seem, at first glance, that it wouldn’t be a fruitful adventure to write a DSL for excel, as spreadsheets themselves are Turing complete, and it also has it’s own smaller DSL (in the form of formulas). But conclusions must not be drawn before knowing the task at hand !
The workflow was very simple12 : given a multitude of excel files (with each containing multiple sheets), the LLM must either copy or transform the data from the excel files to another typed JSON/object (related to balance sheets). The agent would have to locate the relevant data, judge if it can either copy or transform it in some manner in order to fill the given requirement. Now, ignoring the fact that this was an evidence discovery + domain-specific task transformed into one, it called for a DSL :
The current DSL had different reasons to be used: it’s much more compact than the equivalent JSON schema, and, as we discussed above, also allows the model to reason better (as, internally, it does not have to do some sort of complex state management for the nesting structure. Everything is flat). Although this did not allow the agent to complete the task at hand, it did reduce the numbers of errors by a huge margin, as opposed to when it was outputting JSON schema.
In conclusion, I have had quite a lot of fun exploring various ways in which I can utilize DSLs, especially with language models, and how and where I can leverage them. There were a lot of use cases where I thought a DSL fits, but it turned out to be too complex a task, or too simple to require me designing one. That aside, DSL paired with formal methods seem to be a very good directions for the AI labs to train the models in, as this can bar it from writing malicious code in the first place, and give us the safety that we require. It might be short (or not), but this surely feels like the era of DSLs !
Thank you for reading this far !
1 Feels bad to leave out Java and the entire Lisp family, with Clojure and C-lisp. And also Golang and PureScript.
2 This is a real loop hole for me, and leads to my current obsession of understanding theorem provers.
3 It never got it right, and eventually I had to go line by line to fix a small mistake. Although this was with pre-2026 models, back in December 2025.
4 Now I know how non-tech people must feel, minus the lack of enthusiasm
5 Although understanding computational concepts may still be important
6 A very interesting case is that of the Vera programming language, since it’s designed to be used by the LLMs, and them only. It’s design rules explicitly keep in mind the internal workings (as we understand them) of LLMs.
7 I want to be really careful of the words I use, but there’s no other word that coneys a LLM’s capabilities than to say they are more intelligent. Funny how that became a jargon of the AI/Programming community.
[9](#footnote-anchor-9)
Basically going from “def f (a, b)“ → [“def“, “f“, “(“, “a“, “b“, “)“]
[10](#footnote-anchor-10)
And of course other advantages like writing thousands of lines of code, relentlessly pursue a task or code generation. The technology is undeniable, hence a subject of fascination, at least for me :)
11 We could go device specific, by using MLX for mac, Jax/Pytorch otherwise, or could really leverage the DSL and go straight to SIMD/AVX instructions. This also leaves a possibility of proving certain things mathematically by also going straight to Lean4 ! The possibilities are endless, and endlessly interesting by leveraging LLMS.
[12](#footnote-anchor-12)
For us humans apparently, as I later found out