# @x12i/memorix-writer

> Descriptor-driven write layer for Memorix entity/event records and content objects

Latest version **1.36.0** (published 2026-07-21) · 0 weekly downloads

## Install

```sh
npm install @x12i/memorix-writer
pnpm add @x12i/memorix-writer
yarn add @x12i/memorix-writer
bun add @x12i/memorix-writer
```

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 1.36.0 |
| Published | 2026-07-21 |
| First published | 2026-05-26 |
| Weekly downloads | 0 |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=18.0.0 |
| Dependencies | 8 |
| Unpacked size | 483 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Maintainers | x12i |

## Links

- npm: https://www.npmjs.com/package/@x12i/memorix-writer
- Repository: https://github.com/x12i/memorix-mono-repo
- Homepage: https://github.com/x12i/memorix-mono-repo#readme
- Issues: https://github.com/x12i/memorix-mono-repo/issues
- npm.io page: https://npm.io/package/@x12i/memorix-writer

## Dependencies (8)

- [mongodb](https://npm.io/package/mongodb.md) ^6.21.0
- [@x12i/catalox](https://npm.io/package/@x12i/catalox.md) ^5.10.1
- [@x12i/memorix-mongo](https://npm.io/package/@x12i/memorix-mongo.md) ^1.32.0
- [@x12i/memorix-format](https://npm.io/package/@x12i/memorix-format.md) ^2.2.1
- [@x12i/memorix-pipeline](https://npm.io/package/@x12i/memorix-pipeline.md) ^1.35.0
- [@x12i/memorix-db-router](https://npm.io/package/@x12i/memorix-db-router.md) ^1.0.0
- [@x12i/memorix-retrieval](https://npm.io/package/@x12i/memorix-retrieval.md) ^1.33.0
- [@x12i/memorix-descriptors](https://npm.io/package/@x12i/memorix-descriptors.md) ^1.38.0

## Recent versions

- 1.36.0 (latest) — 2026-07-21
- 1.34.0 — 2026-07-19
- 1.33.0 — 2026-07-11
- 1.32.0 — 2026-07-11
- 1.11.0 — 2026-07-05
- 1.10.0 — 2026-07-02
- 1.9.1 — 2026-07-01
- 1.9.0 — 2026-07-01
- 1.8.1 — 2026-07-01
- 1.8.0 — 2026-07-01
- 1.7.0 — 2026-06-27
- 1.6.0 — 2026-06-26
- 1.5.0 — 2026-06-26
- 1.4.0 — 2026-06-24
- 1.3.1 — 2026-06-24
- … 4 more at https://npm.io/package/@x12i/memorix-writer/versions

## README

# @x12i/memorix-writer

Descriptor-driven write layer for Memorix. Turns Catalox write descriptors, entity descriptors, validated input, and optional Markdown/text content into Memorix records and external content object pointers.

Shared MongoDB naming rules: [docs/MEMORIX-DATABASE-CONVENTIONS.md](./docs/MEMORIX-DATABASE-CONVENTIONS.md).

## Architecture

- **Catalox** — `memorix-write-descriptors`, `memorix-object-type-descriptors`. Catalog metadata lives in **MongoDB** (`memorix-catalox` via `@x12i/catalox/mongo`). Firestore is not used for Memorix Catalox.
- **MongoDB** — built-in `MemorixDataTier` + collection-name CRUD (no separate `@x12i/memorix` package)
- **@x12i/memorix-descriptors** — shared catalog ids and descriptor validation (aligned with retrieval)
- **@x12i/helpers** — GCS/S3 content uploads (`contentWriters.gcs` / `contentWriters.s3`)
- **@x12i/memorix-retrieval** (optional) — `returnMode: "retrievalItem"`

## Quick start

Set `MONGO_URI` and provide a Catalox client. Database names, entity vs event routing, and collection resolution are handled internally.

```bash
MONGO_URI=mongodb://localhost:27017
```

```typescript
import {
  createMemorixWriterFromEnv,
  writeMemorixRecord,
} from "@x12i/memorix-writer";

const writer = await createMemorixWriterFromEnv({
  catalox: boundCatalox, // must implement getCatalogItem(appId, catalogId, itemId)
  contentWriters: {
    gcs: myGcsUploader, // uploadObject({ key, body, contentType })
  },
});

const result = await writeMemorixRecord(writer, {
  writeDescriptorId: "asset-analysis-write",
  entityId: "10.150.68.31",
  input: { riskLevel: "HIGH", summary: "..." },
  metadata: { source: { uri: "file://scan.json" } },
  tags: ["risk", "source-scan"],
  narratives: {
    "high-risk": { detectedBy: "risk-worker" },
  },
  content: {
    fields: {
      investigationReport: { body: "# Report\n...", format: "markdown" },
    },
  },
});

await writer.close?.();
```

Lazy connect (same env, no upfront `await`):

```typescript
import { createMemorixWriter, writeMemorixRecord } from "@x12i/memorix-writer";

const writer = createMemorixWriter({ catalox: boundCatalox });
// connects to Mongo on first write using MONGO_URI
```

## Advanced (optional)

Override defaults only when you need to:

| Option | Purpose |
|--------|---------|
| `MEMORIX_ENTITIES_DB` / `MEMORIX_EVENTS_DB` | Non-default database names |
| `MEMORIX_ENTITIES_COLLECTION_*` / `MEMORIX_EVENTS_COLLECTION_*` | Per-type collection overrides |
| `memorix` | Inject a pre-configured `MemorixDataTier` instead of built-in Mongo connect |
| `mongo` | Reuse an existing `MongoClient` |
| `processEnv` | Custom env object (default: `process.env`) |

## Collection resolution

Writes target **`memorix-entities`**, **`memorix-events`**, or **`memorix-knowledge`** based on the write descriptor (`target.kind`, defaulting from the descriptor's `identity.idField` config). Database names follow [Memorix Database Conventions](./docs/MEMORIX-DATABASE-CONVENTIONS.md) (`MEMORIX_ENTITIES_DB`, `MEMORIX_EVENTS_DB`, `MEMORIX_KNOWLEDGE_DB`, …).

## Identity model

Every record this package writes uses the `memorix-record.2.0` envelope — a nested `identity` object, not flat top-level id fields:

```json
{
  "identity": {
    "recordId": "rec_...",
    "target": "entity",
    "targetId": "10.150.68.31",
    "objectType": "assets",
    "contentType": "analysis",
    "version": "memorix-record.2.0"
  },
  "lifecycle": { "createdAt": "...", "modifiedAt": "...", "status": "active" },
  "concept": { "kind": "assets", "name": "10.150.68.31" },
  "data": { "...": "..." }
}
```

`entityId` / `eventId` / `knowledgeId` are **request-time parameter names** on `writeMemorixRecord` — pass exactly one to say which target and which id value you're writing:

| Target | Request field | Written to |
|--------|----------------|------------|
| `entity` | `entityId` | `identity.target: "entity"`, `identity.targetId` |
| `event` | `eventId` | `identity.target: "event"`, `identity.targetId` |
| `knowledge` | `knowledgeId` | `identity.target: "knowledge"`, `identity.targetId` |

They are never stored as flat root fields, and there is no client-facing `idField` concept — clients read/write identity via the `identity` object (and, for narrative/search context, the `concept` object). This package will not add a flat-id or `idField` public API even on request, since it would break the `memorix-record.2.0` contract for every downstream consumer. See [MEMORIX-DATABASE-CONVENTIONS.md](./docs/MEMORIX-DATABASE-CONVENTIONS.md#document-shape) for the full shape and rationale.

Internally, `@x12i/memorix-writer` tolerates **reading** older, pre-2.0 records that only have a flat `entityId`/`eventId` (see [docs/GRAPH-RUNS.md § Identity resolution](./docs/GRAPH-RUNS.md#identity-resolution-source-records)) so graph-run tracking keeps working during a tenant's migration window. That fallback is read-only, internal, and not exported — it does not change what gets written, and it is not something applications should rely on or target.

Collection name resolution order:

1. Explicit override (API/code parameter)
2. Write descriptor `target.targetCollection`
3. Entity descriptor content type `collection`
4. `MEMORIX_ENTITIES_COLLECTION_*` / `MEMORIX_EVENTS_COLLECTION_*` env vars
5. Write descriptor `target.targetCollectionCandidates`
6. Content-type slice `{collectionPrefix}-{postfix}` (e.g. `assets-analysis`)
7. Built-in defaults for known `entityType` values
8. Heuristic (`<entityType>` or `<entityType>-events`)
9. Verify the collection exists in the target database (skipped for `dryRun` / `validateOnly`)

For content-type slices, step 6 runs before canonical entity defaults so `assets` + `analysis` still resolves to `assets-analysis` unless overridden explicitly.

## Generic Annotations

`writeMemorixRecord` and `writeMemorixRecords` expose generic annotation hooks that work across `entity`, `event`, and `knowledge` targets:

| Request field | Written shape |
|---------------|---------------|
| `metadata` | `_memorix.metadata` |
| `tags` | `_memorix.tags` |
| `narratives` | `narratives.{key}` |

Narrative keys use the same top-level `narratives.{key}` shape consumed by `@x12i/memorix-retrieval` helpers such as `fetchMemorixNarrativeRecords`. This is only a generic tag/write primitive; applications still own narrative detection, descriptor design, and domain-specific relation names.

## Operations

| Operation | Default | Notes |
|-----------|---------|--------|
| `add` | yes | Always inserts a new record |
| `upsert` | descriptor-gated | Requires `conflict.matchBy` |
| `patch` | descriptor-gated | Updates writable fields on existing row |
| `replace` | descriptor-gated | Full replace |

## Catalox seeds

Catalog metadata for this package (write descriptors, entity descriptors) is managed in **MongoDB** — the `memorix-catalox` database. The manifest below is the source of truth for what gets applied there.

Validate the write descriptor seed:

```bash
npm run catalox:seed:write-descriptors:validate
```

Apply the manifest to Mongo `memorix-catalox` (uses `MONGO_URI` + `MEMORIX_CATALOX_DB`) — this is the normal way to publish or update descriptors:

```bash
npm run catalox:seed:write-descriptors:apply
```

Seed file: [`catalox-seeds/memorix-write-descriptors.manifest.json`](catalox-seeds/memorix-write-descriptors.manifest.json)

Shipped write descriptors include `asset-analysis-write` (entity) and corpus helpers `content-documents-snapshot-write` / `content-documents-chunk-write` (`knowledge` target). Record builders: [`@x12i/memorix-corpus`](../memorix-corpus/README.md).

## Acceptance criteria

| ID | Status |
|----|--------|
| AC-1 | Generic descriptor-driven write |
| AC-2 | Prefix/postfix collection resolution |
| AC-3 | Identity: exactly one of `entityId` / `eventId` / `knowledgeId`, written to `identity.targetId` |
| AC-4 | Default operation `add` |
| AC-5 | Upsert only when allowed |
| AC-6 | Patch only when allowed |
| AC-7 | Writable field allowlist / unknown fields |
| AC-8 | Required fields |
| AC-9 | Content body → object storage + pointer |
| AC-10 | Existing content pointer |
| AC-11 | Content maxBytes |
| AC-12 | No secrets in descriptors |
| AC-13 | Idempotency |
| AC-14 | `dryRun` |
| AC-15 | `validateOnly` |
| AC-16 | Retrieval delegated when configured |
| AC-17 | Generic metadata, tags, narrative tags, and `knowledge` writes |

## Graph-run tracking (`_graphRuns`) — MRX-FRS-001

System-only APIs for Exellix jobs graph execution tracking. Domain `writeMemorixRecord` rejects `_graphRuns` in input.

```typescript
import {
  markGraphRunStarted,
  markGraphRunFailed,
  writeGraphRunResult,
  clearGraphRun,
  ensureGraphRunIndexes,
} from "@x12i/memorix-writer";
```

| API | Purpose |
|-----|---------|
| `markGraphRunStarted` | Stamp `in_progress` (idempotent per `jobRunId`) |
| `markGraphRunFailed` | Terminal failure stamp |
| `writeGraphRunResult` | Upsert result doc + stamp source `done` (best-effort compensation) |
| `clearGraphRun` | Force re-run via `$unset` |
| `ensureGraphRunIndexes` | Opt-in planning-query indexes |

Full contract: [docs/GRAPH-RUNS.md](./docs/GRAPH-RUNS.md).

## Job-type run tracking (`_jobTypeRuns`) — MRX-CR-003

Parallel stamp APIs keyed by `jobTypeId` (shared `GraphRunEntry` shape). Domain writes reject `_jobTypeRuns` in input.

```typescript
import {
  markJobTypeRunStarted,
  markJobTypeRunCompleted,
  markJobTypeRunFailed,
  ensureJobTypeRunIndexes,
} from "@x12i/memorix-writer";
```

Full contract: [docs/JOB-TYPE-RUNS.md](./docs/JOB-TYPE-RUNS.md).

## Entity collection bootstrap — MRX-CR-005

```typescript
import { initializeEntityCollections } from "@x12i/memorix-writer";

await initializeEntityCollections(client, "assets", {
  contentTypes: ["core", "inferences"],
  graphRunIndexes: true,
  jobTypeRunIndexes: true,
});
```

Idempotent: creates missing collections and ensures standard indexes (`idx_updatedAt`, `idx_graphRuns`, optional `idx_jobTypeRuns`, etc.).

## Development

```bash
npm run build
npm test
```

Mongo collection I/O is built in (`insertMemorixCollectionDocument`, etc. under `src/mongo/`).

## Publish

```bash
npm run build
npm publish --access public
```

Or from the x12i workspace root: `./scripts/publish-memorix-packages.sh`

---
_Source: https://npm.io/package/@x12i/memorix-writer · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
