npm.io
1.37.0 • Published 6d agoCLI

@x12i/memorix-explorer-api

Licence
Version
1.37.0
Deps
17
Size
923 kB
Vulns
0
Weekly
0

@x12i/memorix-explorer-api

HTTP API for Memorix Explorer — a Fastify server that exposes read and write endpoints over MongoDB and Catalox descriptors.

This package is a thin HTTP layer on top of:

Package Role in this API
@x12i/memorix-retrieval All reads — inventory, lists, items, narratives, agents, health
@x12i/memorix-associator Associated snapshot property metadata and storage-to-client associated aliases
@x12i/memorix-descriptors List descriptor mutations; entity descriptor narratives catalog + root property catalog compute
@x12i/memorix-writer Record writes via write descriptors

The React UI lives in @x12i/memorix-explorer (sibling package). You can run this API standalone, embed it in another host, or serve the built Explorer UI from the same process.

Documentation

Guide Topic
docs/README.md Documentation index
Consuming Memorix data Read-only API — snapshots, records, lists, narratives, inventory, Skills cards
Advanced APIs Writes, enrichment, associations, metadata, pipeline registry

Architecture

Client (browser, curl, automation)
  ↓ HTTP /api/explorer/*
memorix-explorer-api (Fastify)
  ↓ getRetrievalStack()     → @x12i/memorix-retrieval + Catalox + Mongo (Xronox)
  ↓ getDescriptorAdmin()    → @x12i/memorix-descriptors (list writes, narratives catalog, rootPropertyCatalog compute)
  ↓ getWriterClient()       → @x12i/memorix-writer (POST /records/write)
MongoDB cluster (payload + metadata)
  memorix-entities / memorix-events / memorix-knowledge  — record payloads (Xronox)
  memorix-catalox — Catalox descriptor metadata (lists, object types, items)

Descriptor boundary: list descriptors and authored narrative catalog entries on entity descriptors are writable through this API (when MEMORIX_EXPLORER_ENABLE_METADATA_WRITES=true). Full Catalox catalog manage + execute lives in @x12i/memorix-catalox-api (:5180). GET /catalogs* on Explorer returns 410 Gone — use /api/catalox/catalogs instead.


Requirements

  • Node.js ≥ 20
  • MongoDB reachable via MONGO_URI (payload databases + memorix-catalox metadata database)
  • Catalox metadata stored in Mongo (MEMORIX_CATALOX_DB, default memorix-catalox) — same cluster as MONGO_URI
  • Optional: OpenRouter or Gemini API key for AI-assisted list suggestions

Quick start

From this package directory:

npm install

# Create .env with at least MONGO_URI (and optional MEMORIX_CATALOX_DB; see Environment below).
# In the monorepo you can copy from ../memorix-explorer/.env as a starting point.

# Apply Catalox seeds for entity/list/item descriptors (once per app/environment)
npm run catalox:seed:memorix-retrieval:apply

# Start the API server (default port 5181)
npm run dev

Verify:

curl -s http://127.0.0.1:5181/health                                     # open — no token
curl -s http://127.0.0.1:5181/api/explorer/health \
  -H "Authorization: Bearer $EXPLORER_API_TOKEN" | jq '.ok, .memorixDb'   # token needed if EXPLORER_API_TOKEN is set

API base URL (local): http://localhost:5181/api/explorer API base URL (deployed): https://explorer.neociso.com/api/explorer

All routes documented below are relative to that base unless noted. See Authentication for the bearer token.


Authentication

Two modes — Authix (browser + bearer sessions) and static M2M bearer — are mutually exclusive guards on /api/explorer/*.

When AUTHIX_API_URL and AUTHIX_API_KEY are set (or AUTHIX_AUTH_MODE=app / sso), Authix protects all /api/* routes except the public auth allowlist (/api/auth/login, /api/auth/sso/*, etc.). Browser users log in via POST /api/auth/login (password) or SSO; the session is an httpOnly cookie. Machine callers can send Authorization: Bearer <authix-token>.

EXPLORER_API_TOKEN is ignored when Authix is enabled — do not set both unless you intend Authix only.

Variable Description
AUTHIX_API_URL Authix service base URL (e.g. https://authix.x12i.com)
AUTHIX_API_KEY Service API key (x-authix-api-key)
AUTHIX_AUTH_MODE app (password login), sso, or disabled
AUTHIX_ADMIN_USERNAME / AUTHIX_ADMIN_PASSWORD Operator credentials for app mode
AUTHIX_APP_ID App id registered in Authix (default memorix-explorer)
Static M2M bearer (Authix disabled only)

When Authix is disabled (AUTHIX_AUTH_MODE=disabled and no AUTHIX_API_URL), you may set EXPLORER_API_TOKEN to require a static bearer on /api/explorer/* only:

curl -s https://explorer.neociso.com/api/explorer/inventory/summary \
  -H "Authorization: Bearer $EXPLORER_API_TOKEN"
  • Exempt (no token): GET /health, /api/auth/*, and OPTIONS preflight.
  • Missing/incorrect token → 401 { "error": "unauthorized" }.
  • Constant-time compared shared secret — not a JWT. Store in deployment secrets (not in this repo).
  • When EXPLORER_API_TOKEN is unset, /api/explorer/* is open.

Deployed note: explorer.neociso.com sets EXPLORER_API_TOKEN in server environment (outside this repo). If Authix is also configured there, redeploy with this fix so /api/auth/login is reachable again.


Running the server

Development
npm run dev          # tsx src/cli.ts serve — loads .env from cwd or ../memorix-explorer/.env
Production
npm run build
npm run serve        # node dist/cli.js serve
CLI (after build or via npx)
npx memorix-explorer-api serve
Programmatic embedding
import {
  createMemorixExplorerApp,
  startMemorixExplorerHttp,
  EXPLORER_API_PREFIX,
} from "@x12i/memorix-explorer-api";

// Start listening
const { url, close } = await startMemorixExplorerHttp({
  port: 5181,
  publicDir: "/path/to/built/explorer-ui", // optional — serves static SPA + fallback
});
console.log(`Listening on ${url}${EXPLORER_API_PREFIX}`);

// Or integrate into an existing Fastify/host setup
const { app } = await createMemorixExplorerApp({ logger: true });
await app.listen({ port: 5181, host: "0.0.0.0" });

When EXPLORER_PUBLIC_DIR (or publicDir option) points at a built Explorer UI (index.html present), non-API routes serve the SPA; API routes remain under /api/explorer.


Environment variables

Required
Variable Description
MONGO_URI MongoDB connection string for the cluster (alias: MONGO_CONNECTION_STRING)
Mongo target databases

Override only when your deployment uses non-default database names. See Memorix Database Conventions.

Variable Default Target
MEMORIX_ENTITIES_DB memorix-entities Entity records (target=entity)
MEMORIX_EVENTS_DB memorix-events Event records (target=event)
MEMORIX_KNOWLEDGE_DB memorix-knowledge Knowledge records (target=knowledge, optional)
MEMORIX_OPERATIONAL_DB memorix-operational Platform ops (*-failed, schema observation, pipeline-registry-parts)
MEMORIX_PIPELINE_REGISTRY_DB (falls back to operational) Optional override for remote pipeline plugin registry only
MEMORIX_CATALOX_DB memorix-catalox Catalox descriptor metadata (lists, object types, items)
Catalox
Variable Default Description
CATALOX_APP_ID memorix Catalox app id (alias: MEMORIX_APP_ID)

Catalox metadata uses the same MONGO_URI cluster; database name defaults to memorix-catalox.

Server
Variable Default Description
EXPLORER_API_PORT 5181 HTTP port (fallback: PORT)
EXPLORER_API_TOKEN (unset) Static M2M bearer on /api/explorer/* when Authix is disabled only. See Authentication
EXPLORER_PUBLIC_DIR ./public if present Path to built Explorer static files
Optional — AI list suggestions
Variable Description
OPENROUTER_API_KEY Enables richer confidence on GET /lists/suggest?mode=ai
GEMINI_API_KEY Alternative AI provider for the same route
Smoke / test helpers
Variable Default Description
SMOKE_BASE http://127.0.0.1:5181/api/explorer Base URL for smoke scripts
SMOKE_STRICT_INVENTORY off Fail inventory smoke if no rows
SMOKE_STRICT_ENTITIES off Fail entity smoke if graph/records empty

HTTP conventions

Base path and methods
  • Explorer API routes: /api/explorer + path (e.g. /api/explorer/health).
  • Process liveness: GET /health{ "ok": true } (does not check Mongo/Catalox).
  • Supported methods on /api/explorer/*: GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS.
  • OPTIONS returns 204 with no body.
  • Responses include Cache-Control: no-store.
  • Request body limit: 1 MB (JSON bodies for POST/PATCH/PUT).
Content type

Send JSON bodies with Content-Type: application/json. Responses are JSON unless serving static UI.

Errors
Status Meaning
400 Missing/invalid query params or JSON body
401 Missing/incorrect bearer token (when EXPLORER_API_TOKEN is set) — body { "error": "unauthorized" }
404 Unknown route or missing list/narrative
422 Write validation failed (POST /records/write)
500 Unexpected server error — body { "error": "..." }
Pagination

Shared query parameters for list-style endpoints:

Param Alias Default Description
limit 50 Page size (clamped 1–500)
offset skip 0 Rows to skip
includeTotal false Include total count in page.total when supported
Param Alias Description
searchText q Full-text search when supported by the underlying list
Sorting

Repeated sort params (preferred for compound sort):

GET /records/collection?entityName=assets&sort=severity:desc&sort=entityId:asc

Legacy single sort:

Param Alias
sortProperty sortPath
sortDirection asc or desc
Filtering

Repeat filter as property:operator:value:

GET /records/collection?entityName=assets&filter=severity:gte:7&filter=status:eq:open
Operator Value notes
eq, ne, gt, gte, lt, lte Scalar comparison
in, nin Comma-separated list
exists true/false (default true if value omitted)
regex String pattern
Targets

Many routes accept target: entity, event, or knowledge. Omit or use all where documented to include all configured targets.


API reference

Health
GET /health

Memorix-aware health check — Mongo bindings, Catalox discovery, warnings, and optional inventory summary.

Query Description
includeInventory 1 / true — attach inventory summary counts

Example:

curl -s "$BASE/health?includeInventory=1"

Response highlights:

{
  "ok": true,
  "generatedAt": "2026-07-01T12:00:00.000Z",
  "mongoUriConfigured": true,
  "memorixDb": "memorix-entities + memorix-events",
  "discoverySample": ["assets", "vulnerabilities"],
  "sourceAware": { "...": "full retrieval health object" },
  "retrieval": {
    "appId": "memorix",
    "entitiesCatalogId": "memorix-object-type-descriptors",
    "discoverySource": "catalox",
    "catalogFallback": false
  },
  "inventorySummary": {
    "orphans": 0,
    "declaredEmpty": 1,
    "matchedPopulated": 12,
    "missingCollections": 0
  },
  "warnings": [],
  "errors": []
}

Use this endpoint before debugging empty lists or inventory issues.


Inventory

Unified inventory and entity graph for Explorer navigation.

GET /inventory/collections · GET /inventory/summary

Same handler — returns MemorixUnifiedInventory rows, issues, and per-target summaries.

Query Description
sourceLens catalox-first (descriptor-first) or db-first (Mongo-first). Default: db-first
target entity, event, knowledge, or all
includeExactCounts 1 / true — run exact countDocuments (slower)
includeIgnored Include collections marked ignored in inventory policy

Example:

curl -s "$BASE/inventory/collections?sourceLens=db-first&includeExactCounts=1"

Each row includes provenance (source, sources), suggested UI actions (actions), and navigation hints (navigation.primaryNarrative when mapped).

GET /inventory/issues

Subset of unified inventory — { issues, summary } only.

GET /inventory/graph

Entity relationship graph for the Entities view.

Query Default Description
includeOrphans true Include orphan Mongo collections in orphanEntities

Example:

curl -s "$BASE/inventory/graph"

Returns entities, orphanEntities, memorixDb, discovery, and catalogRelations.


Records (read)
GET /records/collection

Entity collection — descriptor-backed rows, raw Mongo, or auto-detected mode.

Query Required Description
entityName Yes Object type name (e.g. assets)
target No entity / event / knowledge
listId No List descriptor id (alias: listDescriptorId)
contentType No Restrict to one content type
collectionName No Explicit collection override
mode No descriptor | raw | auto (default auto)
+ pagination, sort, filter, search See HTTP conventions

Example:

curl -s "$BASE/records/collection?entityName=assets&mode=auto&limit=10&includeTotal=1"
GET /records/raw-collection

Read Mongo documents directly without list descriptor projection.

Query Required
target Yes
collectionName Yes
+ pagination, sort, search
GET /records/full

Full record across content types (multi-collection compose).

Query Required
entityName Yes
One of recordId, entityId, eventId, knowledgeId Yes — prefer recordId when the object type uses it
contentTypes No — comma-separated; default all declared types
GET /records/item

Item descriptor view — sections and fields for a single record.

Query Required
entityName Yes
One of recordId, entityId, eventId, knowledgeId Yes — prefer recordId when the object type uses it
itemDescriptorId No — default item for entity
Skills cards (analysis / decisions) — two generic calls

List ids are Catalox metadata, not routes baked into this API. Discover them, then page + open:

# 0) Discover lists for the entity (ids come from Catalox)
curl -sS "$BASE/lists?entityName=assets" | jq '.[] | {id, title, leadingContentType}'

# 1) Page of cards — use the list id returned above
curl -sS "$BASE/lists/$LIST_ID/records?limit=50&includeTotal=1"

# 2) Open card / Explain Decision
curl -sS "$BASE/records/item?entityName=assets&recordId=$ID"
Platform (stable) Instance (Catalox lists catalog)
GET /lists?entityName= Which lists exist, their id / title / leadingContentType
GET /lists/{listId}/records Card fields authored on that list descriptor
GET /records/item Item sections/fields from memorix-item-descriptors

Pick Skills lists by leadingContentType of decisions or analysis (and UI title). Do not hardcode list ids in client code unless you intentionally pin to a known Catalox item for one deployment.

Notes for clients

  • Nested decision blobs (e.g. assets data.exploitability → OT decisionExploitability) are usually item fields, not list fields — use /records/item (or /records/full?...&contentTypes=decisions).
  • Prefer /records/item for Skills open; use /records/full only when you need raw multi-CT documents.
  • A given deployment may seed example list ids (e.g. neo); treat those as catalog data. Field maps for the neo instance: .operational/web-client-intergration/02-skills-card-lists.md.

See also docs/consuming-memorix-data.md.

Ad-hoc Assets Exploitability (no Catalox list / item ids)

Same use case without passing Catalox descriptor ids from client code:

# 1) Page decisions
curl -sS "$BASE/records/collection?entityName=assets&contentType=decisions&limit=50&includeTotal=1"

# 2) Open — exploitability = data.exploitability (default item; or use /records/full)
curl -sS "$BASE/records/item?entityName=assets&recordId=$ID"
# curl -sS "$BASE/records/full?entityName=assets&recordId=$ID&contentTypes=snapshots,decisions"

Full field map and paths: docs/consuming-memorix-data.md § Ad-hoc Assets Exploitability.

GET /records/content

Fetch content for a specific item field (e.g. markdown body, external pointer).

Query Required
entityName Yes
fieldPath Yes (alias: contentKey)
One of entityId, eventId, knowledgeId Yes
itemDescriptorId No
GET /records/raw-item

Single Mongo document by id from a named collection.

Query Required
target Yes
collectionName Yes
recordId Yes
idField No — override identity field
GET /records/workspace

Cross-entity workspace list (pinned / multi-entity views).

Query Description
workspaceListId Workspace list descriptor id
entityName Filter to one entity
+ pagination, sort, search

Snapshots And Associated Data

Normalized snapshot reads expose the client consumption contract from the operational guide. These routes keep storage-compatible names available while presenting associatedInferred as client-facing discovery.

GET /snapshots/{objectType}/{recordId}

Returns a normalized snapshot view:

{
  "objectType": "assets",
  "contentType": "snapshots",
  "recordId": "asset-1",
  "concept": { "...": "..." },
  "data": { "...": "native snapshot data" },
  "analytics": { "...": "optional rollups" },
  "enrichment": { "...": "optional sourced values" },
  "insights": { "...": "optional judgments" },
  "system": { "...": "from _system" },
  "associated": {
    "data": [{ "...": "associatedData[]" }],
    "discovery": [{ "...": "associatedInferred[]" }],
    "analysis": [{ "...": "associatedAnalysis[]" }],
    "custom": {
      "associatedAssets": [{ "...": "custom associated copy" }]
    },
    "properties": []
  },
  "storage": {
    "associatedAliases": {
      "associated.data": "associatedData",
      "associated.discovery": "associatedInferred",
      "associated.analysis": "associatedAnalysis"
    }
  }
}
Query Description
include Comma-separated buckets: data, analytics, enrichment, insights, system, associated
idField Override lookup field. Defaults to recordId
GET /snapshots/{objectType}/{recordId}/associated

Returns only the normalized associated view plus associated-property metadata.

GET /snapshots/{objectType}/{recordId}/associated/{propertyName}

Returns one associated property. propertyName may be a storage name or client alias:

Client/API name Storage property
data associatedData
discovery associatedInferred
inferred associatedInferred
analysis associatedAnalysis
associatedAssets or any associated* same storage property
GET /snapshots/{objectType}/associated-properties

Returns managed plus discovered associated-property metadata for snapshot records. Discovery samples the snapshot collection and treats any root-level associated* property as a valid associated property.

Query Description
limit / offset Sample page for discovery
includeTotal Include total count from the raw collection read

Important semantics:

  • Associated arrays are copied read models from linked record data.
  • Legacy properties (associatedData, associatedDiscovery, …) may include inline recordId / contentType.
  • v2 properties (associated<ObjectType><ContentType>) use flat copied data; optional traceability lives in item-level _system.association when enabled. See memorix-pipeline/docs/association-format.md.
  • Refresh resolves snapshot → snapshot first, then fetches non-snapshot content by matched snapshot recordId when applicable.
  • Refresh is one-way: linked content data → source snapshot associated*[].
  • Associated arrays do not include linked record _system, analytics, enrichment, or insights; query the linked collection directly when those buckets are needed.
  • Item-level _system inside associated arrays is stripped from the default snapshot API view; pass include=system to retain it.
  • Root buckets that do not start with associated are still consumable (analytics, enrichment, insights, _system) and can be resolver inputs when configured.
Association refresh (operations)
Method Route Description
POST /associations/plan Dry-run association plan with fingerprint
POST /associations/apply Apply plan (requires expectedPlanFingerprint when configured)
POST /associations/verify Verify associated array shapes on source collection

Lists (read)
GET /lists?entityName={name}

Discover list descriptors registered for an entity.

Response:

{
  "entityName": "assets",
  "lists": [
    {
      "id": "assets-default",
      "title": "Assets",
      "entity": "assets",
      "leadingContentType": "snapshots",
      "fieldCount": 8
    }
  ]
}
GET /lists/{listId}

Full list descriptor document from Catalox.

GET /lists/{listId}/records

Execute the list — same pagination, sort, filter, and search conventions as /records/collection.

GET /lists/suggest?entityName={name}

Suggest extensions and analytics fields for list authoring.

Query Description
entityName Required
listId Optional — exclude already-configured extensions/analytics
mode automation (default) or ai (requires API key)

Response shape:

{
  "entityName": "assets",
  "listId": null,
  "mode": "automation",
  "extensions": [
    {
      "kind": "extension",
      "contentType": "analysis",
      "mode": "extendFields",
      "confidence": "high",
      "reason": "Content type \"analysis\" is declared on entity but not joined in this list"
    }
  ],
  "analytics": [
    {
      "kind": "analytics",
      "field": "countAnalysis",
      "collection": "assets-analysis",
      "joinBy": "entityId",
      "metric": { "op": "count" },
      "confidence": "medium",
      "reason": "Count documents in analysis per record"
    }
  ]
}

Lists (write)

All list mutations go through @x12i/memorix-descriptors executeDescriptorMutation. Bodies must match MemorixListDescriptor validation.

Method Path Operation
POST /lists Create list descriptor → 201
PATCH /lists/{listId} Update list descriptor
DELETE /lists/{listId} Remove list descriptor
POST /lists/{listId}/extensions Add extension join
DELETE /lists/{listId}/extensions/{contentType} Remove extension
POST /lists/{listId}/analytics Add analytics field
DELETE /lists/{listId}/analytics/{field} Remove analytics field
PUT /lists/{listId}/sort Set compound default sort

Create list (POST /lists): pass a full list descriptor object (must include id, entity, leadingContentType, fields, etc.). See seed examples under memorix-descriptors/catalox-seeds/inputs/list-descriptors/.

Set sort (PUT /lists/{listId}/sort):

{
  "sort": [
    { "property": "severity", "direction": "desc" },
    { "property": "entityId", "direction": "asc" }
  ]
}

Mutation failures return 400 with { "error": "...", "result": { ... } }.


Record writes
POST /records/write

Write Memorix payload documents via a Catalox write descriptor.

Single record:

{
  "writeDescriptorId": "asset-analysis-write",
  "entityId": "10.150.68.31",
  "operation": "upsert",
  "input": { "riskLevel": "HIGH", "summary": "..." },
  "metadata": { "source": { "uri": "file://scan.json" } },
  "dryRun": false,
  "validateOnly": false
}

Batch:

{
  "writeDescriptorId": "asset-analysis-write",
  "operation": "upsert",
  "records": [
    { "entityId": "a", "input": { "...": "..." } },
    { "entityId": "b", "input": { "...": "..." } }
  ],
  "continueOnError": true,
  "dryRun": false
}
Field Description
writeDescriptorId Required — Catalox write descriptor id
operation add, upsert, patch, or replace
entityId / eventId / knowledgeId Exactly one identity for single writes
input Payload object (single write)
records Array of record inputs (batch)
dryRun Plan without writing
validateOnly Validate input only
continueOnError Batch — continue after per-record failure

Returns 200 on success, 422 when validation/write fails. See @x12i/memorix-writer for descriptor shapes and content uploads.


Narratives

The authored catalog lives on entity descriptors at descriptor.narratives (validated MemorixNarrativeDefinition entries). Per-record tags live at doc.narratives.{key} (written by pipeline narrative-sync or Explorer assignment).

Merged list/detail endpoints combine authored catalog + platform-generated signals + optional live Mongo counts. Use the raw endpoint when you need only the stored descriptor map (e.g. Exellix catalog consumption).

GET /narratives

Global narrative catalog (merged).

Query Description
entity Filter to one entity
target Filter by target
agentId Filter by agent scope
includeLiveCounts Attach live record counts
GET /narratives/{entity}

Narratives for one entity (merged).

GET /narratives/{entity}/raw

Authored descriptor map only — Record<slug, MemorixNarrativeDefinition> as stored on the entity descriptor (no signal discovery merge).

GET /narratives/{entity}/{key}

Single narrative (merged enriched summary).

POST /narratives

Create an authored narrative entry on a descriptor. Requires metadata writes.

Catalog shape (kind required):

{
  "entity": "assets",
  "key": "has-vulnerabilities",
  "label": "Has vulnerabilities",
  "kind": "having-signal",
  "sourceRef": "assetVulnerabilities",
  "targetEntity": "vulnerabilities"
}

Implementation shape (legacy condition-based narratives): label, detectionMethod, condition.

PATCH /narratives/{entity}/{key}

Update an authored entry. Platform-generated keys return 409.

DELETE /narratives/{entity}/{key}

Remove from descriptor. Optional ?removeTags=1 clears record tags.

GET /narratives/{entity}/{key}/records

Paginated records tagged with the narrative.

curl -s "$BASE/narratives/assets/high-risk/records?limit=20&includeTotal=1"
Filter any list by narrativeId

Narrative tags sit on snapshots (doc.narratives.{key}), but the same key filters lists and other content types via the virtual filter property narrativeId (alias narrativeKey):

# Default list / snapshots
curl -s "$BASE/lists/vulnerabilities-main-list/records?filter=narrativeId:eq:is-vulnerability"

# Analysis (or discovery/decisions) linked to tagged snapshots
curl -s "$BASE/records/collection?entityName=vulnerabilities&contentType=analysis&filter=narrativeId:eq:is-vulnerability&mode=raw"

# User-facing filter dropdown options
curl -s "$BASE/narratives/vulnerabilities/filter-options"

# Execute a dashboard listQuery object
curl -s -X POST "$BASE/records/query" -H 'Content-Type: application/json' \
  -d '{"entityName":"vulnerabilities","listDescriptorId":"vulnerabilities-main-list","filters":[{"property":"narrativeId","operator":"eq","value":"is-vulnerability"}]}'

eq / in = has tag; ne / nin = missing tag. See Consuming Memorix data — Narrative filter.


Object types & root property catalog

Read-only object-type summaries from Catalox descriptors, plus computed root-envelope property stats.

GET /object-types

All object-type summaries (properties, declarative rootProperties, authored narratives, rootPropertyCatalog when present).

GET /object-types/{name}

Single object-type summary.

GET /object-types/{name}/root-property-catalog

Computed rootPropertyCatalog array. Optional ?contentType=snapshots filters to one content type.

POST /object-types/{name}/root-property-catalog/compute

Full-scan Mongo collections and persist rootPropertyCatalog on the descriptor. Requires metadata writes.

{ "ttlMs": 86400000, "contentTypes": ["snapshots"], "force": false }

Response includes skipped / reason: "fresh" when TTL not expired and force is false.


Agents
GET /agents

Returns the agent registry from inventory policy (array of agent objects). Used by Explorer for agent-scoped narrative filtering.

curl -s "$BASE/agents"

Route summary

Method Path Description
GET /health Memorix + Mongo + Catalox health
GET /inventory/collections, /inventory/summary Unified inventory
GET /inventory/issues Inventory issues only
GET /inventory/graph Entity graph
GET /records/collection Entity collection (descriptor/raw/auto)
GET /records/raw-collection Raw Mongo collection page
GET /records/full Multi-content-type full record
GET /records/item Item descriptor view
GET /records/content Single field content
GET /records/raw-item Raw Mongo document by id
GET /records/workspace Workspace list
GET /snapshots/{objectType}/{recordId} Normalized snapshot view
GET /snapshots/{objectType}/{recordId}/associated Normalized associated arrays
GET /snapshots/{objectType}/{recordId}/associated/{propertyName} One associated property by alias or storage name
GET /snapshots/{objectType}/associated-properties Managed/discovered associated-property metadata
POST /records/write Write record(s)
GET /lists?entityName= List discovery
GET /lists/suggest?entityName= Extension/analytics suggestions
GET /lists/{listId} List descriptor
GET /lists/{listId}/records List rows
POST /lists Create list
PATCH /lists/{listId} Update list
DELETE /lists/{listId} Delete list
POST /lists/{listId}/extensions Add extension
DELETE /lists/{listId}/extensions/{contentType} Remove extension
POST /lists/{listId}/analytics Add analytics
DELETE /lists/{listId}/analytics/{field} Remove analytics
PUT /lists/{listId}/sort Set default sort
GET /object-types Object-type descriptor summaries
GET /object-types/{name} One object-type summary
GET /object-types/{name}/root-property-catalog Computed root envelope property catalog
POST /object-types/{name}/root-property-catalog/compute Recompute and persist root property catalog
GET /narratives Narrative catalog (merged)
GET /narratives/{entity} Entity narratives (merged)
GET /narratives/{entity}/raw Authored narratives map from descriptor
GET /narratives/{entity}/{key} One narrative
POST /narratives Create authored narrative
PATCH /narratives/{entity}/{key} Update authored narrative
DELETE /narratives/{entity}/{key} Delete authored narrative
GET /narratives/{entity}/{key}/records Tagged records
GET /agents Agent registry

Also: GET /health at server root (process liveness only).


Commands

Script Purpose
npm run dev Start API server (port 5181) with tsx
npm run build Compile TypeScript to dist/
npm run serve Production server (node dist/cli.js serve)
npm test Live API smoke tests (server must be running)
npm run test:live Same as npm test — runs all smoke scripts
npm run smoke:api Core health + inventory + narratives smoke
npm run smoke:inventory Inventory lenses + raw/descriptor record drill
npm run smoke:records Workspace + item fetch
npm run smoke:snapshots Normalized snapshot + associated data reads
npm run smoke:narratives Narrative catalog + records
npm run smoke:entities Graph → collection navigation spine
npm run mongo:inventory CLI inventory report (no HTTP server)
npm run catalox:seed:memorix-retrieval:apply Apply Catalox retrieval seeds
npm run catalox:seed:memorix-retrieval:validate Validate seeds without applying

Live test workflow:

# Terminal 1
npm run dev

# Terminal 2
npm test

Catalox seeds

Before first use in a new environment, apply retrieval seeds so entity/list/item descriptors exist:

npm run catalox:seed:memorix-retrieval:apply

Requires MONGO_URI and CATALOX_APP_ID (default memorix). Validates with:

npm run catalox:seed:memorix-retrieval:validate

Migration: lists catalog rename

If upgrading from a deployment that used the legacy lists catalog id, run once per Catalox app:

cd ../memorix-descriptors
CATALOX_APP_ID=memorix node scripts/migrate-list-descriptors-catalog.mjs [--dry-run]

Document Topic
docs/consuming-memorix-data.md Read-only consumption guide
docs/advanced-apis.md Writes, pipeline, associations, metadata
memorix-pipeline docs Enrichment CLI and association format
memorix-retrieval README Underlying read APIs, graph runs, inventory lenses
memorix-descriptors README List descriptor shapes and mutations
memorix-writer README Write descriptors and record operations
memorix-explorer integration How the UI consumes these routes
MEMORIX-CATALOX-CONTRACTS Catalog ids and descriptor JSON formats
MEMORIX-DATABASE-CONVENTIONS Mongo layout and env resolution

Package exports

import {
  createMemorixExplorerApp,
  startMemorixExplorerHttp,
  EXPLORER_API_PREFIX,
} from "@x12i/memorix-explorer-api";

Use these to embed the Explorer API in another Node host or serve the UI from the same process. For custom gateways, proxy HTTP to /api/explorer/* rather than importing internal handlers.