docs/cli.mdtype: Reference

The okf command line.

Eight subcommands over a bundle or a file, a self-contained Native AOT binary with no runtime to install. validate exits non-zero on a non-conformant bundle, so the whole tool drops into CI as one line.

##

Synopsis

okf <command> [args]
CommandArgumentDoes
validate<bundle>Check a bundle against OKF v0.2 conformance (§11)
audit<bundle>Report trust, freshness and lifecycle across the bundle (§5.3–§5.5)
info<bundle>Summarize concepts, types, links and version
index<bundle>(Re)generate every index.md (§8)
graph<bundle>Print the cross-link graph; --dot for Graphviz
parse<file>Parse one document and print its structure
fmt<file>Normalize by parse + re-serialize (-w writes)
render<bundle> --out <dir>Generate a browsable static HTML site from the bundle

Global options: -h/--help prints usage; -V/--version prints the build and spec version; --as-of <YYYY-MM-DD> pins today's date for validate and audit.

Everything after a -- separator is an argument, never an option — which is how a path beginning with - is passed. The rule holds for every verb and every flag, so okf fmt -- notes.md -w treats -w as a second filename rather than as the write-in-place flag; write it as okf fmt -w -- notes.md if that is what you meant. A value belonging to an option is likewise only ever a value: in okf audit b --type --stale, --stale is the type being searched for, not a filter.

$ okf --version
okf 0.5.0 (OKF spec v0.2)
##

validate <bundle>

§11 — exit code is the interface

Loads the bundle, runs the §11 conformance check, and prints every diagnostic followed by a tally. Exits 0 when conformant, 1 otherwise. Warnings never break conformance — only errors do — so recommended-but-missing fields are surfaced without failing the build.

$ okf validate tests/fixtures/appendix_a
[warning] tests/fixtures/appendix_a/tables/users.md: missing recommended frontmatter field `description`
[warning] tests/fixtures/appendix_a/tables/users.md: missing recommended frontmatter field `timestamp`

4 concept(s); 0 error(s), 2 warning(s), 0 info.
✓ conformant with OKF v0.2

--json emits the same diagnostics as machine-readable, camelCase JSON — one object per line, no pretty-printing. Each diagnostic carries a stable code (DiagnosticCode) and, where relevant, a field naming the frontmatter key involved, so a caller can branch on the finding without parsing prose.

$ okf validate tests/fixtures/appendix_a --json
{"bundle":"tests/fixtures/appendix_a","conformant":true,"conceptCount":4,"errorCount":0,"warningCount":2,"infoCount":0,"diagnostics":[{"severity":"warning","code":"MissingRecommendedField","path":"tests/fixtures/appendix_a/tables/users.md","conceptId":"tables/users","field":"description","message":"missing recommended frontmatter field `description`"}, …]}

--as-of <YYYY-MM-DD> pins the date the §5.5 staleness warning is evaluated against. Without it that one diagnostic depends on the day the command runs, so a pipeline asserting on validate's output should pin it rather than let the calendar move underneath.

##

audit <bundle>

§5.3–§5.5 — the corpus, not the concept

Answers questions about the bundle as a whole: how much of it is human-reviewed, what has passed its stale_after instant, what is deprecated. Counts always describe the whole bundle while the worklist describes the selection — audit is a worklist, not an inventory. Always exits 0: a stale concept is editorial hygiene, not a conformance failure.

$ okf audit bundles/acme_retail --as-of 2027-06-01
bundle:     bundles/acme_retail
as of:      2027-06-01
concepts:   9

trust:
     8  human-reviewed
     0  machine-confirmed
     1  unverified

status:
     0  draft
     8  stable
     1  deprecated

stale:      7 of 9 past stale_after

needs attention (7):
  computations/gross-margin-period  stale 2026-12-31  human-reviewed  stable
  computations/revenue-ytd  stale 2026-12-31  human-reviewed  stable
  metrics/gross-margin  stale 2026-12-31  human-reviewed  stable
  metrics/revenue  stale 2026-12-31  human-reviewed  stable
  policies/margin-standard  stale 2026-12-31  human-reviewed  stable
  policies/revenue-recognition  stale 2026-12-31  human-reviewed  stable
  tables/orders  stale 2026-12-31  human-reviewed  stable

With no filter flag it selects exactly what --stale selects and prints the summary above. With any of --stale, --trust, --status or --type it prints one line per matching concept and nothing else, so the output pipes. --as-of pins the observation date to midnight UTC on that day (it never changes the mode), and --json always emits the full document.

# any filter flag switches to one line per concept — pipe-friendly
$ okf audit bundles/acme_retail --trust unverified
skills/run-on-bq  no-stale-after  unverified  stable

The question this exists for — which concepts are past their stale_after instant and have never been verified by a human? — is --stale --trust unverified,machine-confirmed: both tiers, because “machine-confirmed” also means no human ever looked.

##

info <bundle>

a summary, no mutation

Reports the bundle root, declared OKF version (if any), concept count, reserved-file counts, a breakdown by type, and the internal link total with broken-link count. Unparseable files are listed at the end. Always exits 0.

$ okf info tests/fixtures/appendix_a
bundle:     tests/fixtures/appendix_a
concepts:   4
index.md:   0
log.md:     1

