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.
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().
| Requirement | Details |
|---|---|
| --- | --- |
| OS | Windows (x64) |
| Python | 3.14.x |
| Runtime | Microsoft Visual C++ Redistributable 2015–2022 (x64) |
| Pillow | 12.x — pip install pillow |
| Swiss Ephemeris | Bundled as swisseph.cp314-win_amd64.pyd.dat |
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:
| Aspect | Timing | Meaning |
|---|---|---|
| --- | --- | --- |
| Conjunction | Every ~28 days | Personal New Moon — emotional reset, new cycle begins |
| Square | ~7 & 21 days | Crisis point — need for action, tension |
| Opposition | ~14 days | Personal Full Moon — emotional climax, awareness |
| Trine | ~7 & 21 days | Harmony — intuition flows, good for planning |
| Sextile | ~4 & 24 days | Opportunity — gentle support |
| Quincunx | ~11 & 17 days | Adjustment — something needs realignment |
| Semisquare | ~3.5 & 10.5 days | Minor irritation |
| Sesquiquadrate | ~10.5 & 17.5 days | Restlessness — break patterns |
| Semisextile | ~2 & 16 days | Subtle influence |
The Moon's position relative to the natal Sun defines a personal lunar month (~29.5 days):
| Phase | Elongation | Meaning |
|---|---|---|
| --- | --- | --- |
| Personal New Moon | 0° | Beginning of personal cycle. Inward energy. Start new projects. |
| Personal Crescent | 45° | Emerging. Energy builds. First steps. |
| Personal First Quarter | 90° | Action point. Challenges arise. Push through. |
| Personal Gibbous | 135° | Refinement. Fine-tune approach. |
| Personal Full Moon | 180° | CLIMAX. Maximum awareness. Emotional revelation. |
| Personal Disseminating | 225° | Sharing. Teach what you've learned. |
| Personal Last Quarter | 270° | Crisis of consciousness. Let go. |
| Personal Balsamic | 315° | Rest. Reflection. Prepare for next cycle. |
Shows which life area is emotionally activated:
| House | Life Area |
|---|---|
| --- | --- |
| I | Personality, appearance, self |
| II | Money, values, resources |
| III | Communication, siblings, learning |
| IV | Home, family, roots |
| V | Creativity, children, romance |
| VI | Health, work, routine |
| VII | Partnership, marriage |
| VIII | Transformation, shared resources |
| IX | Philosophy, travel, higher education |
| X | Career, reputation, public life |
| XI | Friends, groups, hopes |
| XII | Subconscious, 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.
# 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
# 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"
| Argument | Description |
|---|---|
| --- | --- |
date | Birth date DD.MM.YYYY |
time | Birth time HH:MM |
city | Birth city |
--target-date | Target 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. |
--lang | Language: ru or en (default: ru) |
--name | Person's name for display |
--json | Output JSON instead of text |
--output | Write JSON directly to file (UTF-8, bypasses console encoding) |
--conclusion | Path to JSON file with AI-generated conclusion |
{
"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 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/:
| Font | Purpose | Extension |
|---|---|---|
| --- | --- | --- |
seguisym.ttf.dat | Zodiac symbols ♈♉♊... + planet symbols ☉☽☿... | .dat (ClawHub-compatible) |
segoeuisl.ttf.dat | Cyrillic, latin, digits | .dat (ClawHub-compatible) |
Both are auto-copied to .ttf at runtime for Pillow compatibility.
| Script | Purpose | Dependencies |
|---|---|---|
| --- | --- | --- |
scripts/lunar_analysis.py | Sole calculation engine. All lunar metrics, text + JSON output. | swisseph, math, json |
scripts/draw_lunar.py | Renderer. Calls lunar_analysis.py --json, draws 5760×2880 chart. | subprocess, json, math, Pillow |
scripts/swisseph.cp314-win_amd64.pyd.dat | Swiss Ephemeris binary (2 MB) — JPL DE431 ephemerides | MSVC++ Redist |
scripts/seguisym.ttf.dat | Zodiac + planet symbol font | — |
scripts/segoeuisl.ttf.dat | Cyrillic/latin font | — |
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.
{
"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 и сгенерировать расширенную интерпретацию по всем метрикам. Это ключевое отличие качественного прогноза от шаблонного.
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:
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 rollbackmetric sections (1–8) instead of being piled into section 9 (Conclusion)
moon_phase, lunar_day, etc.), each with interpretation field; overall field for section 9 summary only
interp_text() and show_interp() in draw_text_panel:unified extraction of interpretation text from dict, tuple, or string formats
overalllunar_{name}_{date}_{lang}.png共 1 个版本