okf 1.10.0 → 1.12.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 +294 -0
- data/README.md +310 -445
- data/lib/okf/bundle/folder.rb +24 -5
- data/lib/okf/bundle/linter.rb +1 -1
- data/lib/okf/bundle/search/index.rb +13 -3
- data/lib/okf/bundle/search.rb +93 -13
- data/lib/okf/bundle/skeleton.rb +241 -0
- data/lib/okf/bundle.rb +19 -14
- data/lib/okf/cli/catalog.rb +6 -6
- data/lib/okf/cli/command.rb +241 -14
- data/lib/okf/cli/dirs.rb +118 -0
- data/lib/okf/cli/files.rb +2 -2
- data/lib/okf/cli/graph.rb +115 -9
- data/lib/okf/cli/index.rb +67 -25
- data/lib/okf/cli/loose.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 +33 -2
- data/lib/okf/cli/server.rb +16 -5
- data/lib/okf/cli/stats.rb +36 -11
- data/lib/okf/cli/tags.rb +29 -7
- data/lib/okf/cli/types.rb +1 -1
- data/lib/okf/cli.rb +10 -6
- data/lib/okf/registry.rb +351 -20
- data/lib/okf/render/graph/template.html.erb +504 -103
- data/lib/okf/render/graph.rb +27 -3
- data/lib/okf/server/app.rb +74 -3
- data/lib/okf/server/hub.rb +40 -30
- data/lib/okf/skill/SKILL.md +17 -10
- data/lib/okf/skill/playbooks/consume.md +3 -3
- data/lib/okf/skill/playbooks/maintain.md +4 -3
- data/lib/okf/skill/playbooks/menu.md +3 -2
- data/lib/okf/skill/playbooks/refine.md +30 -3
- data/lib/okf/skill/playbooks/search.md +7 -7
- data/lib/okf/skill/reference/cli.md +171 -32
- data/lib/okf/version.rb +1 -1
- data/lib/okf.rb +10 -0
- metadata +21 -8
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<a href="https://okfgem.com">
|
|
3
3
|
<picture>
|
|
4
4
|
<source media="(prefers-color-scheme: dark)" srcset=".github/hero-dark.png">
|
|
5
|
-
<img src=".github/hero-light.png" width="100%" alt="okf-gem
|
|
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
6
|
</picture>
|
|
7
7
|
</a>
|
|
8
8
|
</p>
|
|
@@ -26,100 +26,20 @@
|
|
|
26
26
|
<b><a href="https://docker.okfgem.com">Docker image</a></b>
|
|
27
27
|
</p>
|
|
28
28
|
|
|
29
|
-
**okf-gem** (`okf` on RubyGems)
|
|
30
|
-
|
|
31
|
-
|
|
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.
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<p align="center">
|
|
36
|
-
<picture>
|
|
37
|
-
<source media="(prefers-color-scheme: dark)" srcset=".github/overview-dark.png">
|
|
38
|
-
<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.">
|
|
39
|
-
</picture>
|
|
40
|
-
</p>
|
|
41
|
-
|
|
42
|
-
Over a bundle the gem gives you the `okf`
|
|
43
|
-
command-line tool (the library API is also usable in-process). Each capability
|
|
44
|
-
below links to the concept that documents it: this gem's own knowledge is an OKF
|
|
45
|
-
bundle, so you can read its design in the format it defends.
|
|
46
|
-
|
|
47
|
-
| Capability | What it answers | Verb |
|
|
48
|
-
| ------------------------------------------------------------- | --------------------------------- | ---------------- |
|
|
49
|
-
| [Companion agent skill](.okf/capabilities/agent-skill.md) | Can an agent author it? | `skill` |
|
|
50
|
-
| [Conformance validator](.okf/capabilities/validator.md) | Is this a legal OKF bundle? (§9) | `validate` |
|
|
51
|
-
| [Curation linter](.okf/capabilities/linter.md) | Is it navigable, complete, fresh? | `lint` / `loose` |
|
|
52
|
-
| [Ranked text search](.okf/capabilities/search.md) | Which concept covers X? | `search` |
|
|
53
|
-
| [Interactive graph server](.okf/capabilities/graph-server.md) | Can I explore it visually? | `server` |
|
|
54
|
-
| [Static render](.okf/capabilities/render.md) | Can I ship a serverless snapshot? | `render` |
|
|
55
|
-
| [Library API](.okf/capabilities/library-api.md) | Can my Ruby program use it? | in-process |
|
|
56
|
-
|
|
57
|
-
And because knowledge rarely lives in one bundle, a per-user
|
|
58
|
-
[registry](.okf/registry.md) gives each bundle a name: `okf registry set ./docs`
|
|
59
|
-
once, then `@docs` works anywhere a `<dir>` does — from any directory — and a
|
|
60
|
-
bare `okf server` hosts every registered bundle behind one hub.
|
|
61
|
-
|
|
62
|
-
> [!TIP]
|
|
63
|
-
> **Browse the gem as knowledge, not just docs.** This README is the front door;
|
|
64
|
-
> the depth lives in the [`.okf/`](.okf) bundle this repo ships. Start at the
|
|
65
|
-
> [overview](.okf/overview.md), then follow the graph into the
|
|
66
|
-
> [capabilities](.okf/capabilities/) (what it does), the
|
|
67
|
-
> [design constraints](.okf/design/) (why it stays this light), and the
|
|
68
|
-
> [format itself](.okf/format/) (what it operates on). Run `okf server .okf` to
|
|
69
|
-
> walk the same bundle as an interactive graph.
|
|
70
|
-
|
|
71
|
-
It is deliberately light so it runs on the Ruby your OS already ships:
|
|
72
|
-
|
|
73
|
-
- works on every Ruby since 2.4, the same floor as [rack](https://github.com/rack/rack),
|
|
74
|
-
its core dependency;
|
|
75
|
-
- only three runtime dependencies: `rack` (the server is a mountable Rack app),
|
|
76
|
-
`webrick` (unbundled from Ruby in 3.0), and
|
|
77
|
-
[`minifts`](https://github.com/serradura/minifts) (the search engine — pure
|
|
78
|
-
Ruby, no dependencies of its own, same 2.4 floor);
|
|
79
|
-
- no ActiveSupport, no native extension, no build step, no JavaScript
|
|
80
|
-
toolchain — the [design constraints](.okf/design/) that hold this line are
|
|
81
|
-
enforced by tests.
|
|
82
|
-
|
|
83
|
-
That range is not aspirational: CI runs the full test suite and RuboCop on every
|
|
84
|
-
one of these on each push.
|
|
85
|
-
|
|
86
|
-
## Try it in four steps
|
|
87
|
-
|
|
88
|
-
From zero to your first bundle.
|
|
89
|
-
|
|
90
|
-
**1. Get the `okf` command.** Two ways in; either one puts `okf` on your `PATH`.
|
|
34
|
+
One install carries the whole workflow, and that is the point of a single gem:
|
|
91
35
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
```
|
|
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.
|
|
96
39
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
okf skill .claude # or: okf skill .agents
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
**3. Start an agent session** where your project lives.
|
|
105
|
-
|
|
106
|
-
```bash
|
|
107
|
-
claude
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
**4. Make your first bundle.** Two ways in, by what you already have: docs keep
|
|
111
|
-
every word, code gets written up for you.
|
|
112
|
-
|
|
113
|
-
```
|
|
114
|
-
/okf migrate <path-to-your-docs> # have docs? adopted in place, bodies verbatim
|
|
115
|
-
/okf produce based on <path-to-your-code> # only code? the skill authors the concepts
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
> [!TIP]
|
|
119
|
-
> **Once you have a bundle**, run `/okf maintain` in the agent session to keep it
|
|
120
|
-
> in sync as the code changes, and `okf server <folder>` to explore it as a graph.
|
|
121
|
-
> In Claude Code, the [plugin](#claude-code-plugin) adds a post-edit curation hook
|
|
122
|
-
> that runs `validate` + `lint` for you.
|
|
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.
|
|
123
43
|
|
|
124
44
|
## Why OKF
|
|
125
45
|
|
|
@@ -187,154 +107,173 @@ timestamp: 2026-07-11T12:00:00Z
|
|
|
187
107
|
```
|
|
188
108
|
|
|
189
109
|
That bundle is this gem's own documentation. Clone the repo and run
|
|
190
|
-
`okf server .okf` to browse it as
|
|
110
|
+
`okf server .okf` to browse it as an interactive graph.
|
|
191
111
|
|
|
192
|
-
##
|
|
112
|
+
## Try it in four steps
|
|
193
113
|
|
|
194
|
-
|
|
195
|
-
> toolchain (skill, `/okf:gem`, and the curation hook). See
|
|
196
|
-
> [Claude Code plugin](#claude-code-plugin). Everywhere else, install the gem:
|
|
114
|
+
From zero to your first bundle.
|
|
197
115
|
|
|
198
|
-
|
|
199
|
-
| ---------------- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
200
|
-
| Tested/Supported | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
116
|
+
**1. Get the `okf` command.** Two ways in; either one puts `okf` on your `PATH`.
|
|
201
117
|
|
|
202
118
|
```bash
|
|
203
|
-
gem install okf
|
|
204
|
-
#
|
|
205
|
-
bundle add okf
|
|
119
|
+
gem install okf # with Ruby
|
|
120
|
+
curl -fsSL https://docker.okfgem.com/install.sh | sh # no Ruby? Docker
|
|
206
121
|
```
|
|
207
122
|
|
|
208
|
-
|
|
209
|
-
|
|
123
|
+
**2. Install the skill.** Teach your agent the format — Claude Code, or any
|
|
124
|
+
other agent.
|
|
210
125
|
|
|
211
126
|
```bash
|
|
212
|
-
|
|
127
|
+
okf skill .claude # or: okf skill .agents
|
|
213
128
|
```
|
|
214
129
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
Prefer not to install Ruby? The official image bundles the CLI, so every `okf`
|
|
218
|
-
command runs against a bundle you mount at `/data`:
|
|
130
|
+
**3. Start an agent session** where your project lives.
|
|
219
131
|
|
|
220
132
|
```bash
|
|
221
|
-
|
|
222
|
-
|
|
133
|
+
claude
|
|
134
|
+
```
|
|
223
135
|
|
|
224
|
-
|
|
225
|
-
|
|
136
|
+
**4. Make your first bundle.** Two ways in, by what you already have: docs keep
|
|
137
|
+
every word, code gets written up for you.
|
|
138
|
+
|
|
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
|
|
226
142
|
```
|
|
227
143
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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.
|
|
232
149
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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>
|
|
237
158
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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:
|
|
242
198
|
|
|
243
199
|
```bash
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
200
|
+
gem install okf
|
|
201
|
+
# or, in a project
|
|
202
|
+
bundle add okf
|
|
247
203
|
```
|
|
248
204
|
|
|
249
|
-
|
|
250
|
-
|
|
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.
|
|
251
207
|
|
|
252
|
-
|
|
208
|
+
### No Ruby? Use Docker
|
|
253
209
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
`--json`, `index`/`catalog`/`files` project down to the fields you ask for
|
|
257
|
-
(`--fields`/`--except`), so nothing pays for output it will not read, and the
|
|
258
|
-
exit codes are stable enough to branch on in CI. The same commands render as
|
|
259
|
-
scannable plain text when a human is the one looking.
|
|
210
|
+
The official image bundles the CLI, so every `okf` command runs against a bundle
|
|
211
|
+
you mount at `/data`:
|
|
260
212
|
|
|
261
213
|
```bash
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
okf loose <dir|@slug> [--json] # list files with no graph links, by folder
|
|
265
|
-
okf search <dir|@slug…|@all> <term…> [--regexp|--fuzzy] # ranked retrieval; @slugs or @all span bundles
|
|
266
|
-
okf index <dir|@slug> [--json] [--area A] [--no-body] # progressive-disclosure map (§6): bodies, rollups, listings
|
|
267
|
-
okf server [DIR|@slug…] [-p PORT] [--bind ADDR] [...] # serve one bundle, or many behind a hub (⌘K searches every one)
|
|
268
|
-
okf render <dir|@slug> [-o FILE] [--layout NAME] [...] # export the graph as one static, self-contained HTML file
|
|
269
|
-
okf registry list [--json] # list registered bundles (* marks the default)
|
|
270
|
-
okf registry set <dir|@slug> [--as SLUG] [--default] # add or update a bundle (a bare `server` serves it)
|
|
271
|
-
okf registry del <dir|@slug> # remove a bundle from the registry
|
|
272
|
-
okf registry default <@slug> | rename <@slug> <new> # move a bundle to the front (the default) / rename it
|
|
273
|
-
|
|
274
|
-
# The registry is a plain JSON file at $OKF_HOME/registry.json (default ~/.okf).
|
|
275
|
-
# It is ordered, and the first entry is the default: `registry default @slug`
|
|
276
|
-
# moves that entry to the front. The subcommand leads and flags follow it:
|
|
277
|
-
# `registry set <dir> --as X`, never `registry --json set <dir>`.
|
|
278
|
-
# A running server reads it at boot — restart after changes.
|
|
279
|
-
# Behind a multi-bundle server, /b/ lists every bundle and ⌘/Ctrl-K switches.
|
|
280
|
-
# @slug names a registered bundle instead of a path — the slug from `registry
|
|
281
|
-
# set`, or bare @ for the default. Anywhere a <dir> goes, an @slug goes:
|
|
282
|
-
# okf lint @handbook works from anywhere. Set $OKF_HOME to point every verb
|
|
283
|
-
# at another registry.
|
|
284
|
-
okf graph <dir|@slug> [--json] [--minimal] [--hubs] # print the knowledge graph (--hubs ranks by inbound links)
|
|
285
|
-
okf catalog | files | tags | types | stats <dir|@slug> [--json] # the browser views, on the CLI
|
|
286
|
-
# `tags --by type|area` regroups the tag index per concept dimension; each row
|
|
287
|
-
# shows count/total, so a tag confined to one area (a domain) reads differently
|
|
288
|
-
# from one spread across several (a cross-cutting concern).
|
|
289
|
-
okf skill <dest> [--here] [--force] # install the companion agent skill
|
|
290
|
-
okf --version
|
|
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
|
|
291
216
|
```
|
|
292
217
|
|
|
293
|
-
|
|
294
|
-
|
|
218
|
+
Tired of the long line? The Docker-backed [`okf` command](https://docker.okfgem.com)
|
|
219
|
+
drops the prefix so every verb reads exactly like the native CLI:
|
|
295
220
|
|
|
296
221
|
```bash
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
…
|
|
302
|
-
✓ conformant (33 warning(s))
|
|
222
|
+
curl -fsSL https://docker.okfgem.com/install.sh | sh # PowerShell: irm https://docker.okfgem.com/install.ps1 | iex
|
|
223
|
+
okf validate .
|
|
224
|
+
okf server .
|
|
225
|
+
```
|
|
303
226
|
|
|
304
|
-
|
|
305
|
-
|
|
227
|
+
Images are published for `linux/amd64` and `linux/arm64` on
|
|
228
|
+
[ghcr.io](https://github.com/serradura/okf-gem/pkgs/container/okf).
|
|
306
229
|
|
|
307
|
-
|
|
308
|
-
|
|
230
|
+
## Where to go next
|
|
231
|
+
|
|
232
|
+
Installed. The rest of this page is each surface the gem gives you over a bundle,
|
|
233
|
+
in the order most people meet them:
|
|
234
|
+
|
|
235
|
+
- **[The graph](#the-graph)** — the whole bundle on one page, live or baked into a
|
|
236
|
+
single HTML file you can host anywhere. Start here if you want to *see* it.
|
|
237
|
+
- **[Agent skill](#agent-skill)** — the verbs your agent runs to author, maintain
|
|
238
|
+
and answer from a bundle, so you stay the editor rather than the typist.
|
|
239
|
+
- **[Claude Code plugin](#claude-code-plugin)** — that skill, a slash command and a
|
|
240
|
+
post-edit curation hook, in two lines.
|
|
241
|
+
- **[Command line](#command-line)** — every view as scannable text or as JSON, with
|
|
242
|
+
exit codes stable enough to gate CI on.
|
|
243
|
+
- **[Library](#library)** — `OKF::Bundle` in your own Ruby, and the graph as a Rack
|
|
244
|
+
app you can mount in an app you already have.
|
|
245
|
+
- **[Extending okf](#extending-okf-and-running-it-safely)** — ship a verb as a gem,
|
|
246
|
+
and what the page does and does not trust in a bundle you did not write.
|
|
247
|
+
|
|
248
|
+
Full reference for every verb and flag lives in
|
|
249
|
+
**[the docs](https://okfgem.com/docs/)**.
|
|
250
|
+
|
|
251
|
+
## The graph
|
|
309
252
|
|
|
310
253
|
<picture>
|
|
311
254
|
<source media="(prefers-color-scheme: dark)" srcset=".github/server-dark.png">
|
|
312
|
-
<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 inspector panel showing the concept's type, tags,
|
|
255
|
+
<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.">
|
|
313
256
|
</picture>
|
|
314
257
|
|
|
315
|
-
_The graph server on this repo's own [`.okf`](.okf) bundle, with the
|
|
316
|
-
|
|
258
|
+
_The graph server on this repo's own [`.okf`](.okf) bundle, with the `overview`
|
|
259
|
+
concept selected. Try it live at
|
|
317
260
|
**[demo.okfgem.com](https://demo.okfgem.com)**._
|
|
318
261
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
It is keyboard-first
|
|
326
|
-
|
|
327
|
-
jumps to the current view's search,
|
|
328
|
-
shortcut.
|
|
329
|
-
|
|
330
|
-
The search box says what it is doing while it does it: a live `7/8` count of
|
|
331
|
-
what the filter kept, and — when a word matches nothing here — a panel naming
|
|
332
|
-
the bundle and the query, offering to search every other bundle instead. The
|
|
333
|
-
query carries over, so nothing is typed twice.
|
|
262
|
+
One page, from a phone to a desktop: the navigation rail becomes a drawer, the
|
|
263
|
+
toolbar folds into a `⚙` sheet, and a tap opens a preview card at the bottom edge
|
|
264
|
+
rather than a panel over the whole viewport, so the graph stays live while you
|
|
265
|
+
read. Drag the card up for the neighbourhood, tap a link and it walks there in
|
|
266
|
+
place.
|
|
267
|
+
|
|
268
|
+
It is keyboard-first: **`⌘/Ctrl-K`** opens a command palette that searches
|
|
269
|
+
concepts, jumps to a view, and — behind a [hub](#one-registry-many-bundles) —
|
|
270
|
+
switches bundles. **`/`** jumps to the current view's search, **`?`** answers with
|
|
271
|
+
every shortcut. Cluster mode boxes the graph by directory and nests as deep as
|
|
272
|
+
your tree does.
|
|
334
273
|
|
|
335
274
|
To skip the server entirely, **`okf render <dir>`** writes that same page as one
|
|
336
|
-
self-contained HTML file, the whole bundle baked in, so you can publish the
|
|
337
|
-
|
|
275
|
+
self-contained HTML file, the whole bundle baked in, so you can publish the graph
|
|
276
|
+
on GitHub Pages or any static host.
|
|
338
277
|
|
|
339
278
|
### One registry, many bundles
|
|
340
279
|
|
|
@@ -350,97 +289,44 @@ okf search @all rate limit # ranked retrieval across every register
|
|
|
350
289
|
okf server # no args: the whole registry behind one hub
|
|
351
290
|
```
|
|
352
291
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
`graph` and `server` are best-effort (§9): a file with invalid frontmatter is
|
|
383
|
-
skipped (and noted on stderr), not fatal, so one bad file never breaks the rest.
|
|
384
|
-
The [graph server](.okf/capabilities/graph-server.md) concept walks the request
|
|
385
|
-
flow and endpoints; the [server trust boundary](#server-trust-boundary) below
|
|
386
|
-
explains how the page handles a bundle you did not author.
|
|
387
|
-
|
|
388
|
-
`lint` (the [curation linter](.okf/capabilities/linter.md)) reports curation
|
|
389
|
-
quality (reachability, backlog, completeness, freshness, provenance, and hygiene)
|
|
390
|
-
separately from `validate`. It is advisory: it exits
|
|
391
|
-
`0` even with findings unless you opt into gating with `--fail-on warn`.
|
|
392
|
-
|
|
393
|
-
```bash
|
|
394
|
-
$ okf lint docs
|
|
395
|
-
OKF lint — docs
|
|
396
|
-
concepts: 37 edges: 87 index.md: 10 log.md: 1
|
|
397
|
-
hubs: features/chat/sources/source-ingestion-pipeline (×12), …
|
|
398
|
-
|
|
399
|
-
Backlog
|
|
400
|
-
· info graph-view.md: referenced by 3 link(s) across 2 concept(s) but does not exist
|
|
401
|
-
! warn features/index.md: index links to missing concept `../../CHANGELOG.md`
|
|
402
|
-
Completeness
|
|
403
|
-
· info features/bundles/entry-editor.md: missing recommended field: description
|
|
404
|
-
Hygiene
|
|
405
|
-
! warn link-suggestions.md: reference-style link `[:approved_ids]` has no matching definition (an invisible broken link)
|
|
406
|
-
|
|
407
|
-
⚠ 3 warn, 31 info
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
That `hubs:` line is the bundle's centre of gravity — the concepts the most links
|
|
411
|
-
point *at*, with their inbound count. **`okf graph <dir> --hubs`** expands it into
|
|
412
|
-
the full ranking and, for each hub, the areas those links come *from*:
|
|
413
|
-
|
|
414
|
-
```bash
|
|
415
|
-
$ okf graph docs --hubs
|
|
416
|
-
Hubs — docs (38 of 40 concepts with inbound links)
|
|
417
|
-
|
|
418
|
-
storage/reconcile ×16 storage 6, shape 4, exploration 3, (root) 1, …
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
That second half is what decides whether a concept sits where it belongs: a hub
|
|
422
|
-
pulled in mostly from outside its own folder is usually homed by history rather
|
|
423
|
-
than by meaning. Together with `okf tags <dir> --by area`, it is the evidence the
|
|
424
|
-
skill's [`refine`](#agent-skill) verb reads before proposing anything.
|
|
425
|
-
|
|
426
|
-
`loose` lists the files that float in the graph: concepts with no cross-links
|
|
427
|
-
in or out (graph degree 0), grouped by folder. It is a curation lens over
|
|
428
|
-
`lint`'s `unlinked` check, distinct from `orphan`. An `index.md` listing makes a
|
|
429
|
-
file _reachable_ (not an orphan) but is not a graph edge, so a listed file
|
|
430
|
-
can still be loose. A loose file may be fine: a terminal leaf like a backlog
|
|
431
|
-
item is loose by design. `loose` surfaces the set for you to judge and
|
|
432
|
-
always exits `0`.
|
|
292
|
+
Related bundles can share a name: `okf registry group backend @handbook @runbooks`
|
|
293
|
+
makes `@backend` stand for the set (members can be groups too, so they nest), and
|
|
294
|
+
`okf search @backend rate limit` or `okf server @backend` then targets all of them
|
|
295
|
+
at once — a durable subset for the two verbs that take several bundles.
|
|
296
|
+
|
|
297
|
+
The registry lives under `$OKF_HOME` (default `~/.okf`) — one per user. For one
|
|
298
|
+
scoped to a single project instead, `okf registry init` drops a
|
|
299
|
+
`.okf-registry.json` in the current directory; okf then discovers it by walking up
|
|
300
|
+
from wherever you run, and every registry op — and every `@slug` — resolves through
|
|
301
|
+
it in place of the global one. So a bare `okf server` inside that repo serves *its*
|
|
302
|
+
bundles with no `$OKF_HOME` setup. The nearest registry wins, and
|
|
303
|
+
`OKF_NO_DISCOVERY=1` forces the global one.
|
|
304
|
+
|
|
305
|
+
Commit that file and it travels with the repo: a bundle under the project root is
|
|
306
|
+
stored relative to the registry, so a checkout on another machine — or a container
|
|
307
|
+
that mounts the repo — resolves the same bundles unchanged. (Bundles outside the
|
|
308
|
+
tree keep absolute paths, which do not travel.)
|
|
309
|
+
|
|
310
|
+
Behind the hub each bundle mounts at `/b/<slug>/`, `/b/` lists them all, and the
|
|
311
|
+
`⌘/Ctrl-K` palette both switches bundles and **searches every one at once** — type
|
|
312
|
+
a few words and the matching concepts appear with their bundle and a snippet, from
|
|
313
|
+
wherever you are.
|
|
314
|
+
|
|
315
|
+
The ⚙ rail opens **Bundles**, the registry on the graph page itself: make
|
|
316
|
+
default, rename, remove, where you are already reading. Those controls are the one
|
|
317
|
+
thing that does not follow you onto a network — bind anywhere but loopback and
|
|
318
|
+
they are refused outright, since `--bind 0.0.0.0` is how a personal tool becomes a
|
|
319
|
+
public one.
|
|
433
320
|
|
|
434
321
|
## Agent skill
|
|
435
322
|
|
|
436
323
|
The gem carries the [companion OKF agent skill](.okf/capabilities/agent-skill.md):
|
|
437
|
-
a `SKILL.md` plus reference
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
CLI reference can never drift from the
|
|
442
|
-
|
|
443
|
-
skill plus a post-edit curation hook.
|
|
324
|
+
a `SKILL.md` plus reference and template files that teach a coding agent to
|
|
325
|
+
author, maintain, and consume OKF bundles and to drive the
|
|
326
|
+
[commands below](#command-line).
|
|
327
|
+
Because the skill ships inside the gem, installing the gem already puts the skill
|
|
328
|
+
on your machine, and the skill's CLI reference can never drift from the
|
|
329
|
+
executable it was released with.
|
|
444
330
|
|
|
445
331
|
The skill routes a small set of verbs. In Claude Code they run as `/okf:gem
|
|
446
332
|
<verb>`; used standalone, the skill infers the verb from your request.
|
|
@@ -452,7 +338,7 @@ The skill routes a small set of verbs. In Claude Code they run as `/okf:gem
|
|
|
452
338
|
| `produce` | Create or extend a bundle from code, docs, or knowledge in people's heads |
|
|
453
339
|
| `migrate` | Adopt existing Markdown docs in place: frontmatter and reserved files added, bodies kept verbatim |
|
|
454
340
|
| `maintain` | Sync the bundle's content with reality after the code or docs change |
|
|
455
|
-
| `refine` | Restructure it for retrieval: evidence-first, cohesion over balance — proposes, never applies
|
|
341
|
+
| `refine` | Restructure it for retrieval: evidence-first, cohesion over balance — proposes, never applies |
|
|
456
342
|
| `consume` | Use the bundle as context for a task, writing back what you learn |
|
|
457
343
|
| `curate` | Structural upkeep as it stands: `validate` + `lint` + `loose` |
|
|
458
344
|
| `doctor` | Install and verify the CLI, then doctor the bundle |
|
|
@@ -463,194 +349,169 @@ first: **`curate`** keeps the bundle *sound* (the structure as it stands),
|
|
|
463
349
|
**`maintain`** keeps it *true* (the code changed, so the content must catch up),
|
|
464
350
|
and **`refine`** changes *where knowledge lives* — the folder a concept sits in,
|
|
465
351
|
a fact re-explained in three overviews. Reach for `refine` when nothing is wrong
|
|
466
|
-
and everything is hard to find
|
|
467
|
-
|
|
468
|
-
you a proposal — it never rearranges your bundle on its own.
|
|
352
|
+
and everything is hard to find. It reads the evidence, then hands you a proposal
|
|
353
|
+
— it never rearranges your bundle on its own.
|
|
469
354
|
|
|
470
|
-
Point it at your agent's config directory
|
|
471
|
-
|
|
472
|
-
the files loose:
|
|
355
|
+
Point it at your agent's config directory and the tree settles in its own
|
|
356
|
+
`skills/okf/` folder, so a shared skills directory never gets the files loose:
|
|
473
357
|
|
|
474
358
|
```bash
|
|
475
359
|
okf skill .claude # Claude Code -> .claude/skills/okf
|
|
476
360
|
okf skill .agents # agent-agnostic -> .agents/skills/okf
|
|
477
361
|
```
|
|
478
362
|
|
|
479
|
-
The
|
|
480
|
-
|
|
481
|
-
Pass `--here` to paste the tree straight into `<dest>`, wherever it is. The
|
|
482
|
-
resolved directory must be empty unless you pass `--force`, so a customized skill
|
|
483
|
-
is never clobbered.
|
|
363
|
+
The resolved directory must be empty unless you pass `--force`, so a customized
|
|
364
|
+
skill is never clobbered.
|
|
484
365
|
|
|
485
|
-
##
|
|
366
|
+
## Claude Code plugin
|
|
486
367
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
you build, interrogate, and analyze with no disk involved, and on-disk
|
|
490
|
-
handles (`OKF::Concept::File`, `OKF::Bundle::Folder`) that add
|
|
491
|
-
load/save/reload/delete, an "ActiveRecord for the filesystem".
|
|
368
|
+
This repository doubles as a Claude Code plugin marketplace, so the whole
|
|
369
|
+
toolchain installs with two commands inside Claude Code:
|
|
492
370
|
|
|
493
|
-
|
|
371
|
+
```
|
|
372
|
+
/plugin marketplace add serradura/okf-gem
|
|
373
|
+
/plugin install okf@okfgem
|
|
374
|
+
```
|
|
494
375
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
376
|
+
The plugin carries three pieces: the [`okf` skill](#agent-skill) above;
|
|
377
|
+
**`/okf:gem`**, a front door that hands its arguments to the skill unchanged (no
|
|
378
|
+
arguments: it orients on your bundle and recommends the next move, never
|
|
379
|
+
auto-runs); and a **curation hook** that runs `okf validate` + `okf lint` after
|
|
380
|
+
every edit inside a bundle and returns the findings as context. The checks are
|
|
381
|
+
the CLI's own, so the feedback is deterministic.
|
|
498
382
|
|
|
499
|
-
|
|
500
|
-
|
|
383
|
+
The hook stays silent outside bundles, and it is config-free to switch off:
|
|
384
|
+
`OKF_CURATE_DISABLED=1` turns it off, `OKF_CURATE_QUIET=1` keeps the findings
|
|
385
|
+
without the install suggestion, and an `<!-- okf-disable -->` comment skips one
|
|
386
|
+
file.
|
|
501
387
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
body: "Joined with [customers](/tables/customers.md).\n"
|
|
506
|
-
)
|
|
507
|
-
|
|
508
|
-
concept.id # => "tables/orders"
|
|
509
|
-
concept.links # => ["/tables/customers.md"] (spec §5 cross-links)
|
|
510
|
-
concept.citations # => [...] (spec §8 # Citations)
|
|
511
|
-
concept.external_links # => [...] (URLs / mailto:)
|
|
512
|
-
concept.to_markdown # => String (inverse of OKF::Markdown::Frontmatter.parse)
|
|
513
|
-
concept.lint # => OKF::Bundle::Linter::Report (the concept-scoped checks)
|
|
514
|
-
|
|
515
|
-
bundle = OKF::Bundle.new(concepts: [ concept ]) # also: reserved:, unparseable:
|
|
516
|
-
bundle.validate # => OKF::Bundle::Validator::Result (spec §9 conformance)
|
|
517
|
-
bundle.lint # => OKF::Bundle::Linter::Report (curation quality)
|
|
518
|
-
bundle.graph # => OKF::Bundle::Graph (#nodes, #edges, #to_h)
|
|
519
|
-
```
|
|
388
|
+
Prefer no plugin? `gem install okf && okf skill .claude` installs the skill
|
|
389
|
+
alone, and the skill itself instructs the agent to run the same checks after
|
|
390
|
+
editing a bundle.
|
|
520
391
|
|
|
521
|
-
|
|
392
|
+
## Command line
|
|
522
393
|
|
|
523
|
-
|
|
524
|
-
|
|
394
|
+
These verbs are written to be read by an **agent first and a person second** —
|
|
395
|
+
that is what the skill drives, with no wrapper in between. Every read verb takes
|
|
396
|
+
`--json`, the list views project down to the fields you ask for
|
|
397
|
+
(`--fields`/`--except`), so nothing pays for output it will not read, and the
|
|
398
|
+
exit codes are stable enough to branch on in CI. The same commands render as
|
|
399
|
+
scannable plain text when a human is the one looking.
|
|
525
400
|
|
|
526
|
-
```
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
401
|
+
```bash
|
|
402
|
+
okf validate <dir|@slug> # is this legal OKF?
|
|
403
|
+
okf lint <dir|@slug> [--fail-on warn] # is it navigable, complete, fresh?
|
|
404
|
+
okf loose <dir|@slug> # concepts with no links in or out
|
|
405
|
+
okf search <dir|@slug…|@all> <term…> # ranked retrieval; @all spans every bundle
|
|
406
|
+
okf index <dir|@slug> [--dir D] [--depth N] # the §6 map: index bodies, rollups, listings
|
|
407
|
+
okf dirs <dir|@slug> [--dir D] [--depth N] # the shape: every directory and what it holds
|
|
408
|
+
okf catalog | files | tags | types | stats <dir|@slug> # the browser views, on the CLI
|
|
409
|
+
okf graph <dir|@slug> [--hubs] [--traffic] # the raw graph; --hubs ranks concepts, --traffic dirs
|
|
410
|
+
okf server [DIR|@slug…] [-p PORT] [--bind ADDR] # the live graph: one bundle, or all of them
|
|
411
|
+
okf render <dir|@slug> [-o FILE] # the same page as one static, self-contained file
|
|
412
|
+
okf registry init | list | set | del | default | rename | group | ungroup # name & group your bundles; @slug works anywhere
|
|
413
|
+
okf skill <dest> # install the companion agent skill
|
|
414
|
+
okf --version
|
|
415
|
+
```
|
|
532
416
|
|
|
533
|
-
|
|
534
|
-
|
|
417
|
+
Exit codes: `0` success, `1` non-conformant bundle (or a `lint --fail-on`
|
|
418
|
+
threshold crossed), `2` usage error. Every flag is in `okf <verb> --help` and in
|
|
419
|
+
[the docs](https://okfgem.com/docs/).
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
$ okf validate docs
|
|
423
|
+
OKF v0.1 conformance — docs
|
|
424
|
+
concepts: 37 index.md: 10 log.md: 1
|
|
425
|
+
! warn features/link-suggestions.md: cross-link target not found: `/graph-view.md` (tolerated under §5.3)
|
|
426
|
+
…
|
|
427
|
+
✓ conformant (33 warning(s))
|
|
535
428
|
|
|
536
|
-
|
|
537
|
-
|
|
429
|
+
$ okf server docs
|
|
430
|
+
serving 37 concepts at http://127.0.0.1:8808 (Ctrl-C to stop)
|
|
538
431
|
|
|
539
|
-
|
|
540
|
-
file.concept # => OKF::Concept (pure)
|
|
541
|
-
file.save; file.delete; file.reload
|
|
432
|
+
$ okf render docs > public/index.html # the same page, static — host it anywhere
|
|
542
433
|
```
|
|
543
434
|
|
|
544
|
-
|
|
545
|
-
`OKF::Bundle::Linter.call(bundle, min_body: 50)`, `OKF::Bundle::Graph.build(bundle)`,
|
|
546
|
-
`OKF::Markdown::Frontmatter.parse(markdown)`. Mounting the graph in Rails, auth
|
|
547
|
-
included: the [Rails guide](https://okfgem.com/docs/guides/rails/) walks it.
|
|
548
|
-
|
|
549
|
-
### Conformance model
|
|
550
|
-
|
|
551
|
-
`validate` (the [conformance validator](.okf/capabilities/validator.md)) implements
|
|
552
|
-
the spec's [§9 conformance definition](lib/okf/skill/reference/SPEC.md#9-conformance)
|
|
553
|
-
exactly. There are three hard conditions, all errors:
|
|
554
|
-
|
|
555
|
-
- **§9.1** every non-reserved file has a parseable YAML frontmatter block;
|
|
556
|
-
- **§9.2** every such block has a non-empty `type`;
|
|
557
|
-
- **§9.3** every `index.md`/`log.md` present follows §6/§7: a nested `index.md`
|
|
558
|
-
has no frontmatter, a root `index.md` carries only `okf_version`, and `log.md`
|
|
559
|
-
date headings are ISO `YYYY-MM-DD`.
|
|
560
|
-
|
|
561
|
-
Everything the spec marks as soft guidance is a warning and never makes a
|
|
562
|
-
bundle non-conformant: missing recommended fields, non-list tags, an unparseable
|
|
563
|
-
timestamp, and broken cross-links (§5.3), which consumers MUST tolerate.
|
|
564
|
-
`OKF::Bundle::Folder#save` validates before publishing, so it never writes a
|
|
565
|
-
bundle that fails §9.
|
|
566
|
-
|
|
567
|
-
### Curation model (`lint`)
|
|
568
|
-
|
|
569
|
-
`validate` asks _"is this §9-conformant?"_ and is forbidden by §9 to reject for
|
|
570
|
-
broken links or missing optional fields. `lint` asks the complementary question,
|
|
571
|
-
_"is this well-curated, navigable, trustworthy?"_, over exactly those tolerated
|
|
572
|
-
things. The two stay separate: `lint` has its own `OKF::Bundle::Linter` and
|
|
573
|
-
report, never emits conformance errors, and is advisory unless you pass
|
|
574
|
-
`--fail-on warn`.
|
|
575
|
-
|
|
576
|
-
Checks span six categories: **reachability** (orphans, not-in-index, disconnected
|
|
577
|
-
islands, unlinked), **backlog** (demand-ranked missing concepts, broken index entries),
|
|
578
|
-
**completeness** (stubs, missing title/description/timestamp), **freshness**
|
|
579
|
-
(`--stale-after`), **provenance** (uncited external claims, broken citations,
|
|
580
|
-
spec §8), and **hygiene** (duplicate titles, unused/undefined reference links,
|
|
581
|
-
self-links). Select with `--only`/`--except`; `--json` emits the full report as JSON.
|
|
582
|
-
|
|
583
|
-
Two loop concerns from the format's own guidance, _contradictions_ and _semantic_
|
|
584
|
-
staleness, need to understand meaning and are not computed here; `lint --json`
|
|
585
|
-
is the structured input an agent consumes to reason about those.
|
|
586
|
-
|
|
587
|
-
## Extending okf
|
|
588
|
-
|
|
589
|
-
This is the other kind of plugin, and it is worth separating from the
|
|
590
|
-
[Claude Code plugin](#claude-code-plugin) below: that one teaches an *agent* to
|
|
591
|
-
use okf, while this one adds behavior to the `okf` command everyone runs.
|
|
592
|
-
|
|
593
|
-
Publish a gem named `okf-*` that carries an `okf/plugin.rb`, and installing it is
|
|
594
|
-
the whole installation: your verb answers to `okf`, appears in `okf help` under
|
|
595
|
-
`installed extensions:`, and behaves like a built-in — nothing to register,
|
|
596
|
-
nothing to configure, no list of known addons in this gem. The same seam takes
|
|
597
|
-
retrieval backends, which is what `okf search --engine NAME` chooses between.
|
|
598
|
-
|
|
599
|
-
Two promises make that safe to install: nothing an addon registers can displace a
|
|
600
|
-
built-in, and a broken addon is skipped and reported rather than taking the CLI
|
|
601
|
-
down with it.
|
|
602
|
-
|
|
603
|
-
The [extension points](.okf/design/extension-points.md) concept has the contract
|
|
604
|
-
and the threat model; `test/integration/cli/cli_plugin_test.rb` is a working
|
|
605
|
-
example to copy.
|
|
606
|
-
|
|
607
|
-
## Server trust boundary
|
|
608
|
-
|
|
609
|
-
> [!NOTE]
|
|
610
|
-
> The graph page defends against a bundle that carries active content in two
|
|
611
|
-
> places. It escapes any graph data inlined into the page (`<` becomes `<`),
|
|
612
|
-
> which keeps that data from breaking out of its `<script>`. And it fetches each
|
|
613
|
-
> concept body on demand, then runs marked's HTML output through
|
|
614
|
-
> [DOMPurify](https://github.com/cure53/DOMPurify) before it reaches the DOM, so
|
|
615
|
-
> a script or event handler hidden in a Markdown body is stripped rather than
|
|
616
|
-
> executed. Descriptions are escaped on the server.
|
|
617
|
-
>
|
|
618
|
-
> That covers the paths that could run code. The page still loads Cytoscape,
|
|
619
|
-
> marked, and DOMPurify from a CDN and renders whatever links and diagrams a body
|
|
620
|
-
> contains, so treat an unfamiliar bundle the way you would treat any document
|
|
621
|
-
> from a source you do not know.
|
|
622
|
-
|
|
623
|
-
The [server trust boundary](.okf/design/server-trust-boundary.md) concept has the
|
|
624
|
-
full write-up: the two data paths, what sanitizing does, and what it leaves to
|
|
625
|
-
your judgment.
|
|
435
|
+
### Reading a big bundle a level at a time
|
|
626
436
|
|
|
627
|
-
|
|
437
|
+
A few hundred concepts is a map nobody reads whole, so `index` and `dirs` descend
|
|
438
|
+
instead of dumping. `--dir` takes a directory **and everything under it**,
|
|
439
|
+
`--depth N` bounds how far below that it goes, and the two compose the way you
|
|
440
|
+
actually walk a tree:
|
|
628
441
|
|
|
629
|
-
|
|
630
|
-
|
|
442
|
+
```bash
|
|
443
|
+
okf dirs @handbook # the shape: every dir, what it holds directly and below
|
|
444
|
+
okf index @handbook --depth 1 --no-body # the top of the map, no prose
|
|
445
|
+
okf index @handbook --dir platform/api # now open one branch — with the chain that places it
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
Naming a `--dir` brings its ancestors along, marked `↑`, so a branch is never
|
|
449
|
+
shown adrift of the context that says what it is — the root `index.md`'s prose
|
|
450
|
+
first among it.
|
|
631
451
|
|
|
452
|
+
For an agent the saving is the whole point. On a 400-concept bundle the full
|
|
453
|
+
`okf index --json` is 313 KB; the skeleton it orients on is 2.8 KB:
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
okf index @handbook --json --depth 1 --except body,listing
|
|
632
457
|
```
|
|
633
|
-
|
|
634
|
-
|
|
458
|
+
|
|
459
|
+
## Library
|
|
460
|
+
|
|
461
|
+
`require "okf"` gives you the whole thing as Ruby objects — two layers: pure
|
|
462
|
+
in-memory data (`OKF::Concept`, `OKF::Bundle`) you build and analyze with no disk
|
|
463
|
+
involved, and on-disk handles (`OKF::Concept::File`, `OKF::Bundle::Folder`) that
|
|
464
|
+
add load/save/reload/delete, an "ActiveRecord for the filesystem".
|
|
465
|
+
|
|
466
|
+
```ruby
|
|
467
|
+
require "okf"
|
|
468
|
+
|
|
469
|
+
folder = OKF::Bundle::Folder.load("docs")
|
|
470
|
+
folder.concepts # => [OKF::Concept]
|
|
471
|
+
folder.validate # => §9 conformance result
|
|
472
|
+
folder.lint # => curation report
|
|
473
|
+
folder.graph # => nodes, edges, indexes
|
|
474
|
+
|
|
475
|
+
require "okf/server/app"
|
|
476
|
+
OKF::Server::App.new(folder) # => a Rack app: the interactive graph, mountable
|
|
635
477
|
```
|
|
636
478
|
|
|
637
|
-
|
|
479
|
+
That last line is the point of the Rack app: the graph mounts inside an app you
|
|
480
|
+
already have, auth included. The [Rails guide](https://okfgem.com/docs/guides/rails/)
|
|
481
|
+
walks it, and the [library API](https://okfgem.com/docs/library/) covers
|
|
482
|
+
the pure layer, the writer, and the lower-level pieces.
|
|
638
483
|
|
|
639
|
-
|
|
640
|
-
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
641
|
-
| `okf` skill | The [companion skill](#agent-skill) above, bundled with the plugin (a generated copy that `rake plugin:sync` keeps identical to `lib/okf/skill`). |
|
|
642
|
-
| `/okf:gem` | The front door: a pass-through that hands its arguments to the skill unchanged, so the [verb table](#agent-skill) 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). |
|
|
643
|
-
| 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. |
|
|
484
|
+
### validate and lint are two different questions
|
|
644
485
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
comment into a file to skip curation for that one.
|
|
486
|
+
`validate` (the [conformance validator](https://okfgem.com/docs/cli/validate/)) asks
|
|
487
|
+
_"is this legal OKF?"_ and implements the spec's
|
|
488
|
+
[§9](lib/okf/skill/reference/SPEC.md#9-conformance) exactly — which means it is
|
|
489
|
+
*forbidden* to reject a bundle for a broken link or a missing optional field.
|
|
650
490
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
491
|
+
`lint` (the [curation linter](https://okfgem.com/docs/cli/lint/)) asks the
|
|
492
|
+
complementary question, _"is this well-curated, navigable, trustworthy?"_, over
|
|
493
|
+
exactly those tolerated things: reachability, backlog, completeness, freshness,
|
|
494
|
+
provenance, hygiene. It is advisory and exits `0` even with findings unless you
|
|
495
|
+
pass `--fail-on warn`.
|
|
496
|
+
|
|
497
|
+
Keeping them apart is what lets you gate CI on conformance without gating it on
|
|
498
|
+
taste. `lint --json` is also the structured input an agent reads to reason about
|
|
499
|
+
the two things no checker can compute — contradictions, and *semantic* staleness.
|
|
500
|
+
|
|
501
|
+
## Extending okf, and running it safely
|
|
502
|
+
|
|
503
|
+
Publish a gem named `okf-*` carrying an `okf/plugin.rb` and installing it is the
|
|
504
|
+
whole installation: your verb answers to `okf` and behaves like a built-in.
|
|
505
|
+
Nothing an addon registers can displace one, and a broken addon is skipped rather
|
|
506
|
+
than taking the CLI down. Contract and threat model:
|
|
507
|
+
[extension points](.okf/design/extension-points.md).
|
|
508
|
+
|
|
509
|
+
The graph page treats a bundle as untrusted content: inlined data is escaped, and
|
|
510
|
+
every concept body is sanitized before it reaches the DOM, so a script hidden in
|
|
511
|
+
Markdown is stripped rather than run. It still loads libraries from a CDN, so
|
|
512
|
+
treat an unfamiliar bundle the way you would treat any document from a source you
|
|
513
|
+
do not know. Full write-up:
|
|
514
|
+
[server trust boundary](.okf/design/server-trust-boundary.md).
|
|
654
515
|
|
|
655
516
|
## Development
|
|
656
517
|
|
|
@@ -668,6 +529,10 @@ docker run --rm -v "$PWD":/src:ro ruby:2.4 bash -c \
|
|
|
668
529
|
"cp -a /src /build && cd /build && rm -f Gemfile.lock && bundle install --quiet && bundle exec rake test"
|
|
669
530
|
```
|
|
670
531
|
|
|
532
|
+
The graph page has its own suite in a real browser (`bundle exec rake
|
|
533
|
+
browser:setup`, then `rake test:browser`). See [AGENTS.md](AGENTS.md) for the
|
|
534
|
+
maintainer guide.
|
|
535
|
+
|
|
671
536
|
## Contributing
|
|
672
537
|
|
|
673
538
|
Bug reports and pull requests are welcome on GitHub at
|