@x12i/memorix-client
Canonical typed HTTP client for Memorix. This is the only implementation of scope headers, errors, Explore, raw Memory, Source checkpoints, schedules, connection probe, and pipeline run control.
New product code should prefer @x12i/memorix-sdk (re-exports this client and adds worker / authoring / testing). Existing @x12i/memorix-client installs remain compatible.
Wire contract = memorix-service OpenAPI.
Install
npm install @x12i/memorix-client@^3.7.0
# preferred for new apps:
npm install @x12i/memorix-sdk@^1.3.0
Requires a running @x12i/memorix-service@^3.7.6 for metadata ensure, MCO, integrations, restricted store, continuous acquisition, incremental-state, and POST /mcp/nexum.
Env resolution for acquisition stores: set MEMORIX_SERVICE_URL or MEMORIX_URL (optional token via MEMORIX_SERVICE_TOKEN / MEMORIX_TOKEN). Memory / noop modes (NEO_*_MODE=memory|off) are for tests and soft-skip only — not production acceptance.
Surfaces
| Area | Methods |
|---|---|
| Explore | getContent, getContext (GET /api/data/content/context; pair with @x12i/memorix-service@3.12.5), listContent, queryContent, countContent (count=true from a live property index), getAbstract, runList (declared listId or abstract properties), compose, composeData / composeDataList (concrete CT .data), writeContent, removeContent, queryRelationships |
| Analytics | analytics.indexes.list, get, validate, register, remove — agent-declared stored paths. Pair with @x12i/memorix-service OpenAPI ≥ 3.11.1 |
| Metadata | ensureMetadata({ pack }) — call once at process start before the first write; throws unless ready |
| Publications | createDraft, list, lastGood, get, commit, getInstances |
| Memory | getRaw, getConnection, commitPage, pull, listRuns |
| Schedules | get, put, pause, resume, runNow, remove (Memory pull intervals) |
| Checkpoints | list, get, put (+ expectedRevision), reset |
| Pipelines | list, get, start, getRun, wait, cancel, retry, resume, listArtifacts, getArtifact |
| Connector ops (MCO) | createConnectorOpClient / resolveConnectorOpClient — overrides + attempt stats (soft-skip when URL unset) |
| Stream checkpoints (INC-01) | createStreamCheckpointClient / resolveStreamCheckpointClient — watermark/revision/hash/cursor |
| Continuous acquisition | createContinuousAcquisitionClient / resolveContinuousAcquisitionClient — schedule/lease/freshness/tick |
| Incremental state | createIncrementalStateClient / resolveIncrementalStateClient — CAS + apply-commit |
| Integration registry | createIntegrationRegistryClient / resolveIntegrationRegistryClient — Stage −1 instances + snapshot token |
| Restricted store | createRestrictedStoreClient / resolveRestrictedStoreClient — FG-A3 put metadata / break-glass content |
| Acquisition stores | resolveStreamCheckpointStore, resolveOpStateStore / createOpStateStore, resolveInstanceRegistry — durable host façades (memory/noop = non-production) |
| MCP (agents) | buildAgentMcpBundle, cursorMcpSnippet / claudeMcpSnippet, createNexumMcpClient — see MCP |
Does not include Mongo, memorix-data, the pipeline engine, a worker server, or the Work APIs Playground UI (private monorepo tool on :5113).
memory.pull is operator-only. Clients built with fromInvokeContext (callback grant) cannot call it — use Explore / checkpoints / raw / commitPage.
Request timeout: when a call does not pass signal, the client aborts after requestTimeoutMs (default 30_000). Timeout errors are MemorixClientError with code REQUEST_TIMEOUT and name the operation (and recordId when applicable). Pass your own signal, or set requestTimeoutMs: 0, to opt out.
Product → Memorix
import { createMemorixClient } from "@x12i/memorix-client";
const mx = createMemorixClient({
baseUrl: "http://127.0.0.1:5100",
orgId: "sandbox1",
agentIds: ["opx"],
caller: "my-app",
// optional: default 30_000; set 0 to disable. Per-call `signal` skips this.
// requestTimeoutMs: 60_000,
});
await mx.ensureMetadata({ pack: myAgentPack }); // once per process start
await mx.explore.writeContent({
objectType: "people",
contentType: "raw",
precondition: "absent",
record: {
recordId: "E-10",
data: { displayName: "Ada" },
concept: {
title: "Ada",
identifiers: { primary: { kind: "recordId", value: "E-10", issuer: "my-app" } },
},
},
});
const person = await mx.explore.getContent({
objectType: "people",
contentType: "raw",
recordId: "E-10",
});
// person is the whole record: record.data is the subject, record.context is the context payload.
const publication = await mx.explore.getContent({
objectType: "security-map",
contentType: "estate-analytics",
recordId: "working/estate-analytics",
discriminatorValue: "publication",
});
// discriminatorValue addresses one instance. The client sends it as a query parameter.
const security = await mx.explore.getContext({
objectType: "endpoint-asset",
contentType: "security-context",
recordId: "object:forti-observed-1",
});
// security is the context object itself (for example { exploitability }).
// agent-context, pre-ai-context, and live-context come back as { agent }, { preAi }, or { live }.
const openPeople = await mx.explore.queryContent({
objectType: "people",
contentType: "raw",
filter: { "data.status": "open" }, // or SafeFilter[]: [{ field, op: "eq", value }]
limit: 50,
});
// openPeople.records + openPeople.pageInfo.nextCursor
const run = await mx.pipelines.start("knowx-associate", {
recordId: "PB-2",
});
const completed = await mx.pipelines.wait(run.runId);
const conn = await mx.memory.getConnection("opx-source");
// Connected | Unreachable | Missing URL
Called service → Memorix
When a pack service declares memorixAccess, Memorix posts a versioned CapabilityInvocation envelope including memorix callback context (+ server-issued grant):
import { fromInvokeContext } from "@x12i/memorix-client";
const mx = fromInvokeContext(request.memorix);
const existing = await mx.explore.listContent({
objectType: "people",
contentType: "snapshots",
});
await mx.checkpoints.list("opx-source");
Access is enforced client-side (method gating) and server-side (HMAC grant). Mutating access[] cannot escalate privileges.
Allowed surfaces: "explore" | "checkpoints" | "raw".
Checkpoint commit
- Model A (preferred): Memory-controlled paging — worker returns
{ page, nextCheckpoint }; Memory lands and commits. - Model B:
mx.memory.commitPage({ …, expectedCheckpointRevision })— land exact raw items then advance checkpoint atomically. Standalonecheckpoints.putis administrative and is not proof of landing.
Scope headers
Every request sends:
x-memorix-org-idx-memorix-agent-idsx-memorix-caller(MX-CALLER-01)x-memorix-invocation-grant(when present fromfromInvokeContext)
MCP (agents)
Product land/read/pipelines stay on createMemorixClient HTTP. Agents also get two MCP servers: MGC (:7480/mcp) and memorix-nexum (:5100/mcp/nexum). See docs/mcp-expert-brief.md in the monorepo.
import {
buildAgentMcpBundle,
createMgcMcpClient,
createNexumMcpClient,
} from "@x12i/memorix-client";
// or: import { … } from "@x12i/memorix-client/mcp";
const bundle = buildAgentMcpBundle({
memorixServiceUrl: process.env.MEMORIX_SERVICE_URL!,
mgcSourceServiceUrl: process.env.MGC_SOURCE_SERVICE_URL,
scope: { orgId: "tgi", agentIds: ["opx"] },
});
// paste bundle.nexum.cursorJson / bundle.mgc.cursorJson into Cursor mcp.json
const mcp = createNexumMcpClient({
baseUrl: process.env.MEMORIX_SERVICE_URL!,
orgId: "tgi",
agentIds: ["opx"],
caller: "my-agent-host",
});
await mcp.listTools();
const snapshots = await mcp.listSnapshots({ knowledgeGraphOnly: true });
await mcp.callTool("nexum_get_snapshot", { recordId: "snap-1" });
const mgc = createMgcMcpClient({
baseUrl: process.env.MGC_SOURCE_SERVICE_URL!,
orgId: "tgi",
agentIds: ["opx"],
caller: "my-agent-host",
});
await mgc.listConnectors();
Canvas HTTP (same dual store as MCP canvas tools): mx.knowledge.*.