Add JSON output format and a separate interpreter binary
deck-engine gains --format json (language-independent, slug-based) so a new dist/interpreter-cli can score how significant a day's transits are without linking the engine itself — it depends only on the JSON shape, via its own minimal parser. Also documents the full reading pipeline end to end (CLAUDE.md, README, docs/) and adds docs/reading.md, a non-technical explanation of what a daily reading contains and means.
This commit is contained in:
@@ -2,9 +2,11 @@
|
||||
|
||||
See [`architecture.md`](architecture.md) for how these fit together.
|
||||
There are two ways to provide input (direct CLI flags, or `run.sh` +
|
||||
`user.properties`) and two output formats (`text`, `html`); the
|
||||
`DailyReading` struct is the programmatic form both outputs are rendered
|
||||
from, and the one the future watchapp will consume directly.
|
||||
`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
|
||||
|
||||
@@ -13,7 +15,7 @@ from, and the one the future watchapp will consume directly.
|
||||
```
|
||||
deck-engine --seed <string> --birth-date YYYY-MM-DD --birth-time HH:MM
|
||||
--birth-utc-offset <hours> --birth-lat <deg> --birth-lon <deg>
|
||||
[--date YYYY-MM-DDTHH:MM] [--format text|html]
|
||||
[--date YYYY-MM-DDTHH:MM] [--format text|html|json]
|
||||
```
|
||||
|
||||
| Flag | Required | Format | Meaning |
|
||||
@@ -25,7 +27,7 @@ deck-engine --seed <string> --birth-date YYYY-MM-DD --birth-time HH:MM
|
||||
| `--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` | Output format, defaults to `text`. |
|
||||
| `--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 `<code>.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>.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). |
|
||||
|
||||
@@ -156,3 +158,93 @@ cards rendered as an image:
|
||||
image links.
|
||||
- Reversed cards get `class="reversed"`, styled with `transform:
|
||||
rotate(180deg)` in the page's inline CSS.
|
||||
|
||||
### `--format json`
|
||||
|
||||
A single JSON object mirroring `DailyReading` exactly — `natal`,
|
||||
`transits`, `spread` — using the **slug** accessors
|
||||
(`astro_body_slug()`, `astro_sign_slug()`, `astro_moon_phase_slug()`,
|
||||
`astro_aspect_slug()`, `tarot_card_slug()`, `tarot_position_slug()`)
|
||||
rather than the display-name ones, so the output is identical regardless
|
||||
of `--lang` — this is the one format meant for another program to parse
|
||||
(`dist/interpreter-cli`, see "The interpreter" below), not for a human to
|
||||
read.
|
||||
|
||||
```json
|
||||
{
|
||||
"natal": {
|
||||
"bodies": [
|
||||
{"body": "sun", "sign": "taurus", "degree_in_sign": 23.4926, "ecliptic_longitude": 53.4926, "house": 3},
|
||||
...
|
||||
],
|
||||
"ascendant_longitude": 348.4123,
|
||||
"houses": ["pisces", "aries", ...]
|
||||
},
|
||||
"transits": {
|
||||
"bodies": [
|
||||
{"body": "sun", "sign": "cancer", "degree_in_sign": 11.5012, "ecliptic_longitude": 101.5012, "house": 5},
|
||||
...
|
||||
],
|
||||
"moon_phase": "waning_gibbous",
|
||||
"aspects": [
|
||||
{"transiting_planet": "sun", "natal_planet": "moon", "type": "opposition", "orb": 3.7021},
|
||||
...
|
||||
]
|
||||
},
|
||||
"spread": {
|
||||
"positions": [
|
||||
{"position": "present", "card": "high_priestess", "reversed": true},
|
||||
...
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `bodies` is always `NUM_BODIES` (10) entries, Sun..Pluto in `Body` enum
|
||||
order; `spread.positions` is always `TAROT_SPREAD_SIZE` (10) entries in
|
||||
`CelticCrossPosition` enum order (Present, Challenge, Crown,
|
||||
Foundation, Recent Past, Near Future, Attitude, Environment, Hopes and
|
||||
Fears, Outcome — see `CLAUDE.md`'s "Tarot" section for why that's not
|
||||
the order most tutorials use).
|
||||
- `natal.houses[i]` is the sign occupying whole-sign house `i + 1`;
|
||||
`houses[0]` is the Ascendant's own sign. `transits.bodies[*].house` is
|
||||
a house number (1-12) into the **natal** chart, not a fresh "houses for
|
||||
right now" chart — same rule as the `text`/`html` output.
|
||||
- All angles are decimal degrees, `%.4f`. `aspects` may be an empty array
|
||||
(a valid "no aspects today"), but the key itself is always present.
|
||||
|
||||
## The interpreter (`interpreter/`, `dist/interpreter-cli`)
|
||||
|
||||
`dist/interpreter-cli` is a separate binary — see `CLAUDE.md`'s
|
||||
"Interpretation" section for the full architecture — that reads a
|
||||
`--format json` document and scores how significant today's transits
|
||||
are. It never links the engine; it only depends on the JSON shape
|
||||
above.
|
||||
|
||||
```bash
|
||||
dist/deck-engine ... --format json | dist/interpreter-cli
|
||||
# or:
|
||||
dist/deck-engine ... --format json > reading.json
|
||||
dist/interpreter-cli reading.json
|
||||
```
|
||||
|
||||
- **Input**: a file path argument, or stdin if no argument (or `-`) is
|
||||
given. Only `"transits"."aspects"` is read — `natal` and `spread` may
|
||||
be present (and are ignored) or omitted entirely, except that
|
||||
`"transits"."aspects"` itself must be present (an empty array is valid
|
||||
and means "no notable transits today"; a missing key is treated as
|
||||
invalid input).
|
||||
- **Output**: a plain-text report — the day's overall significance level
|
||||
(`Quiet`/`Notable`/`Significant`/`Major`), a "worth a deeper Celtic
|
||||
Cross look" line on `Major` days only, and up to 5 of today's aspects
|
||||
ranked by score:
|
||||
|
||||
```
|
||||
Day significance: Significant
|
||||
(a major transit today - worth a deeper Celtic Cross look)
|
||||
|
||||
Top 3 significant transits:
|
||||
1. Transiting Saturn Square natal Sun (orb 0.5°, score 8.10)
|
||||
2. Transiting Pluto Opposition natal Moon (orb 0.2°, score 7.92)
|
||||
3. Transiting Jupiter Trine natal Venus (orb 2.1°, score 3.40)
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user