Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Kerykeion

stars forks
PyPI Downloads PyPI Downloads PyPI Downloads
Package version Supported Python versions

⭐ Like this project? Star it on GitHub and help it grow! ⭐

John Lennon - Natal Chart

Kerykeion is a Python library for astrology. It computes planetary and house positions, detects aspects, and generates SVG charts, including birth, synastry, transit, and composite charts. You can also customize which planets to include in your calculations.

The main goal of this project is to offer a clean, data-driven approach to astrology, making it accessible and programmable.

Kerykeion also integrates seamlessly with LLM and AI applications.

Web API

If you want to use Kerykeion in a web application or for commercial or closed-source purposes, you can try the dedicated web API:

AstrologerAPI

It is open source and directly supports this project.

Table of Contents

Installation

Kerykeion requires Python 3.12 or higher.

pip3 install kerykeion

For more installation options and environment setup, see the Getting Started guide.

Note — supported date range. The default ephemeris data bundled with a fresh install covers the years 1849–2150 (JPL DE440s). Charts outside that range raise a KerykeionException until you install a wider data tier:

import libephemeris
libephemeris.download_leb_for_tier("medium")    # 1550–2650 (upper bound exclusive: through 2649-12-31)
libephemeris.download_leb_for_tier("extended")  # full range, incl. BCE dates

Quick Start

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

subject = AstrologicalSubjectFactory.from_birth_data(
    name="Example Person",
    year=1990, month=7, day=15,
    hour=10, minute=30,
    lng=12.4964,
    lat=41.9028,
    tz_str="Europe/Rome",
    online=False,
)

chart_data = ChartDataFactory.create_natal_chart_data(subject)
chart_drawer = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)

chart_drawer.save_svg(output_path=output_dir, filename="example-natal")
print("Chart saved to", (output_dir / "example-natal.svg").resolve())

This script shows the recommended workflow:

  1. Create an astrological subject via AstrologicalSubjectFactory with explicit coordinates and timezone (offline mode).
  2. Build a ChartDataModel through ChartDataFactory.
  3. Render the SVG via ChartDrawer, saving it to a controlled folder (charts_output).

Use the same pattern for synastry, composite, transit, or return charts by swapping the factory method.

📖 More examples: kerykeion.net/examples

Basic Usage

Below is a simple example illustrating the creation of an astrological subject and retrieving astrological details:

from kerykeion import AstrologicalSubjectFactory

# Create an instance of the AstrologicalSubjectFactory class.
# Arguments: Name, year, month, day, hour, minutes, city, nation
john = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Retrieve information about the Sun:
print(john.sun.model_dump_json())
# > {"name":"Sun","quality":"Cardinal","element":"Air","sign":"Lib","sign_num":6,"position":16.26789435029039,"abs_pos":196.2678943502904,"emoji":"♎️","point_type":"AstrologicalPoint","house":"Sixth_House","retrograde":false,"speed":0.9884519666546676,"declination":-6.39888585742412, ...}
# (additional fields omitted: ecliptic_latitude, nakshatra*, gauquelin_sector, azimuth, altitude_above_horizon, is_out_of_bounds, ...)

# Retrieve information about the first house:
print(john.first_house.model_dump_json())
# > {"name":"First_House","quality":"Cardinal","element":"Fire","sign":"Ari","sign_num":0,"position":19.72351854613349,"abs_pos":19.72351854613349,"emoji":"♈️","point_type":"House","house":null,"retrograde":null,"speed":886.503993869951, ...}
# (additional fields omitted: declination, nakshatra*, gauquelin_sector, azimuth, altitude_above_horizon, is_out_of_bounds, ...)

# Retrieve the element of the Moon sign:
print(john.moon.element)
# > 'Air'

# Whether the Sun stood above the horizon (day chart) or below it (night chart).
# Computed from the Sun's true geometric altitude — independent of the chart's
# zodiac and perspective, so the value holds for sidereal and heliocentric
# charts and at polar latitudes. Note the chart and report still omit the line
# for a heliocentric chart: the value is about the moment, but the drawing has
# no Sun on it to point at — the Sun is the centre body there and is excluded.
print(john.is_diurnal)
# > False

Working offline: pass online=False and specify lng, lat, and tz_str as shown above.
Working online: set online=True and provide city, nation, and a valid GeoNames username. Register for free at geonames.org. You can set the username via the KERYKEION_GEONAMES_USERNAME environment variable or the geonames_username parameter.

📖 Full factory documentation: AstrologicalSubjectFactory

To avoid GeoNames, provide longitude, latitude, and timezone and set online=False:

john = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    city="Liverpool",
    nation="GB",
    lng=-2.9833,  # Longitude for Liverpool
    lat=53.4000,  # Latitude for Liverpool
    tz_str="Europe/London",  # Timezone for Liverpool
    online=False,
)

Generate a SVG Chart

All chart-rendering examples below create a local charts_output/ folder so the tests can write without touching your home directory. Feel free to change the path when integrating into your own projects.

To generate a chart, use the ChartDataFactory to pre-compute chart data, then ChartDrawer to create the visualization. This two-step process ensures clean separation between astrological calculations and chart rendering.

📖 Chart generation docs: Charts Documentation

The info panel in the bottom-left corner reports the chart's diurnality — whether the Sun stood above the horizon (Diurnality: Diurnal) or below it (Diurnality: Nocturnal). Two-wheel charts report both wheels, since each keeps its own, and drop the heading to fit (Natal Nocturnal · Transit Diurnal; a synastry names the two subjects). The line is omitted where it has no referent: any chart not cast from the Earth — a heliocentric one excludes the Sun (it is the centre body), and a Marscentric or Selenocentric one draws a Sun that is not the one measured, since is_diurnal comes from a tropical geocentric Sun — and a midpoint composite, which represents no single sky. A solar arc direction is omitted too: it keeps the nativity's instant, so its value answers for the birth chart rather than for the wheel drawn from it. Pass show_diurnality=False to ChartDrawer to leave it out entirely — the panel then keeps exactly the spacing it had before the line existed.

Tip: The optimized way to open the generated SVG files is with a web browser (e.g., Chrome, Firefox). To improve compatibility across different applications, you can use the remove_css_variables parameter when generating the SVG. This will inline all styles and eliminate CSS variables, resulting in an SVG that is more broadly supported.

Birth Chart

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subject
john = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Pre-compute chart data
chart_data = ChartDataFactory.create_natal_chart_data(john)

# Step 3: Create visualization
birth_chart_svg = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
birth_chart_svg.save_svg(output_path=output_dir, filename="john-lennon-natal")

The SVG file is saved under charts_output/john-lennon-natal.svg.

📖 More birth chart examples: Birth Chart Guide

John Lennon Birth Chart

External Birth Chart

An "external" birth chart places the zodiac wheel on the outer ring, offering an alternative visualization style. external_view is a classic-style feature (the default modern style ignores it and logs a warning), so pass style="classic" explicitly:

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subject
birth_chart = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Pre-compute chart data for external natal chart
chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)

# Step 3: Create visualization with external_view=True (classic style only)
birth_chart_svg = ChartDrawer(chart_data=chart_data, external_view=True)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
birth_chart_svg.save_svg(output_path=output_dir, filename="john-lennon-natal-external", style="classic")

John Lennon External Birth Chart

Synastry Chart

Synastry charts overlay two individuals' planetary positions to analyze relationship compatibility:

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subjects
first = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)
second = AstrologicalSubjectFactory.from_birth_data(
    "Paul McCartney", 1942, 6, 18, 15, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Pre-compute synastry chart data
chart_data = ChartDataFactory.create_synastry_chart_data(first, second)

# Step 3: Create visualization
synastry_chart = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
synastry_chart.save_svg(output_path=output_dir, filename="lennon-mccartney-synastry")

📖 Synastry chart guide: Synastry Chart Examples

John Lennon and Paul McCartney Synastry

Transit Chart

Transit charts compare current planetary positions against a natal chart:

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subjects
transit = AstrologicalSubjectFactory.from_birth_data(
    "Transit", 2025, 6, 8, 8, 45,
    lng=-84.3880,
    lat=33.7490,
    tz_str="America/New_York",
    online=False,
)
subject = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Pre-compute transit chart data
chart_data = ChartDataFactory.create_transit_chart_data(subject, transit)

# Step 3: Create visualization
transit_chart = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
transit_chart.save_svg(output_path=output_dir, filename="john-lennon-transit")

📖 Transit chart guide: Transit Chart Examples

John Lennon Transit Chart

Solar Return Chart (Dual Wheel)

Solar returns calculate the exact moment the Sun returns to its natal position each year:

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.planetary_returns.factory import PlanetaryReturnFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create natal subject
john = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Calculate Solar Return subject (offline example with manual coordinates)
return_factory = PlanetaryReturnFactory(
    john,
    lng=-2.9833,
    lat=53.4000,
    tz_str="Europe/London",
    online=False
)
solar_return_subject = return_factory.next_return_from_date(1964, 10, 1, return_type="Solar")

# Step 3: Pre-compute return chart data (dual wheel: natal + solar return)
chart_data = ChartDataFactory.create_return_chart_data(john, solar_return_subject)

# Step 4: Create visualization
solar_return_chart = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
solar_return_chart.save_svg(output_path=output_dir, filename="john-lennon-solar-return-dual")

📖 Return chart guide: Dual Return Chart Examples

John Lennon Solar Return Chart (Dual Wheel)

Solar Return Chart (Single Wheel)

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.planetary_returns.factory import PlanetaryReturnFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create natal subject
john = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Calculate Solar Return subject (offline example with manual coordinates)
return_factory = PlanetaryReturnFactory(
    john,
    lng=-2.9833,
    lat=53.4000,
    tz_str="Europe/London",
    online=False
)
solar_return_subject = return_factory.next_return_from_date(1964, 10, 1, return_type="Solar")

# Step 3: Build a single-wheel return chart
chart_data = ChartDataFactory.create_single_wheel_return_chart_data(solar_return_subject)

# Step 4: Create visualization
single_wheel_chart = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
single_wheel_chart.save_svg(output_path=output_dir, filename="john-lennon-solar-return-single")

📖 Planetary return factory docs: PlanetaryReturnFactory

John Lennon Solar Return Chart (Single Wheel)

Lunar Return Chart

Lunar returns calculate when the Moon returns to its natal position (approximately monthly):

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.planetary_returns.factory import PlanetaryReturnFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create natal subject
john = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Calculate Lunar Return subject
return_factory = PlanetaryReturnFactory(
    john,
    lng=-2.9833,
    lat=53.4000,
    tz_str="Europe/London",
    online=False
)
lunar_return_subject = return_factory.next_return_from_date(1964, 1, 1, return_type="Lunar")

# Step 3: Build a dual wheel (natal + lunar return)
lunar_return_chart_data = ChartDataFactory.create_return_chart_data(john, lunar_return_subject)
dual_wheel_chart = ChartDrawer(chart_data=lunar_return_chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
dual_wheel_chart.save_svg(output_path=output_dir, filename="john-lennon-lunar-return-dual")

# Optional: create a single-wheel lunar return
single_wheel_data = ChartDataFactory.create_single_wheel_return_chart_data(lunar_return_subject)
single_wheel_chart = ChartDrawer(chart_data=single_wheel_data)
single_wheel_chart.save_svg(output_path=output_dir, filename="john-lennon-lunar-return-single")

John Lennon Lunar Return Chart (Dual Wheel)

John Lennon Lunar Return Chart (Single Wheel)

Composite Chart

Composite charts create a single chart from two individuals' midpoints to represent the relationship entity:

from pathlib import Path
from kerykeion import CompositeSubjectFactory, AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subjects (offline configuration)
angelina = AstrologicalSubjectFactory.from_birth_data(
    "Angelina Jolie", 1975, 6, 4, 9, 9,
    lng=-118.2437,
    lat=34.0522,
    tz_str="America/Los_Angeles",
    online=False,
)

brad = AstrologicalSubjectFactory.from_birth_data(
    "Brad Pitt", 1963, 12, 18, 6, 31,
    lng=-96.7069,
    lat=35.3273,
    tz_str="America/Chicago",
    online=False,
)

# Step 2: Create composite subject
factory = CompositeSubjectFactory(angelina, brad)
composite_model = factory.get_midpoint_composite_subject_model()

# Step 3: Pre-compute composite chart data
chart_data = ChartDataFactory.create_composite_chart_data(composite_model)

# Step 4: Create visualization
composite_chart = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
composite_chart.save_svg(output_path=output_dir, filename="jolie-pitt-composite")

📖 Composite factory docs: CompositeSubjectFactory

Angelina Jolie and Brad Pitt Composite Chart

Wheel Only Charts

For all the charts, you can generate a wheel-only chart by using the method save_wheel_only_svg_file():

📖 Minimalist charts guide: Wheel Only & Aspect Grid Charts

Birth Chart

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subject
birth_chart = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Pre-compute chart data
chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)

# Step 3: Create visualization
birth_chart_svg = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
birth_chart_svg.save_wheel_only_svg_file(output_path=output_dir, filename="john-lennon-natal-wheel")

John Lennon — Natal Chart (Wheel Only)

Wheel Only Birth Chart (External)

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subject
birth_chart = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Pre-compute external natal chart data
chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)

