Architecture
The packages are layers, not alternatives. A real app threads a birth event through all of them; each does one job and hands a plain object to the next.
place + local time
→ caelus-birth resolve IANA zone from coordinates, local → UT (DST-safe)
→ caelus positions, houses, aspects from the UT instant
→ caelus-wheel SSR-safe SVG wheel from the chart object
→ caelus-mcp (optional) the same engine, exposed as AI tools
Only caelus-birth carries runtime dependencies (timezone data); the core
engine stays zero-dependency and I/O-free, and the wheel renders to a string.
That split is why the same chart code runs in the browser, on edge, in Node,
and behind MCP.
One component, end to end
This is the whole pipeline in a single server component — birth input to rendered wheel, with the timezone resolved for you:
localToChart resolves the IANA zone from the coordinates, converts the local
time to UT, and runs engine.chart — returning the chart plus a status
(ok, ambiguous, or nonexistent) so DST edge cases surface instead of
silently producing a wrong chart. See
Edge Cases & Stability for those cases.
Where each package fits
| Layer | Package | Input → output | Runtime deps |
|---|---|---|---|
| Time & place | caelus-birth | local time + coords → UT + zone + status | tz data |
| Engine | caelus | UT instant + location → chart object | none |
| Render | caelus-wheel | chart object → SVG string | none |
| Agents | caelus-mcp | MCP tool call → chart payload | MCP SDK |
Start from the template
caelus-starter is this exact
pipeline as a deployable Next.js app: a birth form, caelus-birth timezone
handling, a server-rendered caelus-wheel, and an optional reading route. Clone
it rather than wiring the layers from scratch.
See the Quickstart for the engine alone, the MCP Setup for the agent layer, and Recipes for queries and event search. Electional Search threads this same pipeline through a richer use case: scanning a window for the best moment, not just rendering one fixed instant.