@thisismydesign/okf-lint
v0.1.0
Published
An opinionated linter for Google's Open Knowledge Format (OKF) knowledge catalogs — errors for spec violations, warnings for missing-but-useful conventions.
Maintainers
Readme
okf-lint
A linter for the Open Knowledge Format (OKF) — Google's open, human- and agent-friendly format for knowledge catalogs.
Think of it as ESLint or RuboCop, but for OKF bundles. okf-lint:
- Reports errors when a bundle violates a mandatory OKF conformance
requirement (e.g. a concept document is missing its
typefield). - Reports warnings when a bundle skips an optional-but-useful convention
(e.g. no
index.md, nolog.md, or a concept document without adescription).
The OKF version is selected per bundle. Supported versions: 0.1. If a
bundle does not specify a version, or specifies one the linter does not support,
the highest supported version is used.
Specification: https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md
Installation
# one-off, no install
pnpm dlx @thisismydesign/okf-lint ./my-bundle
# or add it to a project
pnpm add -D @thisismydesign/okf-lintThis package is published as
@thisismydesign/okf-lint. It targets Node.js ≥ 18 and ships as ESM.
Usage (CLI)
Point it at a bundle directory (the folder that contains your OKF markdown files):
okf-lint ./path/to/bundle./path/to/bundle/tables/customer-metrics.md
7:1 warning Missing recommended `description` field (a one-line summary). recommended-description
✖ 1 problem (0 errors, 1 warning)Options
| Option | Description |
| -------------------- | ------------------------------------------------------ |
| path | Path to the OKF bundle directory (default: .). |
| -f, --format <fmt> | Output format: stylish (default) or json. |
| -q, --quiet | Report errors only (suppress warnings). |
| --max-warnings <n> | Exit non-zero if the number of warnings exceeds <n>. |
| --list-rules | Print every rule for the latest version and exit. |
| -v, --version | Print the okf-lint version and exit. |
| -h, --help | Show help and exit. |
Exit codes
| Code | Meaning |
| ---- | --------------------------------------------------------- |
| 0 | No errors (and warnings within --max-warnings, if set). |
| 1 | Errors found, or warnings exceeded --max-warnings. |
| 2 | Usage or runtime error (bad option, unreadable path, …). |
This makes it CI-friendly:
# fail the build on any error, but tolerate warnings
okf-lint ./bundle
# treat the bundle as a strict, zero-warning catalog
okf-lint ./bundle --max-warnings 0Usage (programmatic)
import { lint, formatStylish } from '@thisismydesign/okf-lint';
const result = lint('./path/to/bundle');
console.log(result.errorCount, result.warningCount);
for (const d of result.diagnostics) {
console.log(`${d.severity} ${d.ruleId} ${d.filePath}:${d.line} — ${d.message}`);
}
// or render the same human-readable report the CLI prints
console.log(formatStylish(result));lint(target, options) returns:
interface LintResult {
diagnostics: Diagnostic[]; // sorted by file, then line/column
errorCount: number;
warningCount: number;
version: ResolvedVersion; // which OKF version was used, and why
}You can pass inline configuration to override rule severities:
lint('./bundle', { config: { rules: { 'recommended-log': 'off' } } });What it checks
OKF v0.1 models a bundle: a hierarchical directory of markdown files. Each
non-reserved .md file is a concept document (YAML frontmatter + markdown
body). Two filenames are reserved: index.md (a navigable listing) and
log.md (an update history).
okf-lint is opinionated: the spec says a bundle is conformant with very few
requirements, and that consumers should tolerate almost everything else. We
honor that split exactly — only true conformance failures are errors;
everything we merely recommend is a warning you can turn off.
Errors — mandatory OKF conformance
These map directly to the spec's conformance requirements. A bundle that produces any of these is not a conformant OKF v0.1 bundle.
| Rule | What it enforces |
| ----------------------- | ----------------------------------------------------------------------------------------- |
| frontmatter-present | Every non-reserved .md file begins with a YAML frontmatter block. |
| frontmatter-parseable | That frontmatter block is parseable YAML (a mapping). |
| type-required | Every frontmatter block has a non-empty type field. |
| index-frontmatter | Only the bundle-root index.md may contain frontmatter; other index.md files must not. |
| index-version-key | The bundle-root index.md frontmatter contains only okf_version. |
| log-date-format | log.md entry headings use ISO 8601 YYYY-MM-DD dates. |
Warnings — optional but useful (the opinionated part)
The spec marks these as optional, and forbids consumers from rejecting a
bundle over them. But they make a catalog dramatically more useful to humans and
agents, so okf-lint nudges you toward them. Disable any you disagree with.
| Rule | Why we recommend it |
| ------------------------- | ------------------------------------------------------------------------------------------ |
| recommended-title | A human-readable display name makes listings and search legible. |
| recommended-description | A one-line summary is what most consumers show first. |
| recommended-timestamp | A last-modified time lets consumers reason about freshness. |
| tags-type | When present, tags should be a list of strings (not a bare scalar). |
| timestamp-format | When present, timestamp should be a valid ISO 8601 datetime. |
| recommended-index | A bundle-root index.md gives readers a navigable, grouped entry point. |
| recommended-log | A log.md records how the catalog evolved — invaluable for consumers tracking changes. |
| log-date-order | Log entries read best newest-first. |
| valid-links | Internal .md cross-links should resolve. (The spec permits broken links; we flag them.) |
| prefer-absolute-links | Bundle-absolute links (/path/to/doc.md) are more robust than relative ones. |
| okf-version-declared | Declaring okf_version lets tools pick the right rules. (See Versioning.) |
| okf-version-supported | Warns when the declared version is newer/unknown to this linter. |
| okf-version-format | okf_version should be a quoted string so e.g. "0.10" isn't parsed as the number 0.1. |
resource and tags are intentionally not required or recommended: many
concepts have no underlying asset, and tags don't always make sense. When you do
provide tags, tags-type checks that it's well-formed.
Run okf-lint --list-rules to print the full, current list.
Versioning
OKF uses <major>.<minor> versions. A bundle may declare the version it
targets via okf_version in its bundle-root index.md frontmatter:
---
okf_version: '0.1'
---
# Tables
- [Customer Metrics](/tables/customer-metrics.md) - Aggregated daily KPIs.okf-lint resolves which rule set to use as follows:
- Declared and supported → validate against that version.
- Declared but unsupported (e.g. a future
0.2) → emit anokf-version-supportedwarning and validate against the most recent supported version anyway (best-effort, as the spec recommends). - Not declared → emit an
okf-version-declaredwarning and validate against the most recent supported version.
The currently supported versions are listed by okf-lint --help. Today that is
just 0.1.
Configuration
Drop a .okflintrc.json in your bundle root (or the directory you run
okf-lint from) to tune rule severities. Each rule can be set to "error",
"warning", or "off":
{
"rules": {
"recommended-timestamp": "off",
"valid-links": "error",
"okf-version-declared": "off"
}
}This is how you make the linter less or more opinionated for your catalog — turn off conventions you don't follow, or promote a warning to a hard error in CI.
Examples
The examples/ directory contains two runnable bundles:
examples/valid— a clean bundle that lints with zero problems.examples/invalid— a bundle that intentionally triggers a representative spread of errors and warnings.
okf-lint examples/valid # ✓ No problems found.
okf-lint examples/invalid # ✖ 10 problems (4 errors, 6 warnings)Development
This repo uses pnpm, TypeScript, ESLint, and Prettier.
pnpm install # install dependencies
pnpm build # compile TypeScript to dist/
pnpm test # run the vitest suite
pnpm typecheck # type-check without emitting
pnpm lint # eslint
pnpm format # prettier --writeAdding a new OKF version
- Create
src/versions/v<major>_<minor>/rules.tsexporting arules: Rule[]array (start by importing and adapting the v0.1 set). - Register it in
src/versions/index.ts(RULE_SETSand, when appropriate,LATEST_VERSION). - Add fixtures under
examples/and assertions intest/.
Rules are small, self-contained objects (meta + run(context)), so most
changes touch only one file.
