Skip to content

Reference for the public Python surface. Generated from docstrings with mkdocstrings.

Package

parsecraft

parsecraft package.

Modules:

  • __about__ –

    Version information for ParseCraft.

  • __main__ –

    Entry point for ParseCraft CLI.

  • adapters –

    Adapters: parse external inputs (Markdown, HTML, ...) into the canonical IR.

  • assets –

    Model-asset manager: pinned downloads, cache, license records.

  • backends –

    Backend protocol + registry — the extension surface of ParseCraft.

  • benchmark –

    Reproducible backend benchmarks over local documents (Phase 2 harness).

  • cache –

    Content-addressed conversion cache (keyed DocumentResult storage).

  • cli –

    CLI module for ParseCraft.

  • config –

    Generic, self-contained configuration engine (Route A).

  • environment –

    Detected host environment — the bridge into parsecraft.routing planning.

  • ir –

    Canonical IR: typed structured chunks + deterministic Markdown projection.

  • pipeline –

    Auto-mode executor: analysis entry points and plan → pages dispatch.

  • providers –

    Judge providers — plug-in modules resolved by routing.judge_providers.

  • routing –

    Auto-mode routing: deterministic signal→intent planning with a judge seam.

IR — models and projection

ir

Canonical IR: typed structured chunks + deterministic Markdown projection.

Modules:

  • markdown –

    Deterministic Markdown projection of the canonical IR.

  • models –

    Canonical intermediate representation for ParseCraft.

Classes:

  • AssetKind –

    Kind of an extracted asset.

  • BBox –

    Axis-aligned bounding box in source coordinates (points).

  • ChunkKind –

    Kind of a structured chunk.

  • ChunkRelation –

    Relation from one chunk to another chunk id.

  • CrossPageRelation –

    Relation between content on different pages.

  • DetectedRegion –

    A region detected on a page (layout signal, not yet content).

  • Diagnostic –

    A recorded, non-fatal observation about a page.

  • DiagnosticLevel –

    Severity of a diagnostic entry.

  • DocumentMetadata –

    Document-level metadata and reproducibility anchors.

  • DocumentResult –

    Root of the canonical IR — everything projections need.

  • ExtractedAsset –

    An asset extracted from a page (image, LaTeX source, CSV, ...).

  • FailureCode –

    Machine-readable cause of a structured pass failure.

  • PageRange –

    Inclusive 1-based page range.

  • PageResult –

    All extracted content of one page, in reading order.

  • PageSignal –

    Deterministic per-page analysis signal (planner input state).

  • PassFailure –

    Structured failure record — typed, never a bare string.

  • PassKind –

    Processing pass that produced or judged a result.

  • PassStatus –

    Outcome of a processing pass.

  • QualitySignal –

    Named quality score in [0, 1] attached to a chunk or document.

  • RegionKind –

    Kind of a detected page region.

  • RelationKind –

    Kind of chunk or cross-page relation.

  • SourceSpan –

    Character span in the original text source.

  • StructuredChunk –

    One typed content unit — the package's currency.

  • TraceEntry –

    One processing pass recorded in the document's trace.

Functions:

  • render_block –

    Render one chunk and its descendants to Markdown, depth-first in order.

  • render_page –

    Render one page: marker comment, then every block in reading order.

  • to_markdown –

    Project a full document to deterministic Markdown (trailing newline).

  • utcnow –

    Timezone-aware now — single home for timestamps in IR construction.

AssetKind

Bases: StrEnum

Kind of an extracted asset.

BBox

Bases: _ValueModel

Axis-aligned bounding box in source coordinates (points).

ChunkKind

Bases: StrEnum

Kind of a structured chunk.

ChunkRelation

Bases: _ValueModel

Relation from one chunk to another chunk id.

CrossPageRelation

Bases: BaseModel

Relation between content on different pages.

DetectedRegion

Bases: BaseModel

A region detected on a page (layout signal, not yet content).

Diagnostic

Bases: BaseModel

A recorded, non-fatal observation about a page.

DiagnosticLevel

Bases: StrEnum

Severity of a diagnostic entry.

DocumentMetadata

Bases: BaseModel

Document-level metadata and reproducibility anchors.

DocumentResult

Bases: BaseModel

Root of the canonical IR — everything projections need.

ExtractedAsset

Bases: BaseModel

An asset extracted from a page (image, LaTeX source, CSV, ...).

FailureCode

Bases: StrEnum

Machine-readable cause of a structured pass failure.

PageRange

Bases: _ValueModel

Inclusive 1-based page range.

PageResult

