OKF conformance (2.0)
What this buys you
Your memory is portable beyond ai-memory. Hand a project bundle to a teammate who runs a different OKF-aware tool — or no tool at all — and they read your decisions, gotchas and procedures as ordinary markdown with standard metadata:
ai-memory export-okf --project myproject -o myproject-bundle.tar.gz
The receiving side unpacks a directory of .md files where every page
declares its type, provenance (generated, sources) and freshness
(stale_after) in the vocabulary Google's Open Knowledge Format
standardized — greppable, Obsidian-openable, importable by anything
OKF-aware. Nothing is held hostage: the export is a validated copy of
the files ai-memory already lives on.
The rest of this page is the design: how conformance is enforced and how existing stores migrate.
ai-memory's wiki is natively an Open Knowledge Format bundle from
2.0 on: every page a consumer reads off disk is a conformant OKF
concept file, and a project's wiki directory is a conformant bundle.
"Native" means the wiki files are the OKF files — no export step
forks the truth (an export --okf / import --okf pair still exists
for moving bundles across tools).
Target: OKF v0.2
Spec: GoogleCloudPlatform/knowledge-catalog, okf/SPEC.md (verified
2026-09-01). v0.2 supersedes v0.1 with two breaking changes
(timestamp → generated: {by, at}; the # Citations body section →
sources frontmatter) and additive trust/lifecycle/provenance
families. Summary of what conformance requires:
- every non-reserved
.mdfile: parseable YAML frontmatter with a non-emptytype; - bundle root
index.mddeclaresokf_version: "0.2"(the only index.md frontmatter allowed) and lists the directory; - reserved names
index.md/log.mdfollow spec structure when present; - consumers MUST tolerate unknown keys — all ai-memory extension fields are spec-safe as-is.
Field mapping
| OKF key | ai-memory source |
|---|---|
type (required) |
derived from path family + existing frontmatter: sessions/ → Session Summary, _rules/ → Rule, gotchas/ → Gotcha, decisions/ → Decision, procedures/ → Procedure, concepts/ → Concept, notes/ → Note, runbooks/ → Runbook, _slots/ → Invariant/State (from slot_kind), _lint/ → Lint Report, _pending/ → Pending Note; kind: frontmatter (fact/note/procedure/decision) wins over the path default when present |
title |
already written by every producer |
description |
existing summary field, when present |
tags |
already written |
generated.by |
actor convention: process:ai-memory/<version> for the zero-LLM consolidator and system writers; <provider-model> (e.g. openai-compat/qwen3:32b) for LLM-written pages; human:<user> for wiki edits attributed via the watcher |
generated.at |
the page version's updated_at |
sources |
session provenance: pages already stamped with session_id/agent get [{resource: "ai-memory://session/<uuid>", author: "<agent>"}] |
stale_after |
existing expires_at (TTL), when present |
status |
deprecated when TTL-expired but retained; otherwise omitted (spec default stable) |
Extension fields kept verbatim (unknown keys are conformant): tier,
kind, slot_kind, entities, pinned, consolidated,
session_id, agent, summary, expires_at.
Bundle boundary
One project scope directory = one bundle: the portable unit of
knowledge is a project. Each project dir gets a generated index.md
(frontmatter okf_version: "0.2", body = directory listing). The
existing _meta.md scope manifest is unchanged — it is ai-memory's
identity record; index.md is the OKF-facing description. Nothing in
the current tree writes index.md, so that reserved name is free.
log.md is not adopted: git is the log.
The hooks do write a raw per-month event ledger at the project root
(log-YYYY-MM.md — ## [ts] event | title lines, no frontmatter). It
is capture, not a concept file, so the export drops it exactly as it
drops log.md, and the conformance gate never sees it (#748). The
exclusion is content-gated, the same way the migration scan's is
(#669): an ordinary page that happens to be named log-2026-09.md
still ships in the bundle and still has to declare a type.
Enforcement: one choke point
Every page write funnels through ops::upsert_page_in_tx. A
deterministic okf::conform_frontmatter(path, frontmatter, meta)
normalization runs there for every new version: fills type /
generated / sources / stale_after from the mapping above,
touches nothing already present, invents nothing non-derivable.
Determinism matters: the identical-content idempotency check hashes
frontmatter, so conforming the same input twice must yield identical
bytes.
Migration of existing stores
Order is fixed; each step gates the next:
- Proactive backup, first, always. The migration compresses the
entire data dir (wiki, SQLite DB, manifests) to
~/ai-memory-backup-pre-2.0-<date>.tar.gz— outside the data dir — verifies the archive is listable and size-sane, and aborts if the backup cannot be written or verified. The archive path is recorded in the wiki meta manifest. - In-place frontmatter rewrite. Same page id, same version row,
body untouched,
updated_atuntouched: no version explosion, no embedding invalidation, noupdated_atstampede. One git commit ("okf-migration") on the wiki, after a pre-migration checkpoint commit. Reindex afterwards. - Generation marker: the migration ships as a
WikiMigration(tracked in thewiki_migrationstable), and the runner now refuses to open a wiki whose table records a migration this binary does not know (NewerWikiFormat) — the downgrade guard mirroring the DB schema-ahead rule. Scope_meta.mdmanifests get theirtypeonly; they are identity records, not concept pages. - Idempotent: a re-run migrates zero pages.
- Homepage notice until the archive is deleted: path, size, date,
plus "everything looks right → delete the archive" and "something
is missing → restore steps" (linking
MIGRATION-2.0.md).
Rollback: restore the archive (blunt, no git knowledge needed), or the
pre-migration git checkpoint + reindex (surgical).
Tests (each with a control that must fail on a broken build)
- Round-trip: page → OKF file on disk → parsed back identical.
- Conformance: every file in a migrated store has parseable
frontmatter + non-empty
type; bundle root carriesokf_version. - No-churn: page ids, version rows, and
updated_atbyte-identical across migration (control: a migration that supersedes pages fails). - Idempotency: second run migrates zero pages.
- Backup gate: archive step broken → migration refuses to run.
- Homepage notice renders the recorded archive path and clears when the file is gone.
- Foreign OKF v0.2 bundle imports into a project;
export-okfemits a bundle a strict reader accepts (a non-conformant page fails the export). Import has no dedicated command by design: the format is native, so unpacking a bundle's concept files into a project's wiki directory and letting the watcher (orreindex) ingest them IS the import path. - Retrieval regression: LongMemEval baseline re-run; no material drop.