Understanding the IR (Intermediate Representation) System in ReportEngine and Document Stitching

The IR (Intermediate Representation) system in ReportEngine is a canonical JSON contract that validates chapter structure before rendering, while document stitching merges multiple validated chapters into a single cohesive document using the DocumentComposer class.

The 666ghj/bettafish repository implements a robust reporting engine that bridges LLM-generated content with multiple output formats. The IR system ensures structural integrity through strict schema validation, while the stitching layer orchestrates multi-chapter documents with automatic anchor management and metadata injection.

What Is the IR (Intermediate Representation) System in ReportEngine?

The IR system serves as the canonical JSON contract that every report generated by the engine must obey. It acts as the bridge between raw LLM output and the final rendered documents (HTML, PDF, Markdown), ensuring that downstream renderers never encounter structural crashes.

Core Components of the IR Schema

The schema definition resides in ReportEngine/ir/schema.py and establishes several critical constraints:

  • Versioning: Every IR payload carries a version field defined by IR_VERSION = "1.0", ensuring backward compatibility as the schema evolves.
  • Allowed Inline Marks: The system restricts text formatting to a whitelist defined in ALLOWED_INLINE_MARKS, including bold, italic, link, and other semantic annotations.
  • Allowed Block Types: Content structure is constrained by ALLOWED_BLOCK_TYPES, which enumerates valid building blocks such as heading, paragraph, list, table, and widget.
  • Chapter Schema: The CHAPTER_JSON_SCHEMA constant defines the complete JSON-Schema for a chapter, specifying required fields like chapterId, title, anchor, order, and blocks, plus optional metadata extensions.

IR Validation with IRValidator

The IRValidator class in ReportEngine/ir/validator.py provides runtime enforcement of the schema. It walks a chapter (or whole document) and checks every field against CHAPTER_JSON_SCHEMA, returning a boolean validity flag and a list of human-readable error paths.

from ReportEngine.ir import IRValidator

validator = IRValidator()
is_ok, errors = validator.validate_chapter(chapter_json)

if not is_ok:
    print("Chapter validation failed:", errors)

Source: ReportEngine/ir/validator.py

How Document Stitching Works in ReportEngine

Document stitching is the process of merging multiple validated chapter JSONs into a single cohesive Document IR. This logic lives in ReportEngine/core/stitcher.py and is encapsulated by the DocumentComposer class.

The DocumentComposer.build_document Method

The build_document method orchestrates the assembly process through several distinct phases:

  1. Collect TOC Anchors: Reads metadata.toc.customEntries to map any user-specified chapterId → anchor overrides via _build_toc_anchor_map.
  2. Sort Chapters: Orders the supplied chapters list by the order field, defaulting to 0 for unspecified entries: ordered = sorted(chapters, key=lambda c: c.get("order", 0)).
  3. Inject Defaults: Generates fallback values for missing required fields:
    • Creates sequential chapterId values (S1, S2, …) if missing.
    • Ensures every chapter has a unique anchor using _ensure_unique_anchor.
    • Guarantees an order value (defaulting to idx * 10 based on position).
  4. Add Placeholder Headings: If a chapter is marked as an error placeholder, _ensure_heading_block inserts a minimal heading block so the Table of Contents can still reference it.
  5. Compose Final IR: Returns a dictionary containing version, reportId, enriched metadata (adding generatedAt timestamp), themeTokens, the ordered chapters array, and any global assets.

Handling Anchor Uniqueness and Defaults

The _ensure_unique_anchor method maintains an internal _seen_anchors set to detect collisions. When a duplicate anchor is detected, the system automatically appends suffixes (-2, -3, etc.) to ensure globally unique identifiers throughout the stitched document.

from ReportEngine.core.stitcher import DocumentComposer

composer = DocumentComposer()

# Example metadata (could include a custom TOC)

metadata = {
    "title": "年度报告",
    "toc": {
        "customEntries": [
            {"chapterId": "intro", "anchor": "overview"},
            {"chapterId": "conclusion", "anchor": "end"},
        ]
    },
    "themeTokens": {"primary": "#123456"},
    "assets": {"logo": "static/logo.png"},
}

# List of chapter payloads (already validated)

chapters = [chapter1, chapter2, chapter3]

