Static topology diagrams for a CouncilEx council module.
Reads the compiled spec via the council module's generated
__council__/0 accessor, builds a canonical intermediate representation
(IR), and renders it to Mermaid or ASCII.
Use cases
- Terminal: quick eyeball of a council's structure during debugging.
Use
topology/2withformat: :asciifor box-drawing-character output that reads in any terminal, ortopology/2(default mermaid) to copy-paste into mermaid.live or a markdown viewer. - Web (future): the same
topology/2string embeds in any HTML page with the Mermaid CDN script. For interactive node editing, consumeto_ir/1from a React Flow component.
This represents static topology — the wiring declared in the
use CouncilEx DSL. Live runtime traces (animated edges as
:member_token events fire) are a separate concern; subscribe to
the run's PubSub topic for that.
Summary
Types
Either a static council module (defines __council__/0) or a
%CouncilEx.DynamicCouncil{} struct.
Functions
Print a diagram for council to stdout when the DIAGRAM env var is set,
optionally accompanied by a description and optionally halting the
script before the council actually runs.
Render the council's sequence diagram (interaction over time).
Render a captured run as a Mermaid sequenceDiagram. events is the ordered
list of PubSub event tuples for the run; pass the council as the optional 2nd
arg to annotate rounds with their static contract. :member_token events are
ignored. See CouncilEx.Diagram.Sequence for details.
Build the canonical IR for a council.
Render the council's static topology (wiring incl. rounds, router, tools, sub-councils).
Types
@type council_ref() :: module() | CouncilEx.DynamicCouncil.t()
Either a static council module (defines __council__/0) or a
%CouncilEx.DynamicCouncil{} struct.
Functions
@spec maybe_print(council_ref(), String.t() | nil) :: :ok | no_return()
Print a diagram for council to stdout when the DIAGRAM env var is set,
optionally accompanied by a description and optionally halting the
script before the council actually runs.
Recognized env vars:
| Var | Effect |
|---|---|
DIAGRAM=ascii (or 1 / true) | ASCII tree |
DIAGRAM=mermaid | Mermaid flowchart TB |
DIAGRAM=sequence | Mermaid sequenceDiagram (interaction over time) |
DIAGRAM=ir | inspect the raw IR struct |
DIAGRAM_ONLY=1 (or true) | print diagram + description, then halt with status 0 — script does not run |
| both unset | no output, no halt |
When DIAGRAM_ONLY is set without DIAGRAM, the format defaults to
ascii. The optional description is printed only when DIAGRAM_ONLY
is set, so the live-run path stays tidy.
Use at the top of examples/*.exs scripts:
CouncilEx.Diagram.maybe_print(MyCouncil, """
Two-member panel with a chair synthesizer. Demonstrates parallel
member execution followed by a synthesis round.
""")Then:
DIAGRAM=ascii mix run examples/foo.exs # diagram + run
DIAGRAM_ONLY=1 mix run examples/foo.exs # diagram + halt
DIAGRAM=mermaid DIAGRAM_ONLY=1 mix run ... # mermaid + halt
@spec sequence( council_ref(), keyword() ) :: String.t()
Render the council's sequence diagram (interaction over time).
Options
:format—:mermaid(default).:asciiis not supported and raises.
@spec sequence_from_events([tuple()], council_ref() | nil) :: String.t()
Render a captured run as a Mermaid sequenceDiagram. events is the ordered
list of PubSub event tuples for the run; pass the council as the optional 2nd
arg to annotate rounds with their static contract. :member_token events are
ignored. See CouncilEx.Diagram.Sequence for details.
@spec to_ir(council_ref()) :: CouncilEx.Diagram.IR.t()
Build the canonical IR for a council.
Accepts either a static council module (defines __council__/0) or a
%CouncilEx.DynamicCouncil{} struct. The latter is lowered via
DynamicCouncil.to_spec/1 before rendering.
@spec topology( council_ref(), keyword() ) :: String.t()
Render the council's static topology (wiring incl. rounds, router, tools, sub-councils).
Options
:format—:mermaid(default) renders aflowchart TB;:asciirenders a box-drawing tree.