OpenProse
SDK API Reference

/internals

The engine room -- the honest deep door. The reconciler-construction spine, the deep domain shapes, the deprecated Reactor*-prefixed port aliases, and the receipt/projection helpers. Stable-but-deep, distinct from the curated front door.

/internals: the engine room

@openprose/reactor/internals is the honest deep door. Every public name that is not on the curated front door (.), the @openai/agents escape hatch (/agents), the substrate and ingress backends (/adapters), or the offline run-phase boundary (/run) re-homes here.

Nothing was removed from the package. These names are simply not on the headline surface. If you are wiring a project from the front door you will never import this subpath -- the facade, the assemblers, and the substrate factories already cover the 90% path. You reach for /internals only when you are re-hosting the reconciler loop by hand against your own ports, or reading the deep domain shapes the front door wraps.

Think of this as stable-but-deep, not unstable. The names here back the same engine the front door drives; they are de-emphasized, not experimental. But it is a wide surface, and the headline vocabulary on the front door is the one we curate for agents. Start there.

What lives here

/internals re-exports the whole engine, grouped by the design doc each module implements (src/internals/index.ts):

GroupModuleWhat it is
The coordination spine../shapesThe shared discriminated unions every other module reads (SHAPES.md).
Cycle + predicate keep-home../cycleThe cycle/predicate shapes (SHAPES.md §8).
The world-model store../world-modelThe content-addressed store object (architecture.md §5.2, §10).
The compiled canonicalizer../canonicalizerThe per-node canonicalizer Forme froze (architecture.md §3.2).
The compiled postcondition validators../postconditionThe commit-gate validators (architecture.md §3.3).
Forme../formeThe compile-phase wiring (architecture.md §3.1, §6.3).
The receipt ledger object../receiptThe receipt builder and the ledger trail (SHAPES.md §4).
The memo re-key + skip decision../memoThe memo key and the skip disposition (SHAPES.md §3).
Composition../compositionSubscriptions-as-props, pins-as-read-isolation (§7).
Forecast../forecastThe continuity clock + self-recheck (architecture.md §3.5).
Evidence resolution../evidence-planEvidence-by-reference resolution (delta.md §A3.1).
Surprise-cost + projection../cost, ../projectionThe observable cost shapes + receipt projection (delta.md §A4).
The run-phase reconciler spine../reactorThe dumb reconciler loop (architecture.md §4.1).
The injection boundary../adaptersThe adapter port contracts, including the deprecated Reactor*-prefixed aliases (architecture.md §5.3).
The SDK assembler spine../sdkcreateReactor / mountDag internals.

These were nine separate doc-only subpaths in the pre-0.3.0 surface (/receipt, /cost, /forme, /evidence-plan, /memo, /forecast, /composition, /projection, /canonicalizer). They held zero consumer usage as standalone import paths, so 0.3.0 folded them into one engine-room door. The load-bearing few names they carried -- ATOMIC_FACET, verifyReceipt, verifyReceiptChain, Receipt -- were pulled forward onto the front door; the rest stay reachable here. Only the import path changed. No name became unavailable.

createSkippedReceipt ships from both ../receipt and ../memo. /internals pins the canonical ../receipt builder over the ../memo star-export, so the name resolves to one implementation -- not a star-merge collision.

The reconciler-construction spine

This is the reason to be here: re-hosting the run-phase loop by hand against custom ports, instead of going through the facade or runProject. The constructor takes injected ports and a fixed compiled topology and returns a handle:

import {
  createReconciler,
  type ReconcilerPorts,
  type ReconcilerTopology,
  type ReconcilerHandle,
  inboundEdges,
  COLD_START_ATOMIC_FINGERPRINT,
} from "@openprose/reactor/internals";

// Construct the dumb reconciler over injected ports + a fixed compiled topology.
// No judge, no policy, no backstop -- the entire decision is fingerprint
// comparison.
const handle: ReconcilerHandle = createReconciler(ports, topology);

The topology is a constructor input (createReconciler(ports, topology), src/reactor/index.ts), not mutable state -- which is exactly why the deferred fixpoint (topology-as-responsibility) attaches additively later: "an epoch names that fact" without reshaping the handle.