# Step 3: Create visualization (external wheel view, classic style only)
birth_chart_svg = ChartDrawer(chart_data=chart_data, external_view=True)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
birth_chart_svg.save_wheel_only_svg_file(
    output_path=output_dir, filename="john-lennon-natal-wheel-external", style="classic"
)

John Lennon — Natal Chart (External Wheel Only)

Synastry Chart

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subjects
first = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)
second = AstrologicalSubjectFactory.from_birth_data(
    "Paul McCartney", 1942, 6, 18, 15, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Pre-compute synastry chart data
chart_data = ChartDataFactory.create_synastry_chart_data(first, second)

# Step 3: Create visualization
synastry_chart = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
synastry_chart.save_wheel_only_svg_file(output_path=output_dir, filename="lennon-mccartney-synastry-wheel")

John Lennon and Paul McCartney Synastry

Change the Output Directory

To save the SVG file in a custom location, specify the output_path parameter in save_svg():

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subjects
first = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)
second = AstrologicalSubjectFactory.from_birth_data(
    "Paul McCartney", 1942, 6, 18, 15, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Pre-compute synastry chart data
chart_data = ChartDataFactory.create_synastry_chart_data(first, second)

# Step 3: Create visualization with custom output directory
synastry_chart = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
synastry_chart.save_svg(output_path=output_dir)
print("Saved to", (output_dir / f"{synastry_chart.first_obj.name} - Synastry Chart.svg").resolve())

Change Language

You can switch chart language by passing chart_language to the ChartDrawer class:

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subject
birth_chart = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Pre-compute chart data
chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)

# Step 3: Create visualization with Italian language
birth_chart_svg = ChartDrawer(
    chart_data=chart_data,
    chart_language="IT"  # Change to Italian
)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
birth_chart_svg.save_svg(output_path=output_dir, filename="john-lennon-natal-it")

You can also provide custom labels (or introduce a brand-new language) by passing a dictionary to language_pack. Only the keys you supply are merged on top of the built-in strings:

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

birth_chart = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)
chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)

custom_labels = {
    "PT": {
        "info": "Informações",
        "celestial_points": {"Sun": "Sol", "Moon": "Lua"},
    }
}

custom_chart = ChartDrawer(
    chart_data=chart_data,
    chart_language="PT",
    language_pack=custom_labels["PT"],
)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
custom_chart.save_svg(output_path=output_dir, filename="john-lennon-natal-pt")

📖 Language configuration guide: Chart Language Settings

The available languages are:

  • EN (English)
  • FR (French)
  • PT (Portuguese)
  • ES (Spanish)
  • TR (Turkish)
  • RU (Russian)
  • IT (Italian)
  • CN (Chinese)
  • DE (German)
  • HI (Hindi)

Minified SVG

To generate a minified SVG, set minify=True in the save_svg() method:

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subject
birth_chart = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Pre-compute chart data
chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)

# Step 3: Create visualization
birth_chart_svg = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
birth_chart_svg.save_svg(
    output_path=output_dir,
    filename="john-lennon-natal-minified",
    minify=True,
)

SVG without CSS Variables

To generate an SVG without CSS variables, set remove_css_variables=True in the save_svg() method:

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subject
birth_chart = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Pre-compute chart data
chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)

# Step 3: Create visualization
birth_chart_svg = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
birth_chart_svg.save_svg(
    output_path=output_dir,
    filename="john-lennon-natal-no-css-variables",
    remove_css_variables=True,
)

This will inline all styles and eliminate CSS variables, resulting in an SVG that is more broadly supported.

Grid Only SVG

