Skip to content

protean ir

The protean ir command group inspects a domain's Intermediate Representation (IR) -- the machine-readable JSON document that captures domain topology after initialization.

All commands accept a --domain option to specify the domain module path.

Commands

Command Description
protean ir show Generate and display the domain's IR
protean ir diff Compare two IR snapshots and classify breaking changes
protean ir check Check whether the materialized IR is fresh or stale

protean ir show

Loads the domain, calls domain.init(), and outputs the IR as JSON or a human-readable summary.

# Full JSON output (pipe to jq, save to file, etc.)
protean ir show --domain=my_app.domain

# Human-readable summary with element counts and cluster details
protean ir show --domain=my_app.domain --format=summary

# Save a canonical baseline for version control (no volatile timestamp)
protean ir show --domain=my_app.domain --canonical > .protean/ir.json

Options

Option Description Default
--domain, -d Path to the domain module (e.g. my_app.domain) Required
--format, -f Output format: json or summary json
--canonical Omit the volatile generated_at timestamp (json format only) false

Canonical baseline output

By default the JSON output includes a generated_at materialization timestamp, which changes on every regeneration. When committing .protean/ir.json as a baseline for protean ir diff, that timestamp is pure noise: it produces a one-line diff on every protean ir show even when nothing about the domain changed.

Pass --canonical to omit generated_at. The $schema, ir_version, checksum, and elements keys are retained (they are content-derived or version markers, and are ignored by ir diff/ir check alike). A canonical baseline therefore changes only when the domain contract changes.

--canonical has no effect with --format=summary, which never prints the timestamp.

JSON output

The full IR document, pretty-printed with 2-space indentation. Contains all sections: domain, clusters, projections, flows, elements, and diagnostics. See the IR specification for the complete structure reference.

Logs are written to stderr, so the JSON on stdout is safe to pipe (protean ir show ... | jq) or redirect to a file without log lines corrupting it.

Summary output

A compact overview showing:

  • Domain name, IR version, and checksum
  • Element counts by type (table)
  • Cluster breakdown (entities, value objects, commands, events per aggregate)
  • Diagnostic warnings, if any
Domain: Ordering
IR Version: 0.1.0
Checksum: sha256:a1b2c3d4...

     Element Counts
┏━━━━━━━━━━━━━━━━━━┳━━━━━━━┓
┃ Element Type      ┃ Count ┃
┡━━━━━━━━━━━━━━━━━━╇━━━━━━━┩
│ AGGREGATE         │     2 │
│ COMMAND           │     3 │
│ COMMAND_HANDLER   │     2 │
│ EVENT             │     4 │
│ EVENT_HANDLER     │     1 │
│ ENTITY            │     1 │
│ VALUE_OBJECT      │     1 │
└───────────────────┴───────┘

Clusters: 2
  Order: 1 entities, 1 VOs, 2 commands, 3 events
  Payment: 0 entities, 0 VOs, 1 commands, 1 events

protean ir diff

Compare two IR snapshots and classify changes as breaking or safe.

# Auto-baseline: compare live domain against .protean/ir.json
protean ir diff --domain my_app.domain

# Compare against a git commit
protean ir diff --domain my_app.domain --base HEAD

# Compare two explicit files
protean ir diff --left baseline.json --right current.json

Options

Option Description Default
--domain, -d Domain module path
--left, -l Path to baseline IR JSON file
--right, -r Path to current IR JSON file
--base, -b Git commit/branch/tag for baseline
--dir Path to .protean/ directory .protean
--format, -f Output format: text or json text

Exit codes (CI-friendly)

Code Meaning
0 No changes detected
1 Breaking changes found
2 Non-breaking changes only

Avro compatibility verdict. Alongside the breaking/safe classification, the diff reports an Avro-style verdict — BACKWARD, FORWARD, FULL, or NONE — matching the rules a schema registry applies to the Avro that protean schema generate --format avro emits:

Verdict Meaning
BACKWARD A consumer on the new schema can read data written with the old schema
FORWARD A consumer on the old schema can read data written with the new schema
FULL Both BACKWARD and FORWARD
NONE Neither

Adding an optional field (or a required field with a static default) is FULL; adding a required field without a default is not BACKWARD; removing a required field is not FORWARD; a type change is NONE. A declared rename is BACKWARD (the emitted schema carries Avro aliases), or FULL when the old field was optional or carried a static default. Visibility flips are payload-neutral for the verdict (they stay breaking).

One rule is Protean-specific: an upcaster that covers the version bump makes an otherwise-incompatible change BACKWARD, because Protean rewrites old payloads to the new shape at read time. A plain schema registry has no knowledge of upcasters and would still report the underlying change (e.g. NONE for a type change) — so this clause reflects what Protean can decode, not what a registry alone would conclude.

The top-level verdict is the domain-wide intersection (the conservative worst case). In --format json, the compatibility block also carries avro_verdicts (a per-element breakdown, since Avro compatibility is per-subject) and the full classified report. The verdict covers the classified schema changes; it is informational — the exit code is still governed by [compatibility] strictness and the breaking-change classification.

Respects .protean/config.toml settings. See Compatibility Checking for configuration details.

protean ir check

Check whether the materialized IR matches the live domain.

protean ir check --domain my_app.domain
protean ir check --domain my_app.domain --format json

Options

Option Description Default
--domain, -d Path to the domain module Required
--dir Path to .protean/ directory .protean
--format, -f Output format: text or json text

Exit codes

Code Meaning
0 IR is fresh (matches live domain)
1 IR is stale (domain has changed)
2 No materialized IR found
3 Schema version mismatch (baseline built against a different schema version)

A version mismatch (code 3) means the stored baseline's ir_version differs from the current schema version, so its checksum is not comparable. The json output reports stored_version and current_version. Regenerate the baseline against the current schema to clear it.

Programmatic access

In Python code, call domain.to_ir() directly:

domain.init()
ir = domain.to_ir()

The returned dict is identical to the JSON output. See Inspecting the IR for usage examples.