# lectio `lectio` is a self-contained Go rewrite of the Python `daily-reading` tool (`ewangelia.py`). It **computes** the day's Catholic liturgical calendar and readings entirely offline — Ordinary Form (modern) or Extraordinary Form (1962) — and shows the text across four public-domain scripture corpora with correct psalm versification. There is no network dependency at all: the calendar, the lectionary citations, and the scripture corpora are all embedded in the binary. Three binaries share the same config and reading pipeline: - **`lectio`** — the CLI (daily readings, version compare, passage lookup, calendar export) - **`lectio-ui`** — a colored, scrollable Bubble Tea terminal reader - **`lectio-web`** — a local HTMX browser UI (bundled, no CDN — works offline) ## Install ```sh make build # ./lectio, ./lectio-ui, ./lectio-web in the current directory make install # builds and installs all three to $PREFIX/bin (default ~/.local/bin) make uninstall # removes them again ``` `PREFIX` can be overridden, e.g. `make install PREFIX=/usr/local`. Cross-compiled binaries for linux/darwin (amd64+arm64) and windows/amd64 land in `dist/` via `make cross`. Requires Go 1.24+ to build. No other dependencies (`go.mod` only pulls in Bubble Tea/Lipgloss for the TUI and go-toml for config parsing). ## `lectio` — the CLI ``` lectio [today] [--all] [--raw] [--width N] [--refresh] lectio date D [--all] [--raw] [--width N] [--refresh] D = YYYY-MM-DD lectio show VERSION [--date D] [--all] [--raw] [--width N] [--refresh] lectio compare LIST [--date D] [--all] [--width N] [--refresh] [--raw] lectio update [--days N] [--from D] lectio --version | -v lectio help | -h | lectio -h ``` Versions (all embedded, public-domain): `wuj` (Wujek), `vul` (Wulgata), `grb` (Grecki), `drb` (Douay-Rheims). Flags: - `--lectionary new|traditional` — override config `lectionary` for this run - `--ui-lang pl|en` — override the interface/citation language for this run - `--all` — show every reading part (1st/2nd reading, psalm, acclamation, gospel); default is the gospel only, unless config `all = true` - `--raw` — omit the banner/headings (for piping) - `--width N` — wrap width; `0` detects the terminal width, else falls back to 80 (120 for `compare`) Exit codes: `0` ok, `1` runtime error, `2` usage error. ### Subcommands `today` (also the default with no subcommand) — the gospel (or `--all`) for today, in the config's `default_version`: ```sh lectio lectio today --all --width 100 ``` `date D` — same, for an arbitrary date: ```sh lectio date 2026-12-25 --all ``` `show VERSION` — one version's text, defaulting to today: ```sh lectio show wuj --date 2026-12-25 ``` `compare LIST` — several versions side by side (LIST is comma-separated; falls back to config `versions` if omitted): ```sh lectio compare wuj,drb --date 2026-04-05 ``` ### Calendar API — JSON & iCal Emit the computed liturgical calendar (day identity + reading citations) as JSON or iCal, offline. Honours the config's form (OF/EF) and custom calendar layers. ```sh lectio 2026-01-06 --format json # one day, JSON lectio --format ical --year 2026 > lectio-2026.ics # a year, iCal feed lectio --format json --from 2026-01-01 --to 2026-01-31 # a range lectio --format ical --year 2026 --form new # override the form ``` `lectio-web` also serves the same data for `webcal://` subscription: - `GET /api/calendar.json?date=…` or `?from=&to=` or `?year=` (+ optional `&form=old|new`) - `GET /calendar.ics?year=…` or `?from=&to=` — served as `text/calendar` - `GET /source` — plain-text source offer (see [License](#license)) The web endpoints validate every input and cap a request's span at ~5 years (1830 days); JSON carries a stable `"schema": "lectio.calendar/1"`. Both feeds also carry `source` / `license` (JSON) and `X-LECTIO-SOURCE` / `X-LECTIO-LICENSE` (iCal), so a subscriber who never opens the HTML UI still gets the AGPL source offer. If you fork lectio and run it as a service, set `config.SourceURL` to your own repository. ## `lectio-ui` — the terminal reader ```sh lectio-ui ``` A full-day, scrollable, colored view built on Bubble Tea. Key bindings: | Key | Action | |---|---| | `tab` / `shift+tab` | cycle to next/previous version | | `←` / `→` | previous/next day | | `j`/`↓`, `k`/`↑` | scroll down/up one line | | `space` / `b` | page down/up | | `g` / `G` | jump to top/bottom | | `q` / `ctrl+c` | quit | Colors are a fixed light/dark-adaptive palette (Catppuccin-style, not configurable per instance): the heading is accented, the citation line is faint, verse numbers are muted, verse text is the default foreground, and the header/footer bars use an inverted background. Colors degrade automatically to plain text when `NO_COLOR` is set or the terminal doesn't support them. ## `lectio-web` — the browser UI ```sh lectio-web ``` Starts a local HTTP server, prints its URL, and best-effort opens it in your default browser (failure to open — headless box, no browser — is silent; just visit the printed URL). The port comes from config `web_port`: `0` (the default) tries `1099` first, then falls back to any free OS-assigned port if `1099` is taken; a non-zero value binds that port exactly and fails if it's already in use. All static assets (htmx, base CSS, theme CSS) are embedded in the binary and served locally — there is no CDN, so the page works fully offline once running. Page controls: - **Date navigation** — a date picker plus `←`/`→` buttons - **Lekcjonarz (lectionary)** — new vs traditional, same as `--lectionary` - **Version checkboxes** — wuj/vul/grb/drb, independent of any one visitor's config - **Zakres (all-parts toggle)** — gospel-only vs every part, same as `--all` - **Układ (display mode)** — horizontal / vertical / interlinear, see below - **Motyw (theme picker)** — swaps the theme stylesheet client-side instantly, no server round trip ### Display modes (`web_display`) - **horizontal** (default) — each version's text stacked in its own block under a shared heading - **vertical** — the same per-version text laid out as side-by-side columns, like the CLI's `compare` - **interlinear** — every version interleaved verse-by-verse by chapter:verse ## Configuration Config file: `~/.config/lectio/config.toml` (XDG-aware; auto-seeded with the built-in defaults on first run), or the path in `$LECTIO_CONFIG` if set. An invalid file falls back to defaults with a warning on stderr. ```toml schema_version = 1 lectionary = "new" # "new" (Ordinary Form) or "traditional" (Extraordinary Form, 1962) versions = ["wuj", "vul", "grb", "drb"] # compare set + TUI cycle order default_version = "vul" # TUI start / `lectio show` default width = 0 # CLI wrap width; 0 = detect terminal all = false # default to all parts (true) or just the gospel (false) reading_version = "" # force a reading corpus (e.g. "wuj", "drb"); blank = auto/Latin web_theme = "transfiguration" # built-in order/season theme or a user theme in ~/.config/lectio/themes/ web_port = 0 # lectio-web port; 0 = try 1099, then any free port web_display = "horizontal" # lectio-web layout: "horizontal" (stacked), "vertical" (columns), "interlinear" (verse-by-verse) # Which parts to show. Both tables are commented out -> every part is shown. # Uncomment a table and set a part to false to hide it; parts you don't list # stay shown. (Parsed as a map: a part is hidden only if explicitly false.) # # [parts.new] # pierwsze_czytanie = true # 1. czytanie (1st reading) # psalm = true # Psalm # drugie_czytanie = true # 2. czytanie (2nd reading, on feasts) # aklamacja = true # Aklamacja (acclamation) # ewangelia = true # Ewangelia (gospel) # # [parts.traditional] # introitus = true # Introit # oratio = true # Collect # lectio = true # Epistle # graduale = true # Gradual / Alleluia / Tract # evangelium = true # Gospel # offertorium = true # Offertory # secreta = true # Secret # communio = true # Communion # postcommunio = true # Postcommunion ``` CLI flags (`--lectionary`, `--ui-lang`, `--all`, …) and `lectio-web` query parameters override the corresponding config values for that run/request only; the file itself is never rewritten. ## Themes `lectio-web` ships 14 built-in, colour-only themes (they set colours — with all spacing, borders and layout fixed in `base.css`). Each theme now also sets a distinct typeface — serif variants (plain, old-style, classic or Iowan), humanist sans, or plain sans — so themes are told apart by face as well as palette, on top of which a monospace reading face can be turned on for any theme (see `web_mono` and the "mono" top-bar toggle below): Religious orders: `transfiguration` (dark, gold/olive, serif — the default), `desert_fathers` (light, sand/umber, Iowan serif), `benedictines` (dark, black/gold, old-style serif), `franciscans` (dark, brown/terracotta, humanist sans), `memento_mori` (dark, bare monospace — no role colours, just plain text), `dominicans` (black & white, classic serif). Liturgical seasons and feasts: `advent` (dark violet, classic serif), `nativity` (light white/gold, old-style serif), `lent` (dark ashen violet, serif), `easter` (light radiant gold, Iowan serif), `pentecost` (red/white/gold, humanist sans), `ordinary` (light green, sans), `epiphany` (dark indigo/gold, serif), `marian` (light blue/white/gold, old-style serif). Set the default with `web_theme` in config, or pick one live from the "motyw" dropdown in the browser UI. To write your own theme, drop a CSS file defining the required role variables/classes (`--bg`, `--fg`, `.heading`, `.citation`, `.vnum`, `.refrain`, link colours, border colours — see `docs/THEMES.md` for the full list and a template) at: ``` ~/.config/lectio/themes/.css ``` Restart (or reload) `lectio-web`; `` appears in the theme list and overrides any built-in theme of the same name. ## Offline by design Everything ships in the binary — there is no cache, no harvest step, and no network access. For any date, `lectio` computes the liturgical day (season, precedence, calendar of saints) and resolves its reading citations from the embedded lectionary tables, then renders the verse text from an embedded scripture corpus. Reading citations are stored in English-canonical form; the Psalms are renumbered per corpus (Hebrew→Vulgate for `wuj`/`vul`/`grb`, kept modern for `drb`), and the citation shown in the heading is formatted in your sigla dialect (`sigla_style` / `ui_language`). The reading text comes from the configured `reading_version` (else the corpus that matches your language, else the complete Latin Vulgate). Where the chosen corpus lacks a passage, the `-L`/liturgy view falls back to the Latin Vulgate, which carries the full canon. > The modern Polish text (Biblia Tysiąclecia) is copyrighted and cannot be > embedded; the public-domain Polish corpus is Wujek (`wuj`), which is > ~16th-century and incomplete. Set `reading_version = "wuj"` for Polish text, > or keep the default Latin Vulgate for a complete, consistent reading. ## Lectionaries Both are computed offline from the embedded calendar engine and lectionary data — no external service: - **new** (default) — the Ordinary Form (post-1969) calendar and lectionary, with the 3-year Sunday cycle (A/B/C) and 2-year weekday cycle (I/II). - **traditional** — the Extraordinary Form (1962 Roman Missal): the temporal and sanctoral of the day with its epistle and gospel. Switch per run with `--lectionary new|traditional`, or set `lectionary` in config for a permanent default. ## License Copyright (C) 2026 Łukasz Kasprzak lectio is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Because this is the **Affero** GPL, section 13 applies to `lectio-web`: if you run a modified version and let people reach it over a network, you must offer those users the source of your modified version. Full text in `LICENSE`; third-party data attributions in `NOTICE`.