Przeglądaj źródła

Update docs to match current code state

- README.md: fixed get_transit_preview description
- Project.md: complete rewrite to reflect actual implementation
  - 12 tools (8 core + 5 _byId)
  - Transit orbs and significance scoring
  - Schema migrations
  - Implementation status
Lukas Goldschmidt 1 miesiąc temu
rodzic
commit
96dcb8a3ce
2 zmienionych plików z 70 dodań i 104 usunięć
  1. 69 103
      PROJECT.md
  2. 1 1
      README.md

+ 69 - 103
PROJECT.md

@@ -4,7 +4,7 @@
 
 ## What We're Building
 
-An MCP server that consumes `ephemeris-mcp:get_sky_state` via MCP-over-SSE client, then performs pure astrological calculations (zodiac signs, houses, aspects, angles) on top of that astronomical data. No interpretation -- only structured JSON output. Includes a person database (SQLite), a Jinja2+vanillaJS dashboard, and a Docker container.
+An MCP server that consumes `ephemeris-mcp:get_sky_state` via MCP-over-SSE client, then performs pure astrological calculations (zodiac signs, houses, aspects, angles) on top of that astronomical data. No interpretation -- only structured JSON output. Includes a person database (SQLite) and a Docker container.
 
 ## Project Structure
 
@@ -12,40 +12,39 @@ An MCP server that consumes `ephemeris-mcp:get_sky_state` via MCP-over-SSE clien
 astro-mcp/
 ├── Dockerfile
 ├── docker-compose.yml
-├── main.py                          # entrypoint, same pattern as ephemeris-mcp
+├── main.py
 ├── requirements.txt
 ├── .gitignore
+├── .env / .env.example
 ├── README.md
 ├── PROJECT.md
-├── run.sh
-├── killserver.sh
-├── restart.sh
-├── tests.sh
+├── run.sh / killserver.sh / restart.sh / tests.sh
 ├── data/                            # SQLite DBs at runtime
 ├── logs/                            # PID + server.log
 ├── src/
 │   └── astro_mcp/
 │       ├── __init__.py
-│       ├── config.py                # PORT=7016, dirs, ephemeris URL
-│       ├── server.py                # FastAPI + FastMCP + lifespan + HTTP routes
-│       ├── ephemeris_client.py      # MCP SSE client calling ephemeris-mcp:get_sky_state
-│       ├── astrology.py             # pure calc: zodiac, houses, aspects, angles
-│       ├── models.py                # Pydantic models / type aliases for chart structs
-│       ├── storage.py               # SQLite: persons table + chart cache
-│       ├── dashboard.py             # Jinja2 templates + dashboard routes
-│       └── tools.py                 # @mcp.tool() definitions (wiring layer)
+│       ├── config.py
+│       ├── server.py
+│       ├── ephemeris_client.py
+│       ├── astrology.py
+│       ├── models.py
+│       ├── storage.py
+│       ├── dashboard.py
+│       └── tools.py
 ├── templates/
 │   ├── base.html
 │   ├── dashboard.html
 │   └── persons.html
 └── tests/
     ├── conftest.py
-    ├── test_astrology.py            # unit tests for pure calc functions
-    ├── test_tools.py                # integration tests with mocked ephemeris client
-    └── test_server.py               # HTTP endpoint smoke tests
+    ├── test_astrology.py
+    ├── test_tools.py
+    ├── test_storage.py
+    └── test_server.py
 ```
 
-## Dependencies (requirements.txt)
+## Dependencies
 
 ```
 fastapi>=0.115.0
@@ -58,49 +57,57 @@ python-dotenv>=1.0.1
 pytest>=8.0.0
 ```
 
-Note: No `pyswisseph` -- all astronomical data comes from ephemeris-mcp via MCP client. No heavy native deps beyond what FastMCP/mcp pulls in.
+No `pyswisseph` -- all astronomical data comes from ephemeris-mcp via MCP client.
 
 ## Key Design Decisions
 
-1. **MCP client pattern**: Same as hermes-mcp's `argus_client.py` -- `sse_client(url)` + `ClientSession`. The ephemeris URL is configurable via `EPHEMERIS_MCP_URL` env var (default `http://ephemeris-mcp:7015/mcp/sse` for Docker, `http://127.0.0.1:7015/mcp/sse` for local dev).
-
-2. **Async throughout**: The ephemeris client is async (`sse_client` is async context manager). The FastMCP tools are `async def`. The SQLite access uses `asyncio.to_thread()` to avoid blocking.
-
-3. **Calculation module is pure sync**: `astrology.py` has no async, no I/O -- just math on dicts/lists. Easy to unit test without any event loop.
-
-4. **Ephemeris client call_sky_state helper**: A single internal async function that calls `ephemeris-mcp:get_sky_state` and returns the parsed dict. All tools go through this. Timeout: 8s.
-
-5. **House systems**: Placidus default, with `house_system` parameter on chart tools. Start with Placidus + Equal House only. The house calculation uses the sidereal time from `get_sky_state` output (`sidereal_time.local_sidereal_time`).
-
-6. **Aspect orbs (defaults)**: conjunction 8, sextile 6, square 8, trine 8, opposition 8. Configurable per-tool via optional `orb_limits` dict.
-
-7. **Person DB schema**:
+1. **MCP client pattern**: `sse_client(url)` + `ClientSession`. Ephemeris URL via `EPHEMERIS_MCP_URL` env var.
+2. **Async throughout**: ephemeris client is async, FastMCP tools are `async def`, SQLite uses `asyncio.to_thread()`.
+3. **Calculation module is pure sync**: `astrology.py` has no async, no I/O.
+4. **Datetime normalization**: all datetimes converted to UTC ISO strings before sending to ephemeris server.
+5. **House systems**: Placidus (default), Equal, Whole Sign.
+6. **Transit orbs**: per-planet radii (Sun/Moon 1.5°, personal 1.0°, slow 1.5°, outer 1.0°), aspect type multipliers (conj/opp 1.0, sq/tr 0.75, sex 0.5). Transit orb = (transiting_radius + natal_radius) × multiplier.
+7. **Transit significance scoring** (0-10): based on aspect type, transiting planet importance, natal target importance, orb tightness.
+8. **Person DB schema** with non-destructive migrations:
    ```sql
    CREATE TABLE persons (
        id TEXT PRIMARY KEY,
        name TEXT NOT NULL,
        nickname TEXT UNIQUE,
-       birth_datetime TEXT NOT NULL,  -- ISO 8601 UTC
+       birth_datetime TEXT NOT NULL,
        latitude REAL NOT NULL,
        longitude REAL NOT NULL,
        elevation REAL DEFAULT 0.0,
-       created_at TEXT NOT NULL       -- ISO 8601 UTC
+       created_at TEXT NOT NULL,
+       updated_at TEXT
    );
+   -- Migration: ALTER TABLE persons ADD COLUMN birthplace TEXT
    ```
 
-8. **Docker**: Based on `python:3.13-slim`, no build-essential needed (no pyswisseph). Health check hits `http://127.0.0.1:7016/health`.
+## MCP Tool Surface (12 tools)
+
+### Core tools (raw birth data)
+
+| Tool | Description |
+|---|---|
+| `get_planetary_positions` | Planetary positions with zodiac signs, degrees, retrograde flags |
+| `calculate_natal_chart` | Full natal chart. Params: birth_datetime, latitude, longitude |
+| `calculate_transit_chart` | Transit chart. Params: birth_datetime, transit_datetime, lat, lon, transit_lat, transit_lon |
+| `calculate_synastry_chart` | Relationship chart. Params: person1_datetime/lat/lon, person2_datetime/lat/lon |
+| `calculate_composite_chart` | Composite chart (midpoint method). Params: same as synastry |
+| `get_transit_preview` | Daily transit-to-natal aspect snapshot. Params: birth_datetime, lat, lon, start_date, end_date |
+| `person_manage` | CRUD for persons DB. Actions: add, get (by id or nickname), list, update, delete |
+| `list_house_systems` | List supported house systems |
 
