astral-chart-api

/home/avalon/.hermes/skills/astrology/astral-chart-api/SKILL.md · raw

Astral Chart API

Use this skill whenever the user asks for any of these:

Hard rule

Do not try to calculate timezone conversion or chart placements with local Python modules such as pytz, timezonefinder, flatlib, or Swiss Ephemeris inside the tenant. A Maya canary tenant once answered “I can't use the pytz module here” and then offered a generic summary; treat that as a regression. The correct behavior is to call the chart API first or clearly report that the chart service failed.

Astral Hermes tenants should use Alex's deployed chart service:

https://transit-list-demo.apps.poofc.com

If a chart calculation tool/API call is possible, make the API call before interpreting. Do not tell the user “I can’t use pytz” and then offer a generic reading.

See references/maya-canary-chart-api-regression.md for the tenant regression that led to this rule and the astral-core@0.1.1 bundle fix.

Available endpoints

GET /api/health
GET /api/time/resolve?date=YYYY-MM-DD&time=HH:mm[:ss]&location=LOCATION
GET /api/time/resolve?date=YYYY-MM-DD&time=HH:mm[:ss]&timezone=IANA_ZONE
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
GET /api/chart/svg?date=YYYY-MM-DD&time=HH:mm[:ss]&location=LOCATION
GET /api/chart/svg?utc=day/month/year/hour/minute/second&coordinates=LAT%20LON
GET /api/chart/svg?...&highlight=Body1,Body2
GET /api/chart/svg?...&transit=day/month/year/hour/minute/second&highlight=NatalBody,TransitBody
GET /api/transits/current

/api/chart/svg returns SVG. Telegram usually needs PNG/JPEG for inline image delivery, so use the helper script in this skill to convert SVG to PNG and reply with MEDIA:/absolute/path.png.

Tenant KB autosave (Phase 4)

After any successful chart compute, persist to the tenant KB so the next reading can recall_person and load_chart instead of recomputing or re-asking for birth data.

# Determine person slug (recall first; create if new)
KB=~/.hermes/skills/astrology/astral-tenant-kb/scripts/kb.py
python3 $KB recall_person "$NAME" >/tmp/p.json
# If null, then:
python3 $KB save_person "$SLUG" --name "$NAME" --birth '{"date":"...","time":"...","location":"...","utc":"...","coordinates":"...","tz":"..."}'

# Compute via /api/chart, then:
python3 $KB save_chart "$SLUG" --chart "@/tmp/chart.json" --birth "@/tmp/birth.json"
# Returns {"hash": "..."} — pass this hash into astrology-reading-compose so the saved reading
# carries chart_hash frontmatter (required for A/B comparison).

Rules: - Idempotent by chart_hash — if load_chart returns a hit, skip recompute. - Never write a chart without a person slug. - This step is owned by the compose layer in normal reading flow, not by raw /api/chart calls. The chart-image helper script does not autosave (charts get cached only when tied to a known person).

Some older Magi/Astral code paths may still reference https://astrodataserver.com/chart or /draw. If those fail with TLS errors such as CERT_HAS_EXPIRED, do not bypass certificate validation. Move the integration to the self-hosted chart service instead:

Chart images in Telegram

When a chart image would help — natal chart, birth chart, aspect explanation, global transit wheel, biwheel/current transits — generate and send an image, not just text.

Telegram delivery rule:

Helper script:

node ~/.hermes/skills/astrology/astral-chart-api/scripts/chart-image-for-telegram.mjs \
  --date 1985-09-26 \
  --time 07:14 \
  --location 'London, UK' \
  --name Alex \
  --json

Implementation note: this script now renders SVG→PNG with local @resvg/resvg-js from the skill directory, not ImageMagick. If it fails with Cannot find module '@resvg/resvg-js', run npm install in ~/.hermes/skills/astrology/astral-chart-api/. It uses /home/avalon/apps/svghanddraw/backend/assets/astro-font/astro-webfont.ttf by default; override with --astro-font /path/to/astro-webfont.ttf if needed.

The script writes files under:

~/.hermes/astral-chart-images/

It prints JSON with:

{ "pngPath": "/absolute/path.png", "svgPath": "/absolute/path.svg", "media": "MEDIA:/absolute/path.png" }

Then send the image by placing the MEDIA: value in the final Telegram response.

Polished styling path: svghanddraw

Alex's chart styling repo is:

https://github.com/firemountain/svghanddraw
/home/avalon/apps/svghanddraw

Use this repo as the styling reference when chart images need to look good. See references/svghanddraw-styling.md for the customization JSON schema, the Telegram-clean recipe, and why the shipped default.json preset is wrong for delivery. Its method is not “make the stock SVG CSS louder”; it:

  1. gets the raw chart SVG,
  2. parses SVG elements/classes with xmldom,
  3. identifies planets/signs/houses/aspects from SVG class names,
  4. renders onto Canvas through Rough.js,
  5. applies preset/customization JSON for roughness, opacity, fill/stroke, hachures, and targeted highlights,
  6. exports PNG/WebP for delivery.