It's possible to generate a grid-only SVG, useful for creating a custom layout. To do this, use the save_aspect_grid_only_svg_file() method:

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subjects
birth_chart = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)
second = AstrologicalSubjectFactory.from_birth_data(
    "Paul McCartney", 1942, 6, 18, 15, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Pre-compute synastry chart data
chart_data = ChartDataFactory.create_synastry_chart_data(birth_chart, second)

# Step 3: Create visualization with dark theme
aspect_grid_chart = ChartDrawer(chart_data=chart_data, theme="dark")

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
aspect_grid_chart.save_aspect_grid_only_svg_file(output_path=output_dir, filename="lennon-mccartney-aspect-grid")

John Lennon — Aspect Grid

Machine-readable point metadata

Rendered <g kr:node="ChartPoint"> elements expose stable kr: attributes for interactive consumers. On every dual wheel (Transit, Synastry, Dual Return, and Progression), kr:house remains the point owner's house and kr:horoscope identifies that owner ring. kr:projectedhouse gives the same point's house in the other subject's cusp system, while kr:projectedhoroscope identifies that target ring. The reciprocal metadata is available in classic/modern, full/wheel-only output even when house-comparison data or tables are disabled.

Each point also carries the physical state the model computed for it — kr:motionstate, kr:speed, kr:declination, kr:oob when the body is out of bounds, plus kr:magnitude, kr:nearpoint and kr:orb on fixed stars — and the chart-level analyses it takes part in: kr:angularity (one attribute listing every angle the point stands on, as Ascendant:0.8991 Medium_Coeli:4.3156, closest first) and kr:stellium. None of these are gated by a rendering option; the opt-in marks above only decide whether a reader sees them drawn. An attribute is absent when the model does not carry the value, so silence means "this chart does not compute it" rather than zero or false — a heliocentric chart states no motion state, a midpoint composite none at all. Attribute names are lowercase letters with no separators (motionstate, not motion_state), because consumers rewrite the namespace with a general pattern and a name carrying an underscore would be dropped silently. See the charts documentation for the full table.

Classic Chart Style

Since v6 the modern concentric-ring layout is the default chart style. The traditional classic wheel remains fully supported: set it at the instance level via ChartDrawer(chart_data=..., style="classic") or per-render via save_svg(style="classic"). Both styles work with all six themes.

Available style values: "modern" (default) and "classic".

Default filenames spell the style out: save_svg() writes "{name} - {chart type} Chart - Modern.svg", and with style="classic" it writes "... - Classic.svg" (wheel-only output uses " - Modern Wheel Only" / " - Classic Wheel Only").

Info-panel keyword arguments (every chart type, both styles):

Parameter Type Default Description
show_diurnality bool True Print the chart's diurnality (Sun above or below the horizon) in the bottom-left info panel. Constructor only — there is no save_svg() override

Modern-only keyword arguments (ignored by the classic style):

Parameter Type Default Description
show_zodiac_background_ring bool True Draw colored zodiac wedges as the outer zodiac annulus around the cusp ring
glyph_size str "medium" Size of the planet cluster — glyph, degrees, sign, minutes and ℞. "small" is the medium cluster at 90%; "large" draws the planet glyph at the classic style's own size — 24px single / 19.2px dual at the default page with the zodiac background ring active, for glyphs at optical weight 1.0 (the per-glyph map stays applied; with the ring off the whole modern wheel, cluster included, draws 1/0.92 larger at every size). On the dual rings parity belongs to the glyph alone: the reading follows the single wheel's ×1.248 progression, so the dual numerals never outgrow the single wheel's. Overridable per render

Dual-chart keyword arguments (Synastry, Transit, Composite, Dual Return):

Parameter Type Default Description
double_chart_aspect_grid_type str "list" Aspect grid layout: "list" (compact vertical list) or "table" (traditional cross-reference grid)

Classic-only constructor arguments (ignored by the modern style, which logs a warning when they are set):

Parameter Type Default Description
external_view bool False Place planets outside the zodiac ring (Natal charts only)
show_degree_indicators bool True Show degree indicators on planets
show_aspect_icons bool True Show aspect icons on aspect lines

Opt-in marks (constructor only, both styles). Six facts the chart data already carries and the wheel did not show. Every one defaults to False, so no chart gains a mark it was not asked for, and every one is silent where it has no referent — a chart with no station, data that never computed a score, a tropical zodiac, a house system that was honoured:

Parameter Type Default Description
show_motion_state bool False Mark a planet at a station: SR where the retrograde phase opens, SD where it closes. Modern recolours the cluster and uses the row that holds RX; classic writes the two letters at the foot of the glyph, where its sits
show_out_of_bounds bool False Badge out-of-bounds planets OOB in the point tables (in the Gauquelin grid, off the declination column)
show_aspect_movement bool False Dash the separating aspect lines; applying ones stay solid
show_relationship_score bool False Print the synastry relationship score in the info panel. Needs a score on the chart data, which create_synastry_chart_data computes by default
show_ayanamsa_value bool False Append the ayanamsa offset in degrees and minutes to the zodiac line of a sidereal chart
show_polar_fallback_note bool False Mark the domification line when the requested house system was undefined at that latitude and another stood in for it
from kerykeion import AstrologicalSubjectFactory, ChartDataFactory, ChartDrawer

# 25 August 1990: Mercury is at a station, Uranus is out of bounds.
station = AstrologicalSubjectFactory.from_birth_data(
    "Mercury Station", 1990, 8, 25, 12, 0,
    lng=-0.1276, lat=51.5074, tz_str="Europe/London",
    online=False, suppress_geonames_warning=True,
)
drawer = ChartDrawer(
    ChartDataFactory.create_natal_chart_data(station),
    show_motion_state=True,
    show_out_of_bounds=True,
    show_aspect_movement=True,
)
svg = drawer.generate_svg_string()

print(station.mercury.motion_state)     # stationary_retrograde
print(station.uranus.is_out_of_bounds)  # True

examples/svg_extended_example.py renders all six, each on a subject that has its referent.

Rendered, with every option on. A mark draws nothing where there is nothing to mark, so no single chart shows the set — these four between them carry every referent, and none of them claims something its own sky does not have:

Stations, out-of-bounds and separating aspects
Mercury at its August 1990 station; Uranus past the obliquity
The same sky, classic
SR at the foot of the glyph, where ℞ sits
Modern wheel with station, out-of-bounds and separating-aspect marks Classic wheel with station, out-of-bounds and separating-aspect marks
Ayanamsa offset
Sidereal Lahiri — the offset next to the mode name
Polar fallback note
Placidus undefined at 78°N, so the line says what drew the cusps
Sidereal chart showing the ayanamsa offset in degrees Polar chart admitting the house-system substitution
Relationship score
The synastry score and its band, in a panel row that was empty
Synastry chart printing the relationship score

Classic Birth Chart

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

john = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

chart_data = ChartDataFactory.create_natal_chart_data(john)
chart = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
chart.save_svg(output_path=output_dir, filename="john-lennon-classic", style="classic")

John Lennon Classic Birth Chart

Classic Synastry Chart

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

john = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)
paul = AstrologicalSubjectFactory.from_birth_data(
    "Paul McCartney", 1942, 6, 18, 15, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

chart_data = ChartDataFactory.create_synastry_chart_data(john, paul)
chart = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
chart.save_svg(output_path=output_dir, filename="lennon-mccartney-synastry-classic", style="classic")

John Lennon Classic Synastry Chart

Classic Transit Chart

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

john = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

transit = AstrologicalSubjectFactory.from_birth_data(
    "Transit", 2025, 3, 4, 12, 0,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

chart_data = ChartDataFactory.create_transit_chart_data(john, transit)
chart = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
chart.save_svg(output_path=output_dir, filename="lennon-transit-classic", style="classic")

John Lennon Classic Transit Chart

Classic Wheel Only

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

john = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

chart_data = ChartDataFactory.create_natal_chart_data(john)
chart = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
chart.save_wheel_only_svg_file(
    output_path=output_dir,
    filename="john-lennon-classic-wheel",
    style="classic",
)

John Lennon Classic Wheel Only

📖 Modern chart examples: Modern Charts Guide

Report Generator

ReportGenerator mirrors the chart-type dispatch of ChartDrawer. It accepts raw AstrologicalSubjectModel instances as well as any ChartDataModel produced by ChartDataFactory—including natal, composite, synastry, transit, and planetary return charts—and renders the appropriate textual report automatically.

📖 Full report documentation: Report Generator Guide

Quick Examples

from kerykeion import ReportGenerator, AstrologicalSubjectFactory, ChartDataFactory

# Subject-only report
subject = AstrologicalSubjectFactory.from_birth_data(
    "Sample Natal", 1990, 7, 21, 14, 45,
    lng=12.4964,
    lat=41.9028,
    tz_str="Europe/Rome",
    online=False,
)
ReportGenerator(subject).print_report(include_aspects=False)

# Single-chart data (elements, qualities, aspects enabled)
natal_data = ChartDataFactory.create_natal_chart_data(subject)
ReportGenerator(natal_data).print_report(max_aspects=10)

# Dual-chart data (synastry, transit, dual return, …)
partner = AstrologicalSubjectFactory.from_birth_data(
    "Sample Partner", 1992, 11, 5, 9, 30,
    lng=12.4964,
    lat=41.9028,
    tz_str="Europe/Rome",
    online=False,
)
synastry_data = ChartDataFactory.create_synastry_chart_data(subject, partner)
ReportGenerator(synastry_data).print_report(max_aspects=12)

Each report contains:

  • A chart-aware title summarising the subject(s) and chart type
  • Birth/event metadata and configuration settings
  • Celestial points with sign, position, daily motion, motion state (including the two named stations, SR and SD), declination, retrograde flag, and house (an out-of-bounds column appears when a point actually is)
  • Arabic Parts, fixed stars (with constellation) and midpoints in tables of their own, when active
  • House cusp tables for every subject involved
  • Essential dignities, nakshatras and Gauquelin sectors, when the chart computed them
  • Lunar phase details when available
  • Chart diurnality (Sun above or below the horizon), when it applies
  • Element/quality distributions, angularities and stelliums, and active configuration summaries (for chart data)
  • Aspect listings tailored for single or dual charts, with symbols for type and movement
  • Dual-chart extras such as house comparisons and relationship scores (when provided by the data)

Technique results are accepted directly, each rendering its own report: ProfectionsModel, FirdariaModel, HoraryIndicatorsModel, MutualReceptionsModel, DominantsModel and ZodiacalReleasingModel.

from kerykeion import AstrologicalSubjectFactory, FirdariaFactory, ReportGenerator

subject = AstrologicalSubjectFactory.from_birth_data("Jane", 1990, 6, 15, 12, 0, "Rome", "IT")
ReportGenerator(FirdariaFactory.from_subject(subject, target_date="2026-06-04")).print_report()

Section Access

All section helpers remain available for targeted output:

from kerykeion import ReportGenerator, AstrologicalSubjectFactory, ChartDataFactory

subject = AstrologicalSubjectFactory.from_birth_data(
    "Sample Natal", 1990, 7, 21, 14, 45,
    lng=12.4964,
    lat=41.9028,
    tz_str="Europe/Rome",
    online=False,
)
natal_data = ChartDataFactory.create_natal_chart_data(subject)

report = ReportGenerator(natal_data)
sections = report.generate_report(max_aspects=5).split("\n\n")
for section in sections[:3]:
    print(section)

📖 Report examples: Report Examples

AI Context Serializer

The context_serializer module transforms Kerykeion data models into precise, non-qualitative XML optimized for LLM consumption. It provides the essential "ground truth" data needed for AI agents to generate accurate astrological interpretations.

📖 Full context serializer docs: Context Serializer Guide

Quick Example

from kerykeion import AstrologicalSubjectFactory, to_context

# Create a subject
subject = AstrologicalSubjectFactory.from_birth_data(
    "John Doe", 1990, 1, 1, 12, 0,
    city="London",
    nation="GB",
    lng=-0.1278,
    lat=51.5074,
    tz_str="Europe/London",
    online=False,
)

# Generate AI-ready context
context = to_context(subject)
print(context)

Output:

<chart name="John Doe">
  <birth_data date="1990-01-01 12:00" city="London" nation="GB" lat="51.51" lng="-0.13" lng_dir="W" tz="Europe/London" />
  <config zodiac="Tropical" house_system="Placidus" perspective="Apparent Geocentric" />
  <planets>
    <point name="Sun" position="10.81" sign="Capricorn" element="Earth" quality="Cardinal" ... />
    <point name="Moon" position="3.27" sign="Pisces" element="Water" quality="Mutable" ... />
    ...
  </planets>
  <houses>...</houses>
  <lunar_phase name="Waxing Crescent" phase="5" degrees_between="52.45" emoji="🌒" />
</chart>

Key Features:

  • XML Output: Well-formed XML with semantic tags, proper escaping, and optional field omission.
  • Standardized Output: Consistent format for Natal, Synastry, Composite, and Return charts.
  • Non-Qualitative: Provides raw data (positions, aspects) without interpretive bias.
  • Prompt-Ready: Designed to be injected directly into system prompts.

Example: Retrieving Aspects

Kerykeion provides a unified AspectsFactory class for calculating astrological aspects within single charts or between two charts:

from kerykeion import AspectsFactory, AstrologicalSubjectFactory

# Create astrological subjects
jack = AstrologicalSubjectFactory.from_birth_data(
    "Jack", 1990, 6, 15, 15, 15,
    lng=12.4964,
    lat=41.9028,
    tz_str="Europe/Rome",
    online=False,
)
jane = AstrologicalSubjectFactory.from_birth_data(
    "Jane", 1991, 10, 25, 21, 0,
    lng=12.4964,
    lat=41.9028,
    tz_str="Europe/Rome",
    online=False,
)

# For single chart aspects (natal, return, composite, etc.)
single_chart_result = AspectsFactory.single_chart_aspects(jack)
print(f"Found {len(single_chart_result.aspects)} aspects in Jack's chart")
print(single_chart_result.aspects[0])

# For dual chart aspects (synastry, transits, comparisons, etc.)
dual_chart_result = AspectsFactory.dual_chart_aspects(jack, jane)
print(f"Found {len(dual_chart_result.aspects)} aspects between Jack and Jane's charts")
print(dual_chart_result.aspects[0])

# Each AspectModel includes:
# - p1_name, p2_name: Planet/point names
# - p1_owner, p2_owner: Subject name string (e.g., "Jack", "Jane")
# - aspect: Aspect type (conjunction, trine, square, etc.)
# - orbit: Actual orb in degrees
# - aspect_degrees: Exact degrees for the aspect (0, 60, 90, 120, 180, etc.)
# - diff: Absolute angular difference between the two points
# - p1_abs_pos, p2_abs_pos: Absolute ecliptic positions
# - p1_speed, p2_speed: Daily speed of each point
# - aspect_movement: "Applying", "Separating", or "Static"

📖 Aspects documentation: Aspects Factory Guide

Advanced Usage with Custom Settings:

from kerykeion import AstrologicalSubjectFactory, AspectsFactory

subject = AstrologicalSubjectFactory.from_birth_data("Jane", 1990, 6, 15, 12, 0, "Rome", "IT")

# Custom aspect set with explicit per-aspect orbs (a list of {name, orb} dicts):
custom_aspects = [
    {"name": "conjunction", "orb": 3},
    {"name": "opposition", "orb": 3},
    {"name": "trine", "orb": 3},
    {"name": "square", "orb": 3},
    {"name": "sextile", "orb": 2},
]
aspects = AspectsFactory.single_chart_aspects(subject, active_aspects=custom_aspects)

# Tighten the orb when an angle (Asc/MC) is involved, or widen specific points:
aspects = AspectsFactory.single_chart_aspects(
    subject,
    axis_orb_limit=2.0,
    point_orb_adjustments={"Sun": 10.0, "Moon": 10.0},
)

📖 Configuration options: Settings Documentation

Relationship Score

Kerykeion can calculate a relationship compatibility score based on synastry aspects, using the method of the Italian astrologer Ciro Discepolo:

from kerykeion import AstrologicalSubjectFactory
from kerykeion.relationship_score.factory import RelationshipScoreFactory

# Create two subjects
person1 = AstrologicalSubjectFactory.from_birth_data(
    "Alice", 1990, 3, 15, 14, 30,
    lng=12.4964,
    lat=41.9028,
    tz_str="Europe/Rome",
    online=False,
)
person2 = AstrologicalSubjectFactory.from_birth_data(
    "Bob", 1988, 7, 22, 9, 0,
    lng=12.4964,
    lat=41.9028,
    tz_str="Europe/Rome",
    online=False,
)

# Calculate relationship score
score_factory = RelationshipScoreFactory(person1, person2)
result = score_factory.get_relationship_score()

print(f"Compatibility Score: {result.score_value}")
print(f"Description: {result.score_description}")

📖 Relationship score guide: Relationship Score Examples

📖 Factory documentation: RelationshipScoreFactory

House Comparison (Synastry Overlay)

HouseComparisonFactory performs a bidirectional house overlay: it reports where each subject's points fall within the other subject's houses — a core synastry technique. It also accepts planetary-return subjects.

from kerykeion import AstrologicalSubjectFactory, HouseComparisonFactory

person_a = AstrologicalSubjectFactory.from_birth_data("Person A", 1990, 5, 15, 10, 30, "Rome", "IT")
person_b = AstrologicalSubjectFactory.from_birth_data("Person B", 1992, 8, 23, 14, 45, "Milan", "IT")

comparison = HouseComparisonFactory(person_a, person_b).get_house_comparison()
for placement in comparison.first_points_in_second_houses:
    print(placement)  # A's points located in B's houses
# comparison.second_points_in_first_houses -> B's points in A's houses

Element & Quality Distribution Strategies

ChartDataFactory now offers two strategies for calculating element and modality totals. The default "weighted" mode leans on a curated map that emphasises core factors (for example sun, moon, and ascendant weight 2.0, angles such as medium_coeli 1.5, personal planets 1.5, social planets 1.0, outers 0.5, and minor bodies 0.3–0.8). Provide distribution_method="pure_count" when you want every active point to contribute equally.

You can refine the weighting without rebuilding the dictionary: pass lowercase point names to custom_distribution_weights and use "__default__" to override the fallback value applied to entries that are not listed explicitly.

from kerykeion import AstrologicalSubjectFactory, ChartDataFactory

subject = AstrologicalSubjectFactory.from_birth_data(
    "Sample", 1986, 4, 12, 8, 45,
    lng=11.3426,
    lat=44.4949,
    tz_str="Europe/Rome",
    online=False,
)

# Equal weighting: every active point counts once
pure_data = ChartDataFactory.create_natal_chart_data(
    subject,
    distribution_method="pure_count",
)

# Custom emphasis: boost the Sun, soften everything else
weighted_data = ChartDataFactory.create_natal_chart_data(
    subject,
    distribution_method="weighted",
    custom_distribution_weights={
        "sun": 3.0,
        "__default__": 0.75,
    },
)

print(pure_data.element_distribution.fire)
print(weighted_data.element_distribution.fire)

All convenience helpers (create_synastry_chart_data, create_transit_chart_data, returns, and composites) forward the same keyword-only parameters, so you can keep a consistent weighting scheme across every chart type.

📖 Element/quality distribution guide: Distribution Documentation

Ayanamsa (Sidereal Modes)

By default, the zodiac type is Tropical. To use Sidereal, specify the sidereal mode:

johnny = AstrologicalSubjectFactory.from_birth_data(
    "Johnny Depp", 1963, 6, 9, 0, 0,
    lng=-87.1112,
    lat=37.7719,
    tz_str="America/Chicago",
    online=False,
    zodiac_type="Sidereal",
    sidereal_mode="LAHIRI"
)

# The ayanamsa offset (degrees) is available on sidereal charts:
print(johnny.ayanamsa_value)  # e.g. 23.34

Kerykeion supports 47 named sidereal modes plus a USER mode for custom ayanamsa definitions (48 total). Mode families include Indian/Vedic (Lahiri, Krishnamurti, Raman, Aryabhata, Suryasiddhanta, True Citra/Pushya/Revati, ...), Western sidereal (Fagan-Bradley, DeLuce, Hipparchos, ...), Babylonian (Kugler, Huber, Britton, ...), galactic alignment, and astronomical reference frames (J2000, J1900, B1950).

Custom ayanamsa (USER mode):

custom = AstrologicalSubjectFactory.from_birth_data(
    "Custom Ayanamsa", 2000, 1, 1, 0, 0,
    lng=0.0, lat=51.5, tz_str="Etc/GMT", online=False,
    zodiac_type="Sidereal",
    sidereal_mode="USER",
    custom_ayanamsa_t0=2451545.0,      # J2000.0 reference epoch
    custom_ayanamsa_ayan_t0=23.5,       # ayanamsa offset at epoch (degrees)
)

📖 Sidereal mode examples: Sidereal Modes Guide

📖 Full list of supported sidereal modes: SiderealMode Schema

House Systems

By default, houses are calculated using Placidus. Configure a different house system as follows:

johnny = AstrologicalSubjectFactory.from_birth_data(
    "Johnny Depp", 1963, 6, 9, 0, 0,
    lng=-87.1112,
    lat=37.7719,
    tz_str="America/Chicago",
    online=False,
    houses_system_identifier="M"
)

📖 House system examples: House Systems Guide

📖 Full list of supported house systems: HouseSystemIdentifier Schema

All house systems available in the ephemeris backend are supported, including Gauquelin Sectors (see Gauquelin Sectors below).

Perspective Type

By default, Kerykeion uses the Apparent Geocentric perspective (the most standard in astrology). Other perspectives (e.g., Heliocentric) can be set this way:

johnny = AstrologicalSubjectFactory.from_birth_data(
    "Johnny Depp", 1963, 6, 9, 0, 0,
    lng=-87.1112,
    lat=37.7719,
    tz_str="America/Chicago",
    online=False,
    perspective_type="Heliocentric"
)

📖 Perspective type examples: Perspective Type Guide

📖 Full list of supported perspective types: PerspectiveType Schema

Themes

Classic Dark Black & White
Modern Style (default) Modern Classic Natal Chart Modern Dark Natal Chart Modern Black and White Natal Chart
Classic Style Classic Natal Chart Dark Natal Chart Black and White Natal Chart

Kerykeion ships three chart themes — Classic (the default: light, with the rainbow zodiac band), Dark, and Black & White (for monochrome printing) — plus the option of no theme at all. Each works in both modern (the default style) and classic chart styles: the theme picks the palette, the style picks the wheel layout. All three meet WCAG AAA on the text a reader reads.

Each theme offers a distinct visual style, allowing you to choose the one that best suits your preferences or presentation needs. If you prefer more control over the appearance, you can opt not to set any theme, making it easier to customize the chart by overriding the default CSS variables.

📖 Theming guide with all examples: Theming Documentation

The Black & White theme renders glyphs, rings, and aspects in solid black on light backgrounds, designed for crisp B/W prints (PDF or paper) without sacrificing legibility.

Here's an example of how to set the theme:

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subject
dark_theme_subject = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon - Dark Theme", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Pre-compute chart data
chart_data = ChartDataFactory.create_natal_chart_data(dark_theme_subject)

# Step 3: Create visualization with dark high contrast theme
dark_theme_natal_chart = ChartDrawer(chart_data=chart_data, theme="dark")

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
dark_theme_natal_chart.save_svg(output_path=output_dir, filename="john-lennon-natal-dark")

John Lennon

Alternative Initialization

Create an AstrologicalSubjectModel from a UTC ISO 8601 string:

from kerykeion import AstrologicalSubjectFactory

subject = AstrologicalSubjectFactory.from_iso_utc_time(
    name="Johnny Depp",
    iso_utc_time="1963-06-09T05:00:00Z",
    city="Owensboro",
    nation="US",
    lng=-87.1112,
    lat=37.7719,
    tz_str="America/Chicago",
    online=False,
)

print(subject.iso_formatted_local_datetime)

If you prefer automatic geocoding, set online=True and provide your GeoNames credentials via geonames_username.

📖 All initialization options: AstrologicalSubjectFactory Documentation

Arabic Parts (Lots)

Kerykeion computes the four classical Arabic Parts (Hellenistic Lots) as activatable points. Add them to active_points to include them in a chart and its aspects:

  • Pars_Fortunae — Part of Fortune (Lot of Fortune; sect-aware: day = Asc + Moon − Sun, night = Asc + Sun − Moon)
  • Pars_Spiritus — Part of Spirit
  • Pars_Amoris — Part of Eros / Love
  • Pars_Fidei — Part of Faith / Necessity
from kerykeion import AstrologicalSubjectFactory
from kerykeion.settings.config_constants import DEFAULT_ACTIVE_POINTS

subject = AstrologicalSubjectFactory.from_birth_data(
    "Jane", 1990, 6, 15, 12, 0, "Rome", "IT",
    active_points=DEFAULT_ACTIVE_POINTS + ["Pars_Fortunae", "Pars_Spiritus", "Pars_Amoris", "Pars_Fidei"],
)
print(subject.pars_fortunae.sign, subject.pars_fortunae.position)

Lunar Nodes (Rahu & Ketu)

Kerykeion supports both True and Mean Lunar Nodes:

  • True North Lunar Node: "True_North_Lunar_Node"
  • True South Lunar Node: "True_South_Lunar_Node"
  • Mean North Lunar Node: "Mean_North_Lunar_Node"
  • Mean South Lunar Node: "Mean_South_Lunar_Node"

By default, only the True nodes are active in charts and aspect calculations. To include the Mean nodes (or customize which nodes appear), pass the active_points parameter to the ChartDataFactory methods.

📖 ChartDataFactory documentation: ChartDataFactory Guide

Example:

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subject
subject = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833,
    lat=53.4,
    tz_str="Europe/London",
    online=False,
)

# Step 2: Pre-compute chart data with custom active points including true nodes
chart_data = ChartDataFactory.create_natal_chart_data(
    subject,
    active_points=[
        "Sun",
        "Moon",
        "Mercury",
        "Venus",
        "Mars",
        "Jupiter",
        "Saturn",
        "Uranus",
        "Neptune",
        "Pluto",
        "Mean_North_Lunar_Node",
        "Mean_South_Lunar_Node",
        "True_North_Lunar_Node",
        "True_South_Lunar_Node",
        "Ascendant",
        "Medium_Coeli",
        "Descendant",
        "Imum_Coeli"
    ]
)

# Step 3: Create visualization
chart = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
chart.save_svg(output_path=output_dir, filename="johnny-depp-custom-points")

Fixed Stars

The default libephemeris backend exposes a 1,447-star catalog. Kerykeion's DEFAULT_FIXED_STARS preset selects 23 commonly used stars: all 15 Behenian stars plus 8 additional bright stars, including the 4 Royal Stars. You may pass any catalog name, not only preset members. Each computed star provides ecliptic longitude, daily motion (speed), equatorial declination, and apparent visual magnitude.

Fixed stars are opt-in: pass the names you want to active_fixed_stars when building the subject. Stars requested this way are computed into subject.fixed_stars and participate automatically in chart rendering and aspect calculations.

from kerykeion import AstrologicalSubjectFactory
from kerykeion.chart_data.factory import ChartDataFactory

subject = AstrologicalSubjectFactory.from_birth_data(
    "John Lennon", 1940, 10, 9, 18, 30,
    lng=-2.9833, lat=53.4, tz_str="Europe/London", online=False,
    active_fixed_stars=["Sirius", "Regulus", "Aldebaran", "Antares", "Fomalhaut"],
)

# Access fixed star data
sirius = subject.find_fixed_star("Sirius")
print(sirius.abs_pos)        # Ecliptic longitude
print(sirius.magnitude)      # -1.46
print(sirius.declination)    # Equatorial declination

# The requested stars are rendered and aspected automatically
chart_data = ChartDataFactory.create_natal_chart_data(subject)

The 23-star preset contains: Regulus, Spica, Aldebaran, Antares, Sirius, Fomalhaut, Algol, Betelgeuse, Canopus, Procyon, Arcturus, Pollux, Deneb, Altair, Rigel, Achernar, Capella, Vega, Alcyone, Alphecca, Algorab, Deneb_Algedi, and Alkaid. Discover other names with FixedStarCatalog.list_all() or FixedStarCatalog.find() from kerykeion.fixed_stars.

📖 Full active points list: Active Points Documentation

JSON Support

You can serialize the astrological subject (the base data used throughout the library) to JSON:

from kerykeion import AstrologicalSubjectFactory

johnny = AstrologicalSubjectFactory.from_birth_data(
    "Johnny Depp", 1963, 6, 9, 0, 0,
    lng=-87.1112,
    lat=37.7719,
    tz_str="America/Chicago",
    online=False,
)

print(johnny.model_dump_json(indent=2))

📖 Data models and schemas: Schemas Documentation

Moon Phase Details

The MoonPhaseDetailsFactory generates a rich lunar phase context from any astrological subject — including illumination, upcoming major phases, next eclipses (solar and lunar), sunrise/sunset, moonrise/moonset, and apparent solar position. All timings use the ephemeris backend for ~1 second precision. moonrise and moonset are ISO-8601 strings in the subject's local zone, with the same instants as Unix timestamps beside them; either is None on the roughly one civil day in thirty that has no such event.

from kerykeion import AstrologicalSubjectFactory, MoonPhaseDetailsFactory, ReportGenerator

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 2025, 4, 1, 7, 51,
    lng=-0.1276, lat=51.5074, tz_str="Europe/London",
    online=False,
)

