moira

Moira

Ephemeris and Astrology Computation Engine

Python MIT License PyPI Precision: ERFA-Audited Ephemeris: JPL DE4xx AI Visibility: Optimized Status: Stable DOI Featured on Launch Llama

Moira is an astronomy-first astrology engine built for transparent astrology calculations, reproducible chart computation, and an inspectable calculation chain from astronomical inputs to astrological outputs. It is an auditable astrology engine with explicit computational policy, deterministic behavior, and readable reduction stages grounded in modern standards and references including JPL DE441, IAU 2000A/2006, ERFA/SOFA-aligned practices, and Gaia DR3-linked star data where applicable. A required C++17 extension (_moira_native, compiled with pybind11) accelerates admitted numerical substrates including nutation, SPK/DAF access, apparent-place evaluation, coordinate transforms, harmogram computation, and selected event-search primitives. Python remains the governing layer for public semantics, doctrine, policy, and orchestration.

Why Moira Exists

Most astrology software surfaces results without exposing the mathematical path. Moira exists as a Swiss Ephemeris alternative for users who need visibility into assumptions, intermediates, and provenance, so astronomy remains the foundation and astrology remains the purpose.

AI and LLM Visibility

Moira is designed to be highly discoverable and understandable by AI agents (e.g., GitHub Copilot, ChatGPT, Claude).

What Makes It Different

Moira is designed for full computational transparency: the computation pipeline is explicit and its stages are named and controllable via the Python API, computational doctrine is explicit rather than hidden in defaults, and validation is treated as first-class evidence rather than post-hoc narrative. The high-performance core (_moira_native) is C++17; the Python layer owns the API surface, orchestration, and per-stage controls.

Who It Is For

Moira is for developers, researchers, and serious practitioners who want a programmable, audit-ready engine for high-integrity astrological work, reproducible pipelines, and methodical comparison against external authorities.

What It Is Not

Moira is not primarily a UI app, not a thin wrapper over opaque compiled stacks, and not convenience-first astrology output generation without traceability.

Quick Capabilities

Moira computes planetary and stellar positions, houses, aspects, lots, dignities, predictive techniques, a full Vedic/Jyotish suite (yogas, Shadbala, Ashtakavarga, upagrahas, avasthas, Jaimini), eclipse and occultation events, and related analytical products on top of a modern astronomical substrate (JPL kernels, IAU models, and validated star frameworks), with a native C++ computational core, Python orchestration layer, inspectable intermediate stages, and an optional FastAPI REST server (moira_server) exposing the engine as typed, versioned routes.


What Moira Computes

Positions and Bodies

Chart Calculation

Predictive Techniques

Vedic / Jyotish Suite

Admitted Vedic surfaces name their governing classical source, modern lineage, or source-scoped witness (including BPHS, Brihat Jataka, Saravali, Phaladeepika, Uttara Kalamrita, Jataka Parijata, Jaimini Upadesa Sutras, and the named 1879 Agastya- and 2024 Bogamuni-attributed Pancha Pakshi witnesses). Where sources disagree or a modern composition is required, Moira exposes the policy or qualification instead of presenting one silent universal rule.

Advanced Astronomy


Quick Start

Moira initializes even when no planetary kernel is present. Kernel-dependent operations (for example chart()) raise a clear MissingEphemerisKernelError until a kernel is configured. See Kernel Setup below before executing planetary examples.

from datetime import datetime, timezone
from moira import Moira

m = Moira()

# 1. Planetary positions
chart = m.chart(datetime(2000, 1, 1, 12, 0, tzinfo=timezone.utc))
print(f"Sun:  {chart.planets['Sun'].longitude:.6f} deg")
print(f"Moon: {chart.planets['Moon'].longitude:.6f} deg")

# 2. House cusps (Placidus, London)
from moira import HouseSystem
houses = m.houses(
    datetime(2000, 1, 1, 12, 0, tzinfo=timezone.utc),
    latitude=51.5074,
    longitude=-0.1278,
    system=HouseSystem.PLACIDUS,
)
print(f"ASC: {houses.asc:.4f} deg  |  MC: {houses.mc:.4f} deg")

# 3. Aspect patterns
from moira.patterns import find_all_patterns
patterns = find_all_patterns(chart.longitudes())
for p in patterns:
    print(f"{p.name}: {', '.join(p.bodies)}")

# 4. House placement lookup
from moira.houses import house_of
sun_house = house_of(chart.planets['Sun'].longitude, houses)
print(f"Sun is in house: {sun_house}")

REST API Server

