okf 1.1.0 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 464529d862280b3385f00fa36a309c81fa03f71db2d2534f11707a04fdca4679
4
- data.tar.gz: 1487c71ef1e70340d0a6212b85f0202ae287c0a1df7b59489f643bdbf63dd05f
3
+ metadata.gz: 95f1db166e67b4a3c4b4fbd679bce25ef19e3de3f50f010e13e6b1630ddacfcf
4
+ data.tar.gz: cef59494dbd959585ba85f631b025eb5ba88ab94e38c6d440ac8aed1b2fbd61a
5
5
  SHA512:
6
- metadata.gz: 6240c78b9b1c23b64c97f980db2aabe5d3126eb0c69e4eb853381bed2e5e1be991a4835c62a806cfb5e219fdb4b3bf4bf3ef8960063d6f30d5fcf2aaf630d8d2
7
- data.tar.gz: 32d943f353984a9d6e7224c881169bf851008976adee4ef6e785878372f225162f4359021b2ab576cf0615dde0b23054b61826ee39b8937356e1759d0dbca0c4
6
+ metadata.gz: ff17b4c61c5e9fb63e63235fb19fb51b75ce7626acafdfaa88a367f5a6c40a2e9c2eabe7af0283fac5cf6edfd1349b22aa900fa23c321522bd29b19e76befd95
7
+ data.tar.gz: 8846d3604a36b3818024f21d88d04cc62bc91d374dac1a7fd34e17d6eb8269fcf72f7675191a1b3243144359d847c734cf049d4025cf962fb5bf7369f7cc8fac
data/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.2.0] - 2026-07-12
4
+
5
+ - Claude Code plugin. The repository now doubles as a plugin marketplace:
6
+ `/plugin marketplace add serradura/okf-gem`, then `/plugin install okf@okfgem`.
7
+ The plugin carries the canonical skill (a generated copy; `rake plugin:sync`
8
+ keeps it in lockstep with `lib/okf/skill`, and a test fails on drift), one
9
+ front-door command (`/okf:gem`: no arguments orients on the CLI, the bundle,
10
+ and what `validate`/`lint` report and recommends the highest-value next move
11
+ without running one, `doctor` installs the gem and doctors the repo's bundle,
12
+ `curate` runs the full validate + lint + loose cycle, anything else hands the
13
+ task to the skill), and a PostToolUse hook that runs `okf validate` +
14
+ `okf lint` after every edit inside a bundle and hands the relevant findings
15
+ back as context: every conformance error, plus the warnings and lint findings
16
+ that concern the edited file. The checks are the CLI's own, so the feedback is
17
+ deterministic. The hook stays silent outside bundles, and when the CLI is
18
+ missing it suggests `/okf:gem` once per session instead of erroring on each
19
+ edit. It is config-free to silence: `OKF_CURATE_DISABLED=1` turns it off,
20
+ `OKF_CURATE_QUIET=1` keeps the findings but drops that suggestion, and an
21
+ `<!-- okf-disable -->` comment in a file skips curation for that one. The skill
22
+ routes through per-verb playbooks (`playbooks/`), and its signature guidance
23
+ lines carry stable `<!-- check:… -->` / `<!-- rule:okf-… -->` markers.
24
+ Nothing under `plugin/` ships in the gem.
25
+
3
26
  ## [1.1.0] - 2026-07-12
4
27
 
5
28
  - The graph server now sanitizes every concept body before rendering it. The
data/README.md CHANGED
@@ -16,26 +16,26 @@
16
16
  <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>
17
17
  <a href="LICENSE.txt"><img src="https://img.shields.io/badge/license-Apache--2.0-blue" alt="License: Apache-2.0"></a>
18
18
  <a href="lib/okf/skill/reference/SPEC.md"><img src="https://img.shields.io/badge/OKF-v0.1-6E56CF" alt="OKF v0.1"></a>
19
+ <a href="#claude-code-plugin"><img src="https://img.shields.io/badge/Claude%20Code-plugin-D97757" alt="Claude Code plugin"></a>
19
20
  </p>
20
21
 
21
22
  **okf-gem** — `okf` on RubyGems — reads, validates, lints, and serves
22
23
  **Open Knowledge Format (OKF)** v0.1 bundles: directories of Markdown files with YAML frontmatter that humans and agents read from one source. It does not define a new place to keep knowledge; it gives you leverage over knowledge that already lives as Markdown. Each file is a _concept_; a directory of them is a _bundle_.
23
24
 
25
+ > **Quick start.** One skill, one command, a curation hook, and a CLI that
26
+ > validates, lints, indexes, and serves your Markdown as a graph. In Claude Code,
27
+ > add the plugin and let it set everything up: `/plugin marketplace add
28
+ serradura/okf-gem`, then `/plugin install okf@okfgem`, then `/okf:gem`. On the
29
+ > command line: `gem install okf`, then `okf validate <dir>`.
30
+
24
31
  Here is what it is able to do:
25
32
 
26
- ```mermaid
27
- flowchart LR
28
- skill["companion<br/>agent skill"] -. authors/curate .-> bundle[("OKF v0.1 bundle<br/>Markdown + YAML")]
29
- bundle --> model["pure model<br/>Concept · Bundle · Graph"]
30
- skill -. execute .-> cli
31
- subgraph cli ["okf CLI"]
32
- validate["validate — legal? §9"]
33
- lint["lint — well-curated?"]
34
- server["server — explore"]
35
- end
36
- model --> cli
37
- model --> library["library API<br/>embed in Ruby"]
38
- ```
33
+ <p align="center">
34
+ <picture>
35
+ <source media="(prefers-color-scheme: dark)" srcset=".github/overview-dark.png">
36
+ <img src=".github/overview.png" width="100%" alt="The companion agent skill authors and curates an OKF v0.1 bundle (Markdown + YAML). A pure model (Concept, Bundle, Graph) reads that bundle and feeds both the okf CLI (validate — legal per §9; lint — well-curated; server — explore) and a library API you embed in Ruby.">
37
+ </picture>
38
+ </p>
39
39
 
40
40
  Over a bundle the gem gives you the `okf`
