Site · Docs · Live demo · Claude plugin · Docker image
okf-gem (okf on RubyGems) is the complete harness for
Open Knowledge Format (OKF) v0.1 bundles: create, maintain, and consume
your project's knowledge with your agent. The package is Agent Skill + CLI/Lib + Graph: an agent skill that authors and curates, a CLI and Ruby library that validate, lint, search, and embed, and a graph to explore, live or static, in one gem that runs 100% local. A bundle is a directory of Markdown files with YAML frontmatter that humans and agents read from one source; each file is a concept. The gem does not define a new place to keep knowledge; it gives you leverage over knowledge that already lives as Markdown.
The package, end to end:
Over a bundle the gem gives you the okf
command-line tool (the library API is also usable in-process). Each capability
below links to the concept that documents it: this gem's own knowledge is an OKF
bundle, so you can read its design in the format it defends.
| Capability | What it answers | Verb |
|---|---|---|
| Companion agent skill | Can an agent author it? | skill |
| Conformance validator | Is this a legal OKF bundle? (§9) | validate |
| Curation linter | Is it navigable, complete, fresh? | lint / loose |
| Ranked text search | Which concept covers X? | search |
| Interactive graph server | Can I explore it visually? | server |
| Static render | Can I ship a serverless snapshot? | render |
| Library API | Can my Ruby program use it? | in-process |
And because knowledge rarely lives in one bundle, a per-user
registry gives each bundle a name: okf registry set ./docs
once, then @docs works anywhere a <dir> does — from any directory — and a
bare okf server hosts every registered bundle behind one hub.
[!TIP] Browse the gem as knowledge, not just docs. This README is the front door; the depth lives in the
.okf/bundle this repo ships. Start at the overview, then follow the graph into the capabilities (what it does), the design constraints (why it stays this light), and the format itself (what it operates on). Runokf server .okfto walk the same bundle as an interactive graph.
It is deliberately light so it runs on the Ruby your OS already ships:
- works on every Ruby since 2.4, the same floor as rack, its core dependency;
- only three runtime dependencies:
rack(the server is a mountable Rack app),webrick(unbundled from Ruby in 3.0), andminifts(the search engine — pure Ruby, no dependencies of its own, same 2.4 floor); - no ActiveSupport, no native extension, no build step, no JavaScript toolchain — the design constraints that hold this line are enforced by tests.
That range is not aspirational: CI runs the full test suite and RuboCop on every one of these on each push.
Try it in four steps
From zero to your first bundle.
1. Get the okf command. Two ways in; either one puts okf on your PATH.
gem install okf # with Ruby
curl -fsSL https://docker.okfgem.com/install.sh | sh # no Ruby? Docker
2. Install the skill. Teach your agent the format — Claude Code, or any other agent.
okf skill .claude # or: okf skill .agents
3. Start an agent session where your project lives.
claude
4. Make your first bundle. Two ways in, by what you already have: docs keep every word, code gets written up for you.
/okf migrate <path-to-your-docs> # have docs? adopted in place, bodies verbatim
/okf produce based on <path-to-your-code> # only code? the skill authors the concepts
[!TIP] Once you have a bundle, run
/okf maintainin the agent session to keep it in sync as the code changes, andokf server <folder>to explore it as a graph. In Claude Code, the plugin adds a post-edit curation hook that runsvalidate+lintfor you.
Why OKF
Project knowledge (why a service exists, what a metric really measures, the reasoning a schema encodes) lives scattered across wikis, code comments, and whoever happened to be in the room, and an agent re-derives it every session. OKF gives it one durable, diffable home, versioned next to the code it describes and read from the same file by people and agents alike. OKF is an open, vendor-neutral format (Google Cloud, 2026); this gem is the Ruby-native way to work with it.
Knowledge already has several homes near an agent, and each holds a different thing. None of the others is built for curated, durable team knowledge:
| OKF bundle (this) | CLAUDE.md / AGENTS.md |
Agent auto-memory | Wiki / Notion | |
|---|---|---|---|---|
| Holds | curated team knowledge | standing instructions | what one agent picked up | human docs |
| Versioned with the code | ✅ | ✅ | ❌ | ❌ |
| Portable across agents | ✅ plain Markdown + YAML | ⚠️ per-harness conventions | ❌ per-agent store | ⚠️ export needed |
| Typed and queryable | ✅ frontmatter + graph | ❌ prose | ❌ | ⚠️ partially |
| Reviewed in PRs | ✅ | ✅ | ❌ implicit | ⚠️ rarely |
| Scales past one context window | ✅ progressive disclosure ( okf index + search) |
❌ loaded whole | ⚠️ partially | n/a |
| Checked by tooling | ✅ exit codes for CI ( okf validate + lint) |
❌ | ❌ | ❌ |
The last two rows are this gem's job. Scaling past one context window is
progressive disclosure — okf index reads the map, okf search pulls only the
concepts a task needs, so the bundle is never loaded whole. And drift never
hides here: the other homes have no detector, but okf validate and lint turn
a bundle's drift into findings you can gate on in CI.
What a bundle looks like
A bundle is just a directory; each concept is one Markdown file whose path is its id. This repo documents itself in OKF, so the tree below is real:
.okf/
├── index.md # progressive-disclosure map (root carries okf_version)
├── log.md # ISO-dated change history, newest first
├── overview.md
├── format/frontmatter.md
├── model/graph.md
└── capabilities/graph-server.md # one concept = one file
The only hard requirement is YAML frontmatter with a non-empty type; everything
else is optional and tolerated when missing. A concept (here the real
capabilities/graph-server.md, body trimmed) reads:
---
type: Capability
title: Interactive graph server (server)
description: A self-contained HTML knowledge graph served over HTTP, and a mountable Rack app.
resource: lib/okf/server/app.rb
tags: [server, graph, rack, diagram]
timestamp: 2026-07-11T12:00:00Z
---
# Overview
`okf server` boots an interactive view of the [graph](../model/graph.md) …
That bundle is this gem's own documentation. Clone the repo and run
okf server .okf to browse it as the graph diagrammed at the top of this file.
Installation
In Claude Code, the plugin is the fastest path: two commands install the whole toolchain (skill,
/okf:gem, and the curation hook). See Claude Code plugin. Everywhere else, install the gem:
| Ruby version | 2.4 | 2.5 | 2.6 | 2.7 | 3.0 | 3.1 | 3.2 | 3.3 | 3.4 | 4.0 |
|---|---|---|---|---|---|---|---|---|---|---|
| Tested/Supported | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
gem install okf
# or, in a project
bundle add okf
From a checkout, this builds the gem and installs it into your Ruby environment,
putting the okf command on your PATH:
bundle exec rake install
Run it with Docker (no Ruby needed)
Prefer not to install Ruby? The official image bundles the CLI, so every okf
command runs against a bundle you mount at /data:
# validate / lint / search / index … mirror the CLI, over the mounted bundle
docker run --rm -v "$PWD:/data" ghcr.io/serradura/okf validate .
# serve the live graph: bind 0.0.0.0 so the host can reach it, and publish the port
docker run --rm -v "$PWD:/data" -p 8808:8808 ghcr.io/serradura/okf server . --bind 0.0.0.0
A container has to bind 0.0.0.0 for the host to reach it at all, which is
exactly the bind that makes the registry read-only. Reading the graph is
unaffected, and there is no flag that opens the registry on that bind — it is a
per-user file, managed from the machine that owns it or from okf registry.
Then open http://127.0.0.1:8808. Images are published for linux/amd64 and
linux/arm64 on
ghcr.io: :latest
tracks the newest release, or pin a version like :1.10.0.
Tired of the long line? Install a Docker-backed okf command,
so every verb drops the docker run prefix and reads exactly like the native CLI
(mount, port, and bind handled for you). Do this only on a machine without the
gem:
curl -fsSL https://docker.okfgem.com/install.sh | sh # or grab the script by hand
okf validate .
okf server .
On Windows the image runs under Docker Desktop (WSL2); install with PowerShell
instead: irm https://docker.okfgem.com/install.ps1 | iex.
Command line
These verbs are written to be read by an agent first and a person second —
that is what the skill drives, with no wrapper in between. Every read verb takes
--json, index/catalog/files project down to the fields you ask for
(--fields/--except), so nothing pays for output it will not read, and the
exit codes are stable enough to branch on in CI. The same commands render as
scannable plain text when a human is the one looking.
okf validate <dir|@slug> [--json] # check OKF v0.1 conformance (§9)
okf lint <dir|@slug> [--json] [--fail-on warn] [...] # report curation-quality issues
okf loose <dir|@slug> [--json] # list files with no graph links, by folder
okf search <dir|@slug…|@all> <term…> [--regexp|--fuzzy] # ranked retrieval; @slugs or @all span bundles
okf index <dir|@slug> [--json] [--area A] [--no-body] # progressive-disclosure map (§6): bodies, rollups, listings
okf server [DIR|@slug…] [-p PORT] [--bind ADDR] [...] # serve one bundle, or many behind a hub (⌘K searches every one)
okf render <dir|@slug> [-o FILE] [--layout NAME] [...] # export the graph as one static, self-contained HTML file
okf registry list [--json] # list registered bundles (* marks the default)
okf registry set <dir|@slug> [--as SLUG] [--default] # add or update a bundle (a bare `server` serves it)
okf registry del <dir|@slug> # remove a bundle from the registry
okf registry default <@slug> | rename <@slug> <new> # move a bundle to the front (the default) / rename it
# The registry is a plain JSON file at $OKF_HOME/registry.json (default ~/.okf).
# It is ordered, and the first entry is the default: `registry default @slug`
# moves that entry to the front. The subcommand leads and flags follow it:
# `registry set <dir> --as X`, never `registry --json set <dir>`.
# A running server reads it at boot — restart after changes.
# Behind a multi-bundle server, /b/ lists every bundle and ⌘/Ctrl-K switches.
# @slug names a registered bundle instead of a path — the slug from `registry
# set`, or bare @ for the default. Anywhere a <dir> goes, an @slug goes:
# okf lint @handbook works from anywhere. Set $OKF_HOME to point every verb
# at another registry.
okf graph <dir|@slug> [--json] [--minimal] [--hubs] # print the knowledge graph (--hubs ranks by inbound links)
okf catalog | files | tags | types | stats <dir|@slug> [--json] # the browser views, on the CLI
# `tags --by type|area` regroups the tag index per concept dimension; each row
# shows count/total, so a tag confined to one area (a domain) reads differently
# from one spread across several (a cross-cutting concern).
okf skill <dest> [--here] [--force] # install the companion agent skill
okf --version
Exit codes: 0 success, 1 non-conformant bundle (or a lint --fail-on
threshold crossed), 2 usage error.
$ okf validate docs
OKF v0.1 conformance — docs
concepts: 37 index.md: 10 log.md: 1
! warn features/link-suggestions.md: cross-link target not found: `/graph-view.md` (tolerated under §5.3)
…
✓ conformant (33 warning(s))
$ okf server docs
serving 37 concepts at http://127.0.0.1:8808 (Ctrl-C to stop)
$ okf render docs > public/index.html # the same page, static — host it anywhere
The graph server on this repo's own .okf bundle, with the
capabilities/graph-server concept selected. Try it live at
demo.okfgem.com.
The page is one template from a phone to a desktop: on small screens the
navigation rail becomes a drawer, the toolbar folds into a ⚙ sheet, and the
panels go full-bleed — rotate a tablet and the layout re-evaluates. On a touch
screen a tap opens a preview card at the bottom edge rather than a panel over
the whole viewport, so the graph stays on screen and live while you read: drag
the card up for the neighbourhood, tap a link in it and it walks there in place.
It is keyboard-first too: ⌘/Ctrl-K opens a command palette in every mode (views
always; bundles too when a hub is serving), /
jumps to the current view's search, and ? answers with a sheet of every
shortcut.
The search box says what it is doing while it does it: a live 7/8 count of
what the filter kept, and — when a word matches nothing here — a panel naming
the bundle and the query, offering to search every other bundle instead. The
query carries over, so nothing is typed twice.
To skip the server entirely, okf render <dir> writes that same page as one
self-contained HTML file, the whole bundle baked in, so you can publish the
graph on GitHub Pages or any static host.
One registry, many bundles
The registry is a per-user, ordered list of bundles in one
plain JSON file ($OKF_HOME/registry.json, default ~/.okf) — hand-editable,
greppable, no database. It stores references, never content: the bundles stay in
the repos that own them.
okf registry set ./docs --as handbook # give the bundle a name
okf lint @handbook # @slug works wherever a <dir> does, from anywhere
okf search @all rate limit # ranked retrieval across every registered bundle
okf server # no args: the whole registry behind one hub
The first entry still on disk is the default — the bundle a bare okf server opens at / and a bare @ names; okf registry default @slug moves an
entry to the front. Behind the hub each bundle mounts at /b/<slug>/, and the
⌘/Ctrl-K palette both switches bundles and searches every one of them at
once — type a few words and the matching concepts appear with their bundle and
a snippet, from wherever you are.
The ⚙ in the rail opens Bundles — the registry on the graph page itself, so
switching the default, renaming an entry or dropping one no longer means finding
/b/ first. Each row carries its size, its health as a word, and which one /
opens. There is no Add: registering a bundle means naming a filesystem path,
which a browser cannot hand over and an agent can (okf registry set <dir>), and
the panel says so instead of leaving the absence to be noticed.
/b/ is the bundles list: every bundle with its size, its health
(conformance plus curation, so a warning is a warning and not a failure), the
default marked, and any entry whose folder has gone missing shown rather than
quietly dropped.
Managing the registry without a terminal happens on the graph page instead, in
the ⚙ Bundles panel — make default, rename, remove, where you are already
reading. Those controls are the one thing that does not follow you onto a
network: bind anywhere but loopback and they are refused outright, with no flag
that says otherwise, since --bind 0.0.0.0 is how a personal tool becomes a
public one. --read-only declines them on loopback too, and is the only switch
there is. Writes rebuild the hub's set as they go, so a rename takes effect on
the next click; a registry change made elsewhere while it runs still wants a
restart to be served. Set $OKF_HOME to point every verb at a different registry.
graph and server are best-effort (§9): a file with invalid frontmatter is
skipped (and noted on stderr), not fatal, so one bad file never breaks the rest.
The graph server concept walks the request
flow and endpoints; the server trust boundary below
explains how the page handles a bundle you did not author.
lint (the curation linter) reports curation
quality (reachability, backlog, completeness, freshness, provenance, and hygiene)
separately from validate. It is advisory: it exits
0 even with findings unless you opt into gating with --fail-on warn.
$ okf lint docs
OKF lint — docs
concepts: 37 edges: 87 index.md: 10 log.md: 1
hubs: features/chat/sources/source-ingestion-pipeline (×12), …
Backlog
· info graph-view.md: referenced by 3 link(s) across 2 concept(s) but does not exist
! warn features/index.md: index links to missing concept `../../CHANGELOG.md`
Completeness
· info features/bundles/entry-editor.md: missing recommended field: description
Hygiene
! warn link-suggestions.md: reference-style link `[:approved_ids]` has no matching definition (an invisible broken link)
⚠ 3 warn, 31 info
That hubs: line is the bundle's centre of gravity — the concepts the most links
point at, with their inbound count. okf graph <dir> --hubs expands it into
the full ranking and, for each hub, the areas those links come from:
$ okf graph docs --hubs
Hubs — docs (38 of 40 concepts with inbound links)
storage/reconcile ×16 storage 6, shape 4, exploration 3, (root) 1, …
That second half is what decides whether a concept sits where it belongs: a hub
pulled in mostly from outside its own folder is usually homed by history rather
than by meaning. Together with okf tags <dir> --by area, it is the evidence the
skill's refine verb reads before proposing anything.
loose lists the files that float in the graph: concepts with no cross-links
in or out (graph degree 0), grouped by folder. It is a curation lens over
lint's unlinked check, distinct from orphan. An index.md listing makes a
file reachable (not an orphan) but is not a graph edge, so a listed file
can still be loose. A loose file may be fine: a terminal leaf like a backlog
item is loose by design. loose surfaces the set for you to judge and
always exits 0.
Agent skill
The gem carries the companion OKF agent skill:
a SKILL.md plus reference
and template files that teach a coding agent to author, maintain, and consume OKF
bundles and to drive the commands above. Because the skill ships inside the gem,
installing the gem already puts the skill on your machine, and the skill's
CLI reference can never drift from the executable it was released with.
Using Claude Code? The plugin below installs this same
skill plus a post-edit curation hook.
The skill routes a small set of verbs. In Claude Code they run as /okf:gem <verb>; used standalone, the skill infers the verb from your request.
| Verb | What it does |
|---|---|
| (none) | Orient on the bundle and recommend the highest-value next move |
search |
Answer a question from the bundle, token-lean: the map, the finder, only the winning bodies |
produce |
Create or extend a bundle from code, docs, or knowledge in people's heads |
migrate |
Adopt existing Markdown docs in place: frontmatter and reserved files added, bodies kept verbatim |
maintain |
Sync the bundle's content with reality after the code or docs change |
refine |
Restructure it for retrieval: evidence-first, cohesion over balance — proposes, never applies |
consume |
Use the bundle as context for a task, writing back what you learn |
curate |
Structural upkeep as it stands: validate + lint + loose |
doctor |
Install and verify the CLI, then doctor the bundle |
<okf-cli-verb> |
Run any CLI verb (validate, lint, search, index, server, the read views) and interpret its output |
Three of those look alike and are not, which is the distinction worth learning
first: curate keeps the bundle sound (the structure as it stands),
maintain keeps it true (the code changed, so the content must catch up),
and refine changes where knowledge lives — the folder a concept sits in,
a fact re-explained in three overviews. Reach for refine when nothing is wrong
and everything is hard to find: a folder grown to twenty concepts, a hub homed by
history, tags that neither connect nor mark. It reads the evidence, then hands
you a proposal — it never rearranges your bundle on its own.
Point it at your agent's config directory (or its skills directory) and the tree
settles in its own skills/okf/ folder, so a shared skills directory never gets
the files loose:
okf skill .claude # Claude Code -> .claude/skills/okf
okf skill .agents # agent-agnostic -> .agents/skills/okf
The destination is required (no default). The skill lands in <dest>/skills/okf,
unless <dest> already ends in skills (→ <dest>/okf) or okf (used as-is).
Pass --here to paste the tree straight into <dest>, wherever it is. The
resolved directory must be empty unless you pass --force, so a customized skill
is never clobbered.
Library
The gem (the library API) is two layers: pure
in-memory data (OKF::Concept, OKF::Bundle)
you build, interrogate, and analyze with no disk involved, and on-disk
handles (OKF::Concept::File, OKF::Bundle::Folder) that add
load/save/reload/delete, an "ActiveRecord for the filesystem".
Pure, in-memory (no disk)
Build knowledge straight from data, with no markdown round-trip, and run every feature against it. This is the surface an embedding app (e.g. a Rails store) uses to reuse the gem over knowledge it already holds as records:
require "okf"
concept = OKF::Concept.new(
path: "tables/orders.md",
frontmatter: { "type" => "BigQuery Table", "title" => "Orders" },
body: "Joined with [customers](/tables/customers.md).\n"
)
concept.id # => "tables/orders"
concept.links # => ["/tables/customers.md"] (spec §5 cross-links)
concept.citations # => [...] (spec §8 # Citations)
concept.external_links # => [...] (URLs / mailto:)
concept.to_markdown # => String (inverse of OKF::Markdown::Frontmatter.parse)
concept.lint # => OKF::Bundle::Linter::Report (the concept-scoped checks)
bundle = OKF::Bundle.new(concepts: [ concept ]) # also: reserved:, unparseable:
bundle.validate # => OKF::Bundle::Validator::Result (spec §9 conformance)
bundle.lint # => OKF::Bundle::Linter::Report (curation quality)
bundle.graph # => OKF::Bundle::Graph (#nodes, #edges, #to_h)
On disk
OKF::Bundle::Folder reads a directory into a pure bundle and materializes one
back; OKF::Concept::File is a single-file handle:
folder = OKF::Bundle::Folder.load("docs")
folder.bundle # => OKF::Bundle (the pure bundle it read)
folder.concepts # => [OKF::Concept] (reserved files excluded)
folder.validate; folder.lint; folder.graph # delegate to the pure core
folder.concept("tables/orders") # => OKF::Concept::File
require "okf/server/app" # the server loads on demand, like the CLI does
OKF::Server::App.new(folder) # => a Rack app: the interactive graph server
# build in memory, then write it out (validates §9 before publishing):
OKF::Bundle::Folder.new(bundle: bundle, root: "out/dir").save
file = OKF::Concept::File.read(root: "docs", path: "tables/orders.md")
file.concept # => OKF::Concept (pure)
file.save; file.delete; file.reload
The lower-level pieces are usable on their own too: OKF::Bundle::Validator.call(bundle),
OKF::Bundle::Linter.call(bundle, min_body: 50), OKF::Bundle::Graph.build(bundle),
OKF::Markdown::Frontmatter.parse(markdown). Mounting the graph in Rails, auth
included: the Rails guide walks it.
Conformance model
validate (the conformance validator) implements
the spec's §9 conformance definition
exactly. There are three hard conditions, all errors:
- §9.1 every non-reserved file has a parseable YAML frontmatter block;
- §9.2 every such block has a non-empty
type; - §9.3 every
index.md/log.mdpresent follows §6/§7: a nestedindex.mdhas no frontmatter, a rootindex.mdcarries onlyokf_version, andlog.mddate headings are ISOYYYY-MM-DD.
Everything the spec marks as soft guidance is a warning and never makes a
bundle non-conformant: missing recommended fields, non-list tags, an unparseable
timestamp, and broken cross-links (§5.3), which consumers MUST tolerate.
OKF::Bundle::Folder#save validates before publishing, so it never writes a
bundle that fails §9.
Curation model (lint)
validate asks "is this §9-conformant?" and is forbidden by §9 to reject for
broken links or missing optional fields. lint asks the complementary question,
"is this well-curated, navigable, trustworthy?", over exactly those tolerated
things. The two stay separate: lint has its own OKF::Bundle::Linter and
report, never emits conformance errors, and is advisory unless you pass
--fail-on warn.
Checks span six categories: reachability (orphans, not-in-index, disconnected
islands, unlinked), backlog (demand-ranked missing concepts, broken index entries),
completeness (stubs, missing title/description/timestamp), freshness
(--stale-after), provenance (uncited external claims, broken citations,
spec §8), and hygiene (duplicate titles, unused/undefined reference links,
self-links). Select with --only/--except; --json emits the full report as JSON.
Two loop concerns from the format's own guidance, contradictions and semantic
staleness, need to understand meaning and are not computed here; lint --json
is the structured input an agent consumes to reason about those.
Extending okf
This is the other kind of plugin, and it is worth separating from the
Claude Code plugin below: that one teaches an agent to
use okf, while this one adds behavior to the okf command everyone runs.
Publish a gem named okf-* that carries an okf/plugin.rb, and installing it is
the whole installation: your verb answers to okf, appears in okf help under
installed extensions:, and behaves like a built-in — nothing to register,
nothing to configure, no list of known addons in this gem. The same seam takes
retrieval backends, which is what okf search --engine NAME chooses between.
Two promises make that safe to install: nothing an addon registers can displace a built-in, and a broken addon is skipped and reported rather than taking the CLI down with it.
The extension points concept has the contract
and the threat model; test/integration/cli/cli_plugin_test.rb is a working
example to copy.
Server trust boundary
[!NOTE] The graph page defends against a bundle that carries active content in two places. It escapes any graph data inlined into the page (
<becomes<), which keeps that data from breaking out of its<script>. And it fetches each concept body on demand, then runs marked's HTML output through DOMPurify before it reaches the DOM, so a script or event handler hidden in a Markdown body is stripped rather than executed. Descriptions are escaped on the server.That covers the paths that could run code. The page still loads Cytoscape, marked, and DOMPurify from a CDN and renders whatever links and diagrams a body contains, so treat an unfamiliar bundle the way you would treat any document from a source you do not know.
The server trust boundary concept has the full write-up: the two data paths, what sanitizing does, and what it leaves to your judgment.
Claude Code plugin
This repository doubles as a Claude Code plugin marketplace, so the whole toolchain installs with two commands inside Claude Code:
/plugin marketplace add serradura/okf-gem
/plugin install okf@okfgem
The plugin carries three pieces:
| Piece | What it does |
|---|---|
okf skill |
The companion skill above, bundled with the plugin (a generated copy that rake plugin:sync keeps identical to lib/okf/skill). |
/okf:gem |
The front door: a pass-through that hands its arguments to the skill unchanged, so the verb table above is the whole routing story — doctor installs and verifies the CLI, curate runs the full cycle (validate + lint + loose), produce/migrate/maintain/consume and any CLI verb do what they say. No arguments: orients on the CLI, the bundle, and what validate/lint report, then recommends the highest-value next move (never auto-runs). |
| Curation hook | After every Write or Edit inside a bundle, runs okf validate + okf lint and returns the findings as context. The checks are the CLI's own, so the feedback is deterministic. |
The hook stays silent outside bundles, and when the CLI is missing it suggests
/okf:gem once per session instead of failing on each edit. It is config-free to
switch off: set OKF_CURATE_DISABLED=1 to turn it off, OKF_CURATE_QUIET=1 to
keep the findings but drop that suggestion, or drop an <!-- okf-disable -->
comment into a file to skip curation for that one.
Prefer no plugin? gem install okf && okf skill .claude installs the skill
alone, and the skill itself instructs the agent to run the same checks after
editing a bundle.
Development
bin/setup # install dependencies
bundle exec rake # tests + RuboCop (what CI runs)
bundle exec rake test # just the test suite
ruby -Ilib exe/okf validate <dir> # run the CLI from a checkout
The suite runs on every supported Ruby; to check the 2.4 floor locally:
docker run --rm -v "$PWD":/src:ro ruby:2.4 bash -c \
"cp -a /src /build && cd /build && rm -f Gemfile.lock && bundle install --quiet && bundle exec rake test"
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/serradura/okf-gem. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
License
The gem is available as open source under the terms of the
Apache License 2.0 (see
LICENSE.txt). The Open Knowledge Format specification bundled with the skill
is authored by Google Cloud Platform and included under its own Apache-2.0
license, Copyright (c) Google LLC. See NOTICE and
lib/okf/skill/reference/APACHE-2.0.txt.
okf-skills by Marco Boffo, a Python
OKF toolkit for Claude Code with a feature-rich interactive graph view, was an
early inspiration for this gem's Claude Code plugin and for the knowledge-as-code
comparison in Why OKF. okf-gem takes a different shape: a Ruby-native
gem built around the okf CLI and an embeddable library.