For local POCs, use raw SVG from transit-list-demo, not astrodataserver.com. A working raw-source test script exists at:

/tmp/render-svghanddraw-from-transit.mjs

It writes:

~/.hermes/astral-chart-images/alex-raw-svg-transit-list-demo-through-svghanddraw.svg
~/.hermes/astral-chart-images/alex-raw-svg-transit-list-demo-through-svghanddraw.png

If future work needs production integration, port the svghanddraw/backend/chartService.js fetch layer from legacy /draw and /chart to:

GET https://transit-list-demo.apps.poofc.com/api/chart/svg?...  # raw SVG
GET https://transit-list-demo.apps.poofc.com/api/chart?...      # JSON

Do not add heavy styling rules into transit-list-demo itself. Keep transit-list-demo as the canonical raw SVG/data provider and apply visual rendering downstream.

Known svghanddraw/raw-SVG rendering pitfalls discovered with transit-list-demo:

Highlighted natal aspects

The chart renderer already supports Magi-style aspect highlighting through the third argument to engine.svg([chart1, chart2?, highlight]). The public SVG endpoint exposes that as highlight=Body1,Body2.

Use it when the answer is about a specific natal aspect:

node ~/.hermes/skills/astrology/astral-chart-api/scripts/chart-image-for-telegram.mjs \
  --date 1985-09-26 \
  --time 07:14 \
  --location 'London, UK' \
  --highlight 'Sun,Saturn' \
  --label 'Alex Sun Saturn aspect' \
  --json

For a single natal chart, highlight=Sun,Saturn highlights both bodies and the aspect line between them if the aspect exists under the service's orb rules.

Highlighted transit-to-natal aspects

For transits, the chart service draws a biwheel when transit= is supplied. Internally the SVG renderer treats chart1 as natal and chart2 as transit, so the highlight order for a biwheel must be:

highlight=NatalBody,TransitBody

This is intentionally different from the user-facing transit label, which should stay:

transiting body → aspect → natal body

Example: for user-facing Mercury Opposition natal Saturn, draw with highlight=Saturn,Mercury:

node ~/.hermes/skills/astrology/astral-chart-api/scripts/chart-image-for-telegram.mjs \
  --utc '26/9/1985/6/14/0' \
  --coordinates '51.5072178 -0.1275862' \
  --transit '14/5/2026/21/14/28' \
  --highlight 'Saturn,Mercury' \
  --label 'Mercury Opposition natal Saturn' \
  --json

Global transit aspect charts

For global/current transits, omit natal data and use --utc now or a specific UTC date as the single chart. Highlight in normal chart order:

node ~/.hermes/skills/astrology/astral-chart-api/scripts/chart-image-for-telegram.mjs \
  --utc now \
  --highlight 'Jupiter,Saturn' \
  --label 'current Jupiter Saturn global aspect' \
  --json

Astrology knowledge-base topology

This skill is one piece of a 3-KB stack that backs every astrology reading. See references/astro-knowledge-topology.md for the full map (Astro Sources Wiki at /home/avalon/astro-sources-wiki with base id astro-sources, Human Design wiki, and the per-user/tenant KB prototype at ~/.hermes/astral-kb-prototype/knowledge/). The legacy /home/avalon/wiki path no longer exists — do not reference it.

Required workflow for natal charts

  1. Extract birth date, local time, and location from the user's message.
  2. If anything is missing, ask for the missing field concisely.
  3. If the user gave a complete local date/time/location, call:
curl -sS 'https://transit-list-demo.apps.poofc.com/api/chart?date=YYYY-MM-DD&time=HH:mm&location=ENCODED_LOCATION'
  1. Use returned placements/points/houses from the API as source truth.
  2. Mention the resolved timezone/UTC conversion if present.
  3. Then interpret using Alex's astrology style, especially traditional rulership chains.

Required workflow for current transits

Call:

curl -sS 'https://transit-list-demo.apps.poofc.com/api/transits/current'

If comparing current transits to a natal chart, calculate the natal chart first, then compare aspects/positions returned by the API.

Response style

For a user who asks “generate my chart” or “make Kathleen's chart,” do this:

  1. Confirm the data used.
  2. Say the chart was calculated through the Astral chart service.
  3. Give compact placements first: - Sun - Moon - Ascendant - MC - key clusters / standout aspects if available
  4. Then give interpretation.
  5. Avoid giant generic disclaimers.

Failure behavior

If the API call fails:

Bad:

I can't use pytz here, but I can still interpret your chart...

Good:

I need the chart service to calculate the actual placements. The location/time lookup failed; can you give me the IANA timezone, e.g. America/Toronto, or should I retry with “Toronto, Ontario, Canada”?

Example

User:

Generate a chart for Kathleen Brown, October 19 1994, 2:34 PM, Toronto Ontario.

Call:

curl -sS 'https://transit-list-demo.apps.poofc.com/api/chart?date=1994-10-19&time=14:34&location=Toronto%2C%20Ontario%2C%20Canada'

Then interpret from the API output, not from memory or guesswork.