Calculates precise lunar phases, Moon transits, aspects to natal planets, lunar days, and personal solar-lunar phases with charts and text analysis.
This skill calculates lunar phases and analyzes the Moon's influence on a person through multiple astrological lenses. It renders a chart with 2 wheels side-by-side (Moon phase + natal chart with transit Moon), 3-group horizontal legend below wheels, and a text analysis panel on the right.
The chart always includes a QR code (for donations) at the bottom of the text panel. By default the bundled rame_small.png.dat is used; users can override with --frame.
All planetary positions are computed using the Swiss Ephemeris library (pyswisseph 2.10.3.2), based on NASA's JPL DE431 ephemerides. Planetary position accuracy: ~0.003°. House cusps: Placidus system via swe.houses_ex().
RequirementDetailsOSWindows (x64)Python3.14.xRuntime****Microsoft Visual C++ Redistributable 2015–2022 (x64)Pillow12.x — pip install pillowSwiss EphemerisBundled as swisseph.cp314-win_amd64.pyd.dat
text
lunar_analysis.py --json → JSON data (all lunar metrics) → draw_lunar.py → PNG image
↕
lunar_analysis.py → text analysis output
lunar_analysis.py is the sole calculation engine. draw_lunar.py renders the chart by calling it via subprocess.
The Moon's position relative to the Sun (elongation angle):
Also calculates: illumination %, distance from Earth (km), exact dates of nearest phases.
The most important personal lunar metric. The transit Moon forms aspects to the natal Moon over a ~28-day cycle:
AspectTimingMeaningConjunctionEvery ~28 daysPersonal New Moon — emotional reset, new cycle beginsSquare~7 & 21 daysCrisis point — need for action, tensionOpposition~14 daysPersonal Full Moon — emotional climax, awarenessTrine~7 & 21 daysHarmony — intuition flows, good for planningSextile~4 & 24 daysOpportunity — gentle supportQuincunx~11 & 17 daysAdjustment — something needs realignmentSemisquare~3.5 & 10.5 daysMinor irritationSesquiquadrate~10.5 & 17.5 daysRestlessness — break patternsSemisextile~2 & 16 daysSubtle influence
The Moon's position relative to the natal Sun defines a personal lunar month (~29.5 days):
PhaseElongationMeaningPersonal New Moon0°Beginning of personal cycle. Inward energy. Start new projects.Personal Crescent45°Emerging. Energy builds. First steps.Personal First Quarter90°Action point. Challenges arise. Push through.Personal Gibbous135°Refinement. Fine-tune approach.Personal Full Moon180°CLIMAX. Maximum awareness. Emotional revelation.Personal Disseminating225°Sharing. Teach what you've learned.Personal Last Quarter270°Crisis of consciousness. Let go.Personal Balsamic315°Rest. Reflection. Prepare for next cycle.
Shows which life area is emotionally activated:
HouseLife AreaIPersonality, appearance, selfIIMoney, values, resourcesIIICommunication, siblings, learningIVHome, family, rootsVCreativity, children, romanceVIHealth, work, routineVIIPartnership, marriageVIIITransformation, shared resourcesIXPhilosophy, travel, higher educationXCareer, reputation, public lifeXIFriends, groups, hopesXIISubconscious, solitude, karma
30 lunar days from New Moon to New Moon, each with specific energy:
Moon's daily motion affects emotional processing:
Also tracks approach to perigee (closer = stronger) or apogee (farther = weaker).
Complete picture of how the transit Moon interacts with every natal planet — shows which psychological functions are emotionally activated.
bash
# Analysis for today
python scripts/lunar_analysis.py 24.04.1983 07:00 Ижевск --lang ru --name "Алексей"
# Analysis for any specific date
python scripts/lunar_analysis.py 24.04.1983 07:00 Ижевск --target-date 05.06.2026 --lang ru
# English output
python scripts/lunar_analysis.py 24.04.1983 07:00 Ижевск --lang en
# JSON output (for renderers / AI)
python scripts/lunar_analysis.py 24.04.1983 07:00 Ижевск --target-date 05.06.2026 --json
bash
# Chart for today (Russian)
python scripts/draw_lunar.py 24.04.1983 07:00 Ижевск --lang ru --name "Алексей"
# Chart for any specific date
python scripts/draw_lunar.py 24.04.1983 07:00 Ижевск --target-date 05.06.2026 --lang ru --name "Алексей"
# English
python scripts/draw_lunar.py 24.04.1983 07:00 Ижевск --target-date 05.06.2026 --lang en --name "Alexey"
ArgumentDescriptiondateBirth date DD.MM.YYYYtimeBirth time HH:MMcityBirth city--target-dateTarget date in DD.MM.YYYY or YYYY-MM-DD format (default: today). Supports any past, present, or future date. When omitted, uses current system date. Supported in both lunar_analysis.py and draw_lunar.py.--langLanguage: ru or en (default: ru)--namePerson's name for display--jsonOutput JSON instead of text--outputWrite JSON directly to file (UTF-8, bypasses console encoding)--conclusionPath to JSON file with AI-generated conclusion
json
{
"name": "Алексей",
"birth_date": "24.04.1983",
"birth_time": "07:00",
"birth_city": "Ижевск, Россия",
"target_date": "05.06.2026",
"moon_phase": {
"name": "Waning Gibbous",
"elongation": 236.33,
"illumination": 77.7,
"distance_au": 0.002669,
"distance_km": 399206
},
"nearest_phases": {
"New Moon": {"date": "15.06.2026", "days_diff": 9.6},
"Full Moon": {"date": "31.05.2026", "days_diff": -5.1}
},
"lunar_day": {"number": 20, "meaning_ru": "День орла..."},
"transit_moon": {"lon": 311.18, "sign": "Capricorn", "speed": 12.14},
"transit_moon_to_natal_moon": {"aspect": "Sesquiquadrate", "orb": 0.91},
"personal_phase": {"key": "last_quarter", "name_ru": "Персональная последняя четверть"},
"transit_moon_house": {"house": 7, "title_ru": "Партнёрство, брак..."},
"moon_speed": {"speed": 12.14, "description_ru": "Нормальная..."},
"transit_moon_aspects": [
{"transit": "Moon", "natal": "Sun", "aspect": "Square", "major": true, "orb": 7.6}
],
"engine": "Swiss Ephemeris v20230604"
}
text
+---------------------------+---------------------------+-------------------+
| | | |
| ФАЗА ЛУНЫ | НАТАЛЬНОЕ КОЛЕСО | TEXT ANALYSIS |
| MOON PHASE WHEEL | NATAL CHART WHEEL | PANEL |
| (3400/2 = 1700 wide) | (1700 wide) | (2360×2880) |
| | | |
| - Phase circle | - Sign sectors (elements)| - Moon phase |
| - Illumination % center | - House cusps (Placidus) | - Nearest phases |
| - Phase degree markers | - Natal planets (circles | - Lunar day |
| - Current position | with letter codes) | - Moon aspects |
| indicator (yellow) | - Transit Moon (outer | - Personal phase |
| | orbit, highlighted) | - House |
| | - ASC/MC lines | - Moon speed |
| | - Aspect lines (colored) | - All aspects |
| | | - Conclusion |
| | | |
+---------------------------+---------------------------+-------------------+
Legend (below wheels, 3 uniform-height groups side by side):
┌─────────────────┬─────────────────┬─────────────────┐
│ ПЛАНЕТЫ │ АСПЕКТЫ │ СТИХИИ │
│ (PLANETS) │ (ASPECTS) │ (ELEMENTS) │
│ │ │ │
│ ♈ SU Sun │ □ Conj │ ■ Огонь │
│ ♉ MO Moon │ ✶ Sext │ ■ Земля │
│ ♊ ME Mercury │ □ Sqr │ ■ Воздух │
│ ... │ △ Trine │ ■ Вода │
│ │ □ Qnc │ │
│ │ ☍ Opp │ │
└─────────────────┴─────────────────┴─────────────────┘
Two bundled fonts in scripts/:
FontPurposeExtensionseguisym.ttf.datZodiac symbols ♈♉♊... + planet symbols ☉☽☿....dat (ClawHub-compatible)segoeuisl.ttf.datCyrillic, latin, digits.dat (ClawHub-compatible)
Both are auto-copied to .ttf at runtime for Pillow compatibility.
ScriptPurposeDependenciesscripts/lunar_analysis.pySole calculation engine. All lunar metrics, text + JSON output.swisseph, math, jsonscripts/draw_lunar.pyRenderer. Calls lunar_analysis.py --json, draws 5760×2880 chart.subprocess, json, math, Pillowscripts/swisseph.cp314-win_amd64.pyd.datSwiss Ephemeris binary (2 MB) — JPL DE431 ephemeridesMSVC++ Redistscripts/seguisym.ttf.datZodiac + planet symbol font—scripts/segoeuisl.ttf.datCyrillic/latin font—
text
Step 1: python scripts/lunar_analysis.py <date> <time> <city> --json --target-date <date>
Step 2: AI analyzes JSON and writes enhanced conclusion to a JSON file
(see AI Conclusion JSON Format below)
Step 3: python scripts/draw_lunar.py <date> <time> <city> --lang ru --name "Name" --conclusion <file.json>
When --conclusion is provided, the AI-generated text is used verbatim in the chart.
Each metric gets its own interpretation section (1–8), and the overall summary
is shown in section 9 (Conclusion). Without --conclusion, the script generates
built-in autonomous interpretations.
The conclusion file must have metric keys at the top level (not nested under metrics).
Each metric contains an interpretation field (string, dict with description, or tuple).
The overall field contains the general summary for section 9.
json
{
"overall": "General summary text for section 9...",
"moon_phase": {
"interpretation": {
"name": "Waning Gibbous",
"description": "Full interpretation text for section 1..."
}
},
"nearest_phases": {
"interpretation": "Interpretation text for section 2..."
},
"lunar_day": {
"interpretation": "Interpretation text for section 3..."
},
"transit_moon_to_natal_moon": {
"interpretation": "Interpretation text for section 4..."
},
"personal_phase": {
"interpretation": ["Phase Name", "Interpretation text for section 5..."]
},
"transit_moon_house": {
"interpretation": "Interpretation text for section 6..."
},
"moon_speed": {
"interpretation": "Interpretation text for section 7..."
},
"transit_moon_aspects": {
"interpretation": "Interpretation text for section 8..."
}
}
Supported interpretation formats:
dict with description key — used by autonomous modetuple/list of [title, text] — used by autonomous mode for personal_phasestring — plain text interpretation (AI mode)The renderer ( draw_text_panel) automatically detects the format and extracts
the text accordingly. AI mode shows full text without truncation; autonomous mode
limits text to keep the chart compact.
⚠️ ПРАВИЛО: ВСЕГДА предоставляй расширенную интерпретацию ИИ, когда это возможно.
Автономная интерпретация (встроенная в скрипт) — это fallback для CLI-использования. Когда скилл вызывается через OpenClaw агент, агент обязан проанализировать JSON и сгенерировать расширенную интерпретацию по всем метрикам. Это ключевое отличие качественного прогноза от шаблонного.
text
Step 1: python scripts/lunar_analysis.py <date> <time> <city> --json --target-date <date>
Step 2: AI analyzes JSON and provides extended interpretation for ALL metrics
Step 3: AI writes conclusion JSON file with overall summary
Step 4: python scripts/draw_lunar.py <date> <time> <city> --lang ru --name "Name" --conclusion <file.json>
Без шага 3-4 карта будет содержать только автономную (краткую) интерпретацию.
The AI should focus on:
Problem: Windows console (cmd/PowerShell) redirects stdout in cp1251/cp866, breaking UTF-8 output even with PYTHONIOENCODING=utf-8.
Solution: lunar_analysis.py supports --output file.json which writes JSON directly to a file via open(..., encoding='utf-8'), completely bypassing the console. draw_lunar.py uses this internally — it passes --output /tmp/lunar_analysis_tmp.json to the subprocess and reads the file directly.
For CLI users: Use --output when redirecting to files:
bash
python scripts/lunar_analysis.py 24.04.1983 07:00 Ижевск --lang ru --json --output result.json
For text output in terminal, set PYTHONIOENCODING=utf-8 and chcp 65001 (cmd) or use PowerShell with $env:PYTHONIOENCODING='utf-8'.
This is an entertainment/educational tool, not a scientific method. Do not make medical or financial decisions based on astrological readings.
--output file.json flag to lunar_analysis.py — writes JSON directly to file in UTF-8, bypassing Windows console cp1251 encoding issues--output internally via temp file for subprocess communicationlunar_{name}_{date}_{lang}.png.ttf and .pyd files shipped as .dat (ClawHub-compatible), auto-copied at runtime__pycache__ and generated .ttf/ .pyd from skill directoryseguisym.ttf instead of text names (Trine, Square, etc.), matching the legend style_get_word_color + ASP_SYMBOL_COLORS mapdraw_lunar.py now supports --target-date flag — previously only lunar_analysis.py supported target dates via positional arg; now both scripts accept --target-datedraw_lunar.py passes --target-date through to lunar_analysis.py subprocess calllunar_analysis.py --target-date as explicit flag — previously only supported as 4th positional argument; now also parsed as --target-date flag for consistencyDD.MM.YYYY and YYYY-MM-DD formats accepted for --target-datemax_w = w // 2 - 20) for 2x faster line breaksoverall text) and autonomous mode ( summary.cycle_energy + summary.intensity)interp_text() robustness: Now handles all conclusion data formats — string, list, dict with description, dict with interpretation key, tuplenonlocal y pattern with mutable list _y = [y] to avoid UnboundLocalError in nested drawing functionsdraw_lunar.py.bak and draw_lunar.py.bak2 kept for rollbackmoon_phase, lunar_day, etc.),
each with interpretation field; overall field for section 9 summary onlyinterp_text() and show_interp() in draw_text_panel:
unified extraction of interpretation text from dict, tuple, or string formatsoveralllunar_{name}_{date}_{lang}.png