OKF bundle navigation contract
OKF bundle navigation contract
Section titled “OKF bundle navigation contract”Mechanic 1 of 5. How a bundle is laid out on disk, which filenames are reserved, and why
the layout is a documented superset of upstream OKF v0.1.
Source of truth: scripts/cocoindex_pipeline/producer/bundle_writer.py; DR-019
(conformance posture); the real published bundle in repo canonical-okf-showcase (renamed from canonical-okf-platform, bl-479 S487)
(first commit 3f66483, 18 concepts).
The layout
Section titled “The layout”A bundle is a git repo whose root holds the reserved bundle-level files (see Reserved filenames) plus one directory per concept category. From the published Platform bundle:
canonical-okf-showcase/├── index.md # BI-5 — regenerated table of contents (§11 okf_version stamp + themes → concepts)├── log.md # BI-11/BI-18/BI-22 — SPEC §7 date-grouped run history├── ontology.json # DR-027 — the materialised effective ontology (see Ontology sync)├── CONFORMANCE.md # hand-authored, producer-preserved — agent-facing guide (replaced the root README, 15/07/2026)├── case-studies/│ ├── corvedale-academies-trust.md│ ├── northgate-borough-council.md│ ├── …│ └── won-bid/ # {132.29} redirect — see below│ └── northgate-borough-council.md├── certifications/│ ├── iso-9001.md│ └── …├── company/│ └── overview.md├── products/│ └── …└── topics/ └── …The published bundle is 18 concepts across case-studies/ (incl. the nested won-bid/
subdir), certifications/, company/, products/, and topics/, plus the reserved
bundle-level files. Each concept is a single markdown file; its path is its identity within
the bundle (BI-2).
Reserved filenames
Section titled “Reserved filenames”Six filenames at the bundle root are reserved and never treated as concept files — the three
producer-generated files (index.md, log.md, ontology.json), the client-owned
ontology-overlay.json ({132.34}), and — since the OKF v0.1 conformance wave (S464 rider
R1) — the two hand-authored, producer-preserved root docs README.md and CONFORMANCE.md:
# scripts/cocoindex_pipeline/producer/bundle_writer.py:174-189INDEX_FILENAME = "index.md"LOG_FILENAME = "log.md"ONTOLOGY_FILENAME = "ontology.json"README_FILENAME = "README.md"CONFORMANCE_FILENAME = "CONFORMANCE.md"OVERLAY_FILENAME = "ontology-overlay.json"_RESERVED_BUNDLE_FILENAMES = frozenset( {INDEX_FILENAME, LOG_FILENAME, ONTOLOGY_FILENAME, README_FILENAME, CONFORMANCE_FILENAME, OVERLAY_FILENAME})This frozenset is what the producer’s previous-run scan excludes when it computes “which
.md files on disk are concepts” (_existing_concept_paths, bundle_writer.py:799-818 — a
recursive rglob("*.md") minus the reserved names). Because README.md and CONFORMANCE.md
are now IN the set, a hand-authored root README.md/CONFORMANCE.md is invisible to the
concept scan — it can never surface as a false Removed entry in log.md (the old cosmetic
wrinkle, now resolved; see Producer operations → CONFORMANCE.md and the producer).
index.md — the table of contents (BI-5)
Section titled “index.md — the table of contents (BI-5)”index.md is fully regenerated every run (regenerate_indexes,
bundle_writer.py:418; assembled by build_index_themes, :455). It is a
themes → concepts progressive-disclosure outline: ##/### headings are themes, and each
concept is a bullet * [title](path.md) — description.
On the first Platform run all 18 concepts sit under a single ## Other heading. That is
not a bug: build_index_themes files any concept not matched by an explicit theme
configuration under the default unthemed_heading (bundle_writer.py:492-501, default
"Other"), and the first run passed no theme_config. Theme grouping is a later refinement;
the format is stable.
log.md — the run history (BI-11/BI-18/BI-22, SPEC §7)
Section titled “log.md — the run history (BI-11/BI-18/BI-22, SPEC §7)”Since the 15/07/2026 conformance wave log.md follows OKF SPEC §7: entries are grouped under
## YYYY-MM-DD ISO-8601 date headings, newest date first, and within a date each run
is a * **Run <ISO-ts> — <Action> (N):** bullet, newest run first. A no-op run still
emits a visible bullet (BI-11 per-run visibility). append_log_entry
(bundle_writer.py:605-652) owns the full-content reconstruction — declare_file has no
prepend mode, so it always takes the FULL desired content: a same-date run’s bullets are
inserted at the top of the existing first date section, otherwise a fresh date section is
prepended above everything (render_log_entry, bundle_writer.py:592-602, is the single-run
shape). The first Platform run’s block is a single Added (18) bullet listing every concept
path — the shape you would expect for a first publication.
The consumer lib/okf/parse-log.ts reads this in lockstep: the FIRST ## heading is the
most recent date, and document order IS reverse-chronological (parseBundleLog,
parse-log.ts:121-140). A legacy fallback is retained for pre-§7 bundles — a file with
no **Run …** bullets anywhere is reversed on read, exactly as the old ## <ISO-timestamp>
append-only parser behaved. A git-sync reconcile that finds conflicts inserts its
### git-sync reconcile findings block immediately AFTER the newest run’s bullet group, never
appended to the tail (_merge_findings_into_log, git_sync.py:568-605).
The added/changed/removed diff a run reports is computed against the on-disk previous-run
keyset (_existing_concept_paths, bundle_writer.py:799-818); it is a report, not the
delete mechanism (the physical write/delete is cocoindex’s reconciliation — see Producer
operations).
Concept file shape
Section titled “Concept file shape”Every concept is YAML frontmatter + a markdown body ending in a # Citations section.
Frontmatter carries type, title, description, timestamp (ISO-8601), tags, and —
where a primary record anchor exists — resource: (a canonical:// pointer). Example
(company/overview.md from the published bundle):
---type: companytitle: Ridgeway Commercial Services Ltd — Company Overviewdescription: An overview of Ridgeway Commercial Services Ltd, a UK-based distributor…timestamp: "2026-07-11T15:16:19.531443Z"resource: canonical://source_documents/9c56fcc6-36a1-5ade-9117-e2e60eff6d5ftags: - company - public-sector - …---The body ends in a # Citations trailer — since the conformance wave a numbered list of REAL
markdown links (SPEC §8), normalised deterministically at write time:
# Citations
[1] [canonical://source_documents/9c56fcc6-…](canonical://source_documents/9c56fcc6-…)[2] [ISO 9001:2015 — Quality Management Certification](/certifications/iso-9001.md)A record anchor keeps its canonical:// URI as both label and target; a concept→concept
cross-link uses the SPEC §5.1 bundle-absolute form — a leading / plus the target’s
rel_path (/certifications/iso-9001.md) — with the target concept’s title as the link
label. The # Citations section and the resource: field are the only two places a
Canonical record pointer may appear (BI-10); a cross-link is never a uuid. The full citation
rules are canonical:// resolution.
The won-bid/ redirect ({132.29})
Section titled “The won-bid/ redirect ({132.29})”A won-bid case_study concept’s identity path (case-studies/<slug>.md) is redirected on
disk into a distinct case-studies/won-bid/<slug>.md sibling directory
(_won_bid_case_study_redirect, bundle_writer.py:211-227) so it can never collide with a
same-slug named-client case study. The producer refuses (raises ValueError) if two drafts
in one run resolve to the same physical path (bundle_writer.py:902-909) — no silent
overwrite.
Conformance posture — a documented superset (DR-019)
Section titled “Conformance posture — a documented superset (DR-019)”The bundle is genuine OKF (GoogleCloudPlatform knowledge-catalog SPEC.md v0.1). After the
15/07/2026 conformance wave (canonical 9a795c5e) the log.md-format (§7) and README §9.1
divergences are RESOLVED; the okf_version: "0.1" stamp (§11) and the CONFORMANCE.md
house rule that DR-019 mandated are now discharged. Two deliberate divergences remain —
spec-legal producer-side strictness, kept on purpose (DR-019, amended 15/07/2026,
reference/decision-register.md):
- A closed, validator-enforced type taxonomy — the concept
typeset and the entity/relation ontology are closed and gated (see Semantic-linter gate), where upstream OKF leaves them open. - The opaque
canonical://scheme — an opaque, vendor-namespaced pointer value rather than a resolvable URL (see canonical:// resolution).
(The machine-facing ontology.json artefact is a further KH extension over the reference
format; it is documented in the bundle’s own CONFORMANCE.md.)
The bundle-root index.md now opens with the §11 frontmatter stamp — exactly one key,
okf_version: "0.1" (regenerate_indexes, bundle_writer.py:418-452; the consumer
parse-index.ts skips the block, stripFrontmatter, parse-index.ts:57-63).
House rules that flow from DR-019: ISO-8601 for the timestamp frontmatter field and all
log.md dates; UK date format only in body prose. Keep the OKF name; do not strip the
extensions.