# Input & output formats See [`architecture.md`](architecture.md) for how these fit together. There are two ways to provide input (direct CLI flags, or `run-engine.sh` + `user.properties`) and three output formats (`text`, `html`, `json`); the `DailyReading` struct is the programmatic form all three are rendered from, and the one the future watchapp will consume directly. `json` is also `interpreter-cli`'s input format — see "The interpreter" at the bottom of this file. ## Input ### Direct CLI flags (`dist/deck-engine`) ``` deck-engine --seed --birth-date YYYY-MM-DD --birth-time HH:MM --birth-utc-offset --birth-lat --birth-lon [--date YYYY-MM-DDTHH:MM] [--format text|html|json] ``` | Flag | Required | Format | Meaning | |---|---|---|---| | `--seed` | yes | any string | Tarot seed. The same seed always produces the same 10-card spread, positions, and orientations (see `rng.c`/`tarot.c`). | | `--birth-date` | yes | `YYYY-MM-DD` | Birth date, local calendar. | | `--birth-time` | yes | `HH:MM` (24h) | Birth time, local clock. | | `--birth-utc-offset` | yes | decimal hours, e.g. `2` or `-5.5` | Hours to **subtract** from local birth time to get UTC (e.g. `2` for CEST). | | `--birth-lat` | yes | decimal degrees | Birth latitude, north positive. | | `--birth-lon` | yes | decimal degrees | Birth longitude, east positive. | | `--date` | no | `YYYY-MM-DDTHH:MM[:SS]` | UTC moment used for today's transits and as the moment the tarot seed is drawn against. Defaults to the current system time. | | `--format` | no | `text` \| `html` \| `json` | Output format, defaults to `text`. `json` always uses language-independent identifiers, ignoring `--lang`. | | `--lang` | no | language code, e.g. `en`, `de` | Reading language, defaults to `en`. Matches a file named `.lang` in `--i18n-dir` (see "Translations" below). Unknown codes or missing files fall back to English with a warning on stderr. | | `--i18n-dir` | no | path | Directory to look for `.lang` in. Defaults to an `i18n/` directory next to the binary itself (resolved from `argv[0]`, so `dist/deck-engine` finds `dist/i18n/` regardless of the caller's working directory). | Birth latitude/longitude only affect the Ascendant/houses — planet signs are geocentric and location-independent. ### `run-engine.sh` + `user.properties` `dist/run-engine.sh [text|html|json] [lang]` wraps the binary for daily use: - **Seed and `--date`** come from the OS clock: `date +%Y-%m-%d` (stable all day) and `date -u +%Y-%m-%dT%H:%M`. - **Birth data and language** are read from `dist/user.properties`, a `key=value` properties file next to the script (`#`-prefixed lines and blank lines are comments; whitespace around `=` is trimmed): ```properties birth_date=1990-05-14 birth_time=14:32 birth_utc_offset=2 birth_lat=52.5200 birth_lon=13.4050 lang=en ``` The file is seeded once from `engine/scripts/user.properties.template` with placeholder values (`YOUR_BIRTH_DATE_HERE`, etc.). `run-engine.sh` checks every birth field for an empty value or a leftover `YOUR_` placeholder and refuses to run with a clear error until the file is filled in; `lang` has no such check since it always has a usable default (`en`). Since `dist/` itself can be wiped (`make clean`, or deleting the directory), the build also keeps a durable backup at `engine/scripts/user.properties.local` (gitignored) once the file looks filled in, and restores from it if `dist/user.properties` is ever missing — see `CLAUDE.md`'s "Build & run". - The optional second argument overrides `lang=` for a single run without editing the file, e.g. `dist/run-engine.sh html de`. - `dist/run-interpreter.sh` (no arguments) is the equivalent wrapper for the interpreter: same OS clock + `user.properties` inputs, but calls `deck-engine --format json` and pipes it straight into `dist/interpreter-cli` — see "The interpreter" below. ### Translations (`--lang`, `dist/i18n/`) Every piece of display text — planet/sign/moon-phase/aspect names, tarot card names and meanings, Celtic Cross position names, and the section headers in the `text`/`html` output — is looked up in a translation catalog with the built-in English text as the fallback for any key the catalog doesn't have. See `CLAUDE.md`'s "Translations" section for the key-naming convention and how to add a new language. `engine/i18n/en.lang` and `de.lang` are the shipped translation files; `make` copies `engine/i18n/*.lang` to `dist/i18n/` (refreshed on every build, like `dist/img/`). Adding a language is just dropping another `.lang` file into `engine/i18n/` — no code changes needed. ## Output ### `DailyReading` (the real output — `reading.h`) `reading_generate()` is the actual API; `text`/`html` below are just two ways of rendering the struct it fills in. This is what the watchapp will read directly once it exists. ```c typedef struct { NatalChart natal; DailyTransits transits; CelticCrossSpread spread; } DailyReading; ``` - **`NatalChart`** (`astro.h`): `bodies[10]` (Sun..Pluto, each a sign + degree-in-sign + raw ecliptic longitude + whole-sign `house` 1-12), `ascendant_longitude`, `houses[12]` (whole-sign: `houses[0]` is the Ascendant's sign). - **`DailyTransits`** (`astro.h`): `bodies[10]` (today's positions, same shape as above — `house` here is the natal chart's house the transiting planet currently occupies, not a fresh "houses for right now" chart), `moon_phase` (one of 8 named phases), `aspects[]` + `aspect_count` (each aspect names a transiting planet, a natal planet, an `AspectType` — conjunction/sextile/square/trine/opposition — and the orb in degrees). - **`CelticCrossSpread`** (`tarot.h`): `positions[10]`, indexed by `CelticCrossPosition` (Present, Challenge, Crown, Foundation, Recent Past, Near Future, Attitude, Environment, Hopes and Fears, Outcome — Waite's own drawing order), each holding a `TarotCard` and a `reversed` bool. ### `--format text` Four `=====`-delimited sections, in order: natal chart (each body's sign + degree + house, then the Ascendant), today's sky (Moon phase, then each body's transiting position + the natal house it currently occupies), today's aspects to the natal chart (one line per aspect, with orb), and the Celtic Cross (one block per position: name, card, `(Reversed)` if applicable, the position's meaning, then the card's meaning). ``` ===== Natal Chart ===== Sun 23.5° Taurus (House 3) Moon 15.2° Capricorn (House 11) ... Ascendant 18.4° Pisces ===== Today's Sky ===== Moon phase: Waning Gibbous Sun 11.5° Cancer (House 5) ... ===== Today's Aspects to Natal Chart ===== Transiting Sun Opposition natal Moon (orb 3.7°) ... ===== Celtic Cross ===== The Present The High Priestess (Reversed) This covers him: the general influence affecting the matter. Passion, moral or physical ardour, conceit, surface knowledge. ... ``` ### `--format html` A single self-contained HTML page (inline `