Bases: BaseModel

All extracted content of one page, in reading order.

PageSignal

Bases: BaseModel

Deterministic per-page analysis signal (planner input state).

PassFailure

Bases: _ValueModel

Structured failure record — typed, never a bare string.

PassKind

Bases: StrEnum

Processing pass that produced or judged a result.

PassStatus

Bases: StrEnum

Outcome of a processing pass.

QualitySignal

Bases: _ValueModel

Named quality score in [0, 1] attached to a chunk or document.

RegionKind

Bases: StrEnum

Kind of a detected page region.

RelationKind

Bases: StrEnum

Kind of chunk or cross-page relation.

SourceSpan

Bases: _ValueModel

Character span in the original text source.

StructuredChunk

Bases: BaseModel

One typed content unit — the package's currency.

kind decides how :func:parsecraft.ir.markdown.to_markdown renders content; metadata carries kind-specific hints (e.g. heading_level, language) as stringly-typed JSON-safe values.

TraceEntry

Bases: BaseModel

One processing pass recorded in the document's trace.

render_block

render_block(chunk: StructuredChunk) -> str

Render one chunk and its descendants to Markdown, depth-first in order.

Source code in src/parsecraft/ir/markdown.py
80
81
82
83
def render_block(chunk: StructuredChunk) -> str:
    """Render one chunk and its descendants to Markdown, depth-first in order."""
    parts = [render_chunk(chunk), *(render_block(child) for child in chunk.children)]
    return "\n\n".join(part for part in parts if part)

render_page

render_page(page: PageResult) -> str

Render one page: marker comment, then every block in reading order.

Source code in src/parsecraft/ir/markdown.py
73
74
75
76
77
def render_page(page: PageResult) -> str:
    """Render one page: marker comment, then every block in reading order."""
    body = "\n\n".join(render_block(block) for block in page.blocks)
    marker = f"<!-- page {page.page_number} -->"
    return f"{marker}\n\n{body}" if body else marker

to_markdown

to_markdown(result: DocumentResult) -> str

Project a full document to deterministic Markdown (trailing newline).

Source code in src/parsecraft/ir/markdown.py
66
67
68
69
70
def to_markdown(result: DocumentResult) -> str:
    """Project a full document to deterministic Markdown (trailing newline)."""
    if not result.pages:
        return ""
    return "\n\n".join(render_page(page) for page in result.pages) + "\n"

utcnow

utcnow() -> datetime

Timezone-aware now — single home for timestamps in IR construction.

Source code in src/parsecraft/ir/models.py
365
366
367
def utcnow() -> datetime:
    """Timezone-aware now — single home for timestamps in IR construction."""
    return datetime.now(UTC)

Backends — protocol and registry

backends

Backend protocol + registry — the extension surface of ParseCraft.

Modules:

  • docling –

    Docling backend family — MIT layout-aware parsing (CPU, heavy extra).

  • errors –

    Backend subsystem exceptions.

  • liteparse –

    LiteParse backend family — Apache-2.0 document parsing, CPU-only.

  • native –

    Built-in native backends: dependency-light document parsers.

  • ocr –

    OCR / document-VLM backend family — light entry points, heavy impls.

  • pandoc –

    Pandoc backend family — office/ODF/EPUB/RTF conversion (ADR-0005).

  • protocol –

    Public backend protocol: what a backend is and what a request carries.

  • registry –

    Backend registry: explicit registration first, lazy entry-point discovery.

  • source –

    Shared file:// URI resolution for source documents.

Classes:

AnalysisResult

Bases: BaseModel

Output of DocumentBackend.analyze — planner input state.

BackendAlreadyRegisteredError

BackendAlreadyRegisteredError(name: str)

Bases: BackendError

Raised when explicit registration collides with an existing name.

Source code in src/parsecraft/backends/errors.py
21
22
23
def __init__(self, name: str) -> None:
    super().__init__(f"backend already registered: {name!r}")
    self.name = name

BackendCapabilities

Bases: BaseModel

Static, import-free facts about a backend.

BackendConfig

Bases: BaseModel

Per-instance backend configuration passed to the factory.

BackendDescriptor

Bases: BaseModel

What the registry hands out: identity + capabilities, no code.

BackendError

Bases: Exception

Base class for all backend subsystem errors.

BackendFactory

Bases: Protocol

What registration accepts: a light module-level object.

descriptor must carry the registry name; __call__ is the only place heavy imports may happen.

Methods:

  • __call__ –

    Build a backend instance for config.

__call__

__call__(config: BackendConfig) -> DocumentBackend

