Gå til hovedinnhold

Terms bundle (.terms.json)

A terms bundle is the portable, lossless serialization of a project's terminology: the concepts a project has agreed on, their terms per locale, and the relations between them.

A terms bundle is an artifact: the shape a project's terms take when they leave the project store, and the shape they are read back from. kapi terms export writes one, kapi store import reads one, and the store is what every lookup and every gate answers from.

Implemented in Go at terms/ktb.

When kapi writes one​

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

kapi terms import accepts csv, tsv, json, tbx, or bundle. Only bundle is lossless; the rest are covered under what the other formats drop.

Where an import looks for one​

A flow that needs a project's terms reads the project's terms store; no flow opens a bundle. kapi store import reads one, and with no path it looks at <project-root>/.kapi/terms.json, the conventional place beside the rest of a project's context files. Name a directory, kapi store import context, to read the terms.json in it. A recipe has no key for a terms file.

Content memory has no single conventional file​

A project has one terms bundle, so one conventional filename works. A project can hold several content-memory bundles; this repository's own dogfood recipe keeps one per surface. An import therefore reads every bundle in .kapi/memory/.

Envelope​

{
"schemaVersion": "1.0",
"kind": "kapi-terms",
"created": "2026-07-26T09:12:04Z",
"generator": { "id": "kapi", "version": "1.2.3" },
"concepts": [],
"relations": []
}
FieldTypeNotes
schemaVersionstringMAJOR.MINOR. Unknown major rejected; unknown minor of a known major accepted.
kindstringAlways kapi-terms.
createdstringRFC 3339. Optional.
generatorobject{id, version}. Optional.
conceptsarrayThe concepts. Always present.
relationsarrayRelations between concepts. Omitted entirely when there are none.

concepts and relations reuse the terms store's own types directly rather than a parallel wire struct, so the serialization cannot drift from the model it serializes.

Determinism​

Marshal produces byte-stable output: concepts and relations sorted by id, terms within a concept sorted, timestamps normalized to UTC, HTML escaping off, two-space indent, trailing newline. Two exports of the same store are the same bytes, so a bundle diffs cleanly and can be hashed as a whole, which is what lets it sit inside a .kpz under the package's Merkle root.

What the other formats drop​

kapi terms export also emits csv, json, and tbx (tsv is accepted on import only). All three are lossy, and the JSON one is the easiest to mistake for the bundle because both are JSON:

  • --format json writes {name, version, concepts} and nothing else. It carries no relations at all, and its envelope has no kind marker, so it cannot be sniffed, and a reader cannot tell which schema it is holding. It is a convenience export for spreadsheets and scripts.
  • --format tbx is the industry interchange format. It has no representation for the cross-links that make a kapi concept useful inside kapi, most notably the entity cross-references content memory uses.
  • --format csv is flat: one row per term, no concept structure and no relations.

Reach for bundle whenever the file is staying inside kapi.

What the bundle leaves out​

  • The store's own tables. A bundle carries the concepts and relations; the terms tables in the project store are what an import writes them into.
  • Match state. Which blocks a term was found in is a check result; kapi terms occurrences reads it from the project's block cache.

See also​