overview = MoonPhaseDetailsFactory.from_subject(subject)

print(f"Phase: {overview.moon.phase_name} {overview.moon.emoji}")
print(f"Illumination: {overview.moon.illumination}")
print(f"Stage: {overview.moon.stage}")

if overview.moon.detailed and overview.moon.detailed.upcoming_phases:
    fm = overview.moon.detailed.upcoming_phases.full_moon
    if fm and fm.next:
        print(f"Next Full Moon: {fm.next.datestamp}")

# Generate a formatted ASCII report
ReportGenerator(overview).print_report()

Report output (truncated):

=====================================================
Moon Phase Overview — Tue, 01 Apr 2025 06:51:00 +0000
=====================================================

+Moon Summary--+--------------------+
| Field        | Value              |
+--------------+--------------------+
| Phase Name   | Waxing Crescent 🌒 |
| Major Phase  | New Moon           |
| Stage        | Waxing             |
| Illumination | 12%                |
| Age (days)   | 3                  |
| Lunar Cycle  | 11.068%            |
| Sun Sign     | Ari                |
| Moon Sign    | Tau                |
+--------------+--------------------+

+Illumination Details-------+
| Field            | Value  |
+------------------+--------+
| Percentage       | 12.0%  |
| Visible Fraction | 0.1161 |
| Phase Angle      | 39.85° |
+------------------+--------+