Build a backend instance for config.

Source code in src/parsecraft/backends/protocol.py
163
164
165
def __call__(self, config: BackendConfig) -> DocumentBackend:
    """Build a backend instance for ``config``."""
    ...

BackendLoadError

BackendLoadError(name: str, cause: Exception | None = None)

Bases: BackendError

Recorded failure to load an entry-point backend (stored, not raised).

Discovery never raises — one broken plugin must not brick the registry. Instances surface via BackendRegistry.load_errors so callers can report them explicitly.

Source code in src/parsecraft/backends/errors.py
34
35
36
37
38
def __init__(self, name: str, cause: Exception | None = None) -> None:
    detail = f": {type(cause).__name__}: {cause}" if cause is not None else ""
    super().__init__(f"failed to load backend {name!r} from entry point{detail}")
    self.name = name
    self.cause = cause

BackendNotFoundError

BackendNotFoundError(name: str)

Bases: BackendError

Raised when a backend name is not registered.

Source code in src/parsecraft/backends/errors.py
13
14
15
def __init__(self, name: str) -> None:
    super().__init__(f"backend not registered: {name!r}")
    self.name = name

BackendRef

Bases: BaseModel

Identity of the backend that produced a result (provenance anchor).

BackendRegistry

BackendRegistry()

Name → (descriptor, factory) binding with lazy plugin discovery.

Thread-safety: all registry state (factories, load_errors, the discovery flag) is guarded by an internal re-entrant lock and discovery runs single-flight. The lock is NEVER held across factory(config) — heavy model loads run outside it, so lookups never stall behind a load. Instances are caller-owned: no memoization, no sharing (see AGENTS.md).

Methods:

  • create –

    Instantiate backend name — the first heavy-import boundary.

  • fingerprint –

    Deterministic identity of the registered backend set — a cache key.

  • get –

    Descriptor for name; raises :class:BackendNotFoundError.

  • list_backends –

    All known descriptors, sorted by name (deterministic output).

  • register –

    Register factory under name explicitly (highest precedence).

  • supported_formats –

    Sorted union of every registered backend's supported formats.

Attributes:

Source code in src/parsecraft/backends/registry.py
54
55
56
57
58
def __init__(self) -> None:
    self._factories: dict[str, BackendFactory] = {}
    self._load_errors: dict[str, BackendLoadError] = {}
    self._entry_points_loaded = False
    self._lock = threading.RLock()

load_errors property

load_errors: dict[str, BackendLoadError]

Copy of recorded entry-point failures — callers must surface these.

create

create(name: str, config: BackendConfig | None = None) -> DocumentBackend

Instantiate backend name — the first heavy-import boundary.

A fresh, caller-owned instance per call (no memoization): residency and VRAM admission belong to the caller, and the registry lock is never held across factory(config) — a multi-minute model load never blocks concurrent lookups or registrations.

Source code in src/parsecraft/backends/registry.py
115
116
117
118
119
120
121
122
123
124
def create(self, name: str, config: BackendConfig | None = None) -> DocumentBackend:
    """Instantiate backend ``name`` — the first heavy-import boundary.

    A fresh, caller-owned instance per call (no memoization): residency
    and VRAM admission belong to the caller, and the registry lock is
    never held across ``factory(config)`` — a multi-minute model load
    never blocks concurrent lookups or registrations.
    """
    factory = self._factory_for(name)
    return factory(config if config is not None else BackendConfig(name=name))

fingerprint

fingerprint() -> str

Deterministic identity of the registered backend set — a cache key.

Derived from each backend's name, version, and supported formats: properties of the installed backend set, never host hardware. Two registries with the same backend set yield the same fingerprint on any machine; changing any backend's identity or formats changes it.

Source code in src/parsecraft/backends/registry.py
104
105
106
107
108
109
110
111
112
113
def fingerprint(self) -> str:
    """Deterministic identity of the registered backend set — a cache key.

    Derived from each backend's name, version, and supported formats:
    properties of the *installed backend set*, never host hardware. Two
    registries with the same backend set yield the same fingerprint on any
    machine; changing any backend's identity or formats changes it.
    """
    canonical = "\n".join(f"{d.name}@{d.version}|{','.join(sorted(d.capabilities.supported_formats))}" for d in self.list_backends())
    return hashlib.sha256(canonical.encode("utf-8")).hexdigest()

get

get(name: str) -> BackendDescriptor

Descriptor for name; raises :class:BackendNotFoundError.

