Open-source project
CatalaLang/catala avatar
CatalaLang/catala

Catala: a legislative programming language whose authors call the compiler unstable

Programming language for literate programming law specification

2,401 stars112 forksOCamlApache-2.0

At a glance

What is it?
An OCaml language for annotating legal text as code, shipping three opam packages, a proof package gated on Z3, and a disclaimer from Inria stating the compiler is yet unstable and lacks some of its features.
Who is it for?
Catala fits research and public-sector teams who need an implementation of a socio-fiscal mechanism whose correspondence to the statute can be shown to the people who wrote the statute, and who are prepared to be reviewers rather than users. It does not fit a production deadline, because the project states plainly that the compiler is unstable and missing features, and because the formal certification is described as partial.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly OCaml, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A nightly channel that is listed older than the current release

The release list is not a simple sequence of version numbers. It holds 1.3.0, titled with the name of a French professional body, published on 2026-10-01; 1.2.1 from 2026-07-06; and between them an entry tagged `nightly` and titled as the latest nightly build, dated 2026-08-22.

So there are two channels, numbered releases and a rolling nightly, and the nightly entry visible here is about six weeks older than 1.3.0. Nothing in the file explains whether the nightly build stopped being published, whether the listing shows only the most recent nightly artifact, or whether the nightly channel lags deliberately.

The last commit to the default branch is dated 2026-10-02, one day after the 1.3.0 tag. For a project installing through opam, the practical question is which of those two channels your lockfile should point at, and the release list is the only place in the repository that answers it.

The project describes its own compiler as unstable

The limitations and disclaimer section is short and unambiguous. Catala is a research project from Inria, the French National Research Institute for Computer Science, and the compiler is described as yet unstable and lacking some of its features.

That sentence is the most important line in the file for anyone planning around this language, and it sits in the same document that describes the ambitions. The language is designed so that each line of legislative text is annotated with its meaning in terms of code, and so that an implementation of a complex socio-fiscal mechanism can be derived from those annotations and then reviewed by domain experts who are lawyers rather than programmers. The compiler can produce a lawyer-readable PDF version of an implementation for exactly that review.

The formal side is described with matching care and matching hedging. Proof material for auditing the partial certification of the compiler lives under `doc/formalization/`. Partial is the operative word: the claim is a partial certification, and nothing in the file upgrades it to a full one.

Default logic is the feature, not an extension

The reason the language exists is structural. Its logical structure is meant to mirror the logical structure of law, and the core concept is definition-under-conditions, built on default logic. That foundation was formalized by Professor Sarah Lawsky in an article titled A Logic for Statutes, which the README links to.

The uniqueness claim is stated with a hedge and should be read with one. The file says Catala is, to the authors' knowledge, the only programming language that embeds default logic as a first-class feature, and that this is why it is the language adapted to literate legislative programming.

Default logic is what lets a statute say a rule applies unless an exception is triggered, with the exception taking precedence automatically, which is the shape most tax and benefit legislation actually has. A language without it forces that structure into nested conditionals, and once flattened into conditionals the correspondence between the code and the text stops being visible to the person who wrote the text.

One repository, three opam packages and a proof target

The root of the repository holds three opam package files rather than one: `catala.opam`, `catala-js.opam` and `catala-proof.opam`, plus a `catala.opam.locked` file pinning a resolved set.

The Makefile shows what each is for. The default dependency target installs `catala.opam`, and a separate target named for the proof package installs `catala-proof.opam` after a first pass that only resolves the depexts. The name of the JavaScript package is used the same way, with its own dependency target. So a user needs one of these, a web target needs another, and anyone auditing the formalization needs the third, which is where the Z3 dependency lives.

Around them sit `compiler/`, `stdlib/`, `runtimes/` and `deps/`. The runtimes tree holds a Python package with its own `pyproject.toml`, and `deps/` carries a date calculation library that also has a `pyproject.toml`, so the build crosses from OCaml into Python and back. `tests/` and `tests-extra/` are separate directories, and the reference test suite has its own readme.

The build wants seven external programs and two opam CLI versions

The Makefile names its required executables in one assignment: groff, python3, node, npm, ninja and pandoc. Each is checked with `which`, and a missing one produces a warning rather than a failure, so an incomplete toolchain produces a build that fails later and less clearly.

The opam invocation is pinned as well, and not consistently between the two files that matter. The Makefile uses `opam --cli=2.1`, while the Dockerfile uses `opam --cli=2.2`. Both are explicit flags, which is a deliberate constraint, and having two versions named in one repository means you cannot satisfy both by upgrading opam to the newest release.