document_ir = composer.build_document(
    report_id="report-2025",
    metadata=metadata,
    chapters=chapters,
)

print(document_ir["version"])          # → "1.0"

print(document_ir["chapters"][0]["anchor"])  # unique, e.g. "overview"

Source: ReportEngine/core/stitcher.py

Complete Workflow: From Chapter Generation to Final Document

The typical pipeline for producing a report in the 666ghj/bettafish repository follows these stages:

  1. Generate each chapter using LLM or other engines → raw JSON payload.
  2. Validate each chapter with IRValidator to ensure schema compliance.
  3. Collect all validated chapter JSONs into a sequential list.
  4. Instantiate DocumentComposer and invoke build_document(report_id, metadata, chapters).
  5. Pass the resulting Document IR to the appropriate renderer (ReportEngine/renderers/*.py) for HTML, PDF, or Markdown output.
from ReportEngine.ir import IRValidator
from ReportEngine.core.stitcher import DocumentComposer

validator = IRValidator()
composer = DocumentComposer()

validated_chapters = []
for raw in raw_chapter_jsons:
    ok, errs = validator.validate_chapter(raw)
    if ok:
        validated_chapters.append(raw)
    else:
        raise ValueError(f"Invalid chapter: {errs}")

final_ir = composer.build_document(
    report_id="my-report",
    metadata=global_metadata,
    chapters=validated_chapters,
)

# `final_ir` can now be rendered to HTML, PDF, etc.

Key Files in the IR and Stitching System

File Role
ReportEngine/ir/schema.py Defines the IR version, allowed inline marks, block types, and the JSON-Schema for chapters.
ReportEngine/ir/validator.py Implements IRValidator – the runtime checker that enforces the schema on each chapter.
ReportEngine/core/stitcher.py Contains DocumentComposer, the component that merges chapter JSONs into a single Document IR, handling ordering, anchor uniqueness, and metadata injection.
ReportEngine/utils/config.py Holds configuration defaults (output directories, template locations) often merged into the final IR’s metadata.
ReportEngine/scripts/validate_ir.py CLI utility that invokes IRValidator on whole IR files – useful for debugging and CI checks.

These files together form the backbone of the IR system and the document stitching process, guaranteeing that every generated report conforms to a strict, versioned contract before it reaches the rendering stage.

Summary

  • The IR (Intermediate Representation) is a canonical JSON contract defined in ReportEngine/ir/schema.py that ensures all report chapters follow a strict, versioned structure before rendering.
  • IR validation is enforced by the IRValidator class in ReportEngine/ir/validator.py, which checks every chapter against the CHAPTER_JSON_SCHEMA and returns detailed error paths for debugging.
  • Document stitching is handled by DocumentComposer in ReportEngine/core/stitcher.py, which sorts chapters by order, injects default chapterId and anchor values, ensures global anchor uniqueness, and composes the final Document IR.
  • The complete workflow involves generating raw chapters, validating them with IRValidator, collecting them into a list, and passing them to DocumentComposer.build_document() to produce a renderer-ready JSON payload.

Frequently Asked Questions

What is the current IR version in ReportEngine?

The current IR version is defined as IR_VERSION = "1.0" in ReportEngine/ir/schema.py. Every Document IR payload includes this version field to ensure backward compatibility and schema compliance across different versions of the rendering engine.

How does ReportEngine handle duplicate chapter anchors?

The DocumentComposer class maintains an internal _seen_anchors set during the stitching process. When _ensure_unique_anchor detects a collision, it automatically appends incremental suffixes such as -2, -3, etc., to create globally unique identifiers throughout the final document.

What happens if a chapter fails IR validation?

If IRValidator.validate_chapter() returns False, it provides a detailed list of human-readable error paths indicating which fields violate the CHAPTER_JSON_SCHEMA. The typical workflow raises a ValueError or logs the errors, preventing invalid chapters from reaching the stitching phase and ensuring renderers never receive malformed data.

Can I customize the table of contents entries during stitching?

Yes, the DocumentComposer.build_document method accepts a metadata dictionary that can include toc.customEntries. This array maps specific chapterId values to custom anchor strings, allowing you to override default anchor generation and ensure TOC links point to specific sections as defined in ReportEngine/core/stitcher.py.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →