Vedākṣha
← Blog

Graph · AI · Neo4j

Why Charts Should Be Graphs

Astrological charts are property graphs. They always were — we just represented them as flat structs. The case for 10 node types, 13 edge types, and emitters that make AI agents actually useful.

December 3, 2025·9 min read·ArthIQ Labs

The standard representation of an astrological chart is a list of planets with floating-point longitudes. Ask most libraries for a chart and you get back something like a dictionary of planet names to degree values. This is not wrong — it is just profoundly incomplete.

A chart is not a list. It is a network of relationships: planets in signs, signs ruling houses, planets aspecting each other, lords of houses placed in other houses. The relationships are the point. They are what a practitioner reads, what a dasha system navigates, what a yoga rule tests. Flattening this network into a struct loses most of the semantically interesting structure before the application ever sees it.

The graph model

A ChartGraph has 10 node types and 13 edge types. The nodes are:

:Chart

Root node — metadata, ayanamsha, house system, epoch.

:Planet

Any graha: Sun, Moon, Mars, Mercury, Jupiter, Venus, Saturn, Rahu, Ketu, plus Ascendant.

:Sign

One of 12 rasis. Carries modality, element, direction, ruler.

:House

One of 12 bhavas. Carries cusp longitude, natural karakatwa.

:Nakshatra

One of 27 lunar mansions. Carries pada, lord, deity, shakti.

:Aspect

A computed aspect event with orb, exactness, applying/separating flag.

:Yoga

A detected yoga rule with its component planets and activation status.

:Dasha

A dasha period — mahadasha, antardasha, or deeper sub-period.

:Dignity

Shadbala component — exaltation, moolatrikona, own, friend, neutral, enemy, debilitation.

:Varga

A divisional chart — D1 through D60 — as a subgraph of the root chart.

The 13 edge types

Edges carry the relationships that practitioners actually reason about. Most of the interesting chart interpretation is a path traversal over these edges.

PLACED_IN_SIGN
(PlanetSign)Planet occupies a rasi.
PLACED_IN_HOUSE
(PlanetHouse)Planet occupies a bhava.
OCCUPIES_NAKSHATRA
(PlanetNakshatra)Planet falls in a nakshatra pada.
RULES
(PlanetSign)Natural rulership (e.g. Mars rules Aries and Scorpio).
LORDS
(PlanetHouse)Owns the house whose cusp falls in its sign.
ASPECTS
(PlanetPlanet)Computed aspect with orb, type, and applying/separating.
ASPECTS_HOUSE
(PlanetHouse)Vedic drishti — whole-sign aspect onto a bhava.
CONJOINS
(PlanetPlanet)Within-orb conjunction, directional flag.
ACTIVATES_YOGA
(PlanetYoga)Planet is a required component of this yoga formation.
HAS_DIGNITY
(PlanetDignity)Shadbala dignity score for this planet in this chart.
PART_OF_DASHA
(PlanetDasha)Planet is the lord of this dasha period.
DISPOSITOR_OF
(PlanetPlanet)Sign-lord chain — planet A rules the sign of planet B.
VARGA_PLACEMENT
(PlanetSign)Divisional chart placement, with varga label as a property.

Four emitters

A ChartGraph is an in-memory structure. Getting it into a useful target is the job of the emitters.

emit.rs
use vedaksha::graph::*;

let graph = compute_chart_graph(jd, lat, lng, &ChartConfig::vedic());

// Neo4j / any Cypher-compatible graph DB
let cypher = graph.emit_cypher();

// SurrealDB
let surreal = graph.emit_surrealql();

// JSON-LD for semantic web / RAG pipelines
let jsonld = graph.emit_jsonld();

// Pre-chunked text for vector embedding
let chunks = graph.emit_embedding_text();

Why this matters for AI agents

When an AI agent receives a flat list of planet-degree pairs, it has to reconstruct the chart's relational structure from scratch. The agent effectively re-implements a simplified version of the chart interpretation layer to answer a question like "which planets aspect the 7th house lord?" This is fragile, slow, and inaccurate.

With a property graph emitter, the agent can run a Cypher query:

Cypherneo4j
MATCH (p:Planet)-[:LORDS]->(h:House {number: 7}))
MATCH (aspector:Planet)-[:ASPECTS]->(p)
RETURN aspector.name, aspector.sign, p.name

The graph model also enables multi-chart queries. Synastry (comparing two charts) is a join between two subgraphs. A transit lookup is an intersection between a natal graph and a transiting planet graph. These queries are awkward with flat arrays; they are natural with a graph schema.

Deterministic node IDs

Every node in the graph has a deterministic ID derived from its content — not a random UUID, not a database sequence. A Planet node ID is a hash of the chart ID plus the planet name. The Chart node ID is derived from the Julian Day, coordinates, and configuration.

This means two identical chart computations produce identical node IDs, which means upserts are idempotent. Load the same chart twice into Neo4j and you get the same graph. This also allows safe merging of multiple charts into a single database without ID collisions.

Embedding text for RAG pipelines

The embedding text emitter generates pre-chunked natural language descriptions of each node and its immediate neighborhood. Each chunk is designed to be the right size for a vector embedding — not the full chart as a wall of text, but semantically coherent fragments like:

"Mars is placed in Scorpio in the 8th house at 14°22'. It is the lord of the 1st and 8th houses. Mars aspects the 2nd house (4th drishti), the 3rd house (7th drishti), and the Ascendant (8th drishti). Mars is in its own sign, giving it strength. It activates the Ruchaka Mahapurusha Yoga."

Every chunk includes the relevant node IDs so the vector store result can be linked back to the graph for follow-up queries. This enables a hybrid retrieval pattern: semantic search finds the relevant chart region, graph traversal answers the precise relational question.

The flat struct representation of a chart is a compression artifact — it drops the relationships to fit into a simpler data model. A property graph is not an elaborate overengineering; it is the natural shape of the data. Everything else — the emitters, the deterministic IDs, the embedding chunks — follows from that starting point.