--- name: total-divination description: "Composite divination reading combining I Ching cast, single tarot pull, and current transit snapshot into one synthesized reading. Use when the user asks for a 'full reading', 'total divination', 'everything', or a multi-oracle session." version: 1.0.0 author: Hermes Agent + Alex license: MIT metadata: hermes: tags: [divination, composite, iching, tarot, transits, multi-oracle] related_skills: [iching-api-reading, tarot-single-card, astral-transit-snapshot, astrology-reading-compose] --- # Total Divination ## When to use Use when the user asks for a **composite / full divination reading** — anything like: - "give me a total divination" - "full reading" - "do the works" - "I Ching + tarot + transits" - "everything you've got" This is an orchestrator that runs three oracles and **synthesizes them into one coherent reading**, not three readings glued together. ## Parameters - **`context`** *(optional, string)* — what the reading is about. Passed through to all three oracles. Example: `"about the project I'm launching this week"`, `"about my creative life right now"`. When absent, all three oracles do open/general readings. - **`subject`** *(optional)* — whose chart the transit snapshot is measured against (default: the user). Routed through `astral-tenant-kb` disambiguation if a non-self person is named. - **`include`** *(optional)* — subset of `[iching, tarot, transits]`. Default: all three. ## Component skills This orchestrator **invokes the three component skills as-is** — it does not re-implement their logic. Load and follow each: 1. `skill_view(name='iching-api-reading')` — six-cast hexagram reading via `iching-study` app at `:4017`. 2. `skill_view(name='tarot-single-card')` — single cryptographic card draw from alexTarot deck JSON. 3. `skill_view(name='astral-transit-snapshot')` — exact-now transit→natal aspects + fast-mover layer. Each component skill keeps its own RNG/API discipline, time anchoring, and pitfall rules. The composite does **not** override them. ## Composite image (parallel) A composite divination image is built **in parallel** with the text synthesis. As soon as the three calculations (six casts resolved, card drawn, transits ranked) are done, fire-and-forget a background process that renders the PNG while you write the reading. The user receives both: the image as a `MEDIA:` attachment, the text as the message body. **Renderer:** `scripts/compose-divination.py` (in this skill's directory). Reads a JSON input file, writes a PNG. Render time ~0.2s on a small composite, fully programmatic (Pillow + the astro-font TTF), no image generator. **Alex's strong preference: build divination/astro composites programmatically — never with an image generator.** Do not propose AI-generated drafts for this composite; if visual direction is unclear, iterate on the Pillow script. **Glyph key** for transit rows: see `references/astro-glyph-key.md`. **Design rules locked in (do not regress these):** - Background `#f7f3ec` parchment, ink `#1a1a1a`, highlight `#E85D2C` (changing-line bars only). - Hexagram bars stacked bottom-up (`lines[0]` = line 1 = bottom). Solid for yang (7/9), broken with center gap for yin (6/8). Changing lines (totals 6 or 9) drawn in highlight; relating hexagram in default ink only — its changes are already shown on the primary. - Arrow `→` between primary and relating, large (~100pt), only rendered when changing lines exist. - Hexagram label format: `#NN · English · Chinese` (e.g. `#21 · Shih Ho · 噬嗑`) — serif ~30pt, CJK ~34pt, English name kept short (no slash-suffixed alternative names). - Transit rows: strict 4-column grid (A: transit planet+sign, B: aspect, C: natal planet+sign, D: annotation). **Symbol block A+B+C is centered on the canvas**; annotation D floats to the right of C and does NOT participate in centering. This is what makes the composition beautiful — Alex's explicit call. - **Planet glyphs full size; sign glyphs ~75% of planet size and drawn in muted gray `(140,130,120)`** so signs sit politely without competing. Aspect glyph at planet size. - **Mars glyph (`J`) is rendered ~83% of normal planet size** — the astro font's Mars sits oversized in its viewbox and dominates other planets otherwise. There's a `mars_font` constant and a `planet_font(ch)` selector that switches per-glyph. If new planet glyphs ever show similar viewbox quirks, extend that selector pattern — don't try to rescale everything globally. - Glyphs drawn via `draw_baseline()` helper so per-glyph bbox bottoms align to a shared baseline (the astro font has inconsistent vertical metrics). - Annotation column D: orb + `applying`/`separating` + ` · in ~Nh` or ` · Nd ago` time-to-exact, in muted gray sans ~13pt. The orchestrator computes `eta_str` from `orb / daily_speed × 24h`; the script just renders it. **Iteration history note:** Each visual refinement Alex requested (bigger labels → bigger arrow → column-justified grid → centered symbol block → smaller gray signs → Mars special-case) compounded — never revert a prior fix when applying a new one. Read the current state of `compose-divination.py` before patching. **Execution pattern (inside the orchestrator's `execute_code` block):** ```python import json, subprocess, tempfile, os, pathlib # After the three oracle calculations have resolved: composite_input = { "tarot": {"image_path": "/home/avalon/apps/alexTarot/public/cards/" + card["img"], "name": card["name"], "reversed": bool(rev)}, "iching": { "primary": {"number": prim["number"], "displayName": prim["displayName"], "chineseName": prim["chineseName"], "character": prim["character"]}, "relating": ({"number": rel["number"], "displayName": rel["displayName"], "chineseName": rel["chineseName"], "character": rel["character"]} if reading["changingLineNumbers"] else None), "lines": [{"total": L["total"], "changing": L["changing"]} for L in reading["lines"]], "changingLineNumbers": reading["changingLineNumbers"], }, "transits": [ {"transit_planet": h["tb"], "transit_sign": , "aspect": h["a"], "natal_planet": h["nb"], "natal_sign": , "orb_str": f"{int(h['orb'])}°{int(round((h['orb']-int(h['orb']))*60)):02d}'", "tag": h["tag"]} for h in top_aspects[:5] ], } # Write input + spawn renderer in background — do not wait tmp_in = tempfile.NamedTemporaryFile('w', suffix='.json', delete=False) json.dump(composite_input, tmp_in); tmp_in.close() out_png = f"/tmp/divination-composite-{os.getpid()}.png" script = "/home/avalon/.hermes/skills/astrology/total-divination/scripts/compose-divination.py" proc = subprocess.Popen(["python3", script, "--input", tmp_in.name, "--output", out_png]) # ... continue with text synthesis ... # At the end, wait briefly for the renderer (it's ~0.2s): proc.wait(timeout=5) assert os.path.exists(out_png) and os.path.getsize(out_png) > 50_000 print("COMPOSITE:", out_png) ``` The composite path is included in the final reply as `MEDIA:` — **placed at the very top of the message** (replacing the bare tarot card image — the composite already contains the card). **Skip rules:** - If the renderer fails for any reason, the reading still ships — just fall back to the bare tarot `MEDIA:` line. Never block the text on the image. - If `include` excludes any oracle, omit its zone from the composite (script handles missing `iching` or `transits` gracefully — pass empty/null). ## Required workflow ### 1. Time + subject + context - Capture local + UTC wall-clock time once at the top of the run (reuse across all three). - Resolve subject (default: user; otherwise disambiguate via `astral-tenant-kb`). - Note `context` verbatim if supplied. ### 2. Run all three oracles in parallel where possible Inside one `execute_code` block, do: - `POST /api/divination/throw-line` six times (with 1–3s gaps) + `POST /api/divination/reading` → I Ching result. - `secrets.choice` on the alexTarot deck JSON + reversal roll → tarot result. - `GET /api/transits/current` + load/compute natal chart + local aspect computation → transit result. The randomized I Ching gaps are still required (ritual gap, not a perf concern). Tarot and transits don't need gaps. Print all three structured results, then compose the reply. ### 3. Compose — the synthesis is the point The reply is **one composite reading**, not three sections stapled together. Each oracle gets a compact "card" of its derivation, but the headline is a **synthesis paragraph that triangulates all three** — looking for resonance, tension, or commentary between them. Examples of resonance to listen for: - I Ching's primary hexagram theme echoed in the tarot card's archetype. - Transit's headline aspect matching the moving-line inflection ("change pressure" in both). - Tarot reversal mirroring a separating/applying transit's direction. - All three pointing at the same life-area when a `context` was supplied. Examples of tension worth surfacing: - I Ching says "stay low" while tarot pulls a fiery upright card → the synthesis names the tension instead of forcing a single message. - Transits show release/separating while I Ching shows building moving lines → time-layering: outer field releasing, inner field still gathering. Never invent resonance that isn't there. If the three feel unrelated, say so — and lean on whichever oracle had the strongest signal (tightest transit orb / clearest moving lines / unambiguous tarot draw). ## Reply formatting Strict order, mobile-readable: 1. **Composite image at the very top.** `MEDIA:` — absolute first line of the reply, nothing before it. The composite already contains the tarot card, both hexagrams (with changing lines highlighted + arrow to relating), and the transit glyph rows. If the composite renderer failed, fall back to `MEDIA:/home/avalon/apps/alexTarot/public/cards/` (bare tarot card) — never ship without an image. 2. **Header line (italic).** Subject · local time (UTC) · `context` if supplied. > *Alex · 2026-05-23 08:24 PDT (15:24 UTC) · context: "about launching this week"* 3. **🎴 Tarot · 🪙 I Ching · 🔭 Transit — one-line slate.** A single compact slate line naming what was drawn, before any interpretation: > **🎴 The Tower (reversed) · 🪙 ䷽ 62 Hsiao Kuo → ䷞ 31 Hsien · 🔭 headline: Uranus □ natal Moon (0°13′, applying)** 4. **✨ The Synthesis (the headline section).** 4–8 sentences. This is the reading. Triangulate the three oracles into one coherent present-moment picture. If `context` was supplied, anchor the synthesis there. End with a **bold one-to-three-sentence one-breath summary**. 5. **Component cards (below the synthesis — derivation).** Three compact sub-sections, each shorter than its standalone version because the synthesis already carried the meaning: **🪙 I Ching** — show the cast stack (line 6 top, line 1 bottom), the hexagram header glyph + number + name (English / Chinese / pinyin) + relating hexagram if changing lines exist, then a 2–4 sentence interpretation. Moving-line text(s) quoted for changing lines. **🎴 Tarot** — bold card name header (with "— Reversed" if applicable), arcana · suit · number line, 2–3 sentence reading. Tie back to the context if any. **🔭 Transit** — top 3 exact-now aspects as bullets (transit-first format with orb in degrees/minutes and applying/separating tag if confident), a 1–2 line fast-layer note (Moon/Mercury/Venus/Sun/Mars highlights + any 48h ingress), and a 2–3 sentence interpretation focused on the tightest aspect. 6. **🌬️ One breath (final).** Single bold sentence distilling the composite. May repeat or refine the synthesis closer. ## Pitfalls - **Don't repeat content.** If the synthesis already named the tension, the component cards should be shorter — not restated paragraphs. - **Don't fabricate resonance.** Three oracles often *don't* agree. Honest divergence is a real reading; forced unity isn't. - **Don't drop component rigor.** The I Ching cast must use the app API. The tarot draw must use `secrets.choice`, never `random`. The transit snapshot must use real positions from `/api/transits/current` + a real natal chart. No mental shortcuts. - **Tarot image always first.** Telegram needs the `MEDIA:` line at the top of the reply. - **Honor `context` everywhere or nowhere.** If context is supplied, all three component readings reflect it. If absent, all three read openly — don't invent a focus for any of them. - **Subject default = user.** For non-self subjects, disambiguate via `astral-tenant-kb` before running the transit snapshot. I Ching and tarot are generally querent-agnostic, but if you're reading *for* someone else, say so in the header. - **Time-anchor once.** Compute local + UTC at the start and reuse — don't let the three oracles capture different timestamps. - **No "folk" language.** Match Alex's style: professional astrologer voice, traditional rulerships, no woo padding. ## Verification - All three component APIs reachable (`iching-study :4017`, `alexTarot :4033`, `transit-list-demo`). - Tarot draw uses `secrets`, not `random`. - I Ching reading run via real six-cast sequence, not synthesized. - Transit snapshot orbs match `astral-transit-snapshot` table (snapshot orbs, not calendar orbs). - Synthesis paragraph references all included oracles (or honestly notes divergence).