Source code in src/parsecraft/backends/registry.py
90
91
92
93
94
95
96
97
def get(self, name: str) -> BackendDescriptor:
    """Descriptor for ``name``; raises :class:`BackendNotFoundError`."""
    self._load_entry_points()
    with self._lock:
        factory = self._factories.get(name)
    if factory is None:
        raise BackendNotFoundError(name)
    return factory.descriptor

list_backends

list_backends() -> list[BackendDescriptor]

All known descriptors, sorted by name (deterministic output).

Source code in src/parsecraft/backends/registry.py
84
85
86
87
88
def list_backends(self) -> list[BackendDescriptor]:
    """All known descriptors, sorted by name (deterministic output)."""
    self._load_entry_points()
    with self._lock:  # snapshot: concurrent register() cannot resize mid-iteration
        return [factory.descriptor for name, factory in sorted(self._factories.items())]

register

register(name: str, factory: BackendFactory) -> None

Register factory under name explicitly (highest precedence).

Source code in src/parsecraft/backends/registry.py
62
63
64
65
66
67
68
69
70
71
72
73
74
def register(self, name: str, factory: BackendFactory) -> None:
    """Register ``factory`` under ``name`` explicitly (highest precedence)."""
    if not isinstance(factory, BackendFactory):
        msg = f"factory for {name!r} does not implement BackendFactory"
        raise TypeError(msg)
    descriptor = factory.descriptor
    if descriptor.name != name:
        msg = f"descriptor name {descriptor.name!r} does not match registration name {name!r}"
        raise ValueError(msg)
    with self._lock:  # check + insert atomically: one winner per name
        if name in self._factories:
            raise BackendAlreadyRegisteredError(name)
        self._factories[name] = factory

supported_formats

supported_formats() -> list[str]

Sorted union of every registered backend's supported formats.

Source code in src/parsecraft/backends/registry.py
 99
100
101
102
def supported_formats(self) -> list[str]:
    """Sorted union of every registered backend's supported formats."""
    formats = {fmt for descriptor in self.list_backends() for fmt in descriptor.capabilities.supported_formats}
    return sorted(formats)

BackendResult

Bases: BaseModel

Converged IR output of DocumentBackend.convert.

ConversionRequest

Bases: BaseModel

Everything a backend may do — bounds live here, not in global state.

cancellation is polled for a True result; timeouts and budgets are hard expectations a backend must honor or return a structured failure.

DependencyUnavailableError

DependencyUnavailableError(module: str, extra: str)

Bases: BackendError

A backend's optional implementation module is not installed.

Source code in src/parsecraft/backends/errors.py
44
45
46
47
def __init__(self, module: str, extra: str) -> None:
    self.module = module
    self.extra = extra
    super().__init__(f"backend dependency {module!r} is not installed — install the {extra!r} extra")

DocumentBackend

Bases: Protocol

A backend: analyzes a source and converts bounded slices of it.

Methods:

  • analyze –

    Collect deterministic signals without converting content.

  • convert –

    Convert the requested slice into canonical IR pages.

analyze

analyze(source: SourceDocument) -> AnalysisResult

Collect deterministic signals without converting content.

Source code in src/parsecraft/backends/protocol.py
144
145
146
def analyze(self, source: SourceDocument) -> AnalysisResult:
    """Collect deterministic signals without converting content."""
    ...

convert

convert(request: ConversionRequest) -> BackendResult

Convert the requested slice into canonical IR pages.

Source code in src/parsecraft/backends/protocol.py
148
149
150
def convert(self, request: ConversionRequest) -> BackendResult:
    """Convert the requested slice into canonical IR pages."""
    ...

ModelAssetDescriptor

Bases: BaseModel

Pinned model-asset metadata (license + reproducibility contract).

PageSignal

Bases: BaseModel

Deterministic per-page analysis signal (planner input state).

SourceDocument

Bases: BaseModel

A document handed to a backend: path-based or in-memory.

CLI

cli

CLI module for ParseCraft.

Modules:

  • app –

    Typer CLI app for ParseCraft.

  • args –

    CLI arguments, options, and flags for ParseCraft.

  • benchmark –

    parsecraft benchmark — reproducible reports over local documents.

  • commands –

    CLI command implementations for ParseCraft.

  • config –

    Configuration diagnostic surface: schema, engine builder, and rendering.

  • convert –

    parsecraft convert — analyze, route, execute, render the IR.

  • errors –

    Shared CLI error type: a message plus the process exit code to use.

  • inspect –

    parsecraft inspect — per-page analysis signals plus a routing preview.

  • models –

    parsecraft models — inspect and manage the pinned model-asset cache.