okf 1.12.0 → 2.0.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +296 -0
  3. data/README.md +94 -466
  4. data/lib/okf/bundle/folder.rb +48 -3
  5. data/lib/okf/bundle/graph.rb +12 -3
  6. data/lib/okf/bundle/linter.rb +470 -47
  7. data/lib/okf/bundle/reader.rb +47 -18
  8. data/lib/okf/bundle/references.rb +111 -0
  9. data/lib/okf/bundle/row_filter.rb +53 -0
  10. data/lib/okf/bundle/search.rb +20 -2
  11. data/lib/okf/bundle/validator/result.rb +6 -3
  12. data/lib/okf/bundle/validator.rb +267 -26
  13. data/lib/okf/bundle/writer.rb +1 -1
  14. data/lib/okf/bundle.rb +124 -8
  15. data/lib/okf/cli/catalog.rb +2 -2
  16. data/lib/okf/cli/command.rb +93 -19
  17. data/lib/okf/cli/dirs.rb +1 -1
  18. data/lib/okf/cli/files.rb +2 -2
  19. data/lib/okf/cli/index.rb +3 -3
  20. data/lib/okf/cli/lint.rb +70 -12
  21. data/lib/okf/cli/references.rb +97 -0
  22. data/lib/okf/cli/search.rb +23 -8
  23. data/lib/okf/cli/stats.rb +3 -39
  24. data/lib/okf/cli/tags.rb +6 -43
  25. data/lib/okf/cli/types.rb +1 -1
  26. data/lib/okf/cli/validate.rb +3 -3
  27. data/lib/okf/cli.rb +4 -1
  28. data/lib/okf/concept/file.rb +17 -2
  29. data/lib/okf/concept.rb +362 -10
  30. data/lib/okf/markdown/citations.rb +41 -4
  31. data/lib/okf/markdown/frontmatter.rb +1 -1
  32. data/lib/okf/markdown/links.rb +67 -7
  33. data/lib/okf/path.rb +17 -3
  34. data/lib/okf/render/graph/template.html.erb +173 -41
  35. data/lib/okf/render/graph.rb +11 -3
  36. data/lib/okf/safe_read.rb +50 -0
  37. data/lib/okf/server/app.rb +47 -15
  38. data/lib/okf/server/hub.rb +1 -1
  39. data/lib/okf/skill/SKILL.md +14 -12
  40. data/lib/okf/skill/playbooks/curate.md +8 -3
  41. data/lib/okf/skill/playbooks/doctor.md +3 -1
  42. data/lib/okf/skill/playbooks/maintain.md +7 -6
  43. data/lib/okf/skill/playbooks/menu.md +5 -4
  44. data/lib/okf/skill/playbooks/migrate.md +31 -8
  45. data/lib/okf/skill/playbooks/produce.md +16 -9
  46. data/lib/okf/skill/playbooks/search.md +2 -2
  47. data/lib/okf/skill/reference/SPEC.md +739 -187
  48. data/lib/okf/skill/reference/authoring.md +154 -35
  49. data/lib/okf/skill/reference/cli.md +160 -44
  50. data/lib/okf/skill/templates/attested-computation.md +41 -0
  51. data/lib/okf/skill/templates/concept.md +13 -6
  52. data/lib/okf/skill/templates/root-index.md +1 -1
  53. data/lib/okf/version.rb +1 -1
  54. data/lib/okf.rb +23 -2
  55. metadata +7 -3
  56. data/CODE_OF_CONDUCT.md +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a83101e62e3b3bc97d7351580d50ecc017be391a5edbde2e8f52388de529111
4
- data.tar.gz: 040be5295642da56cbeed342424872469d1c2b15efcb1b477f10076d7c90fafc
3
+ metadata.gz: 43476118366ed4610628f4692f1c1432e4babe4a9d5749f06eb69fc41738c4e5
4
+ data.tar.gz: 218144bd22483995d933cf9d89f44e9602c2c95255d9e1c95626700a4f5b2f2e
5
5
  SHA512:
6
- metadata.gz: 47fb84d8dffc04eee30eb65adfaca756ae43315e2d152e62692084a5bd04c6a7992529d243b2375412a8339a55db891c3ae18d679e171d5709e9426b93686047
7
- data.tar.gz: 30390e1eecc1570b28531c374b21200309630aad87f821a7c3f25b631ca5285e03b91baab9048f69127931a09368da1ab38a089fc9bc25473c05da3c0fadfe2b
6
+ metadata.gz: 40ccd9ca9a9fe8580856825a972753b0f58ff2158fec6262db84d0b9d504e24c071a78e5b05939c0c5648ac7da67083621085417547ae194a0343ae1de34694b
7
+ data.tar.gz: 506f9d1feb6c6428c9db8845b4880207e904901636b35411b8b85f37dc909abb08b96d82246f06e410c97f6991ccfd947a559eed1d9c5b8d8e429b4790bd5929
data/CHANGELOG.md CHANGED
@@ -5,6 +5,299 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.0.0] - 2026-08-14
9
+
10
+ > Major, not minor. The Breaking entries below change public shapes a shipped
11
+ > consumer already reads: two lint check ids are renamed, the `stale` finding's
12
+ > JSON metric moves from `timestamp` to `generated_at`, and the `timestamp`
13
+ > catalog column is gone. A v0.1 *bundle* still validates with zero warnings —
14
+ > §13.1's fallbacks hold — but spec compatibility and API compatibility are
15
+ > different promises, and semver tracks the second. okf-mcp's open-ended
16
+ > `okf >= 1.13` is closed to `>= 2.0, < 3` in the same release.
17
+
18
+ ### Added
19
+
20
+ - **`okf references` — the §6.3 inventory.** Lists every file under
21
+ `references/`, the non-markdown ones included (the concept model carries
22
+ only markdown, so no other verb can see a `.py` attester or a `.sql`
23
+ computation), with which concepts cite each file through the §6.2
24
+ path-valued fields — plus every pointer into `references/` that resolves to
25
+ nothing. A bare `references/…` written from a subdirectory resolves relative
26
+ to the concept (the §6.2 trap the SPEC's own examples invite), and when the
27
+ leading-slash spelling would have hit, the dangling entry says so. Advisory
28
+ (exit 0); `--json` with `--fields`/`--except` like the other read views.
29
+ Backed by `OKF::Bundle::References` (pure) and
30
+ `OKF::Bundle::Folder#references` (the disk manifest) in the library, and by
31
+ `Markdown::Links.resolve_path` — `#resolve`'s path arithmetic without its
32
+ `.md` gate, since §6.2 fields accept any file.
33
+ - **The §5/§10 families across every surface.** The validator warns on their
34
+ shapes (raw keys only, warnings only — §11's three hard conditions are
35
+ untouched) and its warnings become machine-readable: each carries `check:`
36
+ (a stable id) and `source:` (`spec` | `convention`), with errors keeping
37
+ their exact two-key shape. A root `index.md`'s `okf_version` is actually
38
+ read now — an unknown version warns under §12 and the bundle is consumed
39
+ anyway; unquoted `okf_version: 0.2` (a Psych Float) is accepted.
40
+ - **Eight lint categories with pinned severities** (`Linter::SEVERITIES`, a
41
+ tested constant): Freshness gains `expired` (info, clock-gated — the CLI
42
+ passes today, `--today YYYY-MM-DD` pins it for reproducible CI reports, and
43
+ the pure library runs no clock check unless handed `today:`, confessing via
44
+ `stats[:skipped_checks]`); Provenance gains `broken_source`,
45
+ `unattributed_claim` (warn — only once a concept adopts keyed attribution,
46
+ with the label↔id join case-folded the way GFM resolves footnotes),
47
+ `unused_source`, and `unprefixed_actor` (info — a `verified[].by` outside
48
+ §7's three forms reads as machine-confirmed); a missing `generated.by` is
49
+ the validator's warning alone, never double-reported by lint. Attestation
50
+ gains `incomplete_computation` (warn, on
51
+ neither-or-both computation shapes) and `broken_attestation_ref` (warn — a
52
+ `computation`, `executor.resource` or `attester.resource` on an
53
+ `Attested Computation` naming an in-bundle `.md` that is not there; a contract whose parts are named but
54
+ absent is one no consumer can follow, so it warns rather than informs, with
55
+ the same URL/non-`.md` exemption `broken_source` carries); Migration's `legacy_timestamp` and
56
+ `legacy_citations` (info) name what a v0.1 bundle would change without ever
57
+ failing it. Reports gain `trust` and `status` distributions.
58
+ - **`--fail-on info`** joins `never | warn` — gateability without a severity
59
+ promotion; a migration campaign is
60
+ `okf lint <dir> --only legacy_timestamp,legacy_citations --fail-on info`.
61
+ - **`Linter.call(only:/except:)` refuses an unknown check id** with an
62
+ ArgumentError naming it, instead of silently intersecting to an empty run
63
+ that reports healthy — the library-side twin of the CLI's exit 2, and what
64
+ keeps a caller pinned to a renamed id from reading "checked and fine" over
65
+ a run that ran nothing.
66
+ - **`--status` and `--trust` filters** on catalog, files, search, tags and
67
+ types — `--status` matches the effective value (absent reads `stable`),
68
+ `--trust` folds either tier spelling.
69
+ - **Sources are searchable text** in both Ruby engines (weight 1 — the weight
70
+ the body text carried in v0.1) and snippet-eligible, so a migrated bundle
71
+ keeps its recall and a source-only hit keeps a snippet; the static page
72
+ bakes and indexes the same source text.
73
+ - **Trust as the graph page's third channel**: tier chips, status badges
74
+ (declared non-default only), a generated line, a client-clock stale marker,
75
+ and status/trust filter groups counted off the catalog.
76
+ - The skill teaches v0.2: the vendored SPEC is the published v0.2, a new
77
+ attested-computation template carries §10.3's MUST NOT, and the migrate
78
+ playbook walks the v0.1→v0.2 rewrite.
79
+ - **`Concept#shows_trust?` and `Bundle::RowFilter.shows_trust?` — §5.3's
80
+ display half, in one place.** The tier is always derivable; whether a surface
81
+ should *claim* it is a different question, and the answer is no for a concept
82
+ that declared no §5 family, which is every concept of every v0.1 bundle.
83
+ Claiming it there would paint a provenance verdict onto documents that never
84
+ made one — the false claim the trust system exists to prevent. The rule was
85
+ spelled twice, inline in `/node/meta` and in the page's `showsTrust`, and a
86
+ third consumer (okf-tui, which needs it for a chip, a facet gate, the facet
87
+ counts and the narrowing) is what a hand-copied predicate does not survive:
88
+ a gate disagreeing with the counts beside it reads "unverified 3" over two
89
+ chipped cards. One class method takes the two wire values so a Concept and a
90
+ catalog row ask the same rule; the server now routes through it, and the
91
+ page's client-side twin — unavoidable, since it runs over baked rows with no
92
+ Ruby to call — is pinned equal to it by `parity_test.rb`, truth table and
93
+ source literal both.
94
+ - **`Bundle#okf_version` — the spec version the root index declares (§12)**,
95
+ as the producer wrote it, or nil when it declares none, which §12 permits.
96
+ Stringified and stripped for the reason the validator compares that way: an
97
+ unquoted `okf_version: 0.2` is a Psych Float, and a consumer switching on it
98
+ must not be handed 0.2 the number. Public because the alternative is a
99
+ literal — a consumer naming the version on screen had no way to ask, which is
100
+ how a reader gets told "v0.1" about a bundle declaring 0.2. Unparseable
101
+ frontmatter stays the validator's error to report rather than this reader's
102
+ to raise.
103
+ - **`log_order` [info], the first log-side lint check.** §9 describes the log
104
+ as date-grouped entries, newest first — prose, not an RFC keyword, so
105
+ disorder is curation slack rather than a conformance error: exactly lint's
106
+ side of the split. Only shape-valid headings are compared; a malformed date
107
+ stays the validator's error, reported once.
108
+ - **`unprefixed_actor` now covers `generated.by` too.** §7 gives the actor
109
+ convention to both identity fields; only `verified[].by` was checked, on the
110
+ argument that §5.3 derives trust from nothing else — true, but a
111
+ `generated.by` no form can classify leaves a provenance reader unable to
112
+ tell a person from a process, so it earns the same info finding with its own
113
+ consequence. A *missing* `generated.by` stays the validator's warning.
114
+
115
+ - **`Bundle#stats` and `Bundle#tag_groups` join the library API** —
116
+ extracted from the CLI's `stats` and `tags --by` so the MCP shell reads
117
+ the same rollups instead of hand-copying them: the `by_dir` zero-keeping
118
+ subtlety and the within-group-beside-total tag counting each have one
119
+ home now (`Folder` delegates both). The CLI verbs are pure consumers of
120
+ the extraction; their output is unchanged.
121
+ - **Two long-standing behaviors are documented contract now, each with a
122
+ pinning test.** Hidden files are outside the bundle: the reader excludes
123
+ dot-prefixed files and everything under a dot-prefixed directory — the
124
+ Unix convention, kept so reading a project root cannot pull an installed
125
+ skill or `.github/` templates in as concepts. And a frontmatter `id:`
126
+ renames the concept, not its home — an extension beyond §2's path-derived
127
+ identity, with the recorded split stated where authors read it: the
128
+ identity views (catalog, hubs, `--dir`, search) follow the id, the
129
+ physical views (`index`, `dirs`, stats' `by_dir`) keep the file where it
130
+ lives. Both in the skill's authoring guide.
131
+
132
+ ### Changed
133
+
134
+ - **`validate` warns on a declared-but-blank `status`.** `status: ""` is a
135
+ producer typo, not an absence — §5.4's default belongs to a concept that
136
+ never declared the key — and reading the blank through the default turned it
137
+ into `stable` before the vocabulary check ran, so the one value §5.4 names
138
+ nowhere was the one that never warned.
139
+ - **`lint --stale-after` refuses the ISO spellings it used to reinterpret.**
140
+ It took whatever `Date.iso8601` parsed, so the basic (`20260101`) and week
141
+ (`2026-W01-1`) forms silently became a cutoff nobody asked for — `20260101`
142
+ read as the year 2026 day 01 of month 01 only by luck of the parser, and
143
+ `2026-W01-1` as 2025-12-29. Both now exit 2 naming the accepted shapes. A
144
+ `YYYY-MM-DD` date and a full `2026-01-01T09:00:00Z` timestamp (what a
145
+ concept's own `generated.at` looks like) are both still accepted, the
146
+ timestamp reduced to its date as before. The new `--today` takes the
147
+ narrower grammar — it names a calendar day, not a moment.
148
+ - **The gem targets OKF v0.2** and keeps reading v0.1 under §13.1's two
149
+ sanctioned fallbacks: a legacy `timestamp` reads as `generated.at` (per-key,
150
+ so a half-migrated `generated: { by: … }` beside a `timestamp` keeps its
151
+ date, and no actor is ever invented), and a body `# Citations` list reads as
152
+ `sources` whenever the native key yields zero mappings. One `OKF::Concept`
153
+ class, no version hierarchy; a pure v0.1 bundle still validates with zero
154
+ warnings.
155
+ - **Breaking: lint check ids renamed** — `missing_timestamp` is
156
+ `missing_generated`, `broken_citation` is `broken_source` — so `--only` /
157
+ `--except` lists naming the old ids exit 2. `uncited_external` is redefined
158
+ over `#sources` (a v0.1 `# Citations` still silences it — a prose-only
159
+ section included; so does a migrated `sources:` block). The `stale`
160
+ finding's JSON metric renames `timestamp:` to `generated_at:` (and its
161
+ message says "last updated <generated_at>") — a consumer reading
162
+ `finding.metric.timestamp` gets `null` and must move with it.
163
+ - **Breaking: the `timestamp` catalog column is removed** — `--fields
164
+ timestamp` exits 2 loudly, naming the valid fields. The `concepts` row gains
165
+ `generated_at`, `generated_by`, `generated` (the raw declared-key boolean
166
+ that tells hand-written apart from v0.1-with-timestamp), `trust` (the
167
+ hyphenated wire literals `unverified` | `machine-confirmed` |
168
+ `human-reviewed`), `stale_after`, and a `sources` count. `status` stays the
169
+ raw declared value, `null` when absent. Temporal values render ISO 8601.
170
+ - **Breaking: `Concept#citations` and `Markdown::Citations.targets` are
171
+ removed**, both subsumed by `Concept#sources` / `Citations.entries`.
172
+ - **The staleness boundary is `today >= stale_after`** — a concept is stale
173
+ **on** the day itself, per §5.5. A consumer replacing its own `<`-based
174
+ check shifts by one day and should know it.
175
+ - `GET /node/meta` returns JSON (`{ description, trust: { tier, generated_by,
176
+ generated_at, status, stale_after } }`, null-stripped) instead of an escaped
177
+ HTML fragment; the graph page composes the trust line client-side for served
178
+ and baked pages alike, and computes expiry against the viewer's own clock.
179
+ - The demo Open Graph card URL the graph template points at moved to
180
+ `og-demo-v5.png` (the site's card-art version bump); the old URL keeps
181
+ serving the current art, so nothing breaks in between.
182
+
183
+
184
+ ### Fixed
185
+
186
+ - **A calendar-invalid log heading is now a §11 error.** §9's MUST is ISO
187
+ 8601, and `## 2026-02-30` matched the digit shape while naming a day that
188
+ never existed — the validator now asks `Date.iso8601`, so a log.md is
189
+ conformant only around real dates.
190
+ - **`MAILTO:` is excluded case-insensitively**, like every other scheme (RFC
191
+ 3986). The guard sat inline and case-sensitive beside the case-insensitive
192
+ `SCHEME` regex in three places, so an uppercase mailto whose address ends in
193
+ `.md` resolved as a relative path — a link outside the bundle reported as a
194
+ file inside it. One `Links::MAILTO` now, beside `SCHEME`, for the same
195
+ reason `SCHEME` moved there.
196
+ - **`incomplete_computation` requires the fence, not the heading.** §10.3's
197
+ inline form is a fenced code block under `# Computation`; a heading over
198
+ prose used to count as provided, and a contract with nothing an executor
199
+ could run lint'd clean.
200
+
201
+
202
+ ## [1.13.0] - 2026-08-07
203
+
204
+ ### Added
205
+
206
+ - **`Bundle#directories`** — the bundle's own answer to "does this bundle have
207
+ directory X?", public because every surface now asks it (the CLI's concept
208
+ views, `okf-mcp`'s `dir` refusal) and the API this version's minor bump
209
+ exists for. Introduced by, and argued in, the `root` fix under Fixed below.
210
+
211
+ ### Changed
212
+
213
+ - **The repository became a monorepo, and the gem moved into `okf/`.** Nothing
214
+ about the published gem changes in kind — same name, same library, same `v*` tag
215
+ series, same image, byte-identical in size to a pre-move build — but a checkout is laid out differently: one
216
+ directory per gem, named for the gem it ships, so `okf-mcp/` and the rest can
217
+ land beside the baseline without reshaping anything. `plugin/`,
218
+ `.claude-plugin/`, `.okf/` and the `Dockerfile` stay at the root; the last of
219
+ those because its build context must be the repo root, where the `.git` the
220
+ gemspec's `git ls-files` needs lives. From a checkout it is `cd okf` for
221
+ everything about the gem, and plain `rake` at the root to run every gem's suite
222
+ or to validate this repo's own bundle.
223
+ - **`CODE_OF_CONDUCT.md` no longer ships in the gem** (70 files, from 71). It is
224
+ a repository document and was packaged only because nothing rejected it. The
225
+ gem now carries **its own README** instead of the project's — which also fixes
226
+ a long-standing wart, since the project README opens with images under
227
+ `.github/` that the gemspec has never packaged, so the page on rubygems.org has
228
+ been rendering a broken hero.
229
+ - `changelog_uri` points at `okf/CHANGELOG.md`, where this file now lives.
230
+
231
+ ### Fixed
232
+
233
+ - **A directory really named `root` is nameable again.** `--dir` and `--area`
234
+ accept `root` as a spelling of the bundle root, which is worth a shell quote
235
+ right up until a bundle actually has a `root/` directory — and then the alias
236
+ made it unaddressable, answering for the bundle root instead: the wrong
237
+ concepts, exit 0, nothing said. The alias now yields to a real directory,
238
+ since a convenience is worth less than a directory being reachable at all;
239
+ where no such directory exists nothing changes, which is every bundle that
240
+ has ever relied on the spelling. `okf dirs` carried the same fold into its
241
+ `subtree` column, where it computed the `root` row's subtree against the
242
+ bundle root — so the number on the row disagreed with what `--dir` on that
243
+ row returns, the one thing it promises never to do.
244
+
245
+ "Does this bundle have a `root` directory?" is now asked of the bundle
246
+ (`Bundle#directories`, under Added above) rather than of whichever list a view
247
+ had to hand. The concept views were reading it off the *catalog*, which knows
248
+ only directories holding concepts, so a `root/` carrying nothing but an
249
+ `index.md` stayed folded in `catalog`/`files`/`tags`/`types`/`search` while
250
+ `dirs` and `index` named it correctly — two answers to one question about one
251
+ bundle. And a multi-bundle `okf search @a @b --dir root` resolved per bundle
252
+ inside the loop, so one flag meant the `root/` subtree in the bundle that has
253
+ one and the bundle root in the bundle that does not, merged into a single
254
+ ranking with nothing in the output saying so; the served set resolves it once.
255
+
256
+ `Bundle#directories` counts every file kind that makes a directory real —
257
+ concepts, an `index.md`, and now a scoped `log.md`, which the first cut left
258
+ out: a `root/` holding only its history was invisible to the set, so the
259
+ alias won again for exactly the shape the fix was named after, one file kind
260
+ over. The same seed feeds `directory_index`, so `dirs`, `index` and `stats`
261
+ count a log-only directory too, and every surface answers "does this bundle
262
+ have directory X?" from one list.
263
+ - **`filter_entries` regained its 1.12.0 arity.** The dirs-source fix above
264
+ added a required third parameter to a helper on `CLI::Command` — the base
265
+ every verb inherits, plugin gems' verbs included — so an out-of-tree verb
266
+ calling the released two-argument shape raised `ArgumentError` at runtime.
267
+ The parameter defaults now, and the default is 1.12.0's resolution — the
268
+ helper is handed rows, not the folder, so it has nothing to resolve a real
269
+ `root/` against, and the `root` alias folds exactly as it did; the plugin
270
+ suite drives a 1.12.0-era verb through the two-argument shape to pin it.
271
+ Its sibling `filter_ids` makes the opposite choice on purpose: it *is*
272
+ handed the folder, and its two-argument shape resolves through `dir_scope`,
273
+ because the unconditional fold there was the bug this entry fixes, not a
274
+ contract — an old caller gets the corrected answer rather than the familiar
275
+ wrong one. In-tree callers pass
276
+ the set through `dir_scope`, which also derives it only when a `--dir` or
277
+ `--area` flag will actually consult it — a plain listing no longer pays a
278
+ per-path ancestor walk for a set nothing reads (and `Bundle#directories` is
279
+ memoized, so the verbs that ask twice pay once).
280
+ - **Coverage stopped measuring the plugin's curation hook** for one commit, and
281
+ said so by going *up*: SimpleCov's root defaults to the working directory, so
282
+ moving the gem down a level dropped ~100 tested lines out of the report and
283
+ line coverage read 98.63% against 98.47%. Its root is the repository now, with
284
+ the report still written inside the gem.
285
+
286
+ ### Security
287
+
288
+ - **A symlinked file in a bundle can no longer read past the bundle root.** The
289
+ traversal guard `Path.join_under!` was lexical — it expands the path string,
290
+ and `File.expand_path` does not resolve a symlink — so a link whose name sat
291
+ inside the root but whose target did not passed the check, and the read
292
+ followed it. Every read now realpath-resolves and re-checks against the real
293
+ root: `Path.under?` is the shared pure predicate, `Bundle::Reader` quarantines
294
+ an escaping file into the unparseable bucket (a planted symlink is one bad
295
+ file, not grounds to fail the whole bundle read, which would hand any writer of
296
+ a served directory a denial of service), and `Concept::File` guards its own
297
+ read. A symlink that stays inside the bundle still resolves as before. The gap
298
+ reached every reader; serving a bundle's contents to an agent — as `okf-mcp`
299
+ does — is what surfaced it.
300
+
8
301
  ## [1.12.0] - 2026-07-24
9
302
 
10
303
  ### Added
@@ -1223,6 +1516,9 @@ Initial release.
1223
1516
 
1224
1517
  - Runs on Ruby >= 2.4 with two runtime dependencies: rack and webrick.
1225
1518
 
1519
+ [2.0.0]: https://github.com/serradura/okf-gem/compare/v1.13.0...v2.0.0
1520
+ [1.13.0]: https://github.com/serradura/okf-gem/compare/v1.12.0...v1.13.0
1521
+ [1.12.0]: https://github.com/serradura/okf-gem/compare/v1.11.0...v1.12.0
1226
1522
  [1.11.0]: https://github.com/serradura/okf-gem/compare/v1.10.0...v1.11.0
1227
1523
  [1.10.0]: https://github.com/serradura/okf-gem/compare/v1.9.0...v1.10.0
1228
1524
  [1.9.0]: https://github.com/serradura/okf-gem/compare/v1.8.0...v1.9.0