+Upcoming Phases+---------------------------------+---------------------------------+
| Phase         | Last                            | Next                            |
+---------------+---------------------------------+---------------------------------+
| New Moon      | Sat, 29 Mar 2025 10:57:49 +0000 | Sun, 27 Apr 2025 19:31:09 +0000 |
| First Quarter | ...                             | ...                             |
| Full Moon     | ...                             | ...                             |
| Last Quarter  | ...                             | ...                             |
+---------------+---------------------------------+---------------------------------+

...

You can also get the full model as JSON:

from kerykeion import AstrologicalSubjectFactory, MoonPhaseDetailsFactory

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 2025, 4, 1, 6, 51,
    lng=-0.1276, lat=51.5074, tz_str="Etc/GMT", online=False,
)
overview = MoonPhaseDetailsFactory.from_subject(subject)
print(overview.model_dump_json(exclude_none=True, indent=2))

JSON output (truncated):

{
  "timestamp": 1743490260,
  "datestamp": "Tue, 01 Apr 2025 06:51:00 +0000",
  "sun": {
    "sunrise": "2025-04-01T05:35:33.380154Z",
    "sunset": "2025-04-01T18:34:03.841539Z",
    "solar_noon": "2025-04-01T12:04:48.610846Z",
    "day_length": "PT12H58M30.461385S",
    "next_solar_eclipse": { "type": "Partial Solar Eclipse", "...": "..." }
  },
  "moon": {
    "phase_name": "Waxing Crescent",
    "major_phase": "New Moon",
    "stage": "waxing",
    "illumination": "12%",
    "emoji": "🌒",
    "moonrise": "2025-04-01T06:29:49.367603+00:00",
    "moonrise_timestamp": 1743488989,
    "moonset": "2025-04-01T23:37:11.433132+00:00",
    "moonset_timestamp": 1743550631,
    "next_lunar_eclipse": { "type": "Total Lunar Eclipse", "...": "..." },
    "detailed": { "upcoming_phases": { "...": "..." }, "illumination_details": { "...": "..." } }
  },
  "location": { "latitude": "51.5074", "longitude": "-0.1276" }
}

📖 Full documentation: Moon Phase Details Factory

📖 Examples: Moon Phase Details Examples

Timing Factories

Six lightweight factories that work directly from dates/locations (no full AstrologicalSubject is constructed). Times are returned as timezone-aware UTC datetimes.

Sun Times

SunTimesFactory returns sunrise / sunset / solar-noon / day-length for a civil date at a location, with polar day/night detection.

What the numbers mean. Sunrise and sunset are the moment the Sun's apparent upper limb meets the horizon: the semidiameter is taken from the real Earth–Sun distance rather than a fixed 16′, and refraction from a standard atmosphere (1013.25 hPa, 15 °C), which puts the Sun's geometric centre near −0.83° at the event. The horizon is the level sea horizon at any elevation, which is the convention published rise/set tables use. Solar noon is the meridian transit — the instant the Sun is highest — not the midpoint of sunrise and sunset; the two agree only while the declination is stationary, and away from the solstices the midpoint drifts by up to a minute, more the higher the latitude. Because a transit is a meridian crossing rather than a horizon crossing, solar noon is reported on polar days too, when there is no rise/set pair at all.

Sunrise is not is_diurnal. AstrologicalSubjectModel.is_diurnal tests the Sun's geometric centre against the true horizon — no disc, no atmosphere — because that is the question a chart is cast from. Sunrise counts the Sun as risen as soon as its upper edge shows through the air, which happens earlier. The gap is real and grows towards the poles: about 3.3 min at the equator, 4.4 min at Rome, 8.2 min at Reykjavík and 10 min at Tromsø. Both answers are right to their own question, and neither should ever be derived from the other.

from kerykeion import SunTimesFactory

sun = SunTimesFactory.from_date(
    2026, 5, 28, latitude=41.9028, longitude=12.4964, tz_str="Europe/Rome"
)
print(sun.sunrise, sun.sunset, sun.day_length)

Planetary Hours

PlanetaryHoursFactory computes the 24 unequal Chaldean planetary hours (twelve day + twelve night) for the planetary day containing a moment. Moments before sunrise resolve to the previous planetary day.

from kerykeion import PlanetaryHoursFactory

hours = PlanetaryHoursFactory.from_datetime(
    2026, 5, 28, 11, 30, latitude=41.9028, longitude=12.4964, tz_str="Europe/Rome"
)
print(hours.day_ruler, hours.current_ruler)
for hour in hours.hours[:3]:
    print(hour.index, hour.ruler, hour.start, hour.end)

Void of Course Moon

VoidOfCourseMoonFactory resolves the classical void-of-course Moon — the last exact Ptolemaic aspect to a traditional planet before sign ingress. It is geocentric (no location needed) and supports both the tropical and sidereal zodiacs.

from kerykeion import VoidOfCourseMoonFactory

