ckb/.agents/skills/ckb-export-okf/SKILL.md
Michał Kopeć 65b1e422b3 Add decision log, scriptify OKF export and lint detection
Decision log (VERSION 1.6.0, kb_schema_version 1.4):
- wiki/decisions/ scaffold — numbered NNNN-slug.md records, own index
  (with status vocabulary) and log
- type: decision adds status/decided_on/decided_by/affects/review_on;
  supersedes/superseded_by carry history and must be set on both sides
- New ckb-decide skill: records decisions and answers what/why/who/when,
  what superseded what, and what is still open. Decision pages are
  append-only — a changed mind is a new superseding decision
- Graph gains decided_by and affects edge types
- ckb-ingest routes decisions found in raw material to this format;
  ckb-retrieve gains the decisions index as a cascade step

Scriptified the mechanical skills:
- ckb-export-okf/scripts/export_okf.py does the whole OKF transform
  (frontmatter remap, link rewriting, index/log regeneration, conformance
  validation); --check validates without writing
- ckb-lint/scripts/lint_report.py does the read-only detection half
  (conformance, freshness, confidence, retention, decisions, orphans,
  graph, index/log, source.yaml); judgment calls stay with the model

Also: removed the duplicate personal quiz skill, fixed stale cbk-quiz
doc paths, gitignored __pycache__.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 20:50:36 +02:00

8.3 KiB

name description
ckb-export-okf Export the local wiki/ knowledge base as an Open Knowledge Format (OKF) v0.1-conformant bundle at outputs/okf/, so any generic OKF tool can consume it. Use when the user asks to "export the wiki as OKF", "generate the OKF bundle", "export to OKF", "publish the OKF export", or "sync outputs/okf".

Export to OKF skill

Purpose

Regenerate outputs/okf/ from the current wiki/ tree as a bundle that conforms to Google's Open Knowledge Format (OKF) v0.1 spec (https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md), so any generic OKF consumer (e.g. Google's reference graph visualizer) can read this knowledge base without needing to understand this repo's richer, more opinionated schema (confidence, quality, retention, supersedes, dual-linking, the cascade layers). This is a one-way, on-demand export — wiki/ stays the authoritative source; outputs/okf/ is always a derived artifact of it, never edited by hand and never fed back in.

The whole transform — frontmatter remapping, link rewriting, index and log regeneration, conformance validation — is done by a deterministic Python script, not by reading and rewriting every page by hand. The mapping is a fixed ruleset over a wiki that will keep growing, and a mechanical transform like this belongs in code, not in per-page model reasoning. Nothing in this skill needs an LLM to run correctly; the model's job is to invoke the script and relay its report.

This skill only runs when explicitly invoked — it is deliberately not part of the always-loaded CLAUDE.md/AGENTS.md Ingest/Lint workflows.

Trigger phrases

Use this skill when the user says things like:

  • "export the wiki as OKF" / "export to OKF"
  • "generate the OKF bundle" / "regenerate outputs/okf"
  • "publish the OKF export"
  • "sync outputs/okf with the wiki"

How to run this skill

Step 1 — Run the script

From the repository root:

python3 "<skill-dir>/scripts/export_okf.py"

Resolve <skill-dir> to this skill's own directory. Flags:

  • --check — build into a temporary directory, run the conformance checks, print the report, and write nothing to outputs/. Use this when the user wants to know whether the wiki would export cleanly without touching the working tree (e.g. as part of a review, or before a lint pass).
  • --out DIR — write somewhere other than outputs/okf (rarely needed).

The script deletes and rebuilds the output directory on every run, so the bundle can never accumulate stale files from pages that were since renamed or removed. It touches nothing outside the output directory and runs no git commands.

The exit code is 0 when the generated bundle conforms and 1 when it does not — the report always prints either way, so read it rather than relying on the exit code alone.

Step 2 — Relay the script's report

