Gå til hovedinnhold

Content memory bundle (.memory.json)

A content-memory bundle is the portable, lossless serialization of a project's content memory: the multilingual entries kapi reuses to avoid re-translating text it has already seen, together with where each entry came from.

It is a bundle, not a store. The working store is SQLite — tm.db, under the gitignored .kapi/ state directory — and a bundle is what you get when you export that store into a single reviewable, hashable file. See the overview for why kapi keeps that distinction.

Implemented in Go at memory/kmb.

When kapi writes one

  • kapi memory export --format bundle — the explicit export.
  • kapi pack — as the memory.json member inside a .kpz.

--format accepts tmx or bundle on both kapi memory export and kapi memory import. When the flag is omitted, the format is resolved from the file's extension.

Envelope

{
"schemaVersion": "1.0",
"kind": "kapi-memory",
"created": "2026-07-26T09:12:04Z",
"generator": { "id": "kapi", "version": "1.2.3" },
"entries": [],
"importSessions": []
}
FieldTypeNotes
schemaVersionstringMAJOR.MINOR. A reader rejects an unknown major and accepts unknown minors of a known major.
kindstringAlways kapi-memory. Also the sniffing marker used to detect the format by content.
createdstringRFC 3339. Optional.
generatorobject{id, version} — the tool that produced the file. Optional.
entriesarrayThe content-memory entries. Always present.
importSessionsarrayPer-file import metadata referenced by Origin.sessionId. Optional.

Entry

An entry is multilingual, and this is the design decision that most separates it from TMX. There is no authoritative source language at this layer: variants is a map of locale to run sequence, and the locales are peers. hintSrcLang records which locale the entry was originally authored in, as a hint for matching, not as a privileged field.

FieldTypeNotes
idstringEntry identity.
projectIdstringOptional.
hintSrcLangstringAdvisory authoring locale.
variantsobjectLocale → Run[]. The content itself.
entitiesarrayNamed entities tracked across all variants.
propertiesobjectFree-form string map.
originsarrayWhere this entry came from.
notestringOptional.
created, updatedstringRFC 3339.

Variant content reuses the same Run serialization the content bundle emits, so inline codes, placeholders, and plural/select constructs survive an export/import round trip unchanged rather than being flattened to a string.

Entity mappings

An EntityMapping tracks one named entity across every variant of the entry — a product name, a number, a date — and can cross-link it to a terms concept.

FieldTypeNotes
placeholderIdstringThe placeholder this entity occupies.
typestringEntity type. Optional.
valuesobjectLocale → {text, start, end}.
conceptIdstringCross-link into a terms concept.

values positions are offsets within that locale's variant, so an entity is locatable, not merely named.

Origins and import sessions

origins records provenance per entry (source, key, reference, addedAt, addedBy, sessionId). Where an entry arrived through a file import, sessionId points at an importSessions record holding the per-file metadata captured once at import time — fileKey, fileHash, fileSizeBytes, importedAt, importedBy, toolName, toolVersion, segType, adminLang, srcLang, dataType, originalFormat, originalEncoding, entryCount, and a properties map.

Splitting session metadata out of each entry keeps a large import from repeating the same twenty fields on every row while still letting any entry answer where it came from.

Why JSON and not JSON Lines

Overlays ship in both .overlays.json and .overlays.jsonl; content memory has no line-delimited form.

kapi memory export re-serializes the whole store and canonicalizes it on every write — entries sorted by id, timestamps normalized, deterministic formatting — so the bytes are stable for hashing and diff cleanly under git. There is no append path to optimize for, and an append-only file would defeat exactly the byte-stability that makes the bundle hashable as a unit.

The shape is also not a flat record stream. A bundle is an envelope plus two correlated arrays — entries and the importSessions they reference by id — and JSON expresses that directly. JSON Lines would mean inventing a framing convention to say which line is the envelope and how the two record types interleave.

What is deliberately not in it

  • The SQLite store's indexes. FTS5 and fuzzy-match side tables are derived; kapi memory import rebuilds them after a bulk load.
  • A privileged source language. Deliberate — see above.
  • Fuzzy-match scores or thresholds. Matching is a runtime concern driven by the recipe, not a property of stored content.

Relationship to TMX

TMX is supported (--format tmx) and is the right choice for handing content to a tool outside this project. It is a lossy tier: it has no representation for entity mappings, concept cross-links, per-entry provenance, or import-session metadata, and it assumes a source/target pair rather than peer locales.

Export to TMX to interoperate; keep the bundle when the content is staying inside kapi. Choosing a format covers the trade-off in full.

See also

  • Overview — store, bundle, and committed state.
  • Terms — the terminology bundle and its lookup ladder.
  • Project archive — the .kpz that carries a memory bundle as a member.