The engine ships with an optional FastAPI transport layer (moira_server) that exposes the admitted engine surface as typed, versioned REST routes.

pip install "moira-astro[server]"
uvicorn --factory moira_server:create_app

For latency-sensitive deployments, opt in to one bounded per-worker startup warmup before accepting computational traffic:

$env:MOIRA_SERVER_PREWARM = "1"
uvicorn --factory moira_server:create_app

With prewarm enabled, /ready returns HTTP 503 until the kernel-backed warmup succeeds; /health remains available for liveness diagnostics. Prewarm is disabled by default because each worker pays its own native memory cost.


Requirements and Installation

# Standard install (uses a published wheel when available)
pip install moira-astro

# With the FastAPI REST server (FastAPI, Starlette, Uvicorn, Pydantic)
pip install "moira-astro[server]"

# With Lunar Graze support (spiceypy, laspy, requests)
pip install "moira-astro[lunar-graze]"

This README documents the current main branch. The PyPI badge identifies the latest packaged release; features merged after that release require a source checkout until the next version is published.


Kernel Setup

Moira requires a JPL DE-series SPK planetary kernel for all planetary computation. No kernel is bundled — the files are large and the choice of release belongs to the user.

All kernel reading is performed by Moira’s own native C++ SPK/DAF reader. As of 4.0.0 there is no jplephem runtime fallback: segment types outside the native reader’s support raise an explicit error rather than silently routing through a third-party library.

Ordinary chart and ephemeris calculations read local resources and do not make outbound requests. Network access belongs to acquisition paths such as the kernel downloader, the Horizons/SBDB-backed DAF writer, and uncached optional research resources.

Recommended, release-documented kernels:

Kernel File Size Date range Notes
DE441 de441.bsp ~3.1 GB ~13 200 BCE – ~17 200 CE Original design target; maximum date coverage
DE440 de440.bsp ~114 MiB 1550 BCE – 2650 CE Moira’s recommended modern-range kernel for most users
DE430 de430.bsp ~114 MiB 1550 BCE – 2650 CE Widely deployed predecessor to DE440

Automatic discovery also recognizes DE431 and DE432 for compatibility. That does not make every readable Type-2/3 SPK an admitted release kernel. Kernels outside the release-documented set may be manually readable, but must not be presented as release-validated without a versioned admission record.

Kernel Manager (GUI)

The easiest way to download and configure a kernel is the built-in Tkinter interface. Tkinter is included with official Python installers but is an optional CPython module on some distributions; run python -m tkinter in the intended environment to confirm it is available, or install the Tcl/Tk package supplied by the Python distributor.

moira-kernel-manager

The window shows all supported kernels with extended descriptions (design rationale, date coverage, size trade-offs), live Installed/Missing status for each, and a real progress bar for downloads. You can also point Moira at a .bsp file already on disk without re-downloading.

What the GUI provides:

The GUI and moira-download-kernels supplemental entries are the generic JPL asteroids.bsp and sb441-n373s.bsp resources. They are separate from both Moira asteroid catalogs (the wheel roster and the 10,025-body archive) and from the 497-comet release described below. They remain caller-managed compatibility inputs for explicit small-body workflows; downloading them does not install or substitute for either Moira catalog. moira-download-kernels still does not fetch the 10,025-body archive.

CLI

# List all kernels and their status
moira-download-kernels --list

# Download all missing kernels (interactive prompt)
moira-download-kernels

# Download without prompting
moira-download-kernels --yes

SPK Kernel Writer (GUI)

Moira supports building custom Type 13 SPK kernels using an integrated compiler GUI (built on Tkinter). This utility fetches physical position vectors directly from the JPL Horizons API and packages them into a native-readable binary kernel (.bsp).

moira-daf-writer

What the custom kernel writer provides:

Engine readiness model

Standard location: kernels/<filename>.bsp relative to the repository root, or ~/.moira/kernels/. The engine resolves either automatically.

Custom location: pass the path at construction, or call set_kernel_path() before the first Moira() instantiation:

from moira.spk_reader import set_kernel_path
from moira import Moira

set_kernel_path("/path/to/de440.bsp")
m = Moira()

print(m.is_kernel_available())
print(m.get_kernel_status())
print(m.available_kernels)

Direct download links (JPL):

Small-Body Catalogs (Asteroids and Comets)

The wheel ships catalog moira-asteroids-wheel release 2026.08.14.1: 25 named bodies (including Chiron) as one Type-13 shard under moira/kernels/asteroids_wheel/. After pip install plus a planetary kernel, that roster is position-capable without a separate small-body download.