types:
     1  BigQuery Dataset
     3  BigQuery Table

links:      5 internal (0 broken)

--json works here too, for scripting against the same summary.

$ okf info tests/fixtures/appendix_a --json
{"bundle":"tests/fixtures/appendix_a","okfVersion":null,"conceptCount":4,"indexFileCount":0,"logFileCount":1,"types":{"BigQuery Dataset":1,"BigQuery Table":3},"linkCount":5,"brokenLinkCount":0,"parseErrors":[]}
##

index <bundle>

§8 — progressive disclosure

Regenerates every index.md directory listing in the bundle and prints each path written, then a total. On an empty bundle it prints no index files written (empty bundle?). Exits 0. This command writes files — run it after adding or renaming concepts.

$ okf index ./my_bundle
wrote my_bundle/index.md
wrote my_bundle/tables/index.md

2 index file(s) regenerated.
##

graph <bundle> [--dot]

§6 — cross-links

Prints each concept's outgoing links. Resolved links use ->, broken ones -x. Pass --dot to emit Graphviz DOT (broken edges dashed and red) — pipe it straight into dot.

$ okf graph tests/fixtures/appendix_a
datasets/sales
  -> tables/orders
  -> tables/customers
tables/customers
  -> tables/orders
tables/orders
  -> datasets/sales
  -> tables/customers
$ okf graph tests/fixtures/appendix_a --dot
digraph okf {
  rankdir=LR; node [shape=box, fontsize=10];
  "datasets/sales" -> "tables/orders";
  "datasets/sales" -> "tables/customers";
  "tables/customers" -> "tables/orders";
  "tables/orders" -> "datasets/sales";
  "tables/orders" -> "tables/customers";
}

$ okf graph ./my_bundle --dot | dot -Tsvg > graph.svg
##

parse <file>

§4 — one document

Parses a single concept document (strict UTF-8) and prints its frontmatter keys, whether it has a non-empty type, the body size in bytes, and any links and citations. Exits 0 if the document is conformant, 1 if not.

$ okf parse tests/fixtures/appendix_a/tables/orders.md
frontmatter (6 key(s)):
  type: BigQuery Table
  title: Orders
  description: One row per completed customer order.
  resource: https://console.cloud.google.com/bigquery?…
  tags: [sales, orders]
  timestamp: 2026-05-28T00:00:00Z

has non-empty `type`: true
body: 99 byte(s)

links (2):
  [Absolute] sales dataset -> /datasets/sales.md
  [Absolute] customers -> /tables/customers.md
##

fmt <file> [-w]

the round-trip, made tangible

Parses the document and re-serializes it — normalizing frontmatter and block structure while preserving unknown keys byte for byte. Prints to stdout by default; -w (or --write) writes back in place. Exits 0.

$ okf fmt tests/fixtures/appendix_a/tables/orders.md
---
type: BigQuery Table
title: Orders
description: One row per completed customer order.
resource: https://console.cloud.google.com/bigquery?p=acme&d=sales&t=orders
tags:
  - sales
  - orders
timestamp: 2026-05-28T00:00:00Z
---

# Schema

Part of the [sales dataset](/datasets/sales.md). FK to [customers](/tables/customers.md).
##

render <bundle> --out <dir>

a self-contained static site

Generates a browsable HTML site from the bundle: one page per concept (a frontmatter table, in document order, with unknown producer keys preserved, followed by the rendered body) plus a generated index page built from the same logic as okf index. Inter-concept links are rewired to the generated pages, with backlinks (“Referenced by”) added on each target page; a link to a concept that doesn't exist is flagged and left non-clickable rather than silently dropped or pointed at a 404. External links and in-page anchors are left untouched.

$ okf render tests/fixtures/appendix_a --out ./site
wrote 8 files to ./site

$ ls ./site
assets/  datasets/  index.html  tables/

The output is self-contained — it opens straight from the filesystem (file://) with no server required. Markdown renders client-side, via a vendored copy of marked v15.0.12 (MIT, credited in NOTICE); a DOM sanitizer strips anything the fixed template doesn't expect. GFM task list items survive sanitization as real, disabled <input type="checkbox"> elements with the correct checked state, so a screen reader announces them as checkboxes rather than as decorative text.

There's no full-text search in this slice — a static site has no server to run the shared ConceptSearch scorer against, and duplicating its ranking logic in JavaScript would fork the one place that scorer is meant to live. Search arrives with the planned okf serve companion (the live-server half of this work). Backed by the new, zero-dependency OKF4net.Viewer project, which ships inside the okf binary — it isn't published as a separate NuGet package.

##

Exit codes & CI

copy the file, run it
CodeMeaning
0Success — or, for validate/parse, conformant
1Non-conformant, missing argument, unknown subcommand, or I/O error

Because the binary is self-contained, a CI image needs no .NET runtime, no SDK, no restore:

# any pipeline — fail the build on non-conformant knowledge
okf validate ./bundles/ga4

library.md — the same engine, as a C# API · getting-started.md

##

Install it

winget on Windows, or Native AOT publish

On Windows, install via winget:

$ winget install Coderise.OKF4net

On any OS, build it from source:

$ git clone https://github.com/jchable/okf4net
$ dotnet publish src/OKF4net.Cli -c Release   # self-contained okf binary