Introspection is a standalone Go library that provides generic primitives for visualizing application state using Mermaid diagrams. It was extracted from lifecycle to serve as a reusable foundation for any Go project requiring runtime introspection and topology visualization.
introspection solves the problem of coupling visualization logic to domain logic. Before extraction, each component in lifecycle (Signal, Worker, Supervisor) contained custom Mermaid string concatenation, leading to:
By abstracting these concerns into a library, introspection provides:
TreeDiagram, StateMachineDiagram, ComponentDiagram.NodeStyler, NodeLabeler, PrimaryStyler, PrimaryLabeler.v0.1.2 (Stable)lifecycle (see go.mod).lifecycle delegates all Mermaid rendering to introspection:
graph LR
A[lifecycle.SystemDiagram] --> B[introspection.ComponentDiagram]
B --> C[PrimaryStyler<br/>signal.State]
B --> D[NodeStyler<br/>worker.State]
C --> E[Mermaid String]
D --> E
| Component | Responsibility |
|---|---|
lifecycle |
Provides domain-specific styling logic (signal.PrimaryStyler, worker.NodeLabeler) and configuration (LifecycleDiagramConfig). |
introspection |
Handles structural rendering (graph syntax, indentation, CSS classes) and generic traversal. |
lifecycle uses the Adapter Pattern to bridge domain concepts to the visualization engine:
// lifecycle/diagram_config.go
func LifecycleDiagramConfig() *introspection.DiagramConfig {
return &introspection.DiagramConfig{
PrimaryID: "S",
PrimaryLabel: "Signal Context",
PrimaryNodeLabel: "⚡ Lifecycle Controller",
SecondaryID: "root",
SecondaryLabel: "Supervision Tree",
ConnectionLabel: "governs",
NodeStyler: worker.NodeStyler,
NodeLabeler: worker.NodeLabeler,
PrimaryNodeStyler: signal.PrimaryStyler,
PrimaryNodeLabeler: signal.PrimaryLabeler,
}
}
// lifecycle/introspection.go
func SystemDiagram(sig SignalState, work WorkerState) string {
return introspection.ComponentDiagram(sig, work, LifecycleDiagramConfig())
}
lifecycletrellis, arbour) can use introspection for their own topologies.introspection, not scattered across lifecycle packages.introspection is tested independently with generic test cases, reducing the testing burden on lifecycle.Any Go project can adopt introspection for visualization:
import "github.com/aretw0/introspection"
// Custom domain state
type MyState struct {
ID string
Status string
}
// Custom styler
func MyStyler(state any) string {
s := state.(MyState)
if s.Status == "active" {
return "active"
}
return "stopped"
}
// Generate diagram
diagram := introspection.TreeDiagram(rootState, &introspection.TreeConfig{
RootID: "root",
NodeStyler: MyStyler,
})
The extraction of introspection mirrors the successful extraction of procio (ADR-0010). Both represent Primitive Promotion, where foundational logic is elevated to standalone libraries for broader adoption.
introspection should be highlighted as a Core Dependency in lifecycle documentation, emphasizing that visualization is a first-class concern supported by dedicated tooling rather than ad-hoc string manipulation.