This skill is the local Hermes workflow for turning Alex's transit-list-demo code into reusable transit context and calendar feeds.
It supports two complementary use cases:
The canonical local store is:
~/.hermes/astral-transits/
├── astral-transits.js # generator script
├── profiles/alex.json # Alex profile/natal UTC metadata
├── events/*.json # structured events for Hermes context/RAG
├── calendars/*.ics # Apple/Google import/subscription files
└── reports/*.md # mobile-readable summaries
Use this skill when Alex asks for:
.ics feed for Apple Calendar or Google CalendarDo not invent transit times. Use transit-list-demo via the generator or API.
Local code:
/home/avalon/apps/transit-list-demo
Public API:
https://transit-list-demo.apps.poofc.com
Useful existing API endpoints:
GET /api/health
GET /api/transits/current
GET /api/time/resolve?date=YYYY-MM-DD&time=HH:mm[:ss]&location=LOCATION
GET /api/chart?date=YYYY-MM-DD&time=HH:mm[:ss]&location=LOCATION
GET /api/chart?utc=day/month/year/hour/minute/second&coordinates=LAT%20LON
Important implementation finding: server.js currently exposes current/chart endpoints, but not a dedicated HTTP scan endpoint for date-range transit calendars. Date-range scanning exists in the CLI / Program.scan(start, stop, natal) path. Use the local generator for calendars until a /api/transits/scan endpoint is added.
Confirmed Alex profile file:
~/.hermes/astral-transits/profiles/alex.json
Confirmed birth data:
Date: 1985-09-26
Local time: 07:14:00
Location: London, UK
Timezone: Europe/London
UTC: 1985-09-26T06:14:00.000Z
transit-list-demo natalUtc: 26/9/1985/6/14/0
Coordinates: 51.5072178, -0.1275862
Source: Alex confirmed this in Telegram on 2026-05-13. UTC was resolved through transit-list-demo /api/time/resolve.
Generate global + Alex transit datasets and .ics feeds for the rest of 2026:
~/.hermes/astral-transits/astral-transits.js --kind both --start 2026-05-13 --end 2027-01-01
Generate a full calendar year:
~/.hermes/astral-transits/astral-transits.js --kind both --year 2026
Generate global-only:
~/.hermes/astral-transits/astral-transits.js --kind global --start 2026-06-01 --end 2026-07-01
Generate Alex-only:
~/.hermes/astral-transits/astral-transits.js --kind alex --start 2026-06-01 --end 2026-07-01
Include Moon if Alex explicitly wants a high-volume calendar or a high-frequency timing dataset for strategy research/trading experiments:
~/.hermes/astral-transits/astral-transits.js --kind both --year 2026 --include-moon
For crypto/market-timing research, the Moon should usually be treated as an execution-timing layer rather than a background calendar layer: use Moon ingresses, degree pulses, applying/separating aspects, and translations as frequent testable triggers, with Sun/Mercury/Venus as setup windows and Mars/Saturn/Jupiter as regime filters.
Default planet set excludes Moon for normal calendar signal/noise and excludes South Node because it is always opposite True North Node and creates duplicate node-opposition spam:
Sun, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto, True North Node
The generator writes:
~/.hermes/astral-transits/events/global-START_to_END.json
~/.hermes/astral-transits/events/alex-START_to_END.json
~/.hermes/astral-transits/events/combined-START_to_END.json
~/.hermes/astral-transits/events/current-transits.json
~/.hermes/astral-transits/calendars/global-START_to_END.ics
~/.hermes/astral-transits/calendars/alex-START_to_END.ics
~/.hermes/astral-transits/reports/report-START_to_END.md
JSON is the canonical Hermes context store. ICS is a calendar interchange/export artifact.
Each JSON event has this shape:
{
"id": "global-20260602T224842Z-Sun-Sextile-Saturn",
"kind": "global",
"profileId": null,
"title": "Sun Sextile Saturn",
"summary": "Global transit: Sun Sextile Saturn",
"startUtc": "2026-06-02T22:48:42.000Z",
"endUtc": "2026-06-02T22:48:42.000Z",
"allDay": false,
"eventType": "aspect",
"aspect": "Sextile",
"orb": "exact",
"planet1": "Sun",
"planet2": "Saturn",
"position1": { "degree": 12, "minute": 24, "second": 25, "sign": "Gemini", "longitude": 72.407 },
"position2": { "degree": 12, "minute": 24, "second": 25, "sign": "Aries", "longitude": 12.407 },
"source": "transit-list-demo",
"raw": { }
}
Ingress events use:
{
"eventType": "ingress",
"planet1": "Mercury",
"planet2": "Cancer",
"title": "Mercury enters Cancer"
}
Apple Calendar / Google Calendar can import .ics files directly. For ongoing sync, expose ~/.hermes/astral-transits/calendars/ via a stable HTTPS path, then subscribe to those URLs from calendar clients.
Recommended future hosting path if needed:
https://astral-transits.apps.poofc.com/calendars/global-current.ics
https://astral-transits.apps.poofc.com/calendars/alex-current.ics
For now, deliver or copy the .ics files manually from:
~/.hermes/astral-transits/calendars/
After every generator run, mirror the outputs into astral-tenant-kb so reading skills can pick them up by slug + range.
KB=~/.hermes/skills/astrology/astral-tenant-kb/scripts/kb.py
RANGE=2026-05-13_to_2027-01-01
# global window
python3 $KB save_global_transits $RANGE --json ~/.hermes/astral-transits/events/global-${RANGE}.json
# per-person window
python3 $KB save_transit_profile alex $RANGE --json ~/.hermes/astral-transits/events/alex-${RANGE}.json
python3 $KB save_transit_calendar alex $RANGE --ics ~/.hermes/astral-transits/calendars/alex-${RANGE}.ics
Hard rules:
- Only mirror after the existing transit-first label normalization passes verification (see "Reading Transits into a Hermes Reply" step 4–6).
- range_id format: YYYY-MM-DD_to_YYYY-MM-DD — used as the filename suffix.
- The original ~/.hermes/astral-transits/ tree remains the working set; the KB mirror is the per-person canonical store that reading skills consult.
For a concise mobile response:
If Alex asks for transits as part of another person's reading package, interpret current transits to that subject's natal chart, not Alex's transits. Use the subject's saved natal chart JSON when available, fetch current transits with curl -sS https://transit-list-demo.apps.poofc.com/api/transits/current, then compute major aspects from transiting planets to natal planets/angles with sensible orbs (rough defaults: Moon 1.5°, Mercury/Venus/Mars/Nodes 2°, Sun 2.5°, Jupiter/Saturn 3°, Uranus/Neptune/Pluto 2.5°). Lead with exact/high-impact overlays and synthesize them back into the natal + HD themes.
text
~/.hermes/astral-transits/reports/report-START_to_END.mdstartUtc date.kind=global from kind=alex.kind=alex aspect events, the generator must normalize labels and fields to transiting body → natal body. The raw upstream transit-list-demo scan may emit natal body first because it searches p1 = natal longitude, p2 = transiting planet; keep that raw object only under raw for audit, never as the user-facing title/summary/ICS label.body1Role: "transit", body2Role: "natal", transitPlanet, and natalPlanet before interpreting or importing into downstream knowledge bases. Do not rely on a visually corrected title alone; validate the role fields (planet1 === transitPlanet, planet2 === natalPlanet) so stale natal-first copies fail fast.~/.hermes/astral-transits/events/*.json after normalization and then search both the source store and KB for stale labels such as Saturn Opposition Mercury.Astral Hermes loading states (provisioning spinner, chat stalls, etc.) use a filler-caption layer fed by the daily transit pipeline. The pipeline emits a small captions array alongside the JSON events, and the web app serves it from /api/daily-captions. See chat-interface-development SKILL.md → "Filler caption layer" for the consuming UI shape.
Caption generation rules (Alex called the first-pass invented filler "dumb and cheesy" — these are hard rules):
events/current-transits.json / events/global-*.json) for use before a tenant exists, and per-tenant captions (transits to that person's natal chart, from transits/profiles/<slug>-<range>.json) for use inside a tenant.Pipeline shape:
/data/hermes/astral-daily/global-<timestamp>.json with { generatedAt, transits: {...}, captions: [...] }.GET /api/daily-captions → global captions.<tenant_kb>/transits/daily/<date>.json with natal-overlay captions.GET /api/daily-captions?tenant=<id> → tenant-specific if available, else falls back to global.Caption template examples (templatically derived from JSON, not hand-written one-shots):
"Moon ${deg}° ${sign} — ${signRuler}'s domicile, ${decanRuler}-faced decan.""Day of ${dayRuler}. Moon waxing through ${moonSign}.""${planet} ${deg}° ${sign} — ${face}, ${faceRuler}'s decan." (per visible inner planet)"${transit_planet} applying ${aspect} natal ${natal_planet} (${orb}° orb)." (tenant-only)"${count} planets in ${modality} signs." (when ≥3 share a modality)Generator script lives at astral-hermes-platform/scripts/daily-transits.mjs (planned). It should accept --natal <utc-string> --coordinates <lat lon> to emit per-tenant overlays; without those args, it emits global-only.
node --check ~/.hermes/astral-transits/astral-transits.js passes.{ "ok": true }..ics files contain BEGIN:VCALENDAR and VEVENT entries.Mercury Opposition Saturn), and stale natal-first summaries (e.g. Saturn Opposition Mercury) are absent from generated JSON/ICS/Markdown copies.references/alex-2026-transit-ordering-kb-import.md — session-specific root cause, verification, and downstream KB import guard for natal-first raw scan output./api/transits/current for a date range. That endpoint only gives current positions. Use the local generator/CLI scan.day/month/year/hour/minute/second in UTC.26/9/1985/6/14/0 UTC date string. Do not use recovered/demo SVG values or any unconfirmed Alex birth data..ics at a stable URL and subscribing to it.