Getting Started

Common Tasks

Short recipes for the things people, and AI agents, ask for most. Each returns plain structured data, positions, houses, dignities, dates, with no interpretation; that layer is yours. For the engine itself see Computing Charts; to drive it from a chat agent over MCP, jump to For agents below.

Every recipe assumes an engine:

setup.ts
import { Engine, julianDay } from "caelus";
import { embeddedData } from "caelus/data-embedded";

const engine = new Engine(embeddedData);
const jd = julianDay(2026, 6, 14); // a Julian Day (UT) to work from

Event search (stations, ingresses, rise/set) wants the fuller Node data tier; see Data Tiers for loading it.

Cast a natal chart

chart() takes calendar fields in UT and a place. It returns the bodies (each enriched with its house and dignities), the angles, the twelve cusps, and the aspects found among the bodies.

natal.ts
// 1990-06-10 14:30 UT, Tampa FL (27.95 N, 82.46 W), Placidus houses
const chart = engine.chart(1990, 6, 10, 14, 30, 0, 27.95, -82.46, "placidus");

chart.bodies.sun.lon;   // ecliptic longitude, degrees
chart.angles.asc;       // Ascendant, degrees
chart.cusps;            // [house 1, ..., house 12], degrees
chart.aspects.length;   // aspects within the active orbs

Which house is a planet in?

Each body in a chart carries its 1-based house, so there's nothing to recompute from the cusps.

house.ts
const chart = engine.chart(1990, 6, 10, 14, 30, 0, 27.95, -82.46, "placidus");

chart.bodies.mars.house;   // e.g. 7
chart.bodies.moon.sign;    // e.g. "Cancer"

Essential dignities of a planet

Each body also carries the essential dignities it holds in its sign (domicile, exaltation, detriment, fall). The standalone dignities() answers the same for any body-in-sign without a chart.

dignities.ts
import { dignities } from "caelus";

const chart = engine.chart(1990, 6, 10, 14, 30, 0, 27.95, -82.46, "placidus");
chart.bodies.venus.dignities;  // e.g. ["domicile"]

dignities("mars", "Aries");    // ["domicile"]
dignities("sun", "Libra");     // ["fall"]

Score essential dignities (traditional)

For the full traditional treatment, dignityScore() weights all five dignities (Lilly: rulership 5, exaltation 4, triplicity 3, term 2, face 1; detriment -5, fall -4) for a planet at a longitude in a day or night chart, and almuten() finds the planet that rules a given degree most strongly.

dignity-score.ts
import { dignityScore, almuten } from "caelus";

dignityScore("venus", 32, "day"); // 2 Taurus, day
// { rulership: 5, triplicity: 3, term: 2, total: 10, peregrine: false, ... }

almuten(5, "day"); // ruler of 5 Aries by day -> { planet: "sun", score: 7 }

The aspects in a chart

chart.aspects is the list of aspects among the bodies, each with the two bodies, the aspect name, and the orb from exact.

aspects.ts
const chart = engine.chart(1990, 6, 10, 14, 30, 0, 27.95, -82.46, "placidus");

chart.aspects;
// [{ a: "sun", b: "moon", aspect: "trine", orb: 2.13 }, ...]

Detect aspect patterns

detectPatterns() finds the classical configurations, T-squares, grand trines, grand crosses, yods, kites, mystic rectangles, and stelliums by sign and house, as structured objects. Reported patterns are maximal: a grand cross hides the T-squares it contains. Orbs follow the engine defaults (plus a quincunx for yods) and are overridable.

patterns.ts
import { detectPatterns } from "caelus";

const chart = engine.chart(1990, 6, 10, 14, 30, 0, 27.95, -82.46, "placidus");

detectPatterns(chart);
// [{ kind: "mystic_rectangle", bodies: ["chiron","moon","pluto","venus"], orb: 2.54 }, ...]

Read a chart's signature

chartSignature() summarises a chart's structure as plain counts: element, modality, angularity, quadrant, and hemisphere distributions, plus the dominant element / modality / sign and the classical chart ruler. Counts only, no interpretation.

signature.ts
import { chartSignature } from "caelus";

const chart = engine.chart(1990, 6, 10, 14, 30, 0, 27.95, -82.46, "placidus");

const sig = chartSignature(chart);
sig.elements;   // { fire: 1, earth: 6, air: 1, water: 3 }
sig.dominant;   // { element: "earth", modality: "cardinal", sign: "Capricorn" }
sig.ruler;      // "sun" (ruler of the Ascendant's sign)

When does a planet next station?

stations() returns the retrograde and direct stations in a window, each as [jd, direction].

stations.ts
import { stations } from "caelus";

stations(engine, "mercury", jd, jd + 365);
// [[2461190.4, "retrograde"], [2461214.1, "direct"], ...]

When does a planet change sign (ingress)?

A sign ingress is a longitude crossing of a sign cusp (a multiple of 30°). crossings() returns every JD a body crosses the target longitude in the window.

ingress.ts
import { crossings } from "caelus";