-## MCP Tool Surface (7 tools)
+### _byId tools (database-backed, accept person_id or nickname)
 
 | Tool | Description |
 |---|---|
-| `get_planetary_positions` | Wrapper around ephemeris-mcp, adds sign + degree + retrograde. Optional `bodies` filter. |
-| `calculate_natal_chart` | Full natal chart: planets in signs/houses, aspects (applying/separating), angles. Params: `birth_datetime`, `lat`, `lon`, optional `house_system`, `orb_limits`. |
-| `calculate_transit_chart` | Transit planets + natal-to-transit aspects + transiting planets in natal houses. Same params as natal + `transit_datetime`. |
-| `calculate_synastry_chart` | Two birth data sets -> interaspects, house overlays, composite chart (midpoint method), Davison chart. |
-| `get_transit_preview` | Person ID + time range -> list of events (exact aspects, ingresses, stations, lunar phases). Optional `event_types` filter. |
-| `person_manage` | `action` param: `add`, `get`, `list`, `update`, `delete`. Birth data in add/update. |
-| `list_house_systems` | Discovery tool -- returns supported house systems. |
+| `calculate_natal_chart_by_id` | Natal chart by person_id |
+| `calculate_transit_chart_by_id` | Transit chart by person_id + transit_datetime |
+| `calculate_synastry_chart_by_id` | Synastry for person1_id + person2_id |
+| `calculate_composite_chart_by_id` | Composite for person1_id + person2_id |
+| `get_transit_preview_by_id` | Transit preview by person_id + date range |
 
 ## Docker Compose
 
@@ -112,13 +119,13 @@ services:
     container_name: astro-mcp
     restart: unless-stopped
     ports: ["7016:7016"]
+    env_file: ["./env"]
     environment:
       ASTRO_HOST: 0.0.0.0
       ASTRO_PORT: 7016
       ASTRO_DATA_DIR: /app/data
       ASTRO_LOG_DIR: /app/logs
       ASTRO_DB_PATH: /app/data/astro.sqlite3
-      EPHEMERIS_MCP_URL: http://ephemeris-mcp:7015/mcp/sse
     volumes: ["./data:/app/data", "./logs:/app/logs"]
     healthcheck:
       test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:7016/health').read()"]