The script prints, and you should summarize back to the user:

  • Concept documents exported, and index.md/log.md files regenerated.
  • Wikilinks stripped and /wiki/ links rewritten to bundle-root paths.
  • How many linked//libs/ cross-cascade references were left unconverted — those won't resolve if the bundle is ever moved or shipped standalone, which is spec-compliant (OKF tolerates broken links) but worth stating.
  • Any SOURCE ISSUE: lines. These are problems in wiki/ itself, not in the export — most commonly a page with no type, which the bundle exports as type: unknown. Surface them; the fix belongs in the source wiki (run ckb-lint), not in the export.
  • Any NONCONFORMANT: lines. These are bugs in the export — an intra-bundle link that doesn't resolve, an index with the wrong frontmatter shape, a malformed log header. Do not report the run as successful when these appear; investigate the script rather than hand-patching outputs/okf/.
  • A reminder that outputs/okf/ has been regenerated on disk but not staged or committed — that's a separate step for the user when they're ready to publish the update. (outputs/okf is gitignored by default in this template, so "publish" usually means copying the bundle elsewhere rather than committing it in place.)

What the transform does (for context, not something you need to re-derive)

Concept documents (every .md that isn't index.md/log.md, including overview.md, error-book.md, and query-gaps.md — only index.md and log.md are OKF reserved names):

wiki/ field OKF output field Rule
type type passthrough; a page with no type exports as unknown and is reported as a source issue
(derive) title the first # H1 in the body, else the slugified filename (foo-bar.md → "Foo Bar")
tldr description rename
resource resource passthrough
last_updated timestamp passthrough as-is (bare YYYY-MM-DD is valid ISO 8601 — no time-of-day is fabricated)
confidence, quality, retention, supersedes, superseded_by, freshness_window_days same keys passthrough as OKF extension fields, which consumers must tolerate
kb_schema_version (dropped) the root index.md's frontmatter is spec-limited to okf_version; this key has no valid home in the bundle
(none) tags omitted — no source field to derive it from

Links: the [[Wikilink]] half of every dual-link is dropped, keeping the markdown half (a bare wikilink with no markdown twin degrades to its plain label). Root-absolute /wiki/entities/foo.md becomes /entities/foo.md, since the bundle root is outputs/okf/, not the repo root. Relative links need no change — the export mirrors wiki/'s tree exactly. linked/<name>/... and libs/<name>/... references are left untouched and counted.

Indexes: regenerated from the tree rather than transcribed from the source, so they can't drift. The root index.md carries only okf_version: "0.1" (the one documented exception to "index.md has no frontmatter"); nested indexes carry none. Each body is an H1 plus a flat * [Title](path) - description bullet list of that directory's direct children, sorted by path, with each page's own description as the description text. The source's "Use when" column and prose sections are dropped — they are Claude-agent lazy-loading optimizations with no meaning to a generic OKF consumer. An empty list is spec-valid.

Logs: entries are regrouped under ## YYYY-MM-DD headers (date only, newest date first) as * **Verb**: [affected files] — description (source: ...). CREATE → Creation, UPDATE → Update, DELETE → Deprecation, anything else → Update. The - **Source:** line rides along as the trailing parenthetical rather than being dropped — it's provenance worth keeping. The --- separators between entries are dropped; they aren't part of OKF's log format.

Validation runs against the generated bundle before the report prints: every non-reserved page has a non-empty type; the root index has only okf_version and nested indexes have no frontmatter; every log.md header matches ## YYYY-MM-DD; and every intra-bundle link resolves to a file that exists (cross-cascade linked//libs/ references are exempt by design).

Edge cases

  • Empty wiki/entities/ or wiki/graph/: their index.md is still regenerated, as an H1 with an empty bullet list. An empty index is spec-valid; the directory is never skipped.
  • A future wiki/<newtopic>/ subdirectory: handled automatically — the script discovers directories dynamically, mirrors them, and generates an index for each. No script changes needed.
  • A future wiki/archived/: exported like any other subdirectory. OKF has no notion of archival status; retention/freshness_window_days already ride along as extension fields for any consumer that cares.
  • Non-markdown files in wiki/ (e.g. graph/edges.json): copied verbatim into the same relative position and listed in their directory's index. Dotfiles (.gitadd) are skipped.
  • Re-running with no wiki changes: produces byte-identical output — every directory walk and generated list is sorted. If a run is ever nondeterministic, that's a bug in the script, not expected behavior.

Licensed under the Apache License, Version 2.0 — see LICENSE at the repository root, or http://www.apache.org/licenses/LICENSE-2.0.