lxephemeris
The modern astronomical & astrological computation engine for Python, Node.js, and Rust.
100% memory-safe Rust core. Lock-free multi-threading. Zero external files required to start — with native NASA JPL DE440s support for sub-milliarcsecond precision.
# Works out of the box with zero external files (or loads NASA JPL DE440s if present)
=
=
=
# Full natal snapshot: planets, 23 house systems, aspects, Hermetic lots, lunar phase & sect in ~150 µs
=
Why We Built lxephemeris
If you have ever built a production astrology, horary, Vedic, Human Design, or astronomical API in Python or Node.js, you know the pain of the existing ecosystem.
For nearly three decades, almost every backend in the industry has been forced to glue together Swiss Ephemeris (libswe / pyswisseph) — a C library designed in the 1990s for single-threaded desktop apps — alongside PyEphem and Kerykeion.
When we ran that legacy stack under high concurrency in production, we kept hitting the same architectural walls:
- Global Mutable C State & Thread-Safety Bugs:
libswestores ephemeris paths (swe_set_ephe_path), sidereal modes (swe_set_sid_mode), and topocentric observers (swe_set_topo) in process-globalstaticC variables. If Thread A computes a Vedic (Lahiri) chart while Thread B computes a Western (Tropical) chart, they silently corrupt each other's math. Fixing this in Python required ratusan lines of globalRLockwrappers that killed multi-core throughput. - A Mountain of Monkey-Patches: High-level wrappers had to be patched just to return accurate charts:
Kerykeionsilently clamps latitudes above±66°, causing a 7.85° Ascendant error in Northern Europe, Alaska, and Svalbard, and truncates birth-time seconds (second=0), shifting the Ascendant by up to 15 arcminutes.- Rounding planet longitudes (
round(lon, 4)) before house assignment routinely drops cusp planets into the wrong house. PyEphem'sSun().hlongreturns Earth's heliocentric longitude shifted by180°(breaking Chinese Jieqi solar terms), andephem.Ecliptic(ephem.Moon(obs))rotates topocentric coordinates using static J2000 obliquity (23 arcminutes of error).
- 22 Upstream Calculation & C Buffer Bugs:
- Missing
.se1ephemeris files causelibsweto silently downgrade to a lower-precision fallback without raising an error. swe_house_posreturns an invalid0.0at high latitudes or circumpolar declinations.swe_fixstar2_ut("Mira")matchesMirach(>17° error) due to naive prefix matching in C.- Star-anchored sidereal modes (
True Citra,Revati,Pushya) wobble by ±20.5 arcseconds every year because annual stellar aberration is mixed into the anchor star.
- Missing
- Slow FFI Loops for Transits, Returns & Timelines: Finding a year of exact transit windows, retrograde stations, Void-of-Course Moon intervals, or a 3-pass Saturn Return meant running tens of thousands of Python/JS bisection calls across the C FFI boundary — taking hundreds of milliseconds per request.
- Dependency Sprawl: Teams had to maintain 5–6 different libraries — one for planetary positions, one for lunar phases, one for natal wheels, another for Vedic Panchanga/Dasha, another for Hellenistic Lots, and custom scripts for Human Design gates or Chinese calendars.
So we built lxephemeris from scratch in 100% safe Rust (#![forbid(unsafe_code)]).
No C pointers. No global state. No monkey-patches. Just one ultra-fast, mathematically rigorous engine with first-class native SDKs for Python (PyO3), Node.js / TypeScript (napi-rs), and Rust.
What Makes lxephemeris Better
1. One Engine Replaces 6+ Libraries (Batteries Included)
Instead of stitching together pyswisseph + ephem + kerykeion + custom scripts, lxephemeris ships every major astronomical and astrological subsystem natively in Rust:
- Solar System & 68 Minor Bodies:
Sun..Pluto, 7 Lunar points (Mean_Node,True_Node,Mean_South_Node,True_South_Node,Mean_Lilith,True_Lilith, and smooth $C^2$Interpolated_Lilith), 9 Uranian hypotheticals (Cupido..Poseidon,Isis), and 68 JPLSB441-N16asteroids, centaurs, and dwarf planets (Chiron,Ceres,Pallas,Juno,Vesta,Pholus,Nessus,Eris,Sedna,Haumea,Makemake,Lilith (1181),Proserpina (26), etc.). - 23 House Systems + Polar Safety: Placidus, Koch, Porphyry, Regiomontanus, Campanus, Equal, Whole Sign, Alcabitius, Morinus, Topocentric (Polich-Page), Krusinski, APC, Carter, Sunshine, Gauquelin (36 sectors), and more — with explicit
PolarPolicy(Strict,FallbackToWholeSign,FallbackToPorphyry) so Arctic/Antarctic charts never crash or flip 180°. - Native Event & Timing Solvers:
- Aspects & Transits: Static natal & synastry aspects (
calc_chart_aspects,calc_synastry_aspects), declination parallels/contraparallels, exact sky-to-sky aspect windows (mutual_aspects_in_range), natal transit timelines (natal_transits_in_range), and Void-of-Course Moon intervals (void_of_course_moon_in_range). - Planetary Returns & Stations: Exact Solar, Lunar, Saturn, and Chiron returns (
planetary_return,planetary_returns_in_range) that automatically detect all 3 passes of a retrograde return loop, plus exact retrograde/direct stations (search_stations_in_range).
- Aspects & Transits: Static natal & synastry aspects (
- Vedic / Jyotish Suite:
- 43+1 Sidereal Ayanamsas: All 43 standard models (
Lahiri,True Citra,Krishnamurti (KP),Raman,Fagan-Bradley,Suryasiddhanta,Yukteshwar, etc.) plus custom user-defined ayanamsas — free of annual aberration wobble. - Panchanga, Muhurta & Vargas: Full 5-limb
panchanga(Tithi,Nakshatra + Pada,Yoga,Karana,Vara, plusRahukalam,Yamagandam,Gulika Kalam,Abhijit Muhurta), all 16 Parashara Shodashavarga (D1..D60), and 120-year Vimshottari Dasha (Maha,Antar,Pratyantar).
- 43+1 Sidereal Ayanamsas: All 43 standard models (
- Traditional & Hellenistic Suite: Day/Night chart sect (
chart_sect), 24 Chaldean Planetary Hours (planetary_hours), and 7 Hermetic Lots (Fortune,Spirit,Eros,Necessity,Courage,Victory,Nemesiswith diurnal/nocturnal reversal). - Human Design & Chinese Solar Calendar:
- Human Design: Exact
-88°prenatal Design solar arc solver (human_design_epoch) and 64 I-Ching Mandala Gates × 6 Lines × Color × Tone × Base (map_zodiac_placement). - Chinese Almanac: All 24 Solar Terms (Jieqi / Zhongqi,
solar_terms_in_range), 4 cardinal seasons (seasons_in_year), and lunar phase solvers (lunar_phases_in_range, 8-phase & 28-phaselunar_phase_summary).
- Human Design: Exact
- Fixed Stars, Brady Parans, Eclipses & Occultations:
- 52 Embedded Fixed Stars (VizieR Hipparcos-2
I/311+ XHIPV/137Dwith full 3D space motion) + customsefstars.txt/ JSON catalog loader. - Bernadette Brady Parans (
find_parans) & Schaefer Heliacal Risings/Settings. - Solar & Lunar Eclipses (global & local Besselian solvers with Saros series/member and path width) & Lunar Occultations of stars, planets, and asteroids.
- 52 Embedded Fixed Stars (VizieR Hipparcos-2
2. Zero External Files Required — Or Sub-Milliarcsecond JPL DE440s
- Instant Zero-File Start (
Engine()): Works the second you install it. When no external.bspfiles are configured,lxephemerisuses its built-inDE440s-calibrated analytical engine covering-3000 CE .. +3000 CEwith zero disk I/O. - Observatory-Grade SPK Mode (
Engine.from_data_dir("./data")): Point the engine at NASA JPLDE440s(1849–2150),DE440(1550–2650),DE441(-13200..+17191), orINPOP21aplusasteroids_68_1850_2100.bspfor< 0.003 arcsecondagreement with NASA JPL Horizons.
3. 5–15× Faster (Single-Pass Analytical Velocities)
Legacy ephemeris libraries compute planet speed (°/day) by evaluating the ephemeris 3 separate times ($t - \Delta t, t, t + \Delta t$) and taking a finite difference — which is both 3× slower and prone to $0\circ / 360\circ$ wrap-around glitches.
lxephemerisdifferentiates Chebyshev polynomials, relativistic light-time, aberration, and the IAU 2006/2000A frame rotation matrix analytically in a single pass:12.8 µsper planetary position + instantaneous velocity.~150–240 µsfor a complete natal chart (chart_snapshot).- Releases the Python GIL and runs multi-core Rayon batch queries (
calc_batch,calc_batch_flat_f64,houses_batch) across all CPU cores.
4. Drop-In Migration for Existing pyswisseph Codebases
Don't want to rewrite your whole app at once? lxephemeris includes a thread-safe SweAdapter that mirrors the swisseph API (calc_ut, houses_ex2, fixstar2_ut, get_ayanamsa_ex_ut, sol_eclipse_when_glob, lun_eclipse_when, nod_aps_ut, pheno_ut, rise_trans, azalt, julday, revjul, and SE_* constants) — scoped safely to an engine instance instead of global C state.
How lxephemeris Compares
| Feature | lxephemeris |
Swiss Ephemeris (pyswisseph) |
Kerykeion | PyEphem (ephem) |
Skyfield |
|---|---|---|---|---|---|
| Core Architecture | 100% Safe Rust (#![forbid(unsafe_code)]) |
Legacy C (libswe, 1990s) |
Python wrapper over pyswisseph |
Legacy C (libastro) |
Pure Python / NumPy |
| Thread Safety | Lock-free Send + Sync (0 state bleed) |
❌ Global mutable C static state |
❌ Inherits pyswisseph globals |
⚠️ Mutable Body objects |
✅ Thread-safe |
| Works with 0 External Files | ✅ Built-in analytical engine (-3000..+3000) |
⚠️ Silent fallback if .se1 missing |
✅ Bundles .se1 files |
✅ Analytical only | ❌ Requires downloading .bsp |
JPL DE440s / DE441 Precision |
✅ Native DAF/SPK (< 0.003") |
Compressed .se1 re-fits |
Via pyswisseph |
❌ Truncated VSOP87 (multi-arcsec drift) | ✅ Native SPK |
| Single Body + Speed Latency | 12.8 µs (analytical Jacobian) |
~45–90 µs (3-pt finite diff) |
~25–80 ms per subject |
~80–150 µs |
~600–2,000 µs |
| 23 Houses & Arctic/Polar Safety | ✅ All 23 + explicit PolarPolicy |
⚠️ Silent polar fallback & house_pos=0.0 bug |
❌ Clamps |lat| > 66° (7.85° ASC error) |
❌ No astrological houses | ❌ No astrological houses |
| 68 Astrological Minor Bodies | ✅ Single verified .bsp + Keplerian fallback |
Manage 68 separate .se1 files |
Partial | ❌ Manual orbital elements | Manual SPK segments |
| 43+1 Sidereal Ayanamsas | ✅ Aberration-free star anchors | ⚠️ ±20.5" annual aberration wobble on star anchors |
⚠️ Leaves secondary points tropical | ❌ None | ❌ None |
| Transit, Return & VoC Moon Solvers | ✅ Native Rust Newton-Illinois solvers | ❌ Write your own FFI loops | ❌ Static charts only | ❌ Basic rising/phase only | Discrete almanac only |
| Vedic (Panchanga, Dasha, D1–D60) | ✅ Built-in | ❌ None | ❌ None | ❌ None | ❌ None |
| Traditional (Sect, Hours, 7 Lots) | ✅ Built-in | ❌ None | ❌ None | ❌ None | ❌ None |
Human Design (64 Gates & -88° Arc) |
✅ Built-in | ❌ None | ❌ None | ❌ None | ❌ None |
| SDKs with Identical Math | Python, Node.js/TS, Rust, CLI | C + separate 3rd-party bindings | Python only | Python only | Python only |
Quickstart
Python (lxephemeris)
# 1. Start immediately (zero external files needed) or load NASA JPL DE440s from ./data
=
# engine = lxephemeris.Engine.from_data_dir("./data", verify_manifest_sha256=True)
# 2. Local wall-clock time -> UTC Julian Date (preserves fractional seconds & PEP 495 DST fold)
=
=
# 3. Single body position + analytical speed + visual magnitude
=
=
# 4. Polar-safe houses & cusp boundary guard (eps = 1e-9°)
=
=
# 5. All-in-one Natal Snapshot, Solar Return, Vedic Panchanga, & Human Design Gate
=
=
=
=
Node.js / TypeScript (lxephemeris)
import { Engine, utcFromLocal, houseOfLon, mapZodiacPlacement } from "lxephemeris";
// 1. Start immediately (zero external files needed) or load NASA JPL DE440s from ./data
const engine = new Engine();
// const engine = Engine.fromDataDir("./data", 4, null, true);
const jdUtc = utcFromLocal(2026, 10, 24, 14, 0, 32.5, "Europe/Berlin");
const jdSplit = { jd1: jdUtc, jd2: 0.0 };
const obs = { latitudeDeg: 51.5074, longitudeDeg: -0.1278, altitudeM: 35 };
const sun = engine.calc("Sun", jdSplit, "UTC");
const houses = engine.houses(jdSplit, obs, "P", "UTC", "fallback_to_whole_sign");
const sunHouse = houseOfLon(sun.lonDeg, houses.cuspsDeg, 1e-9);
const snapshot = engine.chartSnapshot(jdUtc, obs);
const hd = mapZodiacPlacement(sun.lonDeg);
console.log(
`Sun: ${sun.lonDeg.toFixed(6)}° in House ${sunHouse} | HD Gate ${hd.hdGate}.${hd.hdLine} | Lots: ${snapshot.lots.length}`
);
Rust (lxephemeris-core)
use ;
Command-Line Interface (lxephemeris-cli)
# Calculate planetary & asteroid positions (works out of the box with zero external files)
# Calculate house cusps & angles
# Vedic Panchanga for New Delhi
# Legacy swetest-compatible output
# Synchronize IERS finals2000A (Delta-T / UT1-UTC) & leap-second tables
# Fetch NASA JPL planetary kernels (de440s, de440, de441, inpop21a)
22 Upstream Bugs Eliminated by Design
Every behavioral difference between lxephemeris and legacy tools is documented and regression-tested in docs/SE_DIVERGENCES.md.
Swiss Ephemeris (SWE-01..SWE-11)
SWE-01(Global State Race Conditions):set_ephe_path,set_sid_mode, andset_topomutate process-global C state. Inlxephemeris, all configuration is immutable or passed per call (Send + Sync).SWE-02(Star-Anchored Ayanamsa Wobble):True Citra,Revati, andPushyainlibsweinclude annual stellar aberration ($\pm 20.5''$ yearly oscillation).lxephemerisevaluates star anchors strictly in the geometric frame.SWE-03(swe_house_posReturning0.0):libswereturns an invalid0.0house position at circumpolar declinations or high latitudes.lxephemerisuses a closed-form 3D horizon/prime-vertical projection valid on $[1.0, 13.0)$.SWE-04(Mira/MirachStar Collision):swe_fixstar2_ut("Mira")prefix-matchesMirach($>17^\circ$ error).lxephemerisuses exact normalized name, Bayer, and Hipparcos ID matching.SWE-05(Sidereal Velocity Double-Nutation): Fixes frame-rate and nutation-rate inconsistencies in sidereal speeds.SWE-06(Silent Ephemeris Fallback): Missing.se1files silently downgrade accuracy inlibswe.lxephemerisvalidates SHA-256 manifests explicitly and exposesengine.is_moshier_mode().SWE-07(Silent Polar House Flips): Replaces silent Porphyry substitution and $180^\circ$ Ascendant flips with explicitPolarPolicy(Strict,FallbackToWholeSign,FallbackToPorphyry).SWE-08(Zero/Negative Stellar Parallax Explosion): Guards Hipparcos-2 parallax $\varpi \le 0$ against division-by-zero and $180^\circ$ sky inversions.SWE-09($0\circ / 360\circ$ Velocity Glitch): Single-pass analytical Jacobians eliminate finite-difference branch-cut spikes at $0^\circ \ Aries$.SWE-10(Besselian Eclipse Aberration Mixing): Separates solar annual aberration from lunar shadow-plane coordinates (0.2–0.6 scontact improvement).SWE-11(SE_MEAN_APOGOscillation): Provides true secular IERS 2003Mean_Lilithalongside osculatingTrue_Lilithand smooth $C^2$Interpolated_Lilith.
PyEphem (EPH-01..EPH-05)
EPH-01(Sun().hlong$180^\circ$ Inversion): Fixes the heliocentric Earth / geocentric Sun confusion that breaks Chinese Jieqi solar terms.EPH-02(Topocentric Moon $0.38^\circ$ Obliquity Error): Rotates topocentric coordinates using true obliquity of date $\varepsilon(t)$ instead of static J2000 obliquity.EPH-03(StaticFixedBodyStars): Applies full 3D Hipparcos-2 proper motion, parallax, and radial velocity in star parans.EPH-04(Truncated VSOP87 / ELP2000 Drift): Replaceslibastroseries with JPLDE440sandDE440-calibrated series.EPH-05(Naive Datetime & DST Fold Loss):utc_from_localenforces explicit IANA timezone + PEP 495folddisambiguation.
Kerykeion (KER-01..KER-06)
KER-01($\pm 66^\circ$ Latitude Clamping): Eliminates the silent latitude clamp that caused a $7.85^\circ$ Ascendant error at Svalbard ($78.22^\circ\text{N}$).KER-02($0.0 \to 0.0001^\circ$ Equator/Greenwich Hack): Handles $(0\circ, 0\circ)$ exactly with zero coordinate falsification.KER-03(Birth-Time Seconds Truncation): Preserves fullf64sub-second precision (preventing up to $15'$ of Ascendant drift).KER-04(Cusp Rounding House Drop):house_of_lonuses a formal1e-9°boundary epsilon instead ofround(lon, 4).KER-05(Mixed Tropical Points in Sidereal Charts): Applies sidereal ayanamsa uniformly across all planets, minor bodies, nodes, Liliths, lots, and fixed stars.KER-06(Hardcoded $23.4367^\circ$ Obliquity): Uses exact IAU 2006/2000A true obliquity and GAST everywhere.
Verification & Benchmarks
lxephemeris is continuously verified against 37,416 golden reference vectors generated from NASA JPL Horizons (DE440 / SB441-N16), IAU SOFA, USNO, and reference astronomical catalogs across 145+ Rust tests, 18 Python test suites, and 12 Node.js test suites:
| Verification Suite | Vectors | Coverage | Status |
|---|---|---|---|
| Core Planetary, 68 Asteroids, 52 Stars & 23 Houses | 10,242 | 1850..2100 full-domain grid across 10 planets, 68 minor bodies, 7 lunar points, 9 Uranians, 52 stars, 23 house systems |
PASS |
| Events, Parans, Eclipses, Occultations & 43 Ayanamsas | 10,540 | Rise/set/transit, 24 Solar Terms (Jieqi), HD -88° solar arc, stations, lunistices, Brady parans, Moshier (-500..+2500 CE), pheno_ut, nod_aps_ut |
PASS |
| Extreme Boundaries & 22 Upstream Bug Immunity Grid | 10,000 | Arctic/Antarctic houses, $0\circ/360\circ$ wrap velocities, retrograde triple passes, circumpolar house_pos, star-anchor sidereal nodes, DST folds |
PASS |
| Vedic Panchanga/Dasha/Vargas, Aspects, Returns & Lots | 5,000 | Panchanga, 16 Parashara Vargas (D1..D60), Vimshottari Dasha, 24 Planetary Hours, 7 Hermetic Lots, exact aspect windows, planetary returns, 64 HD Gates |
PASS |
| First-Principles NASA JPL Horizons & IAU SOFA Oracles | 1,634 | Direct JPL Horizons DE440 ICRF (< 0.003"), SB441-N16 68 minor bodies (< 0.00001"), IAU SOFA pmpx stars, Holden/Munkasey houses |
PASS |
| Total Verified Reference Vectors | 37,416 | 100% Pass across Rust, Python (PyO3), and Node.js (napi-rs) |
100% PASS |
Documentation
- Quickstart & Complete API Reference (
docs/QUICKSTART_AND_API.md) — Examples for every calculation mode, batch API, event solver, Vedic/Traditional/HD module, and CLI command. - Migration Guide from
pyswisseph,PyEphem&Kerykeion(docs/SWE_MIGRATION_GUIDE.md) — Side-by-side before/after examples for Python and TypeScript. - 22 Eliminated Upstream Bugs & Intentional Divergences (
docs/SE_DIVERGENCES.md) — Mathematical breakdown of every bug fixed inlxephemeris. - Mathematical Model Passports (
docs/MODEL_PASSPORTS.md) — Equations, constants, and peer-reviewed citations (IAU SOFA, IERS 2010, JPL DE440, Meeus, Parashara, Schmidt/Hand).
Licensing & Commercial Use
lxephemeris is distributed under a Dual License (LICENSE.md):
-
Free Non-Commercial License (
PolyForm-Noncommercial-1.0.0)
Free for personal projects, hobbyists, academic research, educational institutions, and non-profit organizations — plus a 30-day evaluation grant for commercial teams testinglxephemerisin non-production environments. -
Commercial License (
LicenseRef-Commercial)
Required for commercial products, paid SaaS/APIs, monetized mobile/web apps, and internal business production deployments.- Get a Commercial License: Submit a request at https://procoders.tech/contacts/ or email lxephemeris@procoders.tech.
- 100% Offline Activation (
Ed25519): Commercial customers receive an offline cryptographic license key (LXEPHEMERIS_LICENSE_KEYorLXEPHEMERIS_LICENSE_FILE) verified locally in microseconds — zero runtime phone-home, zero network calls, and perpetual fallback on covered engine releases.
# Verify your commercial license key via CLI, Python, Node.js, or Rust