41
41
  command-line tool (the library API is also usable in-process). Each capability
@@ -68,6 +68,9 @@ It is deliberately light so it runs on the Ruby your OS already ships:
68
68
  - no ActiveSupport, no build step, no JavaScript toolchain — the
69
69
  [design constraints](.okf/design/) that hold this line are enforced by tests.
70
70
 
71
+ That range is not aspirational: CI runs the full test suite and RuboCop on every
72
+ one of these on each push.
73
+
71
74
  ## Why OKF
72
75
 
73
76
  Project knowledge (why a service exists, what a metric really measures, the
@@ -80,6 +83,22 @@ work with it.
80
83
 
81
84
  [okf]: https://cloud.google.com/blog/products/data-analytics/how-the-open-knowledge-format-can-improve-data-sharing
82
85
 
86
+ Knowledge already has several homes near an agent, and each holds a different
87
+ thing. None of the others is built for curated, durable team knowledge:
88
+
89
+ | | OKF bundle (this) | `CLAUDE.md` / `AGENTS.md` | Agent auto-memory | Wiki / Notion |
90
+ | ------------------------------ | ----------------------------------------------- | -------------------------- | ------------------------ | ---------------- |
91
+ | Holds | curated team knowledge | standing instructions | what one agent picked up | human docs |
92
+ | Versioned with the code | ✅ | ✅ | ❌ | ❌ |
93
+ | Portable across agents | ✅ plain Markdown + YAML | ⚠️ per-harness conventions | ❌ per-agent store | ⚠️ export needed |
94
+ | Typed and queryable | ✅ frontmatter + graph | ❌ prose | ❌ | ⚠️ partially |
95
+ | Reviewed in PRs | ✅ | ✅ | ❌ implicit | ⚠️ rarely |
96
+ | Scales past one context window | ✅ progressive disclosure (`okf index`) | ❌ loaded whole | ⚠️ partially | n/a |
97
+ | Checked by tooling | ✅ (`okf validate` + `lint`), exit codes for CI | ❌ | ❌ | ❌ |
98
+
99
+ The last row is this gem's job. The other homes have no detector, so their
100
+ drift stays invisible; a bundle's drift shows up as findings you can gate on.
101
+
83
102
  ## What a bundle looks like
84
103
 
85
104
  A bundle is just a directory; each concept is one Markdown file whose path is its
@@ -119,6 +138,14 @@ That bundle is this gem's own documentation. Clone the repo and run
119
138
 
120
139
  ## Installation
121
140
 
141
+ > **In Claude Code**, the plugin is the fastest path: two commands install the whole
142
+ > toolchain (skill, `/okf:gem`, and the curation hook). See
143
+ > [Claude Code plugin](#claude-code-plugin). Everywhere else, install the gem:
144
+
145
+ | Ruby version | 2.4 | 2.5 | 2.6 | 2.7 | 3.0 | 3.1 | 3.2 | 3.3 | 3.4 | 4.0 |
146
+ | ---------------- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
147
+ | Tested/Supported | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
148
+
122
149
  ```bash
123
150
  gem install okf
124
151
  # or, in a project
@@ -138,9 +165,10 @@ bundle exec rake install
138
165
  okf validate <dir> [--json] # check OKF v0.1 conformance (§9)
139
166
  okf lint <dir> [--json] [--fail-on warn] [...] # report curation-quality issues
140
167
  okf loose <dir> [--json] # list files with no graph links, by folder
168
+ okf index <dir> [--json] [--area A] [--no-body] # progressive-disclosure map (§6): bodies, rollups, listings
141
169
  okf server <dir> [-p PORT] [--bind ADDR] [...] # serve the interactive graph over HTTP
142
170
  okf graph <dir> [--json] [--minimal] [--no-body] # print the knowledge graph
143
- okf catalog | files | tags | stats <dir> [--json] # the browser views, on the CLI
171
+ okf catalog | files | tags | types | stats <dir> [--json] # the browser views, on the CLI
144
172
  okf skill <dest> [--here] [--force] # install the companion agent skill
145
173
  okf --version
146
174
  ```
@@ -212,6 +240,21 @@ and template files that teach a coding agent to author, maintain, and consume OK
212
240
  bundles and to drive the commands above. Because the skill ships inside the gem,
213
241
  installing the gem already puts the skill on your machine, and the skill's
214
242
  CLI reference can never drift from the executable it was released with.
243
+ Using Claude Code? The [plugin](#claude-code-plugin) below installs this same
244
+ skill plus a post-edit curation hook.
245
+
246
+ The skill routes a small set of verbs. In Claude Code they run as `/okf:gem
247
+ <verb>`; used standalone, the skill infers the verb from your request.
248
+
249
+ | Verb | What it does |
250
+ | ---------------- | ------------------------------------------------------------------------------------------------- |
251
+ | _(none)_ | Orient on the bundle and recommend the highest-value next move |
252
+ | `produce` | Create or extend a bundle from code, docs, or knowledge in people's heads |
253
+ | `maintain` | Sync the bundle's content with reality after the code or docs change |
254
+ | `consume` | Use the bundle as context for a task, writing back what you learn |
255
+ | `curate` | Structural upkeep as it stands: `validate` + `lint` + `loose` |
256
+ | `doctor` | Install and verify the CLI, then doctor the bundle |
257
+ | `<okf-cli-verb>` | Run any CLI verb (`validate`, `lint`, `index`, `server`, the read views) and interpret its output |
215
258
 
216
259
  Point it at your agent's config directory (or its skills directory) and the tree
217
260
  settles in its own `skills/okf/` folder, so a shared skills directory never gets
@@ -347,6 +390,34 @@ The [server trust boundary](.okf/design/server-trust-boundary.md) concept has th
347
390
  full write-up: the two data paths, what sanitizing does, and what it leaves to
348
391
  your judgment.
349
392
 
393
+ ## Claude Code plugin
394
+
395
+ This repository doubles as a Claude Code plugin marketplace, so the whole
396
+ toolchain installs with two commands inside Claude Code:
397
+
398
+ ```
399
+ /plugin marketplace add serradura/okf-gem
400
+ /plugin install okf@okfgem
401
+ ```
402
+
403
+ The plugin carries three pieces:
404
+
405
+ | Piece | What it does |
406
+ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
407
+ | `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`). |
408
+ | `/okf:gem` | The front door, routed by argument. No arguments: orients on the CLI, the bundle, and what `validate`/`lint` report, then recommends the highest-value next move (never auto-runs). `doctor`: installs and verifies the `okf` CLI, then doctors the repo's bundle. `curate`: the full curation cycle (`validate` + `lint` + `loose`). Anything else (`produce`, `maintain`, `consume`, a CLI verb): handed to the skill. |
409
+ | 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. |
410
+
411
+ The hook stays silent outside bundles, and when the CLI is missing it suggests
412
+ `/okf:gem` once per session instead of failing on each edit. It is config-free to
413
+ switch off: set `OKF_CURATE_DISABLED=1` to turn it off, `OKF_CURATE_QUIET=1` to
414
+ keep the findings but drop that suggestion, or drop an `<!-- okf-disable -->`
415
+ comment into a file to skip curation for that one.
416
+
417
+ Prefer no plugin? `gem install okf && okf skill .claude` installs the skill
418
+ alone, and the skill itself instructs the agent to run the same checks after
419
+ editing a bundle.
420
+
350
421
  ## Development
351
422
 
352
423
  ```bash
@@ -378,3 +449,9 @@ The gem is available as open source under the terms of the
378
449
  is authored by Google Cloud Platform and included under its own Apache-2.0
379
450
  license, Copyright (c) Google LLC. See `NOTICE` and
380
451
  `lib/okf/skill/reference/APACHE-2.0.txt`.
452
+
453
+ [okf-skills](https://github.com/scaccogatto/okf-skills) by Marco Boffo, a Python
454
+ OKF toolkit for Claude Code with a feature-rich interactive graph view, was an
455
+ early inspiration for this gem's Claude Code plugin and for the knowledge-as-code
456
+ comparison in [Why OKF](#why-okf). okf-gem takes a different shape: a Ruby-native
457
+ gem built around the `okf` CLI and an embeddable library.
@@ -88,7 +88,7 @@ flags. The division of labour is the whole game:
88
88
 
89
89
  The one trap worth carrying in your head: **freshness is off by default** — a plain
90
90
  `okf lint` never reports stale concepts; pass `--stale-after <90d|12w|ISO-date>`
91
- when the bundle carries timestamps.
91
+ when the bundle carries timestamps. <!-- check:stale -->
92
92
 
93
93
  Read [cli.md](reference/cli.md) before *interpreting* a verb's output in depth:
94
94
  what `validate` may and may not reject, lint's categories and check ids, the JSON
@@ -101,17 +101,19 @@ index <dir>` (the §6 map: every directory's index body, rollups, and listings)
101
101
  read `log.md` (the §7 baseline of what changed last) **before** greping or opening
102
102
  leaves. It is the cheapest high-signal context, and the only reliable way to catch
103
103
  enumeration drift: **grep cannot find an index entry that is missing** — you can't
104
- search for the word that should be there but isn't. Per-verb steps are in
105
- [authoring.md](reference/authoring.md) (no `okf` installed? read the root
104
+ search for the word that should be there but isn't. <!-- rule:okf-orient-index -->
105
+ Per-verb steps are in the
106
+ playbooks (the Commands table below; no `okf` installed? read the root
106
107
  `index.md` plus each area's `index.md`).
107
108
 
108
109
  ## The authoring verbs — the craft
109
110
 
110
111
  `produce` (create or extend a bundle), `maintain` (sync it with reality),
111
112
  `consume` (use it as context) carry the judgment the executable can't — this is
112
- where the skill earns its keep. Read [authoring.md](reference/authoring.md)
113
- before doing them, and the verbatim spec [SPEC.md](reference/SPEC.md) when you
114
- need chapter and verse.
113
+ where the skill earns its keep. Each has a playbook (the Commands table below);
114
+ read the modelling craft in [authoring.md](reference/authoring.md) before
115
+ producing or maintaining, and the verbatim spec [SPEC.md](reference/SPEC.md)
116
+ when you need chapter and verse.
115
117
 
116
118
  **No subcommand?** Infer intent: "document this / capture X" → `produce`; "the
117
119
  code changed, update the docs" → `maintain`; a repo already carrying a bundle
@@ -123,11 +125,35 @@ ask.
123
125
  root, but first detect whether the project already keeps its bundle elsewhere
124
126
  (e.g. `docs/`) and prefer that. Commit the bundle alongside the code it describes.
125
127
 
128
+ ## Commands
129
+
130
+ The first word of the arguments picks a row. **No arguments at all** — someone
131
+ asking "what should I do?" — is its own row: read `playbooks/menu.md`, orient on
132
+ the signals, and recommend the highest-value move without running one. When there
133
+ is wording but no matching first word, infer intent as in "No subcommand?" above.
134
+ Read the referenced playbook before executing — it *is* the procedure.
135
+
136
+ | Verb | Category | What it does | Reference |
137
+ |------|----------|--------------|-----------|
138
+ | *(none)* | Orient | recommend the highest-value next move; never auto-run | [playbooks/menu.md](playbooks/menu.md) |
139
+ | `produce` | Author | create or extend a bundle | [playbooks/produce.md](playbooks/produce.md) |
140
+ | `maintain` | Author | sync the bundle's content with reality after a change | [playbooks/maintain.md](playbooks/maintain.md) |
141
+ | `consume` | Use | use the bundle as context for a task | [playbooks/consume.md](playbooks/consume.md) |
142
+ | `curate` | Curate | structural upkeep as it stands: validate + lint + loose | [playbooks/curate.md](playbooks/curate.md) |
143
+ | `doctor` | Setup | install and verify the CLI, then doctor the bundle | [playbooks/doctor.md](playbooks/doctor.md) |
144
+ | `<okf-cli-verb>` | Read | validate, lint, loose, index, catalog, files, tags, types, stats, graph, server, skill | `okf <verb> --help` + [reference/cli.md](reference/cli.md) |
145
+
146
+ Two boundaries worth keeping sharp: `curate` is structural upkeep only — when
147
+ the *content* no longer matches reality, that is `maintain` — and `doctor` is
148
+ the one playbook that does not assume the CLI is installed. In Claude Code with
149
+ the okf plugin, `/okf:gem` routes these same verbs.
150
+
126
151
  ## The lifecycle is a flywheel, not phases
127
152
 
128
153
  produce seeds a bundle; consume reads it; **maintain** runs whenever reality drifts
129
154
  *or* whenever consuming teaches you something durable — that write-back reflex is
130
155
  what keeps a bundle alive instead of rotting into folklore. When you learn
131
- something while consuming, switch to maintain and record it. Full playbooks and the
132
- modelling craft (granularity, choosing `type`, tag vocabulary, topology,
133
- `resource`, links, citations) are in [reference/authoring.md](reference/authoring.md).
156
+ something while consuming, switch to maintain and record it. The playbooks live
157
+ one per verb in `playbooks/` (the Commands table above); the modelling craft
158
+ (granularity, choosing `type`, tag vocabulary, topology, `resource`, links,
159
+ citations) is in [reference/authoring.md](reference/authoring.md).
@@ -0,0 +1,12 @@
1
+ # Playbook: consume — use a bundle as context
2
+
3
+ 1. **Orient first** (the [SKILL.md](../SKILL.md) reflex): `okf index <dir>` maps the
4
+ whole bundle in one pass — every directory's index body, rollups, and listings —
5
+ and `log.md` gives recent history. Then follow links only into the concepts the
6
+ task needs. For a large bundle, `okf graph --json` gives the whole link structure
7
+ at once so you can plan a traversal without opening every file.
8
+ 2. Treat broken links as not-yet-written knowledge, not errors.
9
+ 3. **Write-back reflex:** if you learn something durable while working — a fact the
10
+ bundle lacks, a link it is missing, a concept that no longer matches reality —
11
+ switch to [maintain](maintain.md) and record it. That reflex is what keeps the
12
+ bundle alive.
@@ -0,0 +1,33 @@
1
+ # Playbook: curate an OKF bundle
2
+
3
+ Run the complete curation cycle over the whole bundle and act on the findings
4
+ with the okf skill's judgment. If the `okf` CLI is missing, stop and follow
5
+ [doctor.md](doctor.md) first (in Claude Code: `/okf:gem doctor`).
6
+
7
+ Curation is structural upkeep of the bundle *as it stands*: conformance,
8
+ reachability, backlog, completeness, hygiene. It is not `maintain`, the
9
+ skill's workflow for when the project changed and the bundle's *content*
10
+ must catch up with reality; reach for that one when what is written stopped
11
+ being true. Curating can surface semantic staleness, and when it does,
12
+ switch to `maintain` for those concepts.
13
+
14
+ 1. Locate the bundle: the directory you were given, if any; otherwise a
15
+ `.okf/` directory or a root `index.md` whose frontmatter carries
16
+ `okf_version`.
17
+ 2. Measure: `okf validate <root> --json`, `okf lint <root> --json`,
18
+ `okf loose <root> --json`.
19
+ 3. Interpret through the three lenses the okf skill teaches, and keep them
20
+ separate:
21
+ - conformance errors (§9) are the only hard failures; fix them first,
22
+ always;
23
+ - lint findings are curation debt across reachability, backlog,
24
+ completeness, freshness, provenance, and hygiene. They are advisory;
25
+ rank them by how much each hurts a reader navigating the graph;
26
+ - loose files can be legitimate terminal leaves, so judge each one before
27
+ linking it anywhere.
28
+ 4. Propose, then apply: list the fixes worth making (must-fix errors first,
29
+ then the debt worth settling, then the judgment calls), apply the ones the
30
+ user confirms, or all the obvious ones when the user asked you to just
31
+ clean up.
32
+ 5. Re-measure: run validate + lint again and report the before and after in
33
+ two lines.
@@ -0,0 +1,55 @@
1
+ # Playbook: set up the okf CLI and doctor the bundle
2
+
3
+ You are the installer and doctor for the Open Knowledge Format toolchain. Work
4
+ through the steps in order and report what you find at each one. Ask before any
5
+ install that touches the user's system; everything else, just do.
6
+
7
+ ## 1. Is the CLI already here?
8
+
9
+ Run `okf --version`. If it prints a version, skip to step 3.
10
+
11
+ ## 2. Install the gem
12
+
13
+ Find a Ruby first. The gem runs on any Ruby >= 2.4, so whatever the OS or a
14
+ version manager already ships will do:
15
+
16
+ - `ruby --version`; if absent, check the managers: `rbenv versions`,
17
+ `asdf list ruby`, `mise ls ruby`.
18
+ - Repo has a Gemfile and okf belongs to the project? `bundle add okf`, then use
19
+ `bundle exec okf` everywhere below.
20
+ - Otherwise: `gem install okf`.
21
+
22
+ Troubleshooting, in order of likelihood:
23
+
24
+ - `okf: command not found` right after a successful install: the gem bindir is
25
+ not on PATH. `ruby -e 'puts Gem.bindir'` shows where the executable landed;
26
+ add that to PATH, or refresh the manager's shims (`rbenv rehash`,
27
+ `asdf reshim ruby`).
28
+ - Permission error on the system Ruby: do not reach for sudo. Use
29
+ `gem install --user-install okf` and add `$(ruby -e 'puts Gem.user_dir')/bin`
30
+ to PATH.
31
+ - Windows: a RubyInstaller Ruby works. Run the install from the same shell that
32
+ has `ruby` on PATH, and note the executable is `okf.bat` under Gem.bindir.
33
+
34
+ Verify with `okf --version` before moving on.
35
+
36
+ ## 3. Doctor the bundle
37
+
38
+ 1. Locate a bundle: the directory you were given, if any; otherwise a `.okf/`
39
+ directory, or a root `index.md` whose frontmatter carries `okf_version`.
40
+ 2. Found one? Run `okf validate <root>` and `okf lint <root>`, then summarize
41
+ in a few lines: conformant or not (and the errors if not), the warning
42
+ count, and the top curation findings by category.
43
+ 3. No bundle? Offer to bootstrap one. The okf skill knows how (its "produce"
44
+ workflow); do not scaffold anything without the user's yes.
45
+
46
+ ## 4. Say what changes now
47
+
48
+ Close with a short orientation. In Claude Code with the okf plugin active:
49
+ every Write or Edit that touches an OKF bundle runs `okf validate` and
50
+ `okf lint` automatically, and the findings come back as context to act on.
51
+ The checks are the CLI's own, so the feedback is deterministic. `/okf:gem
52
+ curate` runs the same cycle over the whole bundle on demand, and `/okf:gem`
53
+ with any other arguments (produce, maintain, consume, or a CLI verb) hands
54
+ the task straight to the skill. Without the plugin, the skill itself
55
+ instructs the agent to run the same checks after editing a bundle.
@@ -0,0 +1,67 @@
1
+ # Playbook: maintain — keep a bundle in sync with reality
2
+
3
+ Reach for this when the project changed and the bundle's *content* must catch
4
+ up. The modelling craft behind steps 3 and 7 lives in
5
+ [authoring.md](../reference/authoring.md).
6
+
7
+ 1. **Orient before hunting.** Run `okf index <dir>` (the §6 map — every directory's
8
+ index body, rollups, and listings), read `log.md` (the §7 baseline: what changed
9
+ last), and `okf stats <dir>` (size and shape) *before* you grep. It is the
10
+ cheapest context and it primes the hunt — and it is the only reliable way to
11
+ catch enumeration drift, because **grep cannot find an index entry that is
12
+ missing.** (This is the always-on reflex in [SKILL.md](../SKILL.md).)
13
+ 2. **Find *every* affected concept** — the failure mode is fixing only the obvious
14
+ one. Don't rely on reading the whole bundle; that only scales on tiny ones. Grep
15
+ the changed asset's `resource` URI across the bundle, grep its path/name, and use
16
+ `okf graph --json` to pull the concepts that link *to* the ones you're touching.
17
+ Let grep and the graph find them so nothing drifts silently.
18
+ 3. Update bodies and `timestamp`; fix or add cross-links; create new concepts for
19
+ new assets; mark retired assets with a `**Deprecation**` note rather than
20
+ silently deleting the context that explains them.
21
+ 4. **Update every enumeration that names what you changed — including `index.md`
22
+ bodies**, not just the concept files: a new, renamed, or removed concept changes
23
+ its directory's index listing too. Append a dated `log.md` entry. Step 1's map
24
+ is how you verify this — re-run `okf index` and confirm each listing matches
25
+ reality.
26
+ 5. Run `validate`, then `lint` to catch the curation drift the change introduced —
27
+ new orphans, broken citations, dangling index entries. Add `--stale-after`
28
+ (e.g. `90d`) if concepts carry timestamps: freshness is off by default, so a
29
+ plain `lint` will not tell you what the change left stale.
30
+ 6. **Review loose files** <!-- check:unlinked --> — run `okf loose <dir>` (the
31
+ folder-grouped view of `lint`'s `unlinked` check): the concepts with **no
32
+ cross-links in or out**, which
33
+ float in the graph. This is a semantic pass the tool cannot do for you — for each
34
+ floater, judge intent:
35
+ - **should it link out?** the concept relates to others but says so nowhere —
36
+ write the sentence that explains the relationship and put the link in it;
37
+ - **should something link to it?** it is knowledge others should reach by
38
+ following links, not just via an index — add the inbound link from where it
39
+ belongs;
40
+ - **legitimately terminal?** a backlog item, a spec reference, a leaf reachable
41
+ by design only through its index — leave it. **Terminal-by-design is not a
42
+ defect.** Loose ≠ orphan: an index listing makes a file *reachable* (not an
43
+ orphan) but is not a graph edge, so an indexed file can still float here.
44
+ 7. **Curate the tag vocabulary** <!-- rule:okf-tag-vocabulary --> when the pass
45
+ touched tags, or when `okf tags <dir>` shows a long tail of singletons. Run `okf tags <dir> --by area` and
46
+ `--by type` — the grouped view is the analysis; read each group top-down:
47
+ - **twins** — two tags riding the exact same concepts (equal counts sort them
48
+ adjacent). Merge into one unless each genuinely names a different theme.
49
+ - **group-name echoes** — a tag matching its own group's name (a `format` tag
50
+ inside `format/`, an `overview` tag on an Overview). It restates an axis the
51
+ concept already carries; drop it from those concepts.
52
+ - **singletons** — for each, ask: would an existing tag serve? is it an
53
+ anticipated cluster that concepts landing soon will join? is it a deliberate
54
+ marker (`security`, `deprecated`)? Merge, keep, or drop accordingly — a
55
+ count of 1 is a question, never a verdict.
56
+ - **connective tags** — recurring across groups: these are the vocabulary's
57
+ spine. Protect them; prefer merging others *into* them over renaming them,
58
+ because consumers learn these keys and stability is part of their value.
59
+ The trap in this pass is optimizing the numbers instead of the vocabulary:
60
+ you can reach zero singletons by deleting every tag, and perfect cohesion by
61
+ tagging everything alike. The goal is a small set of tags where each one
62
+ either connects or marks — judged, not counted.
63
+
64
+ Before calling the pass done, walk the
65
+ [Closeout gate](../reference/authoring.md#closeout--the-finishing-gate) once:
66
+ steps 4–7 above cover most of it, and the gate is the check that nothing was
67
+ skipped.
@@ -0,0 +1,34 @@
1
+ # Playbook: menu — "what should I do?" the no-argument front door
2
+
3
+ Reached when `/okf:gem` (or the skill) runs with no verb and no task. Do not
4
+ guess a workflow and do not run one on your own: **orient on the signals, then
5
+ recommend the two or three highest-value moves and let the user pick.** The full
6
+ Commands table in [SKILL.md](../SKILL.md) is the fallback menu; the recommendation
7
+ is the lede.
8
+
9
+ 1. **CLI present?** `okf --version`. If it is missing, the only useful move is
10
+ setup: follow [doctor.md](doctor.md) (install and verify the CLI) and stop
11
+ here. Everything below needs the CLI.
12
+ 2. **Bundle present?** Locate one: the directory you were given, else a `.okf/`
13
+ directory or a root `index.md` whose frontmatter carries `okf_version`.
14
+ - **No bundle** → lead with **`produce`** (create the first bundle from the
15
+ code, docs, or what lives only in people's heads). Nothing else applies yet.
16
+ 3. **Read the bundle's state** from the CLI, not by eyeballing:
17
+ `okf validate <root> --json`, `okf lint <root> --json`, `okf loose <root>
18
+ --json`. Then recommend by what they report, most-blocking first:
19
+ - **`validate` has errors** → lead with **`curate`**: §9 conformance errors are
20
+ the only hard failures, and curate fixes them before anything else.
21
+ - **clean `validate`, but `lint`/`loose` findings** → lead with **`curate`** to
22
+ settle the curation debt (reachability, backlog, completeness, hygiene),
23
+ naming the top one or two categories from the report.
24
+ - **clean across the board** → the bundle is healthy, so lead with **`consume`**
25
+ (put it to work on the task at hand) and offer **`maintain`** as the move for
26
+ when the code or docs have since changed. If the working tree has uncommitted
27
+ changes to the code the bundle describes (`git status`), prefer **`maintain`**:
28
+ that is exactly the drift it exists to close.
29
+ 4. **Freshness is off by default.** If the bundle carries timestamps, note that a
30
+ plain `lint` said nothing about staleness and `okf lint <root> --stale-after
31
+ 90d` is the check that would.
32
+
33
+ Keep it to two or three pointed picks, each with the exact `/okf:gem <verb>` to
34
+ run and a one-line reason from the signals. Never auto-run a workflow from here.
@@ -0,0 +1,23 @@
1
+ # Playbook: produce — create or extend a bundle
2
+
3
+ The craft that makes these steps land well — granularity, choosing `type`, tag
4
+ vocabulary, topology, links, citations — lives in
5
+ [authoring.md](../reference/authoring.md). Read it before a non-trivial produce.
6
+
7
+ 1. Read [SPEC.md](../reference/SPEC.md) if you are unsure of any rule.
8
+ 2. Pick the source(s): **code** (derive concepts from source, READMEs, docstrings,
9
+ config), **docs/wiki** (distill pages into concepts; cite the originals under
10
+ `# Citations`), **manual** (decisions, playbooks, metrics that live only in
11
+ people's heads).
12
+ 3. Choose a domain-based directory layout. One concept per file.
13
+ 4. Write each concept from [templates/concept.md](../templates/concept.md): a
14
+ descriptive `type` from the bundle's vocabulary, recommended fields filled,
15
+ cross-links to related concepts written into prose.
16
+ 5. Add or refresh `index.md` per directory from
17
+ [templates/index.md](../templates/index.md); for the bundle root use
18
+ [templates/root-index.md](../templates/root-index.md) so it carries
19
+ `okf_version: "0.1"`. Append a dated entry to `log.md`.
20
+ 6. **Close out** — walk the
21
+ [Closeout gate](../reference/authoring.md#closeout--the-finishing-gate)
22
+ (`validate` + `lint` are part of it, see [cli.md](../reference/cli.md))
23
+ before finishing.
@@ -27,7 +27,7 @@ Consult the right section on demand instead of re-reading all of [SPEC.md](SPEC.
27
27
  These are the decisions that make or break a bundle. None are enforced by the
28
28
  tools — they are yours to get right.
29
29
 
30
- ### One concept = one file — but what is a concept?
30
+ ### One concept = one file — but what is a concept? <!-- rule:okf-atomic-concept -->
31
31
  A concept is the smallest unit of knowledge someone would want to **link to or
32
32
  cite on its own**. If two things are always referenced together, they are one
33
33
  concept; if either is referenced alone, split them. Err atomic — it is cheap to
@@ -36,7 +36,7 @@ file should split: two `type`s fighting for the frontmatter, two audiences, or a
36
36
  heading that others would plausibly link to directly. The file path (minus `.md`)
37
37
  is the concept's stable ID, so name it for what it *is*, not where it sits today.
38
38
 
39
- ### `type` is the graph's vocabulary
39
+ ### `type` is the graph's vocabulary <!-- rule:okf-type-vocabulary -->
40
40
  `type` is the only required field, and it is the dimension every consumer groups
41
41
  and colours by (the graph server colours nodes by it; graph analysis clusters by
42
42
  it). It is freeform — the spec does not enumerate types — and that freedom is a
@@ -46,7 +46,7 @@ types across files is what makes the graph legible; inventing a new type per fil
46
46
  makes `type` meaningless. Before adding a new type, check what the bundle already
47
47
  uses.
48
48
 
49
- ### Tags are the connective axis — curate them like a vocabulary
49
+ ### Tags are the connective axis — curate them like a vocabulary <!-- rule:okf-tag-vocabulary -->
50
50
  `type` says what a concept *is*; the directory says where it *lives*; `tags` are
51
51
  the only axis that cuts across both. A tag earns its place one of two ways: by
52
52
  **connecting** concepts that type and area don't already group (a `billing` tag
@@ -57,14 +57,14 @@ a tag's clothes. Reuse before minting: run `okf tags <dir>` and pick from the
57
57
  existing vocabulary first; 2–4 tags per concept is plenty. Scattered singletons
58
58
  are how a vocabulary rots into one label per file.
59
59
 
60
- ### Topology: organize by domain, not by type
60
+ ### Topology: organize by domain, not by type <!-- rule:okf-domain-topology -->
61
61
  Lay out directories by what the knowledge is *about* (`services/`, `datasets/`,
62
62
  `decisions/`), not by concept type. The directory tree is itself knowledge — it
63
63
  shows a reader how the system decomposes, and it usually mirrors the shape of the
64
64
  codebase or the org. A `types/`-first layout scatters related concepts and buries
65
65
  the domain.
66
66
 
67
- ### `resource` is the bridge to reality
67
+ ### `resource` is the bridge to reality <!-- rule:okf-resource-bridge -->
68
68
  Set `resource` (a canonical URI) **only** when a concept *is* a real, addressable
69
69
  asset — a table (`bigquery://…`), a service repo, a dashboard, an endpoint. Its
70
70
  presence is what lets `maintain` find every concept affected by a changed asset by
@@ -72,7 +72,7 @@ grepping for that URI. Abstract concepts — a decision, a principle, a metric
72
72
  definition — have no resource, and **omitting it is meaningful**, not laziness. Do
73
73
  not invent placeholder URIs.
74
74
 
75
- ### Links are untyped on purpose
75
+ ### Links are untyped on purpose <!-- rule:okf-untyped-links -->
76
76
  A markdown link asserts only "these two relate." The *kind* of relationship —
77
77
  depends-on, supersedes, derived-from, owns — lives in the **prose around the
78
78
  link**, never in a made-up typed-edge syntax. Write the sentence that explains the
@@ -81,14 +81,14 @@ relationship and put the link inside it. Prefer absolute bundle-relative targets
81
81
  does not exist yet is fine — it is not-yet-written knowledge (§5.3), and `lint`'s
82
82
  backlog will surface it as demand.
83
83
 
84
- ### Provenance is what makes knowledge trustworthy (§8)
84
+ ### Provenance is what makes knowledge trustworthy (§8) <!-- check:uncited_external -->
85
85
  Any external or empirical claim — a latency number, an approval, a quota, a
86
86
  "because X team decided Y" — should carry a citation to its source under a
87
87
  `# Citations` heading. Uncited claims are exactly how a bundle decays into folklore
88
88
  nobody trusts. `lint`'s provenance category exists to catch missing and broken
89
89
  citations; write them as you go so you never have to reconstruct them.
90
90
 
91
- ### Capture the non-obvious — not what code already says
91
+ ### Capture the non-obvious — not what code already says <!-- rule:okf-non-obvious -->
92
92
  A bundle that restates function signatures or config keys goes stale the moment
93
93
  the code changes and adds no knowledge. Capture what you **cannot** derive by
94
94
  reading one source file: the *why* behind a design, cross-cutting relationships,
@@ -96,14 +96,14 @@ decisions and their tradeoffs, operational tribal knowledge, the metric that
96
96
  actually matters. If the code or git history already records it faithfully, link
97
97
  to it rather than duplicating it.
98
98
 
99
- ### Write for both readers at once
99
+ ### Write for both readers at once <!-- rule:okf-dual-audience -->
100
100
  Use structural markdown so an agent can extract deterministically and a human can
101
101
  skim: headings, tables, fenced code, lists. Conventional headings a reader expects
102
102
  are `# Schema` (field/column tables), `# Examples`, and `# Citations`. Fill
103
103
  recommended frontmatter — `title`, `description`, `tags`, `timestamp` (ISO 8601) —
104
104
  whenever it aids consumption.
105
105
 
106
- ### Reserved files
106
+ ### Reserved files <!-- rule:okf-reserved-files -->
107
107
  `index.md` is a directory listing and carries **no frontmatter** — with one
108
108
  exception: the **bundle-root** `index.md` is the only index that may carry
109
109
  frontmatter, and it may carry *only* `okf_version: "0.1"` (§11; `validate` §9.3
@@ -114,90 +114,9 @@ bundle-root [root-index](../templates/root-index.md), [log](../templates/log.md)
114
114
 
115
115
  ## Playbooks
116
116
 
117
- ### produce create or extend a bundle
118
- 1. Read [SPEC.md](SPEC.md) if you are unsure of any rule.
119
- 2. Pick the source(s): **code** (derive concepts from source, READMEs, docstrings,
120
- config), **docs/wiki** (distill pages into concepts; cite the originals under
121
- `# Citations`), **manual** (decisions, playbooks, metrics that live only in
122
- people's heads).
123
- 3. Choose a domain-based directory layout. One concept per file.
124
- 4. Write each concept from [templates/concept.md](../templates/concept.md): a
125
- descriptive `type` from the bundle's vocabulary, recommended fields filled,
126
- cross-links to related concepts written into prose.
127
- 5. Add or refresh `index.md` per directory from
128
- [templates/index.md](../templates/index.md); for the bundle root use
129
- [templates/root-index.md](../templates/root-index.md) so it carries
130
- `okf_version: "0.1"`. Append a dated entry to `log.md`.
131
- 6. **Close out** — walk the Closeout gate below (`validate` + `lint` are part of it,
132
- see [cli.md](cli.md)) before finishing.
133
-
134
- ### maintain — keep a bundle in sync with reality
135
- 1. **Orient before hunting.** Run `okf index <dir>` (the §6 map — every directory's
136
- index body, rollups, and listings), read `log.md` (the §7 baseline: what changed
137
- last), and `okf stats <dir>` (size and shape) *before* you grep. It is the
138
- cheapest context and it primes the hunt — and it is the only reliable way to
139
- catch enumeration drift, because **grep cannot find an index entry that is
140
- missing.** (This is the always-on reflex in [SKILL.md](../SKILL.md).)
141
- 2. **Find *every* affected concept** — the failure mode is fixing only the obvious
142
- one. Don't rely on reading the whole bundle; that only scales on tiny ones. Grep
143
- the changed asset's `resource` URI across the bundle, grep its path/name, and use
144
- `okf graph --json` to pull the concepts that link *to* the ones you're touching.
145
- Let grep and the graph find them so nothing drifts silently.
146
- 3. Update bodies and `timestamp`; fix or add cross-links; create new concepts for
147
- new assets; mark retired assets with a `**Deprecation**` note rather than
148
- silently deleting the context that explains them.
149
- 4. **Update every enumeration that names what you changed — including `index.md`
150
- bodies**, not just the concept files: a new, renamed, or removed concept changes
151
- its directory's index listing too. Append a dated `log.md` entry. Step 1's map
152
- is how you verify this — re-run `okf index` and confirm each listing matches
153
- reality.
154
- 5. Run `validate`, then `lint` to catch the curation drift the change introduced —
155
- new orphans, broken citations, dangling index entries. Add `--stale-after`
156
- (e.g. `90d`) if concepts carry timestamps: freshness is off by default, so a
157
- plain `lint` will not tell you what the change left stale.
158
- 6. **Review loose files** — run `okf loose <dir>` (the folder-grouped view of
159
- `lint`'s `unlinked` check): the concepts with **no cross-links in or out**, which
160
- float in the graph. This is a semantic pass the tool cannot do for you — for each
161
- floater, judge intent:
162
- - **should it link out?** the concept relates to others but says so nowhere —
163
- write the sentence that explains the relationship and put the link in it;
164
- - **should something link to it?** it is knowledge others should reach by
165
- following links, not just via an index — add the inbound link from where it
166
- belongs;
167
- - **legitimately terminal?** a backlog item, a spec reference, a leaf reachable
168
- by design only through its index — leave it. **Terminal-by-design is not a
169
- defect.** Loose ≠ orphan: an index listing makes a file *reachable* (not an
170
- orphan) but is not a graph edge, so an indexed file can still float here.
171
- 7. **Curate the tag vocabulary** when the pass touched tags, or when `okf tags
172
- <dir>` shows a long tail of singletons. Run `okf tags <dir> --by area` and
173
- `--by type` — the grouped view is the analysis; read each group top-down:
174
- - **twins** — two tags riding the exact same concepts (equal counts sort them
175
- adjacent). Merge into one unless each genuinely names a different theme.
176
- - **group-name echoes** — a tag matching its own group's name (a `format` tag
177
- inside `format/`, an `overview` tag on an Overview). It restates an axis the
178
- concept already carries; drop it from those concepts.
179
- - **singletons** — for each, ask: would an existing tag serve? is it an
180
- anticipated cluster that concepts landing soon will join? is it a deliberate
181
- marker (`security`, `deprecated`)? Merge, keep, or drop accordingly — a
182
- count of 1 is a question, never a verdict.
183
- - **connective tags** — recurring across groups: these are the vocabulary's
184
- spine. Protect them; prefer merging others *into* them over renaming them,
185
- because consumers learn these keys and stability is part of their value.
186
- The trap in this pass is optimizing the numbers instead of the vocabulary:
187
- you can reach zero singletons by deleting every tag, and perfect cohesion by
188
- tagging everything alike. The goal is a small set of tags where each one
189
- either connects or marks — judged, not counted.
190
-
191
- ### consume — use a bundle as context
192
- 1. **Orient first** (the [SKILL.md](../SKILL.md) reflex): `okf index <dir>` maps the
193
- whole bundle in one pass — every directory's index body, rollups, and listings —
194
- and `log.md` gives recent history. Then follow links only into the concepts the
195
- task needs. For a large bundle, `okf graph --json` gives the whole link structure
196
- at once so you can plan a traversal without opening every file.
197
- 2. Treat broken links as not-yet-written knowledge, not errors.
198
- 3. **Write-back reflex:** if you learn something durable while working — a fact the
199
- bundle lacks, a link it is missing, a concept that no longer matches reality —
200
- switch to `maintain` and record it. That reflex is what keeps the bundle alive.
117
+ The step-by-step playbooks live in [../playbooks/](../playbooks/), one file per
118
+ verb (produce, maintain, consume, curate, doctor), routed by the Commands table
119
+ in [SKILL.md](../SKILL.md). The Closeout below is their shared finishing gate.
201
120
 
202
121
  ## Closeout — the finishing gate
203
122
 
@@ -105,7 +105,8 @@ But an index listing is **not a graph edge**: a file can be listed in an index y
105
105
  have no cross-links, so it floats in the graph while `lint` reports it as reachable.
106
106
  `loose`/`unlinked` catch exactly that gap. A loose file is not automatically a
107
107
  defect — a terminal leaf (a backlog item, a spec reference) can be loose by design;
108
- `loose` surfaces the set so you can judge intent (see `maintain` in authoring.md).
108
+ `loose` surfaces the set so you can judge intent (see the
109
+ [maintain playbook](../playbooks/maintain.md)).
109
110
 
110
111
  ## index — the progressive-disclosure map (§6)
111
112
 
@@ -148,8 +149,8 @@ in/out link degree). Add `--json` to any for a machine substrate.
148
149
  descending. The "what themes dominate" view. JSON: `{ bundle, count, tags: [{ tag,
149
150
  count, concepts: [id, …] }] }`. `--by type|area` regroups the list per concept
150
151
  dimension with **within-group** counts (a tag spanning groups appears in each) —
151
- the substrate for tag curation; the judgment recipe lives in
152
- [authoring.md](authoring.md)'s maintain playbook. JSON: `{ bundle, count, by,
152
+ the substrate for tag curation; the judgment recipe lives in the
153
+ [maintain playbook](../playbooks/maintain.md). JSON: `{ bundle, count, by,
153
154
  groups: [{ <dim>, count, tags: […] }] }`.
154
155
  - **`types`** — every type with the concepts that carry it, ordered by count
155
156
  descending. The "what kinds of knowledge" view. JSON: `{ bundle, count, types:
data/lib/okf/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OKF
4
- VERSION = "1.1.0"
4
+ VERSION = "1.2.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: okf
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura
@@ -106,6 +106,12 @@ files:
106
106
  - lib/okf/server/templates/graph.html.erb
107
107
  - lib/okf/skill.rb
108
108
  - lib/okf/skill/SKILL.md
109
+ - lib/okf/skill/playbooks/consume.md
110
+ - lib/okf/skill/playbooks/curate.md
111
+ - lib/okf/skill/playbooks/doctor.md
112
+ - lib/okf/skill/playbooks/maintain.md
113
+ - lib/okf/skill/playbooks/menu.md
114
+ - lib/okf/skill/playbooks/produce.md
109
115
  - lib/okf/skill/reference/APACHE-2.0.txt
110
116
  - lib/okf/skill/reference/SPEC.md
111
117
  - lib/okf/skill/reference/authoring.md