The full unified asteroid catalog (10,025 bodies as 401 Type-13 shards in release 2026.08.12.1) and the numbered periodic comet catalog (497 comets as 20 shards in release 2026.07.28.1) are too large to ship inside the wheel and are distributed separately. moira-download-kernels still does not fetch the 10,025-body catalog. Generic JPL files (asteroids.bsp, sb441-n373s.bsp) do not substitute for either Moira catalog.

Search by name, designation, catalog number, or NAIF ID and download the exact published files from the Moira Small-Body Ephemerides archive. The archive maps each body to its shared multi-body shard and provides direct BSP and metadata links, release manifests, coverage/provenance, and SHA-256 receipts. A body search therefore returns the shard containing that body, not a one-body BSP.

For automatic catalog admission of a full external release, place the complete release in asteroids/ or comets/ under a kernel search root (kernels/ at the repository root or ~/.moira/kernels/), with manifest.json, SHA256SUMS, all declared shards, per-shard metadata, and support files together in that directory. Do not retain an additional catalog-version directory between asteroids/ or comets/ and manifest.json. The engine discovers these manifests automatically; no configuration call is required. Release-finalized manifests are verified as complete before any shard is opened, so a lone shard is suitable for independent inspection but is not a complete automatic catalog installation. When both the wheel catalog and a higher-precedence full asteroid catalog are present, first-match discovery leaves the full catalog in charge for bodies it covers. A bundled canonical name alone does not imply position capability for bodies outside the wheel roster.

Distributed catalog releases are immutable and versioned. Each extracted release contains SHA256SUMS; its manifest.json also records the byte length and SHA-256 of every Moira-generated Type-13 kernel and its per-shard build evidence. Verify an extracted release with:

.\.venv\Scripts\python.exe -m moira.small_body_catalog_release verify C:\path\to\catalog-release

Verify individually downloaded files against the manifest and SHA-256 receipts. If a release maintainer or mirror supplies a ZIP produced by Moira’s release tooling, verify that archive before extraction with:

.\.venv\Scripts\python.exe -m moira.small_body_catalog_release verify-archive C:\path\to\catalog-release.zip

Release maintainers finalize an already-built catalog without recalculating its ephemeris using the prepare command documented by python -m moira.small_body_catalog_release --help. A changed file, membership set, sampling policy, or coverage rule always receives a new catalog version; published bytes are never replaced beneath an existing version.

Note for pre-4.0.0 installs: standalone supplemental kernels such as comets.bsp, centaurs.bsp, and minor_bodies.bsp no longer auto-load into the main facade. Automatic catalog discovery is manifest-based; the named Centaurs formerly associated with centaurs.bsp are covered by the wheel catalog. Compatible standalone SPKs remain available only through explicit caller-managed loading where the relevant API admits it.


Data Inventory

Layer Source Bundled Note
IAU 2000A/2006 nutation and precession tables IAU Yes 2,414 terms; native C++ (_moira_native)
DE-series planetary kernel JPL No de430 (~114 MiB), de440 (~114 MiB), or de441 (~3.1 GB); download separately
Named star registry Sovereign (star_registry.csv + JSON provenance) Yes 1,809 stars; license-independent
Deep-sky coordinate-anchor catalog Moira selection; SIMBAD coordinates and identities; NASA Exoplanet Archive host confirmation Yes 60 non-Solar-System anchors; extended-object centers are not physical point masses; per-artifact SHA-256 and source receipt included
Canonical small-body identity registries Moira release catalogs with JPL identity lineage Yes 10,025 asteroid and 497 comet identities; names and disambiguation only, with no positional vectors implied
Wheel asteroid ephemeris JPL Horizons (Moira Type-13 packaging) Yes Catalog moira-asteroids-wheel 2026.08.14.1; 25 named bodies including Chiron; one Type-13 shard
Full position-capable asteroid ephemeris JPL Horizons No 10,025 selected asteroids; 401 Type-13 shards in release 2026.08.12.1; public archive, manifest-discovered; not fetched by moira-download-kernels
Asteroid-family membership catalog Proper25 + retained NASA PDS exclusions Yes 342 families; 200,726 unique numbered asteroids; 221,095 many-to-many membership rows; no positional ephemeris implied
Numbered periodic comet catalog JPL Horizons No 497 comets (1P–516P); 20 Type-13 shards in release 2026.07.28.1; public archive, manifest-discovered

Native C++ Performance