voc = VoidOfCourseMoonFactory.from_datetime(2026, 6, 1, 9, 0, tz_str="Europe/Rome")
print(voc.is_void_of_course, voc.moon_sign, "->", voc.next_sign)
print(voc.last_aspect, voc.next_aspect, voc.ingress)

Lunation Finder

LunationFinderFactory finds the New, First-Quarter, Full and Last-Quarter Moons in a date range (ISO dates, treated as UTC). It is geocentric — no location needed.

from kerykeion import LunationFinderFactory

result = LunationFinderFactory.from_iso_range("2026-01-01", "2026-12-31")
for lunation in result.lunations:
    print(lunation.iso_utc, lunation.phase)  # phase: new / first_quarter / full / last_quarter

# Only full moons:
fulls = LunationFinderFactory.from_iso_range("2026-01-01", "2026-12-31", phases=["full"])

Retrograde Stations

RetrogradeStationFactory finds planetary stations (retrograde and direct turning points) in a date range (Mercury–Pluto by default).

from kerykeion import RetrogradeStationFactory

result = RetrogradeStationFactory.from_iso_range("2026-01-01", "2026-12-31")
for station in result.stations:
    print(station.iso_utc, station.planet, station.station_type)  # station_type: 'SR' (turns retrograde) / 'SD' (turns direct)

Sign Ingresses

SignIngressFactory finds the moments planets cross from one zodiac sign into the next (Sun–Pluto by default; pass planets=["Moon"] to include the fast-moving Moon).

from kerykeion import SignIngressFactory

result = SignIngressFactory.from_iso_range("2026-01-01", "2026-12-31")
for ingress in result.ingresses:
    print(ingress.iso_utc, ingress.planet, "->", ingress.sign)

V6 Advanced Features

Kerykeion v6 adds a suite of advanced astronomical and astrological calculation modules. All v6 features are optional opt-in — existing code works unchanged.

Uranian / Hamburg School Planets

Eight hypothetical planets used in Uranian astrology: Cupido, Hades, Zeus, Kronos, Apollon, Admetos, Vulkanus, Poseidon.

from kerykeion import AstrologicalSubjectFactory

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
    active_points=["Sun", "Moon", "Cupido", "Hades", "Zeus", "Kronos",
                   "Apollon", "Admetos", "Vulkanus", "Poseidon"],
)
print(f"Cupido: {subject.cupido.abs_pos:.4f}")
print(f"Poseidon: {subject.poseidon.abs_pos:.4f}")

Essential Dignities

Ptolemaic essential dignities (Domicile, Exaltation, Detriment, Fall, Term, Peregrine) for any planet.

from kerykeion import AstrologicalSubjectFactory

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
    calculate_dignities=True,
)
print(f"Sun dignity: {subject.sun.essential_dignity}")

Vedic Nakshatras

Lunar mansions with pada and Vimsottari Dasha lord.

The nakshatras divide the sidereal zodiac. A sidereal chart supplies those longitudes itself; on a tropical chart they are rotated by nakshatra_ayanamsa (default "LAHIRI") for the 27-fold division only, so the chart stays tropical and still names the nakshatra a Jyotish chart would name. Pass nakshatra_ayanamsa=None to get back the pre-v6 uncorrected values.

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
    calculate_nakshatra=True,
)
print(f"Moon nakshatra: {subject.moon.nakshatra}, pada: {subject.moon.nakshatra_pada}")
print(f"Rotated by {subject.nakshatra_ayanamsa}: {subject.nakshatra_ayanamsa_value:.4f} deg")

Eclipse Search

Find upcoming solar and lunar eclipses globally or from a specific location.

from kerykeion import EclipseFactory

result = EclipseFactory.search_global(start_year=2025, count=3)
for ecl in result.solar_eclipses:
    print(f"Solar: {ecl.datestamp} ({ecl.type})")
for ecl in result.lunar_eclipses:
    print(f"Lunar: {ecl.datestamp} ({ecl.type})")

📖 Full documentation: Eclipse Factory

Planetary Phenomena

Phase angle, elongation, apparent magnitude, morning/evening star status, and the solar phase.

solar_phase names the classical condition near the Sun — "cazimi", "combust", "under_the_beams" or "free" — read off the elongation against the collection's solar_phase_thresholds (0.2833° / 8.5° / 17° by default, and replaceable, since the schools disagree). is_morning_star / is_evening_star are a different question and purely geometric: which side of the Sun the planet stands on, with no visibility threshold at all.

from kerykeion import PlanetaryPhenomenaFactory, AstrologicalSubjectFactory

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 2000, 1, 1, 12, 0,
    lng=0, lat=0, tz_str="Etc/GMT", online=False,
)
phenom = PlanetaryPhenomenaFactory.from_subject(subject)
venus = next(p for p in phenom.phenomena if p.name == "Venus")
print(f"Venus elongation: {venus.elongation:.2f}, magnitude: {venus.apparent_magnitude:.2f}")
print(f"Solar phase: {venus.solar_phase}")

📖 Full documentation: Planetary Phenomena Factory

Planetary Nodes & Apsides

Ascending/descending node and the orbit's periapsis/apoapsis.

The apsides carry two names for the same two points. periapsis/apoapsis are generic and always correct; perihelion/aphelion are deprecated — they name the Sun, which is right for the planets and wrong for the Moon, which goes round the Earth. apsis_kind says which reading applies ("geocentric" for the Moon alone, whose apoapsis is to the decimal the Black Moon Lilith).

from kerykeion import PlanetaryNodesFactory

nodes = PlanetaryNodesFactory.from_julian_day(2451545.0, planets=["Mars", "Jupiter"])
for entry in nodes.nodes:
    print(f"{entry.planet_name}: ascending node {entry.ascending_node.abs_pos:.2f}")
    print(f"  apoapsis {entry.apoapsis.abs_pos:.2f} ({entry.apsis_kind})")

📖 Full documentation: Planetary Nodes & Apsides

Heliacal Risings & Settings

Find when a planet first becomes visible or disappears in twilight.

from kerykeion import HeliacalFactory

factory = HeliacalFactory()
from kerykeion.ephemeris_backend import ephe
jd = ephe.julday(2025, 1, 1, 0.0)
event = factory.next_heliacal_rising(jd, "Venus", geopos=(12.5, 41.9, 0))
print(f"Venus heliacal rising: {event.datestamp}")

📖 Full documentation: Heliacal Risings & Settings

Occultation Search

Find lunar occultations of planets.

from kerykeion import OccultationFactory
from kerykeion.ephemeris_backend import ephe

factory = OccultationFactory()
jd = ephe.julday(2025, 1, 1, 0.0)
events = factory.search_global(jd, ephe.VENUS, count=3)
for occ in events:
    print(f"{occ.planet_name} occultation: {occ.datestamp} ({occ.type})")

📖 Full documentation: Occultation Factory

Davison Composite Chart

Time-space midpoint composite method (in addition to the existing midpoint composite).

from kerykeion import AstrologicalSubjectFactory, CompositeSubjectFactory

s1 = AstrologicalSubjectFactory.from_birth_data("A", 1990, 3, 15, 10, 0,
    lng=12.5, lat=41.9, tz_str="Europe/Rome", online=False)
s2 = AstrologicalSubjectFactory.from_birth_data("B", 1992, 7, 20, 14, 30,
    lng=-73.9, lat=40.7, tz_str="America/New_York", online=False)

factory = CompositeSubjectFactory(s1, s2)
davison = factory.get_davison_composite_subject_model()
print(f"Davison Sun: {davison.sun.abs_pos:.4f}")

Relocated Charts

Keep planetary positions, recalculate houses for a new location.

from kerykeion import AstrologicalSubjectFactory, RelocatedChartFactory

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
)
relocated = RelocatedChartFactory.relocate(subject, new_lng=139.69, new_lat=35.69, new_city="Tokyo")
print(f"Original ASC: {subject.first_house.abs_pos:.2f}")
print(f"Tokyo ASC: {relocated.first_house.abs_pos:.2f}")

📖 Full documentation: Relocated Chart Factory

Motion State & Stations

Every planet carries a motion_state: "fast", "average", "slow", "retrograde", or one of the three stationary values. The stationary band brackets zero speed on both sides and is tested before the sign, so a planet edging backwards at a hundredth of its mean motion reports a station rather than a plain retrograde. Which station it is comes from the trend, not the sign — both stations are approached from one side of zero and left on the other — so the factory samples the speed again a day later: falling through the band opens the retrograde phase ("stationary_retrograde", SR), rising through it closes the phase ("stationary_direct", SD). Where no second sample is available the generic "stationary" stands.

subject = AstrologicalSubjectFactory.from_birth_data(
    "Mercury Station", 1990, 8, 25, 12, 0,
    lng=-0.1276, lat=51.5074, tz_str="Europe/London", online=False,
)
print(f"Mercury: {subject.mercury.motion_state} at {subject.mercury.speed:.5f}°/day")
# Mercury: stationary_retrograde at 0.01237°/day

ChartDrawer(..., show_motion_state=True) draws these as SR/SD on the wheel; RetrogradeStationFactory finds the instants of the stations themselves.

Declination & Out-of-Bounds Detection

Equatorial declination and OOB detection for all celestial points.

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
)
print(f"Sun declination: {subject.sun.declination:.4f}")
print(f"Sun OOB: {subject.sun.is_out_of_bounds}")

Barycentric & Planetocentric Perspectives

Solar system barycenter or any planet as the observer origin.

bary = AstrologicalSubjectFactory.from_birth_data(
    "Bary", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
    perspective_type="Barycentric",
)
print(f"Barycentric Sun: {bary.sun.abs_pos:.4f}")

Nutation Model

True/mean obliquity and nutation in longitude/obliquity.

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 2000, 1, 1, 12, 0,
    lng=0, lat=0, tz_str="Etc/GMT", online=False,
    calculate_nutation=True,
)
print(f"True obliquity: {subject.nutation.true_obliquity:.4f}")
print(f"Nutation in longitude: {subject.nutation.nutation_longitude:.6f}")

Dynamic Fixed Star Discovery

Auto-discover fixed stars near natal planet positions.

from kerykeion import AstrologicalSubjectFactory, FixedStarDiscoveryFactory

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
)
stars = FixedStarDiscoveryFactory.find_prominent_stars(subject, orb=2.0)
for star in stars:
    print(f"{star.name} at {star.longitude:.2f} (mag {star.magnitude:.1f})")

📖 Full documentation: Fixed Star Discovery

Gauquelin Sectors

36-sector system for statistical astrology research.

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
    calculate_gauquelin=True,
)
print(f"Sun Gauquelin sector: {subject.sun.gauquelin_sector:.2f}")
print(f"Mars Gauquelin sector: {subject.mars.gauquelin_sector:.2f}")

