Presentation / Reports Internals

🤖 Primarily for coding agents. Hello, Claude! Read this before re-deriving the API from source. If it disagrees with the code, the code wins — please update the doc.

Part of the developer docs. User-facing guide: docs/REPORTS.md. To add a section: EXTENDING.

ReportBuilder assembles sections (data dicts) and hands them to a renderer (rich/plain/markdown/html/pdf/prose). Source: src/stellium/presentation/.


ReportBuilder (fluent)

ReportBuilder().from_chart(chart) then chain section methods, then .render(...). Accepts CalculatedChart, Comparison, or MultiChart and adapts output.

Section methods (selection — all return self):

  • Core: with_chart_overview(), with_planet_positions(include_speed=, include_house=, house_systems=), with_house_cusps(systems=).

  • Aspects: with_aspects(mode="all|major|minor|harmonic", include_aspectarian=, ...), with_cross_aspects(...), with_aspect_patterns(...), with_declination_aspects(...).

  • Midpoints: with_midpoints(...), with_midpoint_aspects(...), with_midpoint_trees(...).

  • Dignities: with_dignities(essential="both|traditional|modern|none", ...), with_dispositors(...), with_fixed_stars(...).

  • Points: with_arabic_parts(...), with_declinations(), with_moon_phase().

  • Timing: with_profections(...), with_profections_wheel(...), with_zodiacal_releasing(...), with_zr_visualization(...).

  • Transit calendar: with_stations(end, ...), with_ingresses(end, ...), with_eclipses(end, ...).

  • Meta/custom: with_chart_image(path=None), with_title(title), with_section(custom_section).

Presets: preset_minimal(), preset_standard(), preset_detailed(), preset_full(), preset_positions_only(), preset_aspects_only(), preset_synastry(), preset_transit(), preset_transit_calendar(end, ...).

Render:

report.render(format="rich_table", file=None, show=None)
# format ∈ {rich_table, plain_table, text, prose, markdown, html, pdf}

show defaults to True for terminal formats, False for file formats.

from stellium import ReportBuilder
(ReportBuilder().from_chart(chart)
    .preset_detailed()
    .render(format="markdown", file="report.md"))

ReportSection protocol

@property
def section_name(self) -> str: ...
def generate_data(self, chart) -> SectionData: ...

generate_data returns a SectionData (typed union defined in presentation/section_types.py). The "type" key selects the shape:

Type

Payload keys

TypedDict

"table"

headers, rows

TableData

"key_value"

data (dict)

KeyValueData

"text"

text (str)

TextData

"svg"

content (str)

SvgData

"side_by_side_tables"

tables (list)

SideBySideTablesData

"compound"

sections (list of (name, SectionData))

CompoundData

Important: text-type sections use the "text" key (not "content"). The "content" key is reserved for SVG data. Renderers accept both as a fallback, but new sections should use "text".

Section classes live in presentation/sections/ (core, aspects, dignities, midpoints, midpoint_tree, timing, transits, misc, profection_visualization, zr_visualization). Examples: ChartOverviewSection, PlanetPositionSection, AspectSection, AspectPatternSection, DignitySection, DispositorSection, MidpointSection, ProfectionSection, ZodiacalReleasingSection, StationSection, IngressSection, EclipseSection, MoonPhaseSection, ArabicPartsSection, FixedStarsSection.

Shared helpers in sections/_utils.py: get_object_display, get_sign_glyph, get_aspect_display, get_object_sort_key, get_aspect_sort_key, abbreviate_house_system.


Renderers (renderers.py)

Renderer

Format key

Notes

RichTableRenderer

rich_table

ANSI terminal; print_report (stdout) vs render_report (ANSI-stripped string)

PlainTextRenderer

plain_table / text

ASCII; no deps

MarkdownRenderer

markdown

GFM tables; omits SVG sections

HTMLRenderer

html

self-contained; embeds chart SVG; Noto Sans Symbols

TypstRenderer

pdf

Typst typesetting → bytes; requires typst

ProseRenderer

prose

natural-language; good for pasting into chat / LLM context


Gotchas

  • Sections that need a component/analyzer (patterns, dignities, fixed stars, Arabic Parts, midpoints, ZR) degrade gracefully with a setup hint if the required add_component/add_analyzer wasn’t called on the chart.

  • For Comparison/MultiChart, many sections emit "compound"/"side_by_side_tables".

  • Use absolute paths for with_chart_image() when targeting PDF/HTML.

  • For LLM-facing text prefer chart.to_prompt_text(...) or format="prose".