The Dockerfile also explains its own pinning. Rather than running `opam update`, it says to use a newer parent image, and that parent is `registry.gitlab.inria.fr/lgesbert/ocaml-images:4.14-2026-09-25`, an OCaml 4.14 based image. There is a FIXME in the file as well, noting that pygments sits in the opam depexts but that depexts do not handle the development setup option, so it is never installed by the opam command and has to be added through the system package manager instead.

The Dockerfile says it is not the image you want

The first comment in the Dockerfile is a refusal. The file is only meant for the continuous integration of the compiler's own development, and anyone who wants a base image for the CI of their own Catala project is directed to a container registry hosted at gitlab.inria.fr under the verifisc project, with a specific container registry id in the comment.

That distinction matters because the file does things a general purpose base image should not. It installs from a project-specific opam switch, adds Python packaging tools through the system package manager, and sets the opam switch and PATH environment variables to point inside the image.

The structure is a deliberate caching split. Stage one copies only the opam files so the dependency layer is reused when the compiler changes, then stage two copies the whole repository and rebuilds. The image also sets `OCAMLRUNPARAM=b` so OCaml backtraces appear on failure, which is a debugging aid chosen for a container whose logs people actually read.

Editor support lives in three other repositories

Syntax highlighting for several text editors ships as scripts inside the repository, under `syntax_highlighting/`. Everything else is elsewhere. The VSCode extension comes from the marketplace and bundles a highlighter plus a dedicated language server that offers code navigation, auto-completion and a user experience for test suites, with its source in a separate repository. Code formatting comes from `catala-format`, a separate project built on a tree-sitter grammar for Catala that also lives in its own repository, and once installed it is wired into the editor.

Inside the tree, the highlighting side is the part with three languages: the Python packaging files are per-language directories for English, French and Polish, each with its own Pygments setup. Polish support in a French-origin project is the kind of detail that only shows up in the build files.

Compiler documentation is generated from the source with dune and odoc, so the online API documentation for the master branch is a build artifact rather than a hand-written site. Local generation is one command, `make doc`, after which the output is opened from `doc/odoc.html`. The rest of the repository's public metadata follows common conventions: `publiccode.yml`, `CITATION.cff`, a `CNAME` for the documentation site, Woodpecker for continuous integration, and a blame ignore list for the commits that reformatted the code.

Editorial conclusion

Catala fits research and public-sector teams who need an implementation of a socio-fiscal mechanism whose correspondence to the statute can be shown to the people who wrote the statute, and who are prepared to be reviewers rather than users. It does not fit a production deadline, because the project states plainly that the compiler is unstable and missing features, and because the formal certification is described as partial. Read four things first. Decide which release channel you want, since the release list mixes numbered versions with a rolling nightly entry whose listed build is older than 1.3.0. Budget for a toolchain that is bigger than the language suggests, with pandoc, groff, node, npm, ninja and python3 required by the build and two different opam CLI versions named in two different places. Expect to edit the compiler rather than wrap it, since a law-specification language will meet a statute shape the current scope rules do not cover. And read the limitations section before you promise anyone a certificate, because partial certification is not the same claim as a proof.

Frequently asked questions

What is Catala used for?

It is a domain-specific language for literate legislative programming: you annotate each line of legislative text with its meaning in terms of code, and the compiler derives an implementation that lawyers can review, including a lawyer-readable PDF of it.

Is the Catala compiler ready for production use?

The project says otherwise in its own words. Catala is a research project from Inria, and the compiler is described as yet unstable and lacking some of its features, with the formal certification described as partial.

What makes Catala different from an ordinary domain-specific language?

Default logic is built in as a first-class feature rather than added as a library, through the core concept of definition-under-conditions, which the project traces to a formalization by Professor Sarah Lawsky in an article titled A Logic for Statutes.

Which opam packages does the Catala repository publish?

Three: `catala.opam` for the compiler itself, `catala-js.opam` for the JavaScript side, and `catala-proof.opam` for the formalization, which the Makefile installs through a separate dependency target and which carries the Z3 dependency.

What do I need installed to build the Catala compiler?

The Makefile checks for groff, python3, node, npm, ninja and pandoc, warning about any that are missing, plus an opam switch created with the development setup. The Makefile invokes `opam --cli=2.1` while the Dockerfile uses `opam --cli=2.2`.

Official sources

  1. CatalaLang/catala on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/catalalang-catala.svg)](https://hysenlabs.com/projects/catalalang-catala)