Local Space (Azimuth & Altitude)

Horizon coordinates for all celestial points.

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
    calculate_local_space=True,
)
print(f"Sun azimuth: {subject.sun.azimuth:.2f}, altitude: {subject.sun.altitude_above_horizon:.2f}")

Lilith Variants & Priapus Points

Interpolated Lilith, Mean Priapus, and True Priapus (anti-Lilith points).

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
    active_points=["Sun", "Moon", "Mean_Lilith", "True_Lilith",
                   "Interpolated_Lilith", "Mean_Priapus", "True_Priapus"],
)
print(f"Interpolated Lilith: {subject.interpolated_lilith.abs_pos:.4f}")
print(f"Mean Priapus: {subject.mean_priapus.abs_pos:.4f}")

Transit Exactness & Refinement

Bisection refinement for sub-step precision on exact transit moments.

from datetime import datetime
from kerykeion import AstrologicalSubjectFactory, TransitsTimeRangeFactory, EphemerisDataFactory

natal = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
)

# Generate ephemeris points for the transit period. A 4-hour step keeps the
# sampling finer than half the Moon's in-orb window; the default 1-day step is
# coarse enough that the factory logs a sub-sampling warning for the Moon.
ephemeris = EphemerisDataFactory(
    start_datetime=datetime(2025, 6, 1),
    end_datetime=datetime(2025, 7, 1),
    step_type="hours", step=4,
    lng=11.25, lat=43.77, tz_str="Europe/Rome",
)
points = ephemeris.get_ephemeris_data_as_astrological_subjects()

factory = TransitsTimeRangeFactory(natal, points)
events = factory.get_transit_events(refine_exact_moments=True)
for ev in events.events[:3]:
    print(f"{ev.p1_name} {ev.aspect} {ev.p2_name}: {ev.exact_moment} (orb {ev.min_orb:.4f})")

Primary Directions (Placidus Semi-Arc)

Classical predictive technique with Ptolemy and Naibod rate keys.

from kerykeion import AstrologicalSubjectFactory, PrimaryDirectionsFactory

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
)
directions = PrimaryDirectionsFactory.compute(subject, max_years=30)
for d in directions[:5]:
    print(f"{d.promissor} {d.aspect} {d.significator}: {d.direction_years:.1f} years")

📖 Full documentation: Primary Directions

Secondary Progressions (Day-for-a-Year)

The day-for-a-year technique maps each day after birth to one year of life. The progressed chart is a real ephemeris snapshot, returned as a standard AstrologicalSubjectModel — so every downstream tool (aspects, dignities, chart drawer) works transparently.

from pathlib import Path

from kerykeion import AstrologicalSubjectFactory, SecondaryProgressionFactory
from kerykeion.chart_data.factory import ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

natal = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
)
progressed = SecondaryProgressionFactory.compute(natal, target_year=2026)

# Inspect progressed positions
print(f"Progressed Sun: {progressed.sun.sign} {progressed.sun.position:.2f}°")
print(f"Progressed Moon: {progressed.moon.sign} {progressed.moon.position:.2f}°")

# Generate a biwheel SVG (natal inner ring, progressed outer ring)
data = ChartDataFactory.create_progression_chart_data(natal, progressed)
drawer = ChartDrawer(data)
output_dir = Path("charts_output")
output_dir.mkdir(parents=True, exist_ok=True)
drawer.save_svg(output_path=output_dir, filename="progression-biwheel")

📖 Full documentation: Secondary Progressions

The biwheel shows the natal chart on the inner ring and progressed positions on the outer ring. Astrologers read it by looking for contacts between the two rings: when a progressed planet (outer) reaches a conjunction, square, or trine to a natal planet (inner), it signals a symbolic theme active for roughly one year. Sign ingresses (a progressed planet changing zodiac sign) mark longer-term shifts in how that planetary energy is expressed.

Solar Arc Directions

Solar arc takes the progressed Sun's forward motion and applies it uniformly to every natal point. The result is a structured model with directed positions and directed-to-natal aspect contacts.

from kerykeion import AstrologicalSubjectFactory, SolarArcFactory

natal = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
)
result = SolarArcFactory.compute(natal, target_year=2026)

print(f"Solar arc: {result.solar_arc:.2f}°")
for dp in result.directed_points[:5]:
    ingress = " (sign changed)" if dp.sign_changed else ""
    print(f"  {dp.name}: {dp.directed_sign} {dp.directed_position:.2f}°{ingress}")

for asp in result.directed_to_natal_aspects[:5]:
    print(f"  {asp.directed_point} {asp.aspect} {asp.natal_point} (orb {asp.orb:.2f}°)")

📖 Full documentation: Solar Arc Directions

Midpoints (Cosmobiology / 90° Dial)

Computes every pairwise midpoint of the active points, with the 90° dial position used by cosmobiology and Uranian astrology, plus optional aspect-to-midpoint detection (third-point activations).

from kerykeion import AstrologicalSubjectFactory, MidpointFactory

natal = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
)
midpoints = MidpointFactory.compute(natal, aspect_orb=1.0)

for m in midpoints[:5]:
    activations = ", ".join(
        f"{a.point_name} {a.aspect} ({a.orb:.2f}°)" for a in m.aspects_to_midpoint
    )
    print(f"{m.point_a}/{m.point_b}: {m.midpoint_sign} {m.midpoint_position:.2f}° "
          f"(90° dial: {m.midpoint_modulus_90:.2f}°)"
          f"{' — activated by: ' + activations if activations else ''}")

📖 Full documentation: Midpoints

Astro-Cartography (ACG)

Compute MC, IC, ASC, DSC planetary lines on the world map.

from kerykeion import AstrologicalSubjectFactory, AstroCartographyFactory

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 1985, 4, 15, 8, 30,
    lng=11.25, lat=43.77, tz_str="Europe/Rome", online=False,
)
lines = AstroCartographyFactory.compute(subject)
for line in lines[:5]:
    print(f"{line.planet} {line.line_type}: {len(line.points)} points")

📖 Full documentation: Astro-Cartography

Chart Dominants

DominantsFactory computes a chart's dominant planet / sign / element / quality using a chosen scoring school: "modern" (default), "almuten_figuris" (the traditional "Lord of the Geniture"), or "elemental". Custom schools (the DominantStrategy protocol) and per-point custom_weights are also supported.

from kerykeion import AstrologicalSubjectFactory, DominantsFactory

subject = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")

dominants = DominantsFactory.from_subject(subject, strategy="modern")
print(dominants.dominant_planet, dominants.dominant_sign)
print(dominants.dominant_element, dominants.dominant_quality)

# Traditional Almuten Figuris, with a per-rule audit trail:
almuten = DominantsFactory.from_subject(subject, strategy="almuten_figuris", include_score_breakdown=True)

Zodiacal Releasing (Aphesis)

ZodiacalReleasingFactory computes the Hellenistic time-lord technique of zodiacal releasing (aphesis) from the Lot of Fortune or Spirit, unfolding nested periods (levels L1–L4) with the "loosing of the bond" jumps and peak/angular markers. Requires a known birth time.

from kerykeion import AstrologicalSubjectFactory, ZodiacalReleasingFactory

subject = AstrologicalSubjectFactory.from_birth_data("Jane", 1990, 6, 15, 12, 0, "Rome", "IT")
zr = ZodiacalReleasingFactory.from_subject(subject, lot="fortune", levels=2, target_date="2026-06-04")
print(zr.lot_sign, len(zr.periods), "top-level periods")

Profections (Annual)

ProfectionsFactory computes annual profections — a traditional timing technique where each year of life activates one house (cycling every 12 years). The sign on the cusp determines the Lord of the Year. Respects the subject's house system and supports BCE births.

from kerykeion import AstrologicalSubjectFactory, ProfectionsFactory

subject = AstrologicalSubjectFactory.from_birth_data("Jane", 1990, 6, 15, 12, 0, "Rome", "IT")
profections = ProfectionsFactory.from_subject(subject, target_date="2026-06-04")
print(f"Age {profections.current.age}: house {profections.current.house}, lord {profections.current.lord}")

Firdaria (Planetary Periods)

FirdariaFactory computes the Persian time-lord sequence that divides life into planetary periods. Day charts begin with the Sun (10 years), night charts with the Moon (9 years). Each major period is subdivided among the seven classical planets. All date arithmetic uses Julian Days, so BCE births are supported.

from kerykeion import AstrologicalSubjectFactory, FirdariaFactory

subject = AstrologicalSubjectFactory.from_birth_data("Jane", 1990, 6, 15, 12, 0, "Rome", "IT")
firdaria = FirdariaFactory.from_subject(subject, target_date="2026-06-04")
print(f"Current lord: {firdaria.current.lord}" if firdaria.current else "No current period")

Mutual Receptions

MutualReceptionsFactory detects domicile and exaltation mutual receptions among the seven classical planets (Sun through Saturn). A reception is found when two planets each occupy a sign ruled by the other.

from kerykeion import AstrologicalSubjectFactory, MutualReceptionsFactory

subject = AstrologicalSubjectFactory.from_birth_data("Jane", 1990, 6, 15, 12, 0, "Rome", "IT")
receptions = MutualReceptionsFactory.from_subject(subject)
for r in receptions.receptions:
    print(f"{r.first_planet}{r.second_planet} ({r.reception_type})")

Horary Indicators

HoraryIndicatorsFactory assembles horary significators (querent/quesited via classical rulership), considerations before judgment (Ascendant degree, Saturn placement, Moon void-of-course), and mutual receptions for a question chart.

from kerykeion import AstrologicalSubjectFactory, HoraryIndicatorsFactory

subject = AstrologicalSubjectFactory.from_birth_data("Question", 2026, 6, 4, 15, 30, "Rome", "IT")
indicators = HoraryIndicatorsFactory.from_subject(subject)
print(f"Querent ruler: {indicators.querent.ruler}, Quesited ruler: {indicators.quesited.ruler}")

Documentation

Projects built with Kerykeion

AstrologerStudio is a cloud-based astrology app built on top of Kerykeion.

Development

Clone the repository or download the ZIP via the GitHub interface.

git clone https://github.com/g-battaglia/kerykeion.git
cd kerykeion
uv sync --dev

Using the Swiss Ephemeris Backend (Optional)

Kerykeion uses libephemeris by default (no external data files needed). If you want to use the Swiss Ephemeris C backend instead, install the optional extra and run the setup utility:

pip install kerykeion[swiss]
python -m kerykeion.swisseph_setup

The setup utility downloads the required data files from the official Swiss Ephemeris repository (AGPL-3.0, Astrodienst AG) and asks for license confirmation. Then set the environment variables:

export KERYKEION_BACKEND=swisseph
export KERYKEION_EPHE_PATH=~/.kerykeion/sweph

For the full configuration guide, see Swiss Ephemeris Configuration.

Fixed stars on swisseph: the fixed-star catalog file sefstars.txt is required for any fixed-star feature when using the swisseph backend, and is not bundled with kerykeion (Swiss Ephemeris license belongs to Astrodienst). The setup utility above downloads it automatically; for the manual procedure and a diagnostic warning reference, see the Fixed Stars Catalog section of the configuration guide.

AI Agent Skill

Kerykeion ships a cross-platform Agent Skill that teaches AI coding agents the real v6 API — factories, chart types, backends, sidereal modes, predictive and traditional techniques — so generated code stops guessing method names. It works with any skills-aware agent (Claude Code, Cursor, Codex, Copilot, Gemini CLI, and others).

During the v6 alpha, install from the alpha/v6 branch. The skill is not part of the PyPI package, and the registry command below resolves this repository's default branch — which still carries the v5-era skill. Until v6 is merged to the default branch, clone the branch and copy the folder.

git clone --branch alpha/v6 --depth 1 https://github.com/g-battaglia/kerykeion.git
cd kerykeion

# Claude Code
cp -r skills/kerykeion /path/to/your-project/.claude/skills/kerykeion

# Codex
cp -r skills/kerykeion /path/to/your-project/.agents/skills/kerykeion

# Generic agentskills.io layout (Cursor and others)
cp -r skills/kerykeion /path/to/your-project/skills/kerykeion

Once v6 is the default branch, skills.sh installs it in one step:

npx skills add g-battaglia/kerykeion

Prefer a single-file guide? The package also ships kerykeion/llms.txt, a self-contained AI-agent reference installed with the library. For turning chart data into LLM input at runtime, see AI Context Serializer.

Integrating Kerykeion into Your Project

If you would like to incorporate Kerykeion's astrological features into your application, please reach out via email. Whether you need custom features, support, or specialized consulting, I am happy to discuss potential collaborations.

For commercial or closed-source applications, consider using the paid Astrologer API (RapidAPI plans & pricing) which provides REST endpoints for all Kerykeion functionality.

License

This project is covered under the AGPL-3.0 License. For detailed information, please see the LICENSE file. If you have questions, feel free to contact me at kerykeion.astrology@gmail.com.

As a rule of thumb, if you use this library in a project, you should open-source that project under a compatible license. Alternatively, if you wish to keep your source closed, consider using the paid Astrologer API, which is AGPL-3.0 compliant and also helps support the project.

Since the Astrologer API is an external third-party service, using it does not require your code to be open-source.

This is not legal advice — see the LICENSE file and consult legal counsel for guidance.

Contributing

Contributions are welcome! Feel free to submit pull requests or report issues.

By submitting a contribution, you agree to assign the copyright of that contribution to the maintainer. The project stays openly available under the AGPL for everyone, while the re-licensing option helps sustain future development. Your authorship remains acknowledged in the commit history and release notes.

Citations

If using Kerykeion in published or academic work, please cite as follows:

Battaglia, G. (2025). Kerykeion: A Python Library for Astrological Calculations and Chart Generation.
https://github.com/g-battaglia/kerykeion

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kerykeion-6.0.0a92.tar.gz (826.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kerykeion-6.0.0a92-py3-none-any.whl (874.8 kB view details)

Uploaded Python 3

File details

Details for the file kerykeion-6.0.0a92.tar.gz.

File metadata

  • Download URL: kerykeion-6.0.0a92.tar.gz
  • Upload date:
  • Size: 826.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for kerykeion-6.0.0a92.tar.gz
Algorithm Hash digest
SHA256 77db9922265450da402258517b46b8f64b63127707aee4aba3cd52b90861bf75
MD5 40106ce6bbacaa540900ad0b08ff51c3
BLAKE2b-256 9b57c53b17b675e6b7628559a92658207f40462a14f7755528587ad8289c4a2b

See more details on using hashes here.

File details

Details for the file kerykeion-6.0.0a92-py3-none-any.whl.

File metadata

  • Download URL: kerykeion-6.0.0a92-py3-none-any.whl
  • Upload date:
  • Size: 874.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for kerykeion-6.0.0a92-py3-none-any.whl
Algorithm Hash digest
SHA256 1982670b47794ad30127864c5429e86620f47e05347af65fd8246735b215bbbd
MD5 70ff64f7914a6f46e85d22a13dd83e18
BLAKE2b-256 aacd0b14d67e3468fc39359be5bed670ebf40d384fb51413a8a4b3e5c70ed5b0

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

6.0.0a92 This release

2 files

5.12.9

2 files

5.12.8

2 files

5.12.7

2 files

5.12.6

2 files

5.12.5

2 files

5.12.4

2 files

5.12.3

2 files

5.12.2

2 files

5.12.1

2 files

5.12.0

2 files

5.11.1

2 files

5.11.0

2 files

5.10.1

2 files

5.10.0

2 files

5.9.0

2 files

5.8.1

2 files

5.8.0

2 files

5.7.3

2 files

5.7.2

2 files

5.7.1

2 files

5.7.0

2 files

5.6.3

2 files

5.6.2

2 files

5.6.1

2 files

5.6.0

2 files

5.5.3

2 files

5.5.2

2 files

5.5.1

2 files

5.5.0

2 files

5.4.2

2 files

5.4.1

2 files

5.4.0

2 files

5.3.2

2 files

5.3.1

2 files

5.3.0

2 files

5.2.2

2 files

5.2.1

2 files

5.2.0

2 files

5.1.12

2 files

5.1.11

2 files

5.1.10

2 files

5.1.9

2 files

5.1.8

2 files

5.1.7

2 files

5.1.6

2 files

5.1.5

2 files

5.1.4

2 files

5.1.3

2 files

5.1.2

2 files

5.1.1

2 files

5.1.0

2 files

5.0.2

2 files

5.0.1

2 files

5.0.0

2 files

4.26.3

2 files

4.26.2

2 files

4.26.1

2 files

4.26.0

2 files

4.25.4

2 files

4.25.3

2 files

4.25.2

2 files

4.25.1

2 files

4.25.0

2 files

4.24.7

2 files

4.24.6

2 files

4.24.5

2 files

4.24.4

2 files

4.24.3

2 files

4.24.2

2 files

4.24.1

2 files

4.24.0

2 files

4.23.0

2 files

4.22.0

2 files

4.21.1

2 files

4.21.0

2 files

4.20.0

2 files

4.19.0

2 files

4.18.5

2 files

4.18.4

2 files

4.18.3

2 files

4.18.2

2 files

4.18.1

2 files

4.18.0

2 files

4.17.2

2 files

4.17.1

2 files

4.17.0

2 files

4.16.5

2 files

4.16.4

2 files

4.16.3

2 files

4.16.1

2 files

4.16.0

2 files

4.15.0

2 files

4.14.11

2 files

4.14.10

2 files

4.14.9

2 files

4.14.8

2 files

4.14.7

2 files

4.14.6

2 files

4.14.5

2 files

4.14.4

2 files

4.14.3

2 files

4.14.2

2 files

4.14.1

2 files

4.14.0

2 files

4.13.3

2 files

4.13.2

2 files

4.13.1

2 files

4.13.0

2 files

4.12.8

2 files

4.12.7

2 files

4.12.6

2 files

4.12.5

2 files

4.12.4

2 files

4.12.3

2 files

4.12.2

2 files

4.12.1

2 files

4.12.0

2 files

4.11.1

2 files

4.11.0

2 files

4.10.1

2 files

4.10.0

2 files

4.9.1

2 files

4.9.0

2 files

4.8.1

2 files

4.8.0

2 files

4.7.0

2 files

4.6.2

2 files

4.6.1

2 files

4.6.0

2 files

4.5.1

2 files

4.5.0

2 files

4.4.2

2 files

4.4.1

2 files

4.4.0

2 files

4.3.1

2 files

4.3.0

2 files

4.2.4

2 files

4.2.3

2 files

4.2.2

2 files

4.2.1

2 files

4.2.0

2 files

4.1.1

2 files

4.1.0

2 files

4.0.7

2 files

4.0.6

2 files

4.0.5

2 files

4.0.4

2 files

4.0.3

2 files

4.0.2

2 files

4.0.1

2 files

4.0.0

2 files

3.4.4

2 files

3.4.3

2 files

3.4.2

2 files

3.4.1

2 files

3.4.0

2 files

3.3.2

2 files

3.3.1

2 files

3.3

2 files

3.2

2 files

3.1.9

2 files

3.1.8

2 files

3.1.6

2 files

3.1.5

2 files

3.1.4

2 files

3.1.3

2 files

3.1.2

2 files

3.1.1

2 files

3.1.0

2 files

2.3.12

2 files

2.3.11

2 files

2.3.10

2 files

2.3.9

2 files

2.3.8

2 files

2.3.7

2 files

2.3.6

2 files

2.3.5

2 files

2.3.4

2 files

2.3.3

2 files

2.3.2

2 files

2.3.1

2 files

2.3.0

2 files

2.2.8

2 files

2.2.7

2 files

2.2.6

2 files

2.2.5

2 files

2.2.4

2 files

2.2.2

2 files

2.2.1

2 files

2.2.0

2 files

2.1.16

2 files

2.1.15

2 files

2.1.14

2 files

2.1.12

2 files

2.1.11

2 files

2.1.10

2 files

2.1.9

2 files

2.1.8

2 files

2.1.6

2 files

2.1.5

2 files

2.1.4

2 files

2.1.2

2 files

2.1.1

2 files

2.1.0

2 files

2.0.0

2 files

1.3.0

2 files

1.2.15

2 files

1.2.12

2 files

1.2.11

2 files

1.2.10

2 files

1.2.9

2 files

1.2.8

2 files

1.2.7

2 files

1.2.5

2 files

1.2.4

2 files

1.2.3

2 files

1.2.2

2 files

1.2.1

2 files

1.2.0

2 files

1.1.0

2 files

1.0.5

2 files

1.0.2

2 files

1.0.1

2 files

1.0.0

2 files

0.9.6

2 files

0.9.5

2 files

0.9.3

2 files

0.9.2

2 files

0.9.1

2 files

0.0.9

2 files

0.0.3.2

2 files

0.0.3

2 files

0.0.2.5

2 files

0.0.2.2

1 file

0.0.2.1

1 file

0.0.2.0

1 file

0.0.1.3

1 file

0.0.1.2

2 files

0.0.1.1

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page