Moira’s required numerical extension (_moira_native) is implemented in C++17 with pybind11. Published wheels install the compiled extension directly; source distributions build it during installation. Admitted native paths include IAU 2000A nutation, SPK/DAF access and segment evaluation, apparent planetary evaluation through NativePlanetaryEvaluator, selected coordinate transforms, light-time primitives, harmogram computation, precession, and selected event-search kernels.

Python remains responsible for public policy, result semantics, orchestration, and event-search branches that have not been explicitly admitted to the native substrate. This selective boundary matters most in phenomenon searches where Python-owned doctrine can reuse native numerical primitives thousands of times without pretending the entire technique is native-owned.


Validation Evidence

Moira is validated as a three-layer corpus. Each layer has its own correct evidence standard.

Astronomy layer — authoritative physical oracles first, enforced regression thereafter. References: IAU ERFA/SOFA, JPL Horizons, NASA catalogs, IERS.

Astrology layer — named primary texts, source-owned fixtures, and doctrine-grounded invariants; bounded external chart-software comparison where its settings and mathematical product are actually commensurate. Swiss Ephemeris and Astro.com are secondary comparators, not Moira’s governing runtime or universal authority.

Experimental layer — subsystem-specific surfaces for sovereign or modern domains. Domains: sovereign fixed stars, variable stars, multiple star systems, galactic transforms, eclipse Saros classification.

Every validated claim must pass three gates:

  1. Gate of Source — inputs and reference data are tied to an independent authority.
  2. Gate of Flow — the computational path is explicit and inspectable.
  3. Gate of Validation — outputs meet a product-appropriate external authority, source-owned golden, independent invariant, or explicitly bounded secondary comparison.

When residuals remain, Moira isolates the discrepancy by identity, time scale, frame, correction regime, and product semantics before classifying it as a defect, a model-basis difference, or unresolved evidence. Agreement between two internally consistent systems is not assumed when they answer different mathematical questions.

The reports below are dated evidence ledgers, not self-updating assertions. Release-specific changes and validation boundaries are recorded in the changelog and the 6.1.0 release notes.

Report Verification Source
VALIDATION_ASTRONOMY.md Product-specific IAU ERFA/SOFA, JPL Horizons, NASA, IERS, and invariant evidence with named tolerances and qualifications.
PLANETARY_REDUCTION_PIPELINE.md Major-body route identity, reader-bound time and context ownership, reduction stages, compatibility boundary, and target/time/frame-matched Horizons contracts.
VALIDATION_ASTROLOGY.md Primary texts, source-owned goldens, doctrine tables, invariants, and bounded Swiss/Astro.com corroboration where applicable.
VALIDATION_EXPERIMENTAL.md Dated subsystem evidence and explicit partial-status boundaries for sovereign and modern products.

The Reduction Pipeline

graph TD
    A[JPL Planetary Kernel\nChebyshev state vectors] --> B[SSB Barycentric Position\nkm · ICRF]
    C[Sovereign Star Registry\n1809 named stars] --> D[Stellar Astrometric Position\nproper motion · parallax]
    B --> E[1 · Light-Time Iteration\nbody at t − τ  where τ = d/c]
    E --> F[2 · Gravitational Deflection\nSun · Jupiter · Saturn]
    F --> G[3 · Annual Aberration\nrelativistic · IAU SOFA]
    G --> H[4 · IAU 2006 Frame Bias\nICRF → Mean Equator J2000]
    D --> H
    H --> I[5 · IAU 2006 Precession\nP03 polynomial series]
    I --> J[6 · IAU 2000A Nutation\n1358 luni-solar + 1056 planetary terms]
    J --> K[True Equinox and Equator of Date]
    K --> L[7 · Topocentric Parallax\nWGS-84 · optional]
    L --> R[8 · Diurnal Aberration\nobserver rotation · optional]
    R --> M[Atmospheric Refraction\nsky altitude only · optional]
    K --> N[Ecliptic Projection\nTrue obliquity of date]
    N --> O[Zodiacal Longitude · Latitude · Distance]
    K --> P[Sidereal Frame · Ayanamsa\noptional]
    K --> Q[House Cusps · 22 Systems\nrequires lat/lon]

Worked Example: Mars at 2000-01-01 12:00 UT1

This snapshot is reproduced by planet_reduction_breakdown_at("Mars", 2451545.0, reader) with the admitted DE441 kernel. The input is JD_UT1 2451545.0; it is about 63.829 seconds after the exact J2000.0 TT epoch and is therefore not labelled as exact J2000.0.

Time: JD_UT1 2451545.000000 → JD_TT 2451545.000739  (ΔT = +63.829 s)