@@ -128,62 +135,21 @@ services:
       start_period: 20s
 ```
 
-## Implementation Order
-
-### Phase 1 -- Scaffold
-- Create directory structure, `.gitignore`, `requirements.txt`, `src/astro_mcp/` package
-- `main.py` entry point (copy ephemeris-mcp pattern)
-- `config.py` (PORT=7016, dirs, EPHEMERIS_MCP_URL)
-- `server.py` basic FastAPI + FastMCP with `/health` and `/`
-- `run.sh`, `killserver.sh`, `restart.sh`, `tests.sh`
-- Dockerfile + docker-compose.yml
-- Verify: `./run.sh` starts, `curl /health` returns ok, commit
-
-### Phase 2 -- Astrology calculation module (pure, no I/O)
-- `astrology.py`: zodiac sign from ecliptic longitude, house cusps (Placidus + Equal), aspect detection with orbs, angle calculation (ASC/MC from sidereal time)
-- Pydantic models for chart structures
-- `tests/test_astrology.py`: comprehensive unit tests
-- Verify: `pytest tests/test_astrology.py -q` passes, commit
-
-### Phase 3 -- Ephemeris client + planetary positions tool
-- `ephemeris_client.py`: `call_sky_state(datetime, lat, lon)` using `sse_client`
-- `tools.py`: `get_planetary_positions` tool -- calls sky_state, adds sign/degree/retrograde to each body
-- Test with mocked client
-- Verify: tool returns enhanced body array, commit
-
-### Phase 4 -- Person storage + management
-- `storage.py`: persons DB, same cache pattern as ephemeris-mcp but using `asyncio.to_thread` for DB access
-- `person_manage` tool (add/get/list/update/delete)
-- `tests/test_tools.py`: person CRUD tests
-- Verify: CRUD round-trips, commit
-
-### Phase 5 -- Natal chart tool
-- Wire `calculate_natal_chart` in `tools.py`
-- Calls `call_sky_state` -> feeds planetary positions into astrology module -> assembles full chart dict
-- Test with mocked ephemeris output: verify all chart sections present (planets, houses, aspects, angles)
-- Verify: structured natal chart output, commit
-
-### Phase 6 -- Transit + Synastry tools
-- `calculate_transit_chart`: calls sky_state twice (natal + transit datetimes), computes aspects between them
-- `calculate_synastry_chart`: calls sky_state twice, computes interaspects, house overlays, composite (midpoint), Davison
-- Tests for both
-- Verify, commit
-
-### Phase 7 -- Transit preview
-- `get_transit_preview`: Given person_id + start/end range, iterates through time steps to find exact aspects (orb <= 0d01), ingresses (sign changes), retrograde stations (speed_lon sign changes), lunar phase changes
-- Uses the person DB + ephemeris client calls
-- This is the most algorithmically complex tool -- scan daily then refine with hourly substeps around detected events
-- Verify, commit
-
-### Phase 8 -- Dashboard
-- `dashboard.py`: Jinja2 templates mounted on FastAPI routes (`/dashboard`, `/dashboard/persons`, `/dashboard/persons/<id>`)
-- Vanilla JS for add/edit/delete persons via fetch API
-- Templates: base layout, person list, person detail with chart preview link
-- Mount routes in `server.py` lifespan or at module level
-- Verify: browser test, commit
-
-### Phase 9 -- Integration + docs
-- Full test suite running via `tests.sh`
-- `README.md`: tool descriptions, example calls, Docker usage
-- `PROJECT.md`: technical specs, schema, architecture
-- Final commit and push
+## Implementation Status
+
+### Completed
+- Phase 1: Scaffold, server, scripts, Docker
+- Phase 2: Astrology calculation module (pure math)
+- Phase 3: Ephemeris client + all MCP tool definitions
+- Phase 4: Person storage + management
+- Phase 5: Natal chart tool
+- Phase 6: Transit + Synastry tools
+- Phase 7: Transit preview (daily snapshots with significance scoring)
+- Composite chart tool (standalone)
+- _byId convenience tools for all chart functions
+- Schema migrations for birthplace column
+- 102 tests passing
+
+### Remaining
+- Phase 8: Dashboard (Jinja2 + vanilla JS for person management)
+- Phase 9: Final integration + docs

+ 1 - 1
README.md

@@ -38,7 +38,7 @@ SSE transport at `http://localhost:7016/mcp/sse`
 | `calculate_transit_chart` | Transit chart with natal-to-transit aspects. Params: birth_datetime, transit_datetime, latitude, longitude, transit_latitude, transit_longitude |
 | `calculate_synastry_chart` | Relationship chart for two people. Params: person1_datetime/lat/lon, person2_datetime/lat/lon |
 | `calculate_composite_chart` | Composite chart via midpoint method. Params: same as synastry |
-| `get_transit_preview` | Significant transit events for a person ID over a time range |
+| `get_transit_preview` | Daily transit-to-natal aspect snapshot. Params: birth_datetime, latitude, longitude, start_date, end_date |
 | `person_manage` | CRUD for persons database (name, nickname, birthplace, birth_datetime, lat/lon, elevation) |
 | `list_house_systems` | List supported house systems |