okf 1.11.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +193 -1
- data/README.md +77 -428
- data/lib/okf/bundle/folder.rb +25 -2
- data/lib/okf/bundle/reader.rb +39 -16
- data/lib/okf/bundle/search.rb +5 -5
- data/lib/okf/bundle/skeleton.rb +241 -0
- data/lib/okf/bundle.rb +37 -17
- data/lib/okf/cli/catalog.rb +6 -6
- data/lib/okf/cli/command.rb +139 -19
- data/lib/okf/cli/dirs.rb +1 -1
- data/lib/okf/cli/files.rb +1 -1
- data/lib/okf/cli/graph.rb +115 -9
- data/lib/okf/cli/index.rb +2 -2
- data/lib/okf/cli/registry.rb +152 -15
- data/lib/okf/cli/render.rb +3 -2
- data/lib/okf/cli/search.rb +53 -8
- data/lib/okf/cli/server.rb +9 -5
- data/lib/okf/cli/stats.rb +8 -8
- data/lib/okf/cli/tags.rb +2 -2
- data/lib/okf/cli.rb +3 -3
- data/lib/okf/concept/file.rb +17 -2
- data/lib/okf/path.rb +17 -3
- data/lib/okf/registry.rb +351 -20
- data/lib/okf/render/graph/template.html.erb +211 -7
- data/lib/okf/render/graph.rb +27 -3
- data/lib/okf/safe_read.rb +50 -0
- data/lib/okf/server/app.rb +13 -3
- data/lib/okf/server/hub.rb +5 -3
- data/lib/okf/skill/SKILL.md +5 -1
- data/lib/okf/skill/playbooks/menu.md +2 -1
- data/lib/okf/skill/playbooks/refine.md +26 -0
- data/lib/okf/skill/reference/cli.md +81 -21
- data/lib/okf/version.rb +1 -1
- data/lib/okf.rb +2 -0
- metadata +4 -3
- data/CODE_OF_CONDUCT.md +0 -10
data/README.md
CHANGED
|
@@ -1,240 +1,66 @@
|
|
|
1
|
-
|
|
2
|
-
<a href="https://okfgem.com">
|
|
3
|
-
<picture>
|
|
4
|
-
<source media="(prefers-color-scheme: dark)" srcset=".github/hero-dark.png">
|
|
5
|
-
<img src=".github/hero-light.png" width="100%" alt="okf-gem, the Open Knowledge Format toolkit. Everything OKF, in one gem: author, curate, and consume your project's knowledge, with your agent. 100% local. Start at https://okfgem.com/#try. Three pieces in one install: the Agent Skill (the brain) authors, curates and consumes; the CLI/Lib (the muscle) validates, lints and does full-text search; the Graph (the dashboard) searches and explores it, live or static. Available from RubyGems, as a Docker image, and as a Claude Code plugin.">
|
|
6
|
-
</picture>
|
|
7
|
-
</a>
|
|
8
|
-
</p>
|
|
9
|
-
|
|
10
|
-
<p align="center">
|
|
11
|
-
<a href="https://rubygems.org/gems/okf"><img src="https://img.shields.io/gem/v/okf" alt="Gem version"></a>
|
|
12
|
-
<a href="https://rubygems.org/gems/okf"><img src="https://img.shields.io/gem/dt/okf" alt="Downloads"></a>
|
|
13
|
-
<a href="https://github.com/serradura/okf-gem/pkgs/container/okf"><img src="https://img.shields.io/badge/ghcr.io-okf-2496ED?logo=docker&logoColor=white" alt="Docker image"></a>
|
|
14
|
-
<a href="https://github.com/serradura/okf-gem/actions/workflows/main.yml"><img src="https://github.com/serradura/okf-gem/actions/workflows/main.yml/badge.svg" alt="CI"></a>
|
|
15
|
-
<a href="https://github.com/serradura/okf-gem"><img src="https://img.shields.io/badge/ruby-%3E%3D%202.4-black" alt="Ruby >= 2.4"></a>
|
|
16
|
-
<a href="LICENSE.txt"><img src="https://img.shields.io/badge/license-Apache--2.0-blue" alt="License: Apache-2.0"></a>
|
|
17
|
-
<a href="lib/okf/skill/reference/SPEC.md"><img src="https://img.shields.io/badge/OKF-v0.1-6E56CF" alt="OKF v0.1"></a>
|
|
18
|
-
<a href="#claude-code-plugin"><img src="https://img.shields.io/badge/Claude%20Code-plugin-D97757" alt="Claude Code plugin"></a>
|
|
19
|
-
</p>
|
|
20
|
-
|
|
21
|
-
<p align="center">
|
|
22
|
-
<b><a href="https://okfgem.com">Site</a></b> ·
|
|
23
|
-
<b><a href="https://okfgem.com/docs/">Docs</a></b> ·
|
|
24
|
-
<b><a href="https://demo.okfgem.com">Live demo</a></b> ·
|
|
25
|
-
<b><a href="https://claude.okfgem.com">Claude plugin</a></b> ·
|
|
26
|
-
<b><a href="https://docker.okfgem.com">Docker image</a></b>
|
|
27
|
-
</p>
|
|
28
|
-
|
|
29
|
-
**okf-gem** (`okf` on RubyGems or Docker) gives your project's knowledge one
|
|
30
|
-
durable home in your repo, in Markdown your team and your agents both read: the
|
|
31
|
-
decisions and the reasoning an agent cannot re-derive from the code, versioned
|
|
32
|
-
beside the code they explain.
|
|
33
|
-
|
|
34
|
-
One install carries the whole workflow, and that is the point of a single gem:
|
|
35
|
-
|
|
36
|
-
- an **Agent Skill**, so your agent writes and curates the knowledge instead of you;
|
|
37
|
-
- a **CLI and Ruby library**, so it stays correct: validated, linted, and searchable in milliseconds;
|
|
38
|
-
- a **Graph**, so anyone can see the shape of what the team knows, live or as one static file you can host anywhere.
|
|
39
|
-
|
|
40
|
-
The package is **Agent Skill + CLI/Lib + Graph**. It runs 100% local, adds no
|
|
41
|
-
service to your stack, and does not define a new place to keep knowledge: it
|
|
42
|
-
gives you leverage over the Markdown you already have.
|
|
43
|
-
|
|
44
|
-
## Why OKF
|
|
45
|
-
|
|
46
|
-
Project knowledge (why a service exists, what a metric really measures, the
|
|
47
|
-
reasoning a schema encodes) lives scattered across wikis, code comments, and
|
|
48
|
-
whoever happened to be in the room, and an agent re-derives it every session. OKF
|
|
49
|
-
gives it one durable, diffable home, versioned next to the code it describes and
|
|
50
|
-
read from the same file by people and agents alike. [OKF][okf] is an open,
|
|
51
|
-
vendor-neutral format (Google Cloud, 2026); this gem is the Ruby-native way to
|
|
52
|
-
work with it.
|
|
53
|
-
|
|
54
|
-
[okf]: https://cloud.google.com/blog/products/data-analytics/how-the-open-knowledge-format-can-improve-data-sharing
|
|
55
|
-
|
|
56
|
-
Knowledge already has several homes near an agent, and each holds a different
|
|
57
|
-
thing. None of the others is built for curated, durable team knowledge:
|
|
58
|
-
|
|
59
|
-
| | OKF bundle (this) | `CLAUDE.md` / `AGENTS.md` | Agent auto-memory | Wiki / Notion |
|
|
60
|
-
| ------------------------------ | ----------------------------------------------------- | -------------------------- | ------------------------ | ---------------- |
|
|
61
|
-
| Holds | curated team knowledge | standing instructions | what one agent picked up | human docs |
|
|
62
|
-
| Versioned with the code | ✅ | ✅ | ❌ | ❌ |
|
|
63
|
-
| Portable across agents | ✅ plain Markdown + YAML | ⚠️ per-harness conventions | ❌ per-agent store | ⚠️ export needed |
|
|
64
|
-
| Typed and queryable | ✅ frontmatter + graph | ❌ prose | ❌ | ⚠️ partially |
|
|
65
|
-
| Reviewed in PRs | ✅ | ✅ | ❌ implicit | ⚠️ rarely |
|
|
66
|
-
| Scales past one context window | ✅ progressive disclosure<br>(`okf index` + `search`) | ❌ loaded whole | ⚠️ partially | n/a |
|
|
67
|
-
| Checked by tooling | ✅ exit codes for CI<br>(`okf validate` + `lint`) | ❌ | ❌ | ❌ |
|
|
68
|
-
|
|
69
|
-
The last two rows are this gem's job. Scaling past one context window is
|
|
70
|
-
progressive disclosure — `okf index` reads the map, `okf search` pulls only the
|
|
71
|
-
concepts a task needs, so the bundle is never loaded whole. And drift never
|
|
72
|
-
hides here: the other homes have no detector, but `okf validate` and `lint` turn
|
|
73
|
-
a bundle's drift into findings you can gate on in CI.
|
|
74
|
-
|
|
75
|
-
## What a bundle looks like
|
|
76
|
-
|
|
77
|
-
A bundle is just a directory; each concept is one Markdown file whose path is its
|
|
78
|
-
id. This repo documents _itself_ in OKF, so the tree below is real:
|
|
1
|
+
# okf
|
|
79
2
|
|
|
80
|
-
|
|
81
|
-
.
|
|
82
|
-
├── index.md # progressive-disclosure map (root carries okf_version)
|
|
83
|
-
├── log.md # ISO-dated change history, newest first
|
|
84
|
-
├── overview.md
|
|
85
|
-
├── format/frontmatter.md
|
|
86
|
-
├── model/graph.md
|
|
87
|
-
└── capabilities/graph-server.md # one concept = one file
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
The only hard requirement is YAML frontmatter with a non-empty `type`; everything
|
|
91
|
-
else is optional and tolerated when missing. A concept (here the real
|
|
92
|
-
`capabilities/graph-server.md`, body trimmed) reads:
|
|
93
|
-
|
|
94
|
-
```markdown
|
|
95
|
-
---
|
|
96
|
-
type: Capability
|
|
97
|
-
title: Interactive graph server (server)
|
|
98
|
-
description: A self-contained HTML knowledge graph served over HTTP, and a mountable Rack app.
|
|
99
|
-
resource: lib/okf/server/app.rb
|
|
100
|
-
tags: [server, graph, rack, diagram]
|
|
101
|
-
timestamp: 2026-07-11T12:00:00Z
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
# Overview
|
|
3
|
+
**The complete Open Knowledge Format toolkit: an agent skill, a CLI and library,
|
|
4
|
+
ranked search, and a live knowledge graph. 100% local.**
|
|
105
5
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
That bundle is this gem's own documentation. Clone the repo and run
|
|
110
|
-
`okf server .okf` to browse it as an interactive graph.
|
|
111
|
-
|
|
112
|
-
## Try it in four steps
|
|
6
|
+
[Site](https://okfgem.com) · [Docs](https://okfgem.com/docs/) ·
|
|
7
|
+
[Live demo](https://demo.okfgem.com) ·
|
|
8
|
+
[Project README](https://github.com/serradura/okf-gem#readme)
|
|
113
9
|
|
|
114
|
-
|
|
10
|
+
OKF (Open Knowledge Format) is portable project knowledge: Markdown files with
|
|
11
|
+
YAML frontmatter that both humans and agents read from one source. This gem is
|
|
12
|
+
the Ruby-native way to work with it — the decisions and the reasoning an agent
|
|
13
|
+
cannot re-derive from the code, versioned beside the code they explain.
|
|
115
14
|
|
|
116
|
-
|
|
15
|
+
One install carries the whole workflow: an **Agent Skill** so your agent writes
|
|
16
|
+
and curates the knowledge, a **CLI and Ruby library** so it stays correct, and a
|
|
17
|
+
**Graph** so anyone can see the shape of what the team knows.
|
|
117
18
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
```
|
|
19
|
+
It adds no service to your stack. `rack`, `webrick` and `minifts` are the only
|
|
20
|
+
runtime dependencies, there is no native extension and no build step, and it runs
|
|
21
|
+
on every Ruby since **2.4** — the one your OS already ships.
|
|
122
22
|
|
|
123
|
-
|
|
124
|
-
other agent.
|
|
23
|
+
## Install
|
|
125
24
|
|
|
126
25
|
```bash
|
|
127
|
-
|
|
26
|
+
gem install okf
|
|
27
|
+
# or, in a project
|
|
28
|
+
bundle add okf
|
|
128
29
|
```
|
|
129
30
|
|
|
130
|
-
|
|
31
|
+
No Ruby? The official image carries the CLI:
|
|
131
32
|
|
|
132
33
|
```bash
|
|
133
|
-
|
|
34
|
+
docker run --rm -v "$PWD:/data" ghcr.io/serradura/okf validate .
|
|
134
35
|
```
|
|
135
36
|
|
|
136
|
-
|
|
137
|
-
every
|
|
37
|
+
The Docker-backed [`okf` command](https://docker.okfgem.com) drops the prefix so
|
|
38
|
+
every verb reads exactly like the native CLI.
|
|
138
39
|
|
|
139
|
-
|
|
140
|
-
/okf migrate <path-to-your-docs> # have docs? adopted in place, bodies verbatim
|
|
141
|
-
/okf produce based on <path-to-your-code> # only code? the skill authors the concepts
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
> [!TIP]
|
|
145
|
-
> **Once you have a bundle**, run `/okf maintain` in the agent session to keep it
|
|
146
|
-
> in sync as the code changes, and `okf server <folder>` to explore it as a graph.
|
|
147
|
-
> In Claude Code, the [plugin](#claude-code-plugin) adds a post-edit curation hook
|
|
148
|
-
> that runs `validate` + `lint` for you.
|
|
149
|
-
|
|
150
|
-
The package, end to end:
|
|
151
|
-
|
|
152
|
-
<p align="center">
|
|
153
|
-
<picture>
|
|
154
|
-
<source media="(prefers-color-scheme: dark)" srcset=".github/overview-dark.png">
|
|
155
|
-
<img src=".github/overview-light.png" width="760" alt="The package: the Agent Skill (your coding agent authors and curates, you stay the editor) writes and maintains the bundle, a folder of Markdown + YAML in your repo where one concept is one file and links between files are the knowledge graph. The bundle is read by the CLI/Lib (validate: legal OKF per section 9; lint: well-curated and fresh; search: ranked retrieval; require okf for Ruby objects) and by the Graph, in four modes: okf server (a live local server), okf render (the same page exported as one static, self-contained HTML file you can host anywhere), okf registry (every registered bundle behind one hub), and OKF::Server::App (the Rack app mounted in a Rails route). One gem, 100% local, Ruby 2.4 or newer, only rack, webrick and minifts as dependencies.">
|
|
156
|
-
</picture>
|
|
157
|
-
</p>
|
|
158
|
-
|
|
159
|
-
What the gem does, and which verb does it. This table is the map; **[the
|
|
160
|
-
docs](https://okfgem.com/docs/)** are the manual.
|
|
161
|
-
|
|
162
|
-
| Capability | What it answers | Verb |
|
|
163
|
-
| ------------------------------------------------------------- | --------------------------------- | -------------------------- |
|
|
164
|
-
| [Companion agent skill](https://okfgem.com/docs/skill/) | Can an agent author it? | `skill` |
|
|
165
|
-
| [Conformance validator](https://okfgem.com/docs/cli/validate/) | Is this a legal OKF bundle? | `validate` |
|
|
166
|
-
| [Curation linter](https://okfgem.com/docs/cli/lint/) | Is it navigable, complete, fresh? | `lint` / `loose` |
|
|
167
|
-
| [Ranked text search](https://okfgem.com/docs/cli/search/) | Which concept covers X? | `search` |
|
|
168
|
-
| [Read views](https://okfgem.com/docs/cli/) | What is in here, and where? | `index` / `dirs` / `catalog` |
|
|
169
|
-
| [Interactive graph server](https://okfgem.com/docs/cli/server/) | Can I explore it visually? | `server` |
|
|
170
|
-
| [Static render](https://okfgem.com/docs/cli/render/) | Can I ship a serverless snapshot? | `render` |
|
|
171
|
-
| [Library API](https://okfgem.com/docs/library/) | Can my Ruby program use it? | in-process |
|
|
172
|
-
|
|
173
|
-
And because knowledge rarely lives in one bundle, a per-user
|
|
174
|
-
[registry](.okf/registry.md) gives each bundle a name: `okf registry set ./docs`
|
|
175
|
-
once, then `@docs` works anywhere a `<dir>` does — from any directory — and a
|
|
176
|
-
bare `okf server` hosts every registered bundle behind one hub.
|
|
177
|
-
|
|
178
|
-
> [!TIP]
|
|
179
|
-
> **Browse the gem as knowledge, not just docs.** This README is the front door;
|
|
180
|
-
> the depth lives in the [`.okf/`](.okf) bundle this repo ships. Start at the
|
|
181
|
-
> [overview](.okf/overview.md), then follow the graph into the
|
|
182
|
-
> [capabilities](.okf/capabilities/) (what it does), the
|
|
183
|
-
> [design constraints](.okf/design/) (why it stays this light), and the
|
|
184
|
-
> [format itself](.okf/format/) (what it operates on). Run `okf server .okf` to
|
|
185
|
-
> walk the same bundle as an interactive graph.
|
|
186
|
-
|
|
187
|
-
**It installs on the Ruby your OS already ships** — every Ruby since 2.4, three
|
|
188
|
-
small dependencies, no native extension and no build step — so there is nothing
|
|
189
|
-
to provision and nothing to keep up to date. The
|
|
190
|
-
[design constraints](.okf/design/) that hold that line are enforced by tests on
|
|
191
|
-
every supported Ruby.
|
|
192
|
-
|
|
193
|
-
## Installation
|
|
194
|
-
|
|
195
|
-
> **In Claude Code**, the plugin is the fastest path: two commands install the whole
|
|
196
|
-
> toolchain (skill, `/okf:gem`, and the curation hook). See
|
|
197
|
-
> [Claude Code plugin](#claude-code-plugin). Everywhere else, install the gem:
|
|
40
|
+
## Four steps to your first bundle
|
|
198
41
|
|
|
199
42
|
```bash
|
|
200
|
-
|
|
201
|
-
#
|
|
202
|
-
bundle add okf
|
|
43
|
+
okf skill .claude # 1. teach your agent the format (or: okf skill .agents)
|
|
44
|
+
claude # 2. start an agent session where your project lives
|
|
203
45
|
```
|
|
204
46
|
|
|
205
|
-
Tested and supported on every Ruby from **2.4 through 4.0**. From a checkout,
|
|
206
|
-
`bundle exec rake install` builds and installs it locally.
|
|
207
|
-
|
|
208
|
-
### No Ruby? Use Docker
|
|
209
|
-
|
|
210
|
-
The official image bundles the CLI, so every `okf` command runs against a bundle
|
|
211
|
-
you mount at `/data`:
|
|
212
|
-
|
|
213
|
-
```bash
|
|
214
|
-
docker run --rm -v "$PWD:/data" ghcr.io/serradura/okf validate .
|
|
215
|
-
docker run --rm -v "$PWD:/data" -p 8808:8808 ghcr.io/serradura/okf server . --bind 0.0.0.0
|
|
216
47
|
```
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
48
|
+
/okf migrate <path-to-your-docs> # 3a. have docs? adopted in place, bodies verbatim
|
|
49
|
+
/okf produce based on <path-to-your-code> # 3b. only code? the skill authors the concepts
|
|
50
|
+
```
|
|
220
51
|
|
|
221
52
|
```bash
|
|
222
|
-
|
|
223
|
-
okf validate .
|
|
224
|
-
okf server .
|
|
53
|
+
okf server <folder> # 4. explore what you got, as a live graph
|
|
225
54
|
```
|
|
226
55
|
|
|
227
|
-
|
|
228
|
-
[ghcr.io](https://github.com/serradura/okf-gem/pkgs/container/okf).
|
|
56
|
+
Then `/okf maintain` keeps it in sync as the code changes.
|
|
229
57
|
|
|
230
|
-
##
|
|
58
|
+
## The command line
|
|
231
59
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
exit codes are stable enough to branch on in CI. The same commands render as
|
|
237
|
-
scannable plain text when a human is the one looking.
|
|
60
|
+
Written to be read by an **agent first and a person second** — that is what the
|
|
61
|
+
skill drives, with no wrapper in between. Every read verb takes `--json`, the
|
|
62
|
+
list views project down to the fields you ask for (`--fields`/`--except`), and
|
|
63
|
+
the exit codes are stable enough to branch on in CI.
|
|
238
64
|
|
|
239
65
|
```bash
|
|
240
66
|
okf validate <dir|@slug> # is this legal OKF?
|
|
@@ -244,10 +70,10 @@ okf search <dir|@slug…|@all> <term…> # ranked retrieval; @all sp
|
|
|
244
70
|
okf index <dir|@slug> [--dir D] [--depth N] # the §6 map: index bodies, rollups, listings
|
|
245
71
|
okf dirs <dir|@slug> [--dir D] [--depth N] # the shape: every directory and what it holds
|
|
246
72
|
okf catalog | files | tags | types | stats <dir|@slug> # the browser views, on the CLI
|
|
247
|
-
okf graph <dir|@slug> [--hubs]
|
|
73
|
+
okf graph <dir|@slug> [--hubs] [--traffic] # the raw graph; --hubs ranks concepts, --traffic dirs
|
|
248
74
|
okf server [DIR|@slug…] [-p PORT] [--bind ADDR] # the live graph: one bundle, or all of them
|
|
249
75
|
okf render <dir|@slug> [-o FILE] # the same page as one static, self-contained file
|
|
250
|
-
okf registry list | set | del | default | rename
|
|
76
|
+
okf registry init | list | set | del | default | rename | group | ungroup # name & group your bundles
|
|
251
77
|
okf skill <dest> # install the companion agent skill
|
|
252
78
|
okf --version
|
|
253
79
|
```
|
|
@@ -256,146 +82,23 @@ Exit codes: `0` success, `1` non-conformant bundle (or a `lint --fail-on`
|
|
|
256
82
|
threshold crossed), `2` usage error. Every flag is in `okf <verb> --help` and in
|
|
257
83
|
[the docs](https://okfgem.com/docs/).
|
|
258
84
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
…
|
|
265
|
-
✓ conformant (33 warning(s))
|
|
266
|
-
|
|
267
|
-
$ okf server docs
|
|
268
|
-
serving 37 concepts at http://127.0.0.1:8808 (Ctrl-C to stop)
|
|
269
|
-
|
|
270
|
-
$ okf render docs > public/index.html # the same page, static — host it anywhere
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
### Reading a big bundle a level at a time
|
|
274
|
-
|
|
275
|
-
A few hundred concepts is a map nobody reads whole, so `index` and `dirs` descend
|
|
276
|
-
instead of dumping. `--dir` takes a directory **and everything under it**,
|
|
277
|
-
`--depth N` bounds how far below that it goes, and the two compose the way you
|
|
278
|
-
actually walk a tree:
|
|
279
|
-
|
|
280
|
-
```bash
|
|
281
|
-
okf dirs @handbook # the shape: every dir, what it holds directly and below
|
|
282
|
-
okf index @handbook --depth 1 --no-body # the top of the map, no prose
|
|
283
|
-
okf index @handbook --dir platform/api # now open one branch — with the chain that places it
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
Naming a `--dir` brings its ancestors along, marked `↑`, so a branch is never
|
|
287
|
-
shown adrift of the context that says what it is — the root `index.md`'s prose
|
|
288
|
-
first among it.
|
|
85
|
+
**A registry names your bundles.** `okf registry set ./docs --as handbook` once,
|
|
86
|
+
then `@handbook` works anywhere a `<dir>` does, from any directory; `okf search
|
|
87
|
+
@all rate limit` spans every one of them, and a bare `okf server` hosts them all
|
|
88
|
+
behind one hub. `okf registry init` scopes one to a single project instead, and a
|
|
89
|
+
committed `.okf-registry.json` travels with the repo.
|
|
289
90
|
|
|
290
|
-
|
|
291
|
-
`
|
|
91
|
+
**A big bundle is read a level at a time.** `okf index --depth 1 --except
|
|
92
|
+
body,listing` is the map an agent orients on — on a 400-concept bundle, 2.8 KB
|
|
93
|
+
against the full 313 KB — and `--dir` then opens one branch, bringing the
|
|
94
|
+
ancestors that say what it is.
|
|
292
95
|
|
|
293
|
-
|
|
294
|
-
okf index @handbook --json --depth 1 --except body,listing
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
## The graph
|
|
298
|
-
|
|
299
|
-
<picture>
|
|
300
|
-
<source media="(prefers-color-scheme: dark)" srcset=".github/server-dark.png">
|
|
301
|
-
<img src=".github/server-light.png" alt="The okf graph server: a force-directed knowledge graph with a concept selected, its neighbors highlighted and the rest of the bundle dimmed, and the inspector panel showing the concept's type, description, tags, and every concept it links to and from, each labelled with its type.">
|
|
302
|
-
</picture>
|
|
303
|
-
|
|
304
|
-
_The graph server on this repo's own [`.okf`](.okf) bundle, with the `overview`
|
|
305
|
-
concept selected. Try it live at
|
|
306
|
-
**[demo.okfgem.com](https://demo.okfgem.com)**._
|
|
307
|
-
|
|
308
|
-
One page, from a phone to a desktop: the navigation rail becomes a drawer, the
|
|
309
|
-
toolbar folds into a `⚙` sheet, and a tap opens a preview card at the bottom edge
|
|
310
|
-
rather than a panel over the whole viewport, so the graph stays live while you
|
|
311
|
-
read. Drag the card up for the neighbourhood, tap a link and it walks there in
|
|
312
|
-
place.
|
|
313
|
-
|
|
314
|
-
It is keyboard-first: **`⌘/Ctrl-K`** opens a command palette that searches
|
|
315
|
-
concepts, jumps to a view, and — behind a [hub](#one-registry-many-bundles) —
|
|
316
|
-
switches bundles. **`/`** jumps to the current view's search, **`?`** answers with
|
|
317
|
-
every shortcut. Cluster mode boxes the graph by directory and nests as deep as
|
|
318
|
-
your tree does.
|
|
319
|
-
|
|
320
|
-
To skip the server entirely, **`okf render <dir>`** writes that same page as one
|
|
321
|
-
self-contained HTML file, the whole bundle baked in, so you can publish the graph
|
|
322
|
-
on GitHub Pages or any static host.
|
|
323
|
-
|
|
324
|
-
### One registry, many bundles
|
|
325
|
-
|
|
326
|
-
The [registry](.okf/registry.md) is a per-user, ordered list of bundles in one
|
|
327
|
-
plain JSON file (`$OKF_HOME/registry.json`, default `~/.okf`) — hand-editable,
|
|
328
|
-
greppable, no database. It stores references, never content: the bundles stay in
|
|
329
|
-
the repos that own them.
|
|
330
|
-
|
|
331
|
-
```bash
|
|
332
|
-
okf registry set ./docs --as handbook # give the bundle a name
|
|
333
|
-
okf lint @handbook # @slug works wherever a <dir> does, from anywhere
|
|
334
|
-
okf search @all rate limit # ranked retrieval across every registered bundle
|
|
335
|
-
okf server # no args: the whole registry behind one hub
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
Behind the hub each bundle mounts at `/b/<slug>/`, `/b/` lists them all, and the
|
|
339
|
-
`⌘/Ctrl-K` palette both switches bundles and **searches every one at once** — type
|
|
340
|
-
a few words and the matching concepts appear with their bundle and a snippet, from
|
|
341
|
-
wherever you are.
|
|
342
|
-
|
|
343
|
-
The ⚙ rail opens **Bundles**, the registry on the graph page itself: make
|
|
344
|
-
default, rename, remove, where you are already reading. Those controls are the one
|
|
345
|
-
thing that does not follow you onto a network — bind anywhere but loopback and
|
|
346
|
-
they are refused outright, since `--bind 0.0.0.0` is how a personal tool becomes a
|
|
347
|
-
public one.
|
|
348
|
-
|
|
349
|
-
## Agent skill
|
|
350
|
-
|
|
351
|
-
The gem carries the [companion OKF agent skill](.okf/capabilities/agent-skill.md):
|
|
352
|
-
a `SKILL.md` plus reference and template files that teach a coding agent to
|
|
353
|
-
author, maintain, and consume OKF bundles and to drive the commands above.
|
|
354
|
-
Because the skill ships inside the gem, installing the gem already puts the skill
|
|
355
|
-
on your machine, and the skill's CLI reference can never drift from the
|
|
356
|
-
executable it was released with.
|
|
357
|
-
|
|
358
|
-
The skill routes a small set of verbs. In Claude Code they run as `/okf:gem
|
|
359
|
-
<verb>`; used standalone, the skill infers the verb from your request.
|
|
360
|
-
|
|
361
|
-
| Verb | What it does |
|
|
362
|
-
| ---------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
363
|
-
| _(none)_ | Orient on the bundle and recommend the highest-value next move |
|
|
364
|
-
| `search` | Answer a question from the bundle, token-lean: the map, the finder, only the winning bodies |
|
|
365
|
-
| `produce` | Create or extend a bundle from code, docs, or knowledge in people's heads |
|
|
366
|
-
| `migrate` | Adopt existing Markdown docs in place: frontmatter and reserved files added, bodies kept verbatim |
|
|
367
|
-
| `maintain` | Sync the bundle's content with reality after the code or docs change |
|
|
368
|
-
| `refine` | Restructure it for retrieval: evidence-first, cohesion over balance — proposes, never applies |
|
|
369
|
-
| `consume` | Use the bundle as context for a task, writing back what you learn |
|
|
370
|
-
| `curate` | Structural upkeep as it stands: `validate` + `lint` + `loose` |
|
|
371
|
-
| `doctor` | Install and verify the CLI, then doctor the bundle |
|
|
372
|
-
| `<okf-cli-verb>` | Run any CLI verb (`validate`, `lint`, `search`, `index`, `server`, the read views) and interpret its output |
|
|
373
|
-
|
|
374
|
-
Three of those look alike and are not, which is the distinction worth learning
|
|
375
|
-
first: **`curate`** keeps the bundle *sound* (the structure as it stands),
|
|
376
|
-
**`maintain`** keeps it *true* (the code changed, so the content must catch up),
|
|
377
|
-
and **`refine`** changes *where knowledge lives* — the folder a concept sits in,
|
|
378
|
-
a fact re-explained in three overviews. Reach for `refine` when nothing is wrong
|
|
379
|
-
and everything is hard to find. It reads the evidence, then hands you a proposal
|
|
380
|
-
— it never rearranges your bundle on its own.
|
|
381
|
-
|
|
382
|
-
Point it at your agent's config directory and the tree settles in its own
|
|
383
|
-
`skills/okf/` folder, so a shared skills directory never gets the files loose:
|
|
384
|
-
|
|
385
|
-
```bash
|
|
386
|
-
okf skill .claude # Claude Code -> .claude/skills/okf
|
|
387
|
-
okf skill .agents # agent-agnostic -> .agents/skills/okf
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
The resolved directory must be empty unless you pass `--force`, so a customized
|
|
391
|
-
skill is never clobbered.
|
|
392
|
-
|
|
393
|
-
## Library
|
|
96
|
+
## The library
|
|
394
97
|
|
|
395
98
|
`require "okf"` gives you the whole thing as Ruby objects — two layers: pure
|
|
396
99
|
in-memory data (`OKF::Concept`, `OKF::Bundle`) you build and analyze with no disk
|
|
397
100
|
involved, and on-disk handles (`OKF::Concept::File`, `OKF::Bundle::Folder`) that
|
|
398
|
-
add load/save/reload/delete
|
|
101
|
+
add load/save/reload/delete.
|
|
399
102
|
|
|
400
103
|
```ruby
|
|
401
104
|
require "okf"
|
|
@@ -411,106 +114,52 @@ OKF::Server::App.new(folder) # => a Rack app: the interactive graph, mountab
|
|
|
411
114
|
```
|
|
412
115
|
|
|
413
116
|
That last line is the point of the Rack app: the graph mounts inside an app you
|
|
414
|
-
already have, auth included. The
|
|
415
|
-
|
|
416
|
-
the pure layer, the
|
|
117
|
+
already have, auth included. The
|
|
118
|
+
[Rails guide](https://okfgem.com/docs/guides/rails/) walks it, and the
|
|
119
|
+
[library API](https://okfgem.com/docs/library/) covers the pure layer, the
|
|
120
|
+
writer, and the lower-level pieces.
|
|
417
121
|
|
|
418
|
-
|
|
122
|
+
## validate and lint are two different questions
|
|
419
123
|
|
|
420
|
-
`validate`
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
*forbidden* to reject a bundle for a broken link or a missing optional field.
|
|
124
|
+
`validate` asks *"is this legal OKF?"* and implements the spec's
|
|
125
|
+
[§9](lib/okf/skill/reference/SPEC.md#9-conformance) exactly — which means it is *forbidden* to
|
|
126
|
+
reject a bundle for a broken link or a missing optional field.
|
|
424
127
|
|
|
425
|
-
`lint`
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
pass `--fail-on warn`.
|
|
128
|
+
`lint` asks the complementary question, *"is this well-curated, navigable,
|
|
129
|
+
trustworthy?"*, over exactly those tolerated things: reachability, backlog,
|
|
130
|
+
completeness, freshness, provenance, hygiene. It is advisory and exits `0` even
|
|
131
|
+
with findings unless you pass `--fail-on warn`.
|
|
430
132
|
|
|
431
133
|
Keeping them apart is what lets you gate CI on conformance without gating it on
|
|
432
134
|
taste. `lint --json` is also the structured input an agent reads to reason about
|
|
433
135
|
the two things no checker can compute — contradictions, and *semantic* staleness.
|
|
434
136
|
|
|
435
|
-
## Extending
|
|
137
|
+
## Extending it
|
|
436
138
|
|
|
437
139
|
Publish a gem named `okf-*` carrying an `okf/plugin.rb` and installing it is the
|
|
438
140
|
whole installation: your verb answers to `okf` and behaves like a built-in.
|
|
439
141
|
Nothing an addon registers can displace one, and a broken addon is skipped rather
|
|
440
|
-
than taking the CLI down.
|
|
441
|
-
|
|
142
|
+
than taking the CLI down. [`okf-mcp`](https://rubygems.org/gems/okf-mcp) is the
|
|
143
|
+
first one — install it and `okf mcp` serves your bundles over the Model Context
|
|
144
|
+
Protocol, with nothing in this gem naming it.
|
|
442
145
|
|
|
443
|
-
The graph page treats a bundle as untrusted content: inlined data is escaped
|
|
146
|
+
The graph page treats a bundle as untrusted content: inlined data is escaped and
|
|
444
147
|
every concept body is sanitized before it reaches the DOM, so a script hidden in
|
|
445
148
|
Markdown is stripped rather than run. It still loads libraries from a CDN, so
|
|
446
149
|
treat an unfamiliar bundle the way you would treat any document from a source you
|
|
447
|
-
do not know.
|
|
448
|
-
[server trust boundary](.okf/design/server-trust-boundary.md).
|
|
150
|
+
do not know.
|
|
449
151
|
|
|
450
|
-
##
|
|
152
|
+
## More
|
|
451
153
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
/plugin install okf@okfgem
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
The plugin carries three pieces: the [`okf` skill](#agent-skill) above;
|
|
461
|
-
**`/okf:gem`**, a front door that hands its arguments to the skill unchanged (no
|
|
462
|
-
arguments: it orients on your bundle and recommends the next move, never
|
|
463
|
-
auto-runs); and a **curation hook** that runs `okf validate` + `okf lint` after
|
|
464
|
-
every edit inside a bundle and returns the findings as context. The checks are
|
|
465
|
-
the CLI's own, so the feedback is deterministic.
|
|
466
|
-
|
|
467
|
-
The hook stays silent outside bundles, and it is config-free to switch off:
|
|
468
|
-
`OKF_CURATE_DISABLED=1` turns it off, `OKF_CURATE_QUIET=1` keeps the findings
|
|
469
|
-
without the install suggestion, and an `<!-- okf-disable -->` comment skips one
|
|
470
|
-
file.
|
|
471
|
-
|
|
472
|
-
Prefer no plugin? `gem install okf && okf skill .claude` installs the skill
|
|
473
|
-
alone, and the skill itself instructs the agent to run the same checks after
|
|
474
|
-
editing a bundle.
|
|
475
|
-
|
|
476
|
-
## Development
|
|
477
|
-
|
|
478
|
-
```bash
|
|
479
|
-
bin/setup # install dependencies
|
|
480
|
-
bundle exec rake # tests + RuboCop (what CI runs)
|
|
481
|
-
bundle exec rake test # just the test suite
|
|
482
|
-
ruby -Ilib exe/okf validate <dir> # run the CLI from a checkout
|
|
483
|
-
```
|
|
484
|
-
|
|
485
|
-
The suite runs on every supported Ruby; to check the 2.4 floor locally:
|
|
486
|
-
|
|
487
|
-
```bash
|
|
488
|
-
docker run --rm -v "$PWD":/src:ro ruby:2.4 bash -c \
|
|
489
|
-
"cp -a /src /build && cd /build && rm -f Gemfile.lock && bundle install --quiet && bundle exec rake test"
|
|
490
|
-
```
|
|
491
|
-
|
|
492
|
-
The graph page has its own suite in a real browser (`bundle exec rake
|
|
493
|
-
browser:setup`, then `rake test:browser`). See [AGENTS.md](AGENTS.md) for the
|
|
494
|
-
maintainer guide.
|
|
495
|
-
|
|
496
|
-
## Contributing
|
|
497
|
-
|
|
498
|
-
Bug reports and pull requests are welcome on GitHub at
|
|
499
|
-
<https://github.com/serradura/okf-gem>. This project is intended to be a safe,
|
|
500
|
-
welcoming space for collaboration, and contributors are expected to adhere to
|
|
501
|
-
the [code of conduct](CODE_OF_CONDUCT.md).
|
|
154
|
+
The [project README](https://github.com/serradura/okf-gem#readme) carries the
|
|
155
|
+
diagrams, the comparison with `CLAUDE.md`, agent auto-memory and wikis, and the
|
|
156
|
+
Claude Code plugin. The [docs](https://okfgem.com/docs/) are the manual. And the
|
|
157
|
+
repo documents *itself* in OKF — clone it and run `okf server .okf` to read this
|
|
158
|
+
gem's own knowledge as a graph.
|
|
502
159
|
|
|
503
160
|
## License
|
|
504
161
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
is authored by Google Cloud Platform and included under its own Apache-2.0
|
|
509
|
-
license, Copyright (c) Google LLC. See `NOTICE` and
|
|
162
|
+
Apache-2.0; see `LICENSE.txt`. The Open Knowledge Format specification bundled
|
|
163
|
+
with the skill is authored by Google Cloud Platform and included under its own
|
|
164
|
+
Apache-2.0 license, Copyright (c) Google LLC. See `NOTICE` and
|
|
510
165
|
`lib/okf/skill/reference/APACHE-2.0.txt`.
|
|
511
|
-
|
|
512
|
-
[okf-skills](https://github.com/scaccogatto/okf-skills) by Marco Boffo, a Python
|
|
513
|
-
OKF toolkit for Claude Code with a feature-rich interactive graph view, was an
|
|
514
|
-
early inspiration for this gem's Claude Code plugin and for the knowledge-as-code
|
|
515
|
-
comparison in [Why OKF](#why-okf). okf-gem takes a different shape: a Ruby-native
|
|
516
|
-
gem built around the `okf` CLI and an embeddable library.
|
data/lib/okf/bundle/folder.rb
CHANGED
|
@@ -42,6 +42,10 @@ module OKF
|
|
|
42
42
|
@bundle.graph(minimal: minimal, body: body)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
def skeleton
|
|
46
|
+
@bundle.skeleton
|
|
47
|
+
end
|
|
48
|
+
|
|
45
49
|
def catalog
|
|
46
50
|
@bundle.catalog
|
|
47
51
|
end
|
|
@@ -50,6 +54,10 @@ module OKF
|
|
|
50
54
|
@bundle.hubs
|
|
51
55
|
end
|
|
52
56
|
|
|
57
|
+
def directories
|
|
58
|
+
@bundle.directories
|
|
59
|
+
end
|
|
60
|
+
|
|
53
61
|
def directory_index
|
|
54
62
|
@bundle.directory_index
|
|
55
63
|
end
|
|
@@ -100,6 +108,17 @@ module OKF
|
|
|
100
108
|
Concept::File.read(root: @root, path: path)
|
|
101
109
|
end
|
|
102
110
|
|
|
111
|
+
# The raw markdown bytes for one concept id — read once through the same
|
|
112
|
+
# containment guard as #concept, but without the parse #concept pays for,
|
|
113
|
+
# so a caller that wants the file verbatim (never a re-serialized copy)
|
|
114
|
+
# does one read, not a read plus a discarded frontmatter parse. nil when no
|
|
115
|
+
# concept has that id; raises Path::Error if the file has become a symlink
|
|
116
|
+
# escaping the root, and the reader's own SystemCallError if it has gone.
|
|
117
|
+
def concept_source(id)
|
|
118
|
+
path = @bundle.paths_by_id[id] or return nil
|
|
119
|
+
Concept::File.new(root: @root, path: path).read
|
|
120
|
+
end
|
|
121
|
+
|
|
103
122
|
# Materialize the in-memory bundle to disk (Writer validates §9 before
|
|
104
123
|
# publishing, so a malformed bundle is never written).
|
|
105
124
|
def save(overwrite: false)
|
|
@@ -127,8 +146,12 @@ module OKF
|
|
|
127
146
|
end
|
|
128
147
|
|
|
129
148
|
def log_content(path)
|
|
130
|
-
|
|
131
|
-
|
|
149
|
+
# Live, but through the same containment as every other read: a log.md
|
|
150
|
+
# that was a real file at boot and is a symlink out of the root now falls
|
|
151
|
+
# back to the boot snapshot rather than serving the target — the same
|
|
152
|
+
# answer a vanished file gets, since an escape is a file we must not read.
|
|
153
|
+
SafeRead.read!(@root, File.join(@root, path))
|
|
154
|
+
rescue SystemCallError, Path::Error
|
|
132
155
|
@bundle.reserved_content(path)
|
|
133
156
|
end
|
|
134
157
|
end
|