The handle exposes the four drive verbs, sync and async:

MemberWhat it does
reconcile(event)Handle one wake for one node: memo/skip, single-flight schedule, commit, propagate. Returns the disposition, the receipt written, and the downstream wakes to enqueue.
drain(initial)Drain a seeded queue of wakes to a fixpoint, honoring single-flight + coalescing + propagation. Returns the ordered per-node results.
reconcileAsync(event)The async sibling: awaits the one bounded LLM session. A wake delivered while a render is in flight marks the node dirty and collapses into exactly one coalesced follow-up -- never a second concurrent render, never a lost wake.
drainAsync(initial)The async fixpoint loop: awaits each reconcileAsync fully before shifting the next event, preserving the sync path's exact ordering and one-render-in-flight guarantee.

The supporting names complete the loop you would hand-roll: inboundEdges resolves a node's subscribed edges off the topology; memoKeyMoved, movedFacetsBetween, and propagationTargets are the comparison + propagation helpers; and COLD_START_ATOMIC_FINGERPRINT (asFingerprint("cold-start:empty")) is the reserved cold-start atomic fingerprint a node carries before its first render. The full ledger-port (ReceiptLedgerPort) and world-model-port (WorldModelStorePort) contracts the handle reads through are here too.

Most callers should not hand-host the reconciler. The facade wires createReactor + the run-phase compile for you and returns one typed handle. Reach for createReconciler only when you genuinely own the ports -- a custom evidence plan, an alternate persistence story, an embedding host that drives the loop on its own cadence. See the reconciler and receipts for the behavior you are taking responsibility for.

The deprecated Reactor*-prefixed port aliases

In the pre-0.3.0 surface the adapter port types carried a Reactor* prefix. 0.3.0 made the short names the headline vocabulary -- StorageAdapter, WorldModelStore, ClockAdapter -- which is what /adapters and the Substrate record use. The original Reactor*-prefixed names are kept reachable from /internals as deprecated aliases (src/adapters/types.ts):

// The short name is the headline vocabulary used by Substrate;
// the Reactor*-prefixed original is the deprecated alias, kept reachable here.
export type StorageAdapter = ReactorStorageAdapter;
// likewise: WorldModelStore = ReactorWorldModelStore,
//           ClockAdapter    = ReactorClockAdapter

These are type aliases, not separate implementations -- a downstream still pinned to ReactorStorageAdapter keeps compiling. Prefer the short names in new code. Nothing was removed; the prefixed names are simply no longer the door you are pointed at.

The receipt and projection helpers

Receipt verification lives on the front door (verifyReceipt / verifyReceiptChain). The proof-projection helpers -- deriving a sharable proof summary that avoids private payload fields -- live here, alongside the deep receipt shapes they operate on (src/receipt/index.ts, src/projection/index.ts):

import { verifyReceipt } from "@openprose/reactor";
import {
  inspectReceiptProof,
  projectReceiptProof,
  type LedgerReceipt,
  type ReceiptProofInspection,
} from "@openprose/reactor/internals";

export function inspectStoredReceipt(receipt: LedgerReceipt) {
  const verification = verifyReceipt(receipt);
  if (!verification.ok) {
    throw new Error(verification.errors.join("; "));
  }
  return inspectReceiptProof(receipt);
}

export function publicReceiptEvidence(proof: ReceiptProofInspection) {
  const result = projectReceiptProof({ tier: "public", proof });
  if (!result.ok) {
    throw new Error(result.errors.join("; "));
  }
  return result.projection;
}

inspectReceiptProof reads a stored receipt into a ReceiptProofInspection; projectReceiptProof({ tier, proof }) projects that inspection down to a tier (for example "public") that drops private payload fields. The verify split is deliberate: the everyday verifyReceipt is on the front door, and the deeper projection machinery -- bound to the receipt domain shapes -- stays in the engine room.

Honest scope, unchanged from the receipt model: in v1 verified means tamper-evident at the meaning layer and chain-consistent -- not yet a cryptographic byte hash, and a receipt records what changed and why, not when or by whom. projectReceiptProof projects what the chain attests; it does not manufacture an audit fact the receipt does not yet carry.

Where to go next

On this page