Stage Operation Engine receipt Longitude contribution
0 Geometric geocentric SSB-to-Mars minus SSB-to-Earth; λ = 327.975456°; distance = 276,697,408.4 km reference
1 Light-time iteration τ = 0.010683 days = 15.383 min −15.762371″
2 Gravitational deflection Sun, Jupiter, and Saturn −0.003057″
3 Annual aberration Earth barycentric velocity; relativistic −14.069158″
4 IAU 2006 frame bias ICRF to dynamical mean J2000 +0.000300″
5 IAU 2006 precession P03; mean equator/ecliptic of date +0.006571″
6 IAU 2000A nutation Δψ = −13.932004″; Δε = −5.769413″ −13.932004″
7–8 Topocentric parallax and diurnal aberration disabled for this geocentric example 0

Final position: Aquarius 27° 57′ 48″  ·  λ = 327.963300°  ·  β = −1.067779°  ·  distance = 1.849688 AU  ·  speed = +0.775674°/day

Total visible reduction from the geometric J2000-ecliptic reference to the final true-of-date ecliptic longitude: −43.759719 arcseconds.

The stage contributions above come from the typed reduction receipt. They should not be reconstructed by subtracting unrelated coordinate frames or by treating apparent=False as “no frame transformation.”

Pipeline Controls

Selected correction policies can be toggled via planet_at(). The table below shows the measurable effect of disabling each exposed policy in this JD_UT1 = 2451545.0 Mars snapshot.

Parameter Default Effect on snapshot longitude Function
apparent=True True Full pipeline active planet_at()
apparent=False Omits light-time, deflection, and aberration while retaining the declared ecliptic-of-date frame and nutation policy. Δ = +29.835 arcsec planet_at()
aberration=False Aberration stage skipped. Δ = +14.069 arcsec planet_at()
grav_deflection=False Deflection stage skipped. Δ = +0.003 arcsec planet_at()
nutation=False Nutation skipped; mean equinox used. Δ = +13.932 arcsec planet_at()
observer_lat/lon None When supplied together, adds WGS-84 topocentric parallax and observer-rotation diurnal aberration; the effect is body-, location-, and epoch-dependent. planet_at()
refraction=True True Applies the declared pressure, temperature, and humidity model to geometric sky altitude. sky_position_at()
delta_t_policy None Controls UT → TT conversion branch (IERS tables, polynomial, hybrid physical) both

Project Documentation

The canonical documentation tree lives in wiki/. The flat moira.wiki/ Git wiki mirror is generated from it by .\.venv\Scripts\python.exe scripts\sync_git_wiki.py and should not be edited by hand. Website-publishable documents are governed by website_docs/publication_sources.json and built with .\.venv\Scripts\python.exe scripts\build_website_docs_bundle.py. After changing server routes, run .\.venv\Scripts\python.exe scripts\sync_rest_api_reference.py in an environment with the server extra installed; CI checks its generated OpenAPI inventory, the Git wiki mirror, and the website publication manifest for drift.

Document Contents
CHANGELOG.md Versioned release history and current unreleased boundary.
RELEASE_NOTES_6.1.0.md Published 6.1.0 release notes, validation summary, and explicit exclusions.
01_LIGHT_BOX_DOCTRINE.md Transparency and derivation as design constraints.
BEYOND_SWISS_EPHEMERIS.md Capabilities enabled by sovereign catalogs, explicit policy, and modern Python.
WHY_MOIRA_DOES_NOT_COMPRESS_DEXX.md How Moira reads published JPL SPK records versus how Swiss reads packed .se1.
MIGRATING_FROM_SWISS_EPHEMERIS.md Contract-first porting guide for Swiss flags, bodies, time scales, units, houses, REST, and dual-run verification.
HOUSE_SYSTEM_DIVERGENCE.md House-system derivation and discretionary divergence from conventional Swiss-facing behavior.
PHYSICAL_HELIACAL_VISIBILITY_CAPABILITY_MATRIX.generated.md Current physical-visibility admission, evidence classes, tolerances, and closed exclusions.
PHYSICAL_HELIACAL_VISIBILITY_API_INVENTORY.generated.md Generated Python/facade/REST/OpenAPI inventory for the opt-in physical contract.
CONSTITUTIONAL_PROCESS.md The Subsystem Constitutional Process — the development and governance protocol.
MOIRA_ROADMAP.md Living implementation roadmap and improvement register; validation claims remain owned by the validation ledgers and release notes.

License

MIT (c) 2026 TheDaniel166. See PROVENANCE.md for license and Swiss-lineage provenance clarity.