@exellix/exellix-runtime
v3.7.0
Published
Execution matrix runtime: Catalox-shaped catalogs, Mongo matrix row lifecycle, claims, and orchestration hooks that inject @exellix/graph-engine executeGraph.
Readme
@exellix/exellix-runtime
Integrating a BFF or worker? → docs/client-integration.md (install, Mongo, reads, jobs HTTP, checklist) · docs/graph-execution-record-placement.md (record →
runtime.inputonly) · docs/README.md (full index)
TypeScript runtime for orchestrating Exellix graph execution at scale: an execution matrix ties many inputs (from xmemory) to one or more graphs, tracks per-graph lifecycle (not-started → in-progress → completed | failed | skipped), stores successful inferences on the row document, and records failures in a separate collection. Design-time matrix definitions live in Catalox; durable execution state lives in MongoDB (matrix rows, failures, snapshots, and config collections — opened via createExellixMatrixDataTier from this package; @exellix/exellix-jobs composes this package for worker semantics). Individual graph runs go through @exellix/graph-engine (this package depends on ^6.0.1; createExellixGraphRuntime().executeGraph receives { model: GraphModelObject, runtime: GraphRuntimeObject }, and MatrixGraphExecuteOverrides is the optional runtime layer after the matrix supplies jobId, job, input, and executionMemory).
Why keep this package: @exellix/exellix-jobs (worker deployable) wraps claims and operator HTTP. Read dashboards and Mongo wiring live here too (openMatrixReadTier, createExellixMatrixDataTier). The domain — contracts, materialization, orchestration, Memorix bridge, eligibility — is centralized in @exellix/exellix-runtime.
This package does not embed a web UI; it exposes the data-tier API your BFF and @exellix/exellix-jobs build on. Read-only dashboards use openMatrixReadTier (or lower-level fetchExecutionMatrixNavigatorPage, fetchSourceJoinView, etc.). Published builds track package.json / CHANGELOG.md. Memorix integration targets @x12i/xmemory-store ≥ 2.9.8 and @x12i/xmemory-scoper ≥ 1.9.11 (scoped views, scoped-data reads, graph-entry inventory): besides runMongoAggregate and namespace-scoped getXmemoryTierStatistics, this package re-exports tier factories (createXmemoryDataTier / createScoperMongoClient), filter catalog (getTierFilterCatalog, cache clears), and shared fetch predicates (buildTierFetchMatch, buildDatePresetMatches, resolveSurfaceDbCollection, stableScopeKey, facet/metadata constants) so hosts can build dashboards and list endpoints without a second import path. For Layer-01 graph entry payloads, use loadGraphEntryMemorixPayload (scoper-only I/O) and buildExecutionSeedWithMemorixLayer; for structured record gates aligned with graph-engine, import evaluateStructuredDataFilters (and helpers) from this package — same implementation as @exellix/graph-engine.
Architecture
flowchart LR
subgraph design [Design time]
Catalox[Catalox native catalog]
end
subgraph source [Source data]
Xmemory[xmemory-scoper / store]
end
subgraph runtime [Runtime]
Materializer[Materializer]
Store[ExecutionMatrixRuntime]
Orchestrator[Orchestrator]
Engine[graph-engine executeGraph]
end
Catalox --> Materializer
Xmemory --> Materializer
Materializer --> Store
Store --> Orchestrator
Orchestrator --> Engine
Engine --> Store- Catalox — Matrix template (
metadata.catalogType: "execution-matrix"):data.input,data.graphs[](references to graph ids). Graph definitions (e.g. catalogexellix-graphs,metadata.catalogType: "graphs"):data.graphId,data.mappedInput[],data.execution(priority, optionalconditions/conditionRelations). See docs/execution-matrix-runtime.md. Repo-local seed example:npm run use-case:create-exellix-graphs-catalog. - xmemory — Your host resolves selectors into concrete
inputrows (XmemoryInputResolverin code). - Mongo matrix collections —
exellix_execution_matrix_rowsandexellix_execution_matrix_failures(and related config collections) hold runtime rows, statuses, inferences, and failure payloads. Open them withcreateExellixMatrixDataTierfrom@exellix/exellix-runtime— hosts should not wire@x12i/xronox-storedirectly. - Executable graphs — DAG JSON must satisfy graph-engine 6.x canonical rules (see
assertCanonicalGraphDocument). Model root:id, optionalversion,modelConfig({ cases: [{ modelConfig, when? }] }),jobKnowledge,nodes, optionaledges,variables, required rootresponse, optionalmetadata(design-time fields such asgraphEntrylive undermetadataonly).nodesmust be aGraphNode[]array (record-keyed maps are rejected). Task nodes:skillKey/variableson the node root; payload bindings ininputsConfig; prompts and variable hooks intaskVariable(deprecated:node.inputs). Execution wiring (narrix,aiTaskProfile/webScoping,executionStrategies,aiTasksOutputValidation,modelConfig,llmCall, local-skill paths, …) belongs undertaskConfiguration, notmetadata. Runtime: flat fields onruntime.inputonly (graph-engine ≥ 5.16 does not promotejob.raw→input.raw); see docs/graph-execution-record-placement.md.runtime.input→executionMemory.input; optionalruntime.inputsis a separate caller bag onRunTaskRequest.inputs. Variables: job/graph bucketjobVariables.*(aliasvariables.*); task buckettaskVariables.*(see docs/format/). Author web retrieval undertaskConfiguration.aiTaskProfile.webScopingonly. Layer-01 seeding:buildExecutionSeedFromGraphEntry(delegates to graph-engine). Memorix Layer-01:loadGraphEntryMemorixPayload+buildExecutionSeedWithMemorixLayer. Structured gates:evaluateStructuredDataFilters. Run-log metadata on task responses:runLog,logxerRunIdonly. Narrative: docs/exellix-graph-format.md · typed contracts: docs/format/graph-model-object-format.md.
Related packages
| Package | Role |
|---------|------|
| @exellix/exellix-runtime (this repo) | One library for hosts: Mongo (createExellixMatrixDataTier), reads (openMatrixReadTier), materialize, claims, health helpers — not a standalone HTTP server. |
| @exellix/exellix-jobs | Optional separate process: supervised claims + operator HTTP (/v1/health, /workers/status, …). Your BFF still uses runtime for dashboards. |
| @exellix/graph-engine | Playground and matrix executeGraph — see client-boundary.md. |
Deprecated: @exellix/exellix-matrix-persister, @exellix/exellix-matrix-read → use this package ≥ 3.1.
Requirements
- Node.js 18+ (recommended 20+) for native
fetch/cryptousage in the dependency tree. - npm (or compatible) with access to registries configured for scoped packages (for example
@exellix/*,@x12i/*via.npmrcif you use GitHub Packages or a private registry).
Installation
From the repository root:
npm installThe package is intended to be published or installed from a registry / monorepo workspace (npm pack, GitHub Packages, etc.). Run npm run build before publish so dist/ matches package.json exports.
Mongo wiring: import createExellixMatrixDataTier from @exellix/exellix-runtime (3.1+). The separate @exellix/exellix-matrix-persister package is deprecated — use runtime only.
Integrating a host (BFF / worker): see docs/client-integration.md.
Build and verification
Copy .env.example to .env when running Mongo-backed checks locally.
One command
| Command | What runs |
|---------|-----------|
| npm run verify | build + unit tests (default, no Mongo) |
| npm run verify:ci | Same as verify (explicit CI alias) |
| npm run verify:all | build + unit + live + read smoke (skips live/smoke if env missing; use --require-mongo to fail instead) |
npm run verify # fast — always safe in CI
npm run verify:all # full stack when .env has MONGO_URI (+ smoke ids)Orchestrator: scripts/verify-suite.mjs — import runVerify, runVerifyAll, runUnitTests, runLiveTests, runReadSmoke, hasMongoEnv, hasReadSmokeEnv.
Individual steps
npm run build # tsc → dist/
npm run test # alias for test:unit
npm run test:unit # vitest, src/**/*.spec.ts (no Mongo)
npm run test:live # test/execution-matrix/*.live*.spec.ts
npm run test:smoke # matrix-read CLI (alias: matrix:read)
npm run test:watch # vitest watch mode
npm run cli -- help # unified toolbox CLI (matrix-link, matrix-read, health, catalox-inventory)
npm run matrix:link # link graph → matrix + materialize rows
npm run matrix:read # read-only dashboard JSON
npm run catalox:inventory| Script | Requires |
|--------|----------|
| test:unit / verify | Nothing |
| test:live | MONGO_URI (+ writable execution_db / config_db) |
| test:smoke / matrix:read | MONGO_URI (+ .env.test fixture ids, auto-seeded) |
| test:matrix:seed | MONGO_URI — creates test-only config in Mongo |
| matrix:link | MONGO_URI, GRAPH_ID, MATRIX_CATALOG_ID (or .env.test for fixture) |
Smoke optional env: MATRIX_RUN_ID, INPUT_GROUP_BY_PATH, execution_db, config_db, MULTI_GRAPH_LIMIT, NAVIGATOR_LIMIT, INCLUDE_NAVIGATOR=0; for entityFacet: MATRIX_READ_MEMORIX_ENABLED=true, ENTITY_TYPE, NAMESPACE.
Release status: docs/blockers/GAP-ANALYSIS.md · docs/blockers/README.md
Quick start
Typical flow: validate a Catalox matrix item → materialize rows → persist → claim → run graph → update status.
import {
executionMatrixPayloadFromCatalogItem,
graphCatalogPayloadFromCatalogItem,
materializeExecutionMatrixRuntimeRows,
processNextMatrixClaim,
processNextMatrixGraphExecution,
} from '@exellix/exellix-runtime';
// Plus: createExellixMatrixDataTier, createExecutionMatrixRuntime, createExellixConfigStore from @exellix/exellix-runtime,
// and createExellixGraphRuntime from @exellix/graph-engine.
// 1) Load matrix + graph definitions from Catalox (each { data, metadata })
const payload = executionMatrixPayloadFromCatalogItem(matrixCatalogItem);
const graphRecords = payload.graphs.map((id) =>
graphCatalogPayloadFromCatalogItem(graphCatalogItemsById.get(id)),
);
// 2) Resolve inputs (from xmemory or any source) into one row per unit of work
const inputRows = [{ entityId: 'e-1' /* … */ }];
const rows = materializeExecutionMatrixRuntimeRows({
matrixCatalogId: 'my-matrix-catalog',
matrixItemId: matrixCatalogItem.itemId,
matrixRunId: 'batch-2026-04-26',
payload,
graphRecords,
inputRows,
});
// 3) const tier = await createExellixMatrixDataTier({}); then createExecutionMatrixRuntime(tier.rows, tier.failures, { snapshots: tier.snapshots }).
// (MONGO_URI / execution_db / MONGO_ROLE come from env by default — see “Mongo, execution_db, ERC” below)
// then runtime.insertRuntimeRow(row) for each row.
// 4) Worker — pick a mode:
// await processNextMatrixClaim(
// {
// runtime,
// executeGraph: graphRuntime.executeGraph.bind(graphRuntime),
// resolveGraphEntry: ({ graphId }) => graphEntryById.get(graphId),
// },
// { matrixCatalogId: 'my-matrix-catalog', matrixRunId: 'batch-2026-04-26', graphId: 'my-graph.v1' },
// );
// Runtime mode (single run): provide an external jobId, optionally enable graph-engine debugMode.
// Graph-engine 5.x: a single canonical executor handles both regular and debug runs; pass
// `debugMode: true` and the response carries `ExecuteGraphResult.debug.nodes`.
// await processNextMatrixClaim(
// {
// runtime,
// executeGraph: graphRuntime.executeGraph.bind(graphRuntime),
// resolveGraphEntry: ({ graphId }) => graphEntryById.get(graphId),
// },
// {
// matrixCatalogId: 'my-matrix-catalog',
// matrixRunId: 'batch-2026-04-26',
// graphId: 'my-graph.v1',
// jobId: 'job_ext_123',
// debugMode: true,
// },
// );
// Or “next one” across several graphs (tries graph ids in order):
// await processNextMatrixGraphExecution(
// { runtime, executeGraph, resolveGraphEntry: ({ graphId }) => graphEntryById.get(graphId) },
// { matrixCatalogId: 'my-matrix-catalog', matrixRunId: 'batch-2026-04-26', graphIds: ['g.a', 'g.b'] },
// );
// Optional: resolve graphEntry from a loaded graph document — same as graph-engine:
// resolveGraphEntryFromGraph(loadedGraph) // metadata.graphEntry
// Optional: validate requiredExecutionPaths after seeding — validateExecutionSeedPaths(execution, graphEntry)
//
// Optional: Layer-01 Memorix + graph entry — load scoped-data / narrative / snapshot via scoper, merge into seed:
// import { loadGraphEntryMemorixPayload, buildExecutionSeedWithMemorixLayer } from '@exellix/exellix-runtime';
// const memorix = await loadGraphEntryMemorixPayload(
// { nx, opDb: 'xmemory-op', metadataDb: 'xmemory-meta' },
// { mode: 'scoped-data-by-source-key', entityType: 'subnet', sourceId: row.input.sourceId },
// );
// if (!memorix.ok) { /* handle GraphEntryXmemoryLoadCodes */ }
// const { execution } = buildExecutionSeedWithMemorixLayer(graphEntry, row.input, memorix.seedSources);
//
// Optional: structured dataFilters preflight (same semantics as graph-engine executor):
// import { evaluateStructuredDataFilters, EXELLIX_STRUCTURED_DATA_FILTERS_V1 } from '@exellix/exellix-runtime';
// const gate = evaluateStructuredDataFilters(graphEntry.conditions?.dataFilters, scopedDataPayload);
//
// Optional: forward LLM / traceability overrides to `executeGraph` per worker default + per-call.
// Per-call shallow-merges over deps; absent fields fall back to graph-engine env defaults.
// See docs/execution-matrix-runtime.md → "Forwarding LLM / traceability overrides to executeGraph".
// await processMatrixGraphBatch(
// {
// runtime,
// executeGraph: graphRuntime.executeGraph.bind(graphRuntime),
// resolveGraphModel: ({ graphId }) => graphModelById.get(graphId),
// resolveGraphEntry: ({ graphId }) => graphEntryById.get(graphId),
// executeOverrides: { modelConfig: { cases: [{ modelConfig: { xynthesisModel: 'xynth-default', skillModel: 'skill-default' } }] }, runLogMode: 'summary' },
// },
// {
// matrixCatalogId: 'my-matrix-catalog',
// matrixRunId: 'batch-2026-04-26',
// graphIds: ['g.a', 'g.b'],
// limit: 1,
// jobId: 'job_ext_123',
// executeOverrides: { modelConfig: { cases: [{ modelConfig: { xynthesisModel: 'xynth-fast', skillModel: 'skill-fast' } }] }, runTaskExecutionMode: 'trace' },
// },
// );For tests and local scripts without Mongo atomic updates, use MemoryMatrixCollection with createExecutionMatrixRuntime and serializeClaims: true (see tests under src/execution-matrix/*.spec.ts).
Client toolbox
High-level helpers and a unified CLI for the operations hosts repeat: open Mongo, link a graph into a matrix config, publish operational state, materialize runtime rows, read dashboards, probe connectivity, and run Catalox inventory.
Programmatic API
Import from @exellix/exellix-runtime:
| Function | Purpose |
|----------|---------|
| openMatrixClientBundle | createExellixMatrixDataTier + createExecutionMatrixRuntime + createExellixConfigStore (default serializeClaims: true) |
| ensureGraphLinkedInMatrix | Create matrix config or append graphId to payload.graphs |
| ensureExecutionMatrixConfigForGraph | Idempotent graph + matrix bootstrap for a single graph (Studio dev hosts) |
| publishGraphForMatrixRun | patchOperational (e.g. Published + Running) with optimistic concurrency |
| loadGraphRecordsForMatrix | Load graph payloads for every id on a matrix config |
| resolveDefaultMaterializeInputRows | One row per mappedInput entry, or [{}] |
| materializeAndInsertMatrixRows | Materialize + insertRuntimeRow when matrix already references the graph |
| linkAndMaterializeMatrixRun | Full flow: link → optional publish → materialize → insert (opens/closes bundle unless you pass deps) |
Example (same as a one-off link-and-materialize script):
import { linkAndMaterializeMatrixRun } from '@exellix/exellix-runtime';
const result = await linkAndMaterializeMatrixRun({
matrixCatalogId: 'my-matrix-1',
graphId: 'live_g2_1778998284284_vfz22c',
matrixRunId: `run-${Date.now()}`,
// dryRun: true, // preview rows without insert
// publishOperational: false,
});
console.log(result.rowCount, result.matrixRowIds);Lower-level pieces remain available: buildMatrixMaterializeContext (Catalox items), materializeExecutionMatrixRuntimeRows, openMatrixReadTier, orchestration (processNextMatrixClaim, …). See docs/client-integration.md.
CLI
After npm run build:
npx exellix-runtime help
npx exellix-runtime matrix-link --graph-id=G --matrix-catalog-id=M
npx exellix-runtime matrix-read
npx exellix-runtime health --probe-dependencies
npx exellix-runtime catalox-inventory -- --format=markdown --out=reports/inventory.md| npm script | Command | Requires |
|------------|---------|----------|
| npm run cli | exellix-runtime <command> | — |
| npm run matrix:link | matrix-link | MONGO_URI, GRAPH_ID, MATRIX_CATALOG_ID (or flags) |
| npm run matrix:read | matrix-read | MONGO_URI, MATRIX_CATALOG_ID, GRAPH_ID |
| npm run test:smoke | alias for matrix:read | same as matrix-read |
| npm run catalox:inventory | catalox-inventory | Firebase and/or MONGO_URI (see CLI help) |
Loads repo .env then .env.test (test-only smoke ids — never production). Run npm run test:matrix:seed once to create the fixture in Mongo. Run npx exellix-runtime help matrix-link for flags (--dry-run, --skip-operational, --input-rows-json, …).
Public API (by concern)
| Area | Main symbols | Role |
|------|----------------|------|
| Types | ExecutionMatrixRuntimeRecord, ExecutionMatrixCatalogPayload, ExecutionMatrixStatus, MatrixGraphExecuteOverrides, ExecutionMatrixStepSummary, RecordsEligibilityPolicy, SourceExecutionStatusMap, re-exported ExecuteGraphInput / GraphExecutionRequest / GraphModelObject / GraphRuntimeObject / HostExecuteGraphRunOptions (from @exellix/graph-engine), … | Shared contracts |
| Graph format | Types Graph, GraphDocumentMetadata, GraphNode, TaskNode, FinalizerNode, GraphEntryContract, GraphResponseContract, finalizer / catalog-planning types (CatalogRequestEntry, …); assertCanonicalGraphDocument, getCanonicalGraphDocumentViolations, CANONICAL_GRAPH_TOP_LEVEL_KEYS, mergeGraphDocumentModel, EXELLIX_GRAPH_MODEL_VARIABLE_KEY, validateCatalogPlanning, isCatalogBinding, isCatalogRequestEntry, ExellixGraphError, ExellixGraphErrorCode | Executable DAG JSON model — graph-engine 5.x: nodes array, task skillKey / variables on the node root, execution fields under taskConfiguration (see TaskNode.taskConfiguration / TaskNodeTaskConfiguration in @exellix/graph-engine). Re-exported here so hosts validate without a second dependency; normative prose in docs/exellix-graph-format.md |
| Status | normalizeExecutionMatrixStatus | Canonical status strings (e.g. legacy not-strated → not-started) |
| Collections | executionMatrixStoreCollectionDefs, collection name constants | Used by createExellixMatrixDataTier / internal wiring |
| Persistence | ExecutionMatrixRuntime, createExecutionMatrixRuntime | CRUD, claims, completion, listFailureRecords / getFailureRecord / getLatestFailureRecordForRowGraph, batchLookupSourceExecutionStatuses |
| Catalox | parseExecutionMatrixCatalogPayload, executionMatrixPayloadFromCatalogItem, parseGraphCatalogPayload, graphCatalogPayloadFromCatalogItem | Validate / parse matrix + graph catalog data |
| Materialization | materializeExecutionMatrixRuntimeRows, sortGraphRecordsForMatrix, mergeMappedInputEntries, buildExecutionSeedFromGraphEntry, resolveInputRowsWithResolver; re-exported resolveGraphEntryFromGraph, createResolveGraphEntryFromLoader, validateExecutionSeedPaths, types BuildExecutionSeedSources / BuildExecutionSeedResult | Rows from matrix + graph records; buildExecutionSeedFromGraphEntry delegates to @exellix/graph-engine (Layer-01 paths such as input for the flat MAIN bucket — not legacy input.raw); matrix row fields → runtime.input; optional runtimeScope on materialize + resolver for tenant/xmemory alignment |
| RunTask preflight | buildTaskNodeRunTaskRequest, validateTaskNodeRunTaskConfig, validateTaskNodeRunTaskInvoke, analyzeTaskNodeRunTaskRequest, validateRunTaskConfig, analyzeRunTaskRequest, … | Re-exported from @exellix/graph-engine 6.x — BFF/CI validation without a second import; unit tests: graph-engine-preflight-reexport.spec.ts |
| Graph entry + Memorix (scoper) | loadGraphEntryMemorixPayload, buildExecutionSeedWithMemorixLayer, GraphEntryXmemoryLoadCodes, request union types (mode: scoped-data-row, scoped-data-by-source-key, narrative, snapshot-scoped-data) | Loads Layer-01 artifacts via @x12i/xmemory-scoper only (no raw xmemory-store reads for entity bodies in this helper). Modes: entity+question (getXScopedDataByEntityAndQuestionId), entity type + source/document id (getXScopedDataDocumentBySourceKey), narrative (getScopedAnswer / getScopedAnswerWithContext), snapshot (getScopedDataFromSnapshot). Merge with matrix input using buildExecutionSeedWithMemorixLayer. Unit tests: graph-entry-xmemory-load.spec.ts |
| Structured dataFilters | evaluateStructuredDataFilters, evaluateDataFilterPredicate, getStructuredDataFilterPathViolations, isStructuredDataFiltersV1, EXELLIX_STRUCTURED_DATA_FILTERS_V1, types EvaluateStructuredDataFiltersResult, EvaluateStructuredDataFiltersOptions, StructuredDataFiltersV1, ConditionsDataFilters | Re-exported from @exellix/graph-engine (≥ 5.3.8, aligned with 6.x) — same semantics as the executor for graph-entry / task conditions.dataFilters. Pass the scoped data payload as record (the object whose properties back data.* paths). Unit tests: graph-engine-datafilters-reexport.spec.ts |
| Orchestration | processNextMatrixClaim, processMatrixClaimForRow, claimNextAcrossGraphs, processMatrixGraphBatch, processNextMatrixGraphExecution, processAllMatrixGraphExecutions, executeMatrixGraphForClaim, mergeClaimExtraFilter, mergeMatrixGraphExecuteOverrides, createMatrixExecuteGraphAdapter, OrchestratorExecuteGraphInput | Claim → choose mode (runtime: external jobId, optional debugMode: true; autonomous: generated stable jobId) → resolve GraphModelObject → build GraphRuntimeObject → single executeGraph({ model, runtime }) call → persist; optional runtimeScope on deps merges into extraFilter; optional executeOverrides merge into runtime only |
| Source resolver | createMatrixSourceResolverFromRecordLikeDataSource, createMatrixSourceResolverFromEffectiveConfig, diffSourceIdsAgainstMatrix, DEFAULT_MATRIX_SOURCE_LIST_CAP | Wire record / query-snapshot sources for fetchSourceJoinView / run loop; event / storage need custom resolvers |
| UI / BFF (read dashboards) | openMatrixReadTier → graphDashboard, multiGraphOverview, sourceJoinView, navigatorPage, entityFacet, listFailureRecords, getFailureRecord (client-integration.md). Lower-level: fetchExecutionMatrixNavigatorPage, fetchSourceJoinView, runtime.listFailureRecords, … when you already hold ExecutionMatrixRuntime |
| Records eligibility | rollupSourceExecutionStatuses, evaluateRecordsEligibility, pickFresherExecutionStepSummary, defaultRecordsSourceKeyPath; types ExecutionMatrixStepSummary, SourceExecutionStatusMap, RecordsEligibilityPolicy, BatchLookupSourceExecutionStatusesOptions | Multi-graph / cross-matrix views keyed by stable source id (input.sourceId by default); distinct from catalog EligibilityPolicy — see docs/execution-matrix-runtime.md → “Records eligibility” |
| Memorix op-tier + entity facet | fetchMemorixMatrixEntityFacet (namespace required), pickTierEntityTypeSectionCounts, buildMatrixRowEntityTypeExtraFilter, buildSnapshotsReadFilter, ExecutionMatrixRuntime.countSnapshots, RECOMMENDED_TIER_STATS_SCOPED_DATA_GROUP_PATHS, thing/view/Memorix-snapshot filter builders, listXmemoryTierThings / listXmemoryTierThingsPaged, scoped-views / scoped-data helpers in xmemory-op-tier.ts, memorix-matrix-entity-facet.ts | Operational tier + getXmemoryTierStatistics (per-surface matchedDocTotal + paginated entityTypes); re-exported getTierFilterCatalog, clearTierFetchCaches, buildTierFetchMatch, tier factories — see docs/execution-matrix-runtime.md → “Entity-type facet” |
| Memorix inference persister | prepareMemorixRecordForGraph, createMemorixInferencePersister, createMemorixInferencePersisterFromXronox, buildMemorixInferenceCollectionName | Optional side-channel persistence: strip top-level source _id before graph execution, then write graph outputs to ${entityName}-infernces in MEMORIX_DB (default memorix) — see docs/execution-matrix-runtime.md → “Opt-in Memorix inference persister” |
| XMemory store (passthrough) | createXmemoryDataTier, withEnrichmentFallback, getScoperStoreBindings, getTierFilterCatalog, getXmemoryTierStatistics, clearTierFetchCaches, buildTierFetchMatch, resolveXmemoryStoreEnv, ENV_KEYS, TIER_* / DEFAULT_* constants | Same symbols as @x12i/xmemory-store — import from @exellix/exellix-runtime for one dependency surface; see src/execution-matrix/index.ts |
| Matrix Mongo wiring | createExellixMatrixDataTier | Opens Mongo collections; pass handles to createExecutionMatrixRuntime / createExellixConfigStore |
| Client toolbox | openMatrixClientBundle, ensureGraphLinkedInMatrix, publishGraphForMatrixRun, materializeAndInsertMatrixRows, linkAndMaterializeMatrixRun, … | Host scripts / BFF bootstrap without re-wiring Mongo; see Client toolbox |
| Catalox host | buildMatrixMaterializeContext | Pair matrix + graph native items into validated payload + graphRecords after fetch |
Matrix types, orchestration, createExellixMatrixDataTier, and xmemory re-exports live in src/execution-matrix/index.ts. @x12i/xronox-store is not re-exported from the package root (see docs/migrations/v3-xronox-internal-only.md).
Persistence and concurrency
| Collection | Primary key | Purpose |
|------------|-------------|---------|
| exellix_execution_matrix_rows | matrixRowId | Per-input row: execution[] (per-graph status), inferences[] (successful finalOutput slices) |
| exellix_execution_matrix_failures | failureId | Failure audit trail (reason, trace, runLog, …) |
Collection I/O follows the xronox-shaped document API (insert / getByKey / readMany / update) on the handles you pass into createExecutionMatrixRuntime (typically from createExellixMatrixDataTier). This package does not open a native Mongo Db handle itself. Claims use read–modify–write on the rows collection; serializeClaims defaults to true so overlapping workers serialize claimNext / claimRecord (set serializeClaims: false only for a single dedicated worker). getStatusCounts walks eligible rows via store reads; countFailureRecords counts failure docs via readMany (capped). Prefer listFailureRecords / getFailureRecord over calling the failures collection directly (docs/client-boundary.md).
Per-graph tracking: each row’s execution[] holds one slot per catalog graph (graphId, status, jobId, lastAttempt, …). inferences[] stores successful outputs keyed by graphId. Read tabs / dashboards with fetchExecutionMatrixMultiGraphOverview, fetchExecutionMatrixNavigatorPage, listWaiting / listCompleted / …, fetchSourceJoinView, or raw listRecords.
Optional Memorix inference persistence: call prepareMemorixRecordForGraph before graph execution to remove source _id from the graph input while retaining it as itemId. After execution, call persistInferences on a MemorixInferencePersister to write { _itemId, infernces, metadata } documents to ${entityName}-infernces. Array outputs write one document per item.
Env: MONGO_URI, execution_db, config_db, roles
Env-Ready rule: each package documents env for itself only. @x12i/xronox documents ERC 2.0 for the engine (README, ERC 2.0). @x12i/xronox-store documents its constructor contract (mongoUri, mongoDb, …) — it does not own execution_db or other keys defined by this library.
This package (@exellix/exellix-runtime) reads the keys in .env.example when factories are called without overrides.
| Env / option | Role |
|--------------|------|
| MONGO_URI | Required for live factories / npm run test:live unless you pass mongoUri explicitly. |
| execution_db | Operational DB name (rows, failures, snapshots). Default exellix-runtime. |
| config_db | Configuration DB name (ExellixConfigStore). Default exellix. |
| MEMORIX_DB | Optional inference side-channel DB for createMemorixInferencePersisterFromXronox. Default memorix. |
| MONGO_ROLE | xronox role for the runtime store; default execution. |
| CONFIG_MONGO_ROLE | Optional role for the config store; falls back to MONGO_ROLE, then config. |
| MEMORIX_MONGO_ROLE | Optional role for the Memorix inference persister; falls back to MONGO_ROLE, then memorix. |
Monitoring: treat dashboards and alerts as a UI concern; this library exposes list + getStatusCounts (optional failure-count helpers belong in this repo per reports/roles-and-boundaries.md). Matrix retry / reconciliation policy belongs to this runtime or the product deployable that runs it; xronox-store remains a generic document store.
Optional runtimeScope (tenant / partition)
When a run must be scoped (tenant, shard, etc.), pass the same optional object everywhere:
materializeExecutionMatrixRuntimeRows({ …, runtimeScope })— shallow-merged onto each rowinputafter the resolved work-unit row (scope overwrites colliding keys). Use Mongo document paths that match claim filters, e.g.{ "input.tenantId": "acme" }.resolveInputRowsWithResolver(selector, resolver, runtimeScope)— forwarded toXmemoryInputResolver(selector, runtimeScope)so xmemory queries see the same scope.ProcessMatrixClaimDeps.runtimeScope— merged into orchestratedextraFilteronclaimNext/claimRecord/ batch (mergeClaimExtraFilterin the orchestrator; scope wins on duplicate keys).
Documentation
| Document | Contents |
|----------|-----------|
| docs/README.md | Documentation index — reading paths by role |
| docs/client-integration.md | Client implementation guide — install, bootstrap, reads, worker, jobs HTTP (3.1+) |
| docs/client-boundary.md | Graph-engine playground vs execution-matrix host responsibilities |
| docs/bff-matrix-adapter.md | Suggested BFF routes (companion to client-integration) |
| docs/blockers/GAP-ANALYSIS.md | Gap analysis + last npm test / test:live status |
| docs/blockers/README.md | CHECKLIST-* per package + BLOCKER-* upstream items |
| docs/migrations/v3-xronox-internal-only.md | Runtime 3.x: Mongo via createExellixMatrixDataTier; xronox factories on internal/xronox-matrix only |
| docs/inspection-and-testkit-ownership.md | Keep inspection / testkit on graph-engine; alias policy |
| docs/xmemory-resolver-pattern.md | XmemoryInputResolver contract and tenant scope alignment |
| Graph entry Memorix bridge (code) | src/execution-matrix/graph-entry-xmemory-load.ts | loadGraphEntryMemorixPayload / buildExecutionSeedWithMemorixLayer; upstream FR status notes under reports/ |
| docs/execution-matrix-runtime.md | End-to-end behavior, Catalox convention, collections, Mongo vs memory |
| docs/exellix-graph-format.md | Graph JSON authoring (Narrix, local skills, layers 01/08) |
| docs/format/graph-model-object-format.md | Static GraphModelObject contract (response, inputsConfig, modelConfig.cases, …) |
| docs/format/graph-runtime-object-format.md | Per-run GraphRuntimeObject (input / inputs, variable buckets, jobVariables) |
| docs/format/task-node-model-object-format.md | TaskNode model fields |
| docs/format/task-node-runtime-object-format.md | Per-node runtime overrides (runtime.nodes[nodeId]) |
| reports/roles-and-boundaries.md | Canonical split: this package vs product/deployer decisions vs Catalox / xmemory / graph-engine / xronox-store |
| reports/exellix-runtime-gap-closure-roadmap.md | This repo’s remaining runtime backlog + real upstream FRs |
| reports/fr-graph-engine-execute-graph-input-parity.md | Historical FR / notes. Graph-engine 5.x frames execution as { model, runtime }; this package exposes the model/runtime types and keeps MatrixGraphExecuteOverrides scoped to optional runtime fields |
| reports/host-decisions-needed.md | Product/deployer decisions that dependency READMEs cannot answer |
| .env.example | Env keys createExellixMatrixDataTier reads (MONGO_URI, execution_db, config_db, …) |
| documentations/execution-matrix-catalog-content.md | Design-phase catalog content shape for Catalox authors |
Package entry
- Module:
import { … } from '@exellix/exellix-runtime'or@exellix/exellix-runtime/execution-matrix(same surface; seepackage.jsonexports). - Types: emitted next to
dist/afternpm run build.
Layout
src/execution-matrix/ # implementation + unit tests (*.spec.ts co-located)
test/execution-matrix/ # live Mongo integration tests (*.live*.spec.ts)
src/client-toolbox/ # host helpers (link, materialize, open bundle) — published API
src/cli/ # unified `exellix-runtime` CLI (bin)
src/dev/ # thin smoke entry → matrix-read CLI
use-cases/ # repo-local Catalox seed / operator scripts (not published in dist)
docs/ # runtime and graph format docs
reports/ # role boundaries, product decisions, and runtime backlog
documentations/ # authoring specs (catalog content, conventions)
dist/ # build output (gitignored in typical setups)Dependencies (summary)
@exellix/graph-engine^6.0.1 — InjectedcreateExellixGraphRuntime().executeGraphreceivesExecuteGraphInput = { model: GraphModelObject, runtime: GraphRuntimeObject }. Graph JSON: arraynodes; required rootresponse;modelConfig/ task overrides as{ cases: [...] }; taskinputsConfig+taskVariable(not legacynode.inputs); execution config undertaskConfiguration; planning-onlymetadata. Runtime:inputvsinputsare distinct; variable bucketsjobVariables.*/taskVariables.*.evaluateStructuredDataFiltersmatches executor semantics for structured gates.MatrixGraphExecuteOverridesmerges intoruntime(modelConfigasModelConfigSelectionor flat{ xynthesisModel, skillModel },aliasConfig,nodes, memory bags, run-log options, …). This repo wrapsbuildExecutionSeedFromGraphEntry, re-exports model/runtime types and matrix host helpers, and documents contracts under docs/format/. Run-log metadata on mockedrunTaskresponses:runLog,logxerRunIdonly.openMatrixReadTier(this package, 3.1+) — read dashboards; used bynpm run matrix-read:smoke. Replaces@exellix/exellix-matrix-read.createExellixMatrixDataTier(this package, 3.1+) — Mongo matrix + config collections; replaces@exellix/exellix-matrix-persister.@x12i/xmemory-store^2.9.8 — Declared dependency (tier factories, statistics, scoped-data reads); re-exported fromsrc/execution-matrix/index.tsfor one import surface. Required for the matrix-read smoke script when enabling Memorix (MATRIX_READ_MEMORIX_ENABLED=true).@x12i/xronox-store(direct dependency) — document collection implementation behindcreateExellixMatrixDataTier. Not re-exported from the package root.@x12i/xmemory-scoper^1.9.11 — Scoped views, scoped-data reads (getXScopedDataByEntityAndQuestionId,getXScopedDataDocumentBySourceKey), narrative helpers, graph-entry Memorix inventory, etc.loadGraphEntryMemorixPayloadin this repo calls into scoper with anNxMongoClientyou supply (typically fromcreateNxMongoAdapter+createXmemoryDataTierwiring).@x12i/catalox— Declared for consumers that wire catalogs; matrix code imports graph-engine types and leaves Catalox wiring to your host.
What's new: typed data sources, run-mode loop, and configuration CRUD
The execution matrix now models the full data tier between source data and graph runs:
- Graph entry + Memorix +
dataFilters(2.6.8+) —loadGraphEntryMemorixPayload/buildExecutionSeedWithMemorixLayer(graph-entry-xmemory-load.ts): scoper-backed Layer-01 loads (scoped-data-row,scoped-data-by-source-key,narrative,snapshot-scoped-data).evaluateStructuredDataFiltersand related symbols are re-exported from graph-engine for BFF / CI gate preview. See CHANGELOG.md 2.6.8 and unit tests undersrc/execution-matrix/*xmemory*.spec.ts/graph-engine-datafilters-reexport.spec.ts. - Records eligibility (2.2+) —
rollupSourceExecutionStatusesmerges rows into a source key → graph id → step summary map;ExecutionMatrixRuntime.batchLookupSourceExecutionStatusesruns cappedlistRecordsqueries across multiple{ matrixCatalogId, matrixRunId?, graphIds? }scopes;evaluateRecordsEligibilityapplies optional required outcomes (missing graph ⇒not-started) and per-graph cooldown vslastAttempt.endedAt.buildXScopedDataEntityTypeFilter(catalogId)shares the canonicalentityType/entity_typefilter for Memorix scoped-data counts (tier.env.scopedDataCollection, defaultx-scoped-data). Details: docs/execution-matrix-runtime.md → “Records eligibility”, “Memorix operational tier”. - Typed
dataSourceon the matrix payload (event/storage/record/query-snapshot), each with its own polling cadence and validation. SeeDataSource. - Execution mode (
continuousvssingle-pass) decoupled from the source kind.continuousruns an in-process loop driven by anAbortSignalthe host owns;single-passruns one cycle and returns. No timers, no cron — seerunMatrixContinuously/runMatrixOncePassinsrc/execution-matrix/run-loop.ts. - Matrix claim eligibility — catalog
EligibilityPolicypluseligibilityToClaim(policy, now)to derive{ fromStatuses, extraFilter }.lastAttemptis persisted on each runtime step (status,endedAt,modelProfile?,jobId?) so age / model-profile filters work across re-runs. (Separate from records graph eligibility in the bullet above.) - Snapshots —
query-snapshotsources run a JS transform undernode:vm(best-effort isolation, hard-capped at 5s wall clock) and persist the result inexellix_execution_matrix_snapshots. CRUD viaruntime.insertSnapshot / getSnapshot / listSnapshots(optionalentityTypeon records;countSnapshots,extraFilter,skipon list). - Entity-type facet (2.2.2+) —
fetchMemorixMatrixEntityFacetcombines Memorixthings/ scoped views / scoped data / x-snapshots samples + tier statistics (entityTypesbuckets per surface, aligned with@x12i/xmemory-store) with matrix rows and matrix snapshots. Callers must passnamespace(partition key for tier analytics). docs/execution-matrix-runtime.md → “Entity-type facet”. - Source-aware listings —
listWaiting / listInProgress / listCompleted / listFailed / listSkippedplusfetchSourceJoinView(deps, q)which diffs the upstream source (viaMatrixSourceResolver) against materialized matrix rows. - Two-database split — operational data (
exellix-runtimeDB) and configuration (exellixDB) are both opened bycreateExellixMatrixDataTierfrom this package. The runtime never touches those DBs except throughExecutionMatrixRuntime+ExellixConfigStoreconstructed from the returned handles. - Configuration CRUD —
ExellixConfigStore.matrices.{create,get,update,delete,list,getEffectiveConfig}and.graphs.{...}with optimistic concurrency (expectedVersion) and re-validation on every write. Run loops can be dispatched bymatrixCatalogIdviarunMatrixOncePassByCatalogId/runMatrixContinuouslyByCatalogId, which re-resolve config at the start of every cycle so live edits propagate without restart. - No runner CRUD. Lifecycle stays on the host: start = call
runMatrixContinuously; stop =controller.abort().
Full reference and rationale: docs/execution-matrix-runtime.md → "Database split", "Data sources", "Execution mode and polling", "Eligibility", "Records eligibility", "Memorix operational tier", "Entity-type facet", "Snapshots", "Source-join view", "Run-mode loop and on-demand single pass", "Configuration CRUD".
