# colitur *computus liturgicus* — a safe, highly-tested, deterministic engine that computes and validates liturgical calendars for multiple rites, with template-driven output. Starting with the Roman EF (1962) and OF forms; extensible to other traditions. Computes day-identity (season, celebration, rank, colour, cycle, precedence) and reading citations, correct to year 9999. See the design and rules research under `docs/` (local). ## Build ```sh opam switch create . 5.2.0 -y # first time: local OCaml switch opam install -y dune alcotest qcheck qcheck-alcotest sexplib ppx_sexp_conv dune build dune test # fast suite (~3s) COLITUR_EXHAUSTIVE_SWEEP=1 dune test --force # + every year 1583-9999 (~50s) dune exec colitur -- easter 2026 # Easter and its Easter-relative anchors dune exec colitur -- temporal 2026 # the EF temporal cycle only, one line per day dune exec colitur -- day 2026 # the full resolved EF calendar (temporal + sanctoral) ``` ## Rendering ```sh # The ordo booklet has a table of contents (page numbers via \pageref), so # it needs TWO pdflatex passes -- the first pass leaves every entry showing # "??"; the second resolves them. A single pass is not a bug in the # template, it is just an unfinished build. Either form works: dune exec colitur -- table --year 2027 --template templates/ef/ordo.tex > ordo.tex && pdflatex ordo.tex && pdflatex ordo.tex # or: latexmk -pdf ordo.tex # The wall calendar has no cross-references, so one pass is enough: dune exec colitur -- table --year 2027 --template templates/ef/grid.tex > grid.tex && pdflatex grid.tex dune exec colitur -- publish --from 2027 --to 2027 --out ./public ``` See `colitur-templates(5)` for the template format (syntax, escaping, the full field reference) and `colitur(1)` for `emit`, `table`/`render` and `publish` in full. ## Language Every command's output is names, not slugs, by default (`--raw` restores the bare-slug form). Start a new translation from the shipped Latin table, edit a couple of entries, check it, and render with it -- every line below is real, not transcribed: ```sh $ dune exec colitur -- lang --dump la > my-lang.ini $ sed -i \ -e 's/^ef-circumcision = .*/ef-circumcision = My Own Circumcision Text/' \ -e 's/^ef-epiphany = .*/ef-epiphany = My Own Epiphany Text/' \ my-lang.ini $ dune exec colitur -- lang --check my-lang.ini my-lang.ini: 725 of 725 celebrations named, 0 missing, 0 unknown $ dune exec colitur -- day 2026 --lang ./my-lang.ini | head -1 2026-01-01 thursday christmastide - ef-circumcision class-1 white My Own Circumcision Text ``` `--check` reports what a language file is still missing, and rejects any entry naming a slug that does not exist (a typo, otherwise silently dead). `colitur lang --list` shows what this build can find; `colitur config --show` shows the effective `--lang` (and every other setting) plus where it came from. See `colitur(1)`'s `NAMING` section and `colitur-config(5)` for both in full. ## License AGPL-3.0-or-later. See `LICENSE`.