# lectio `lectio` is a self-contained Go rewrite of the Python `daily-reading` tool (`ewangelia.py`). It fetches the day's Catholic liturgical readings and shows them across five scripture versions with correct psalm versification, and can run entirely offline once a date has been harvested. There are no external tool dependencies at runtime, and no network dependency at all in offline mode. Three binaries share the same config and reading pipeline: - **`lectio`** — subcommand CLI (`today`, `date`, `show`, `compare`, `update`) - **`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: `pl` (Polski, niedziela.pl), `wuj` (Wujek), `vul` (Wulgata), `grb` (Grecki), `drb` (Douay-Rheims). Global flags (any subcommand, any position): - `--offline` — skip the network, use cached/harvested data only - `--lectionary new|traditional` — override config `lectionary` for this run - `--lang pl|en` — override config `traditional_lang` for this run Per-command flags: - `--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`) - `--refresh` — bypass the cache and re-fetch - `--date D` — date as `YYYY-MM-DD` (`show`/`compare` only; default: today) Exit codes: `0` ok, `1` runtime error (fetch/parse), `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 pl,wuj,drb --date 2026-04-05 ``` `update [--days N] [--from D]` — harvest future dates' scripture citations into the offline sigla store (see "Offline mode" below); does not respect `--lectionary`/`--offline`, it always harvests the modern (niedziela.pl) lectionary: ```sh lectio update --days 30 ``` ## `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 | | `r` | refresh (re-fetch the current date) | | `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/paragraph text is the default foreground, a psalm's refrain line is italic, 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** — pl/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 - **Passage lookup** — a free-text reference box (e.g. `J 20:1`) rendered against the currently checked versions ### 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. `pl` cannot participate (niedziela.pl prose carries no verse numbers), so it is silently substituted with `wuj` (dropped entirely if `wuj` is already selected) ## 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" (niedziela.pl) or "traditional" (missalemeum, 1962) traditional_lang = "pl" # vernacular for traditional propers: "pl" or "en" versions = ["pl", "wuj", "vul", "grb", "drb"] # compare set + TUI cycle order default_version = "pl" # 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) offline = false # true = never fetch; read only harvested sigla + cache 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 (`--offline`, `--lectionary`, `--lang`) 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 fonts, spacing, borders and layout fixed in `base.css`). A theme may additionally set `--theme-font` to change the reading face, and 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 — the default), `desert_fathers` (light, sand/umber), `benedictines` (dark, black/gold), `franciscans` (dark, brown/terracotta), `memento_mori` (dark, greyscale, monospace), `dominicans` (black & white). Liturgical seasons and feasts: `advent` (dark violet), `nativity` (light white/gold), `lent` (dark ashen violet), `easter` (light radiant gold), `pentecost` (red/white/gold), `ordinary` (light green), `epiphany` (dark indigo/gold), `marian` (light blue/white/gold). 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 mode and `lectio update` Two data stores back offline use, both outside the config file: - **Cache** (`~/.cache/lectio/`) — parsed HTML/JSON of dates already fetched normally; used automatically before hitting the network. - **Sigla store** (`~/.local/share/lectio/sigla.tsv`) — just the section labels and scripture citations (no reading text) for dates harvested by `lectio update`. Workflow: while online, run ```sh lectio update --days 30 ``` to walk forward from today (or `--from D`) harvesting citations into the sigla TSV, stopping at niedziela.pl's unpublished horizon (or after `--days N` days; `0`, the default, means "until unpublished"). Later, with `offline = true` in config (or `--offline` on any command), reads come only from the cache/sigla store, never the network — and since the sigla store holds no `pl` text, `pl` is transparently substituted with `wuj` wherever a version list would otherwise include it (CLI, TUI, and `lectio-web`'s interlinear mode all apply this the same way). Offline mode currently only supports the "new" (modern) lectionary — `lectionary = traditional` combined with offline is rejected with an error, since traditional propers aren't harvested by `update`. ## Lectionaries - **new** (default) — scrapes the modern Polish lectionary from `niezbednik.niedziela.pl`, one page per day. - **traditional** — the 1962 Roman Missal's propers of the day, fetched from the `missalemeum.com` JSON API in either Polish or English (`traditional_lang` / `--lang`; no other language is supported). Switch per run with `--lectionary new|traditional`, or set `lectionary` in config for a permanent default. ## License MIT — see `LICENSE`.