Skip to content

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).


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).

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-189
INDEX_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 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).

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: company
title: Ridgeway Commercial Services Ltd — Company Overview
description: 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-e2e60eff6d5f
tags:
- 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.

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):

  1. A closed, validator-enforced type taxonomy — the concept type set and the entity/relation ontology are closed and gated (see Semantic-linter gate), where upstream OKF leaves them open.
  2. 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.