// Mars entering Gemini (60 degrees), within the next ~2 years
const [next] = crossings(engine, "mars", 60, jd, jd + 800);

Lunar phases in a window

phases.ts
import { lunarPhases } from "caelus";

lunarPhases(engine, jd, jd + 90);
// [[jd, "new"], [jd, "first_quarter"], [jd, "full"], ...]

Transits to a natal chart

when() answers "when is this configuration true?" over a range. To find when a transiting planet aspects a natal point, take that point's longitude from the natal chart and search for the aspect. Each result is an [jdStart, jdEnd] interval, the window the aspect holds within orb.

transits.ts
import { when, aspect, julianDay } from "caelus";

const natal = engine.chart(1990, 6, 10, 14, 30, 0, 27.95, -82.46, "placidus");
const start = julianDay(2026, 1, 1);
const end = julianDay(2027, 1, 1);

// transiting Mars conjunct the natal Sun, within 1 degree of exact
const windows = when(engine, aspect("mars", "conjunction", natal.bodies.sun.lon), start, end);
windows[0]; // [jdStart, jdEnd] of the first pass

Sunrise and sunset at a place

riseSet() returns the JD of the next event after jdStart, or null if it doesn't occur (e.g. polar day or night).

riseset.ts
import { riseSet } from "caelus";

// next sunrise and sunset over Tampa (27.95 N, 82.46 W) after jd
const sunrise = riseSet(engine, "sun", jd, 27.95, -82.46, "rise");
const sunset = riseSet(engine, "sun", jd, 27.95, -82.46, "set");

Parans (co-angular bodies)

parans() finds bodies that are simultaneously on the angles (rising, culminating, setting, anti-culminating) over a day at a latitude, within a stated tolerance. Latitude only; the daily pattern is longitude-independent.

parans.ts
import { parans } from "caelus";

parans(engine, jd, 27.95); // 30-minute window by default
// [{ a: "jupiter", a_angle: "rise", b: "mars", b_angle: "mtransit", gap_min: 20, ... }, ...]

The next solar return

solarReturn() returns the JDs in a window where the Sun returns to its natal longitude; pass the first into chartAt() for the return chart.

return.ts
import { solarReturn, julianDay } from "caelus";

const natalJd = julianDay(1990, 6, 10, 14, 30, 0);
const [returnJd] = solarReturn(engine, natalJd, jd, jd + 366);
const returnChart = engine.chartAt(returnJd, 27.95, -82.46, "placidus");

A local birth time, done right

The core takes UT. Real birth times are local wall-clock, and a naive conversion silently lands the chart hours off. caelus-birth resolves the time zone from the coordinates offline and applies historical daylight-saving rules.

birth.ts
import { localToChart } from "caelus-birth";

// born 1988-02-14 08:15 local in London
const { chart, utc, zone } = localToChart(
{ year: 1988, month: 2, day: 14, hour: 8, minute: 15, lat: 51.5, lon: -0.12 },
engine,
"placidus",
);
chart.angles.asc; // computed from the correct UT instant

A Vedic snapshot: nakshatra and current dasha

Caelus is sidereal-aware. Take the Moon's longitude in a sidereal zodiac, read its nakshatra, and find the active Vimshottari period for a date. See Vedic & Jyotish for vargas, the other dashas, and the yogas.

vedic.ts
import { nakshatra, vimshottariActive, julianDay } from "caelus";

const birthJd = julianDay(1990, 6, 10, 14, 30, 0);
const moonLon = engine.longitude("moon", birthJd, { zodiac: "sidereal:lahiri" });

nakshatra(moonLon);                       // { name, pada, lord, ... }
vimshottariActive(moonLon, birthJd, jd);  // { maha, antar, pratyantar } for "now"

For agents over MCP

The same capabilities are exposed as MCP tools, so a chat agent can do real astrological work and get back structured, interpretation-free JSON, the agent supplies the meaning. Connect the server first (see MCP Setup), then reach for:

  • natal_chart / current_sky: a full chart (bodies with house and dignities, angles, cusps, aspects) for a moment and place.
  • transits: transiting bodies and the aspects they make to a natal chart.
  • find_aspect_dates: when a given aspect is exact across a date range.
  • sky_events: stations, ingresses, lunar phases, rise/set in a window.
  • synastry / composite: geometry between two charts.
  • dignities, void_of_course, planetary_hours, returns, progressions: the classical building blocks.
  • aspect_patterns / chart_signature: the named configurations (T-squares, grand trines, yods, stelliums) and a chart's element, modality, and quadrant counts with its ruler.
  • similar_skies, electional_search, cosmic_weather: when the sky last resembled a moment, the best window for a set of aspects, and a date's active configurations and stations.

Each tool returns numbers and structured objects, never an interpretation, so it composes cleanly into whatever reasoning or prose the agent is doing. The full list and schemas live in MCP Setup.

See also

  • Recipes for the advanced surface: the when() query language, configuration matching, and rendering a chart wheel.
  • Playground to run charts and wheels live in the browser.
  • API Reference for the full package surface.