okf 2.1.0 → 2.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 +4 -4
- data/.okf/capabilities/agent-skill.md +112 -0
- data/.okf/capabilities/bundles-manager.md +144 -0
- data/.okf/capabilities/graph-server.md +678 -0
- data/.okf/capabilities/index.md +26 -0
- data/.okf/capabilities/library-api.md +82 -0
- data/.okf/capabilities/linter.md +83 -0
- data/.okf/capabilities/read-views.md +228 -0
- data/.okf/capabilities/render.md +66 -0
- data/.okf/capabilities/search.md +297 -0
- data/.okf/capabilities/validator.md +60 -0
- data/.okf/cli.md +214 -0
- data/.okf/design/browser-tests.md +211 -0
- data/.okf/design/core-shell-split.md +73 -0
- data/.okf/design/index.md +17 -0
- data/.okf/design/integration-first.md +140 -0
- data/.okf/design/packaging.md +65 -0
- data/.okf/design/ruby-floor.md +53 -0
- data/.okf/design/runtime-dependencies.md +82 -0
- data/.okf/design/search-engines.md +154 -0
- data/.okf/design/server-trust-boundary.md +139 -0
- data/.okf/index.md +40 -0
- data/.okf/log.md +724 -0
- data/.okf/model/bundle.md +47 -0
- data/.okf/model/concept.md +75 -0
- data/.okf/model/graph.md +59 -0
- data/.okf/model/index.md +9 -0
- data/.okf/model/skeleton.md +76 -0
- data/.okf/overview.md +87 -0
- data/.okf/registry.md +432 -0
- data/.okf/structure/format-layer.md +59 -0
- data/.okf/structure/index.md +22 -0
- data/.okf/structure/search.md +53 -0
- data/.okf/structure/the-analysers.md +60 -0
- data/.okf/structure/the-cli.md +99 -0
- data/.okf/structure/the-disk-shell.md +76 -0
- data/.okf/structure/the-model.md +81 -0
- data/.okf/structure/the-server.md +74 -0
- data/.okf/structure/the-skill.md +52 -0
- data/.okf/testing/adding-a-verb.md +76 -0
- data/.okf/testing/index.md +12 -0
- data/.okf/testing/the-harness.md +45 -0
- data/CHANGELOG.md +161 -16
- data/README.md +226 -17
- data/lib/okf/cli/command.rb +8 -3
- data/lib/okf/cli/registry.rb +306 -47
- data/lib/okf/cli.rb +1 -1
- data/lib/okf/registry.rb +448 -22
- data/lib/okf/render/graph/template.html.erb +6 -2
- data/lib/okf/server/hub.rb +6 -2
- data/lib/okf/skill/reference/cli/registry.md +49 -6
- data/lib/okf/skill/reference/cli.md +1 -1
- data/lib/okf/version.rb +1 -1
- metadata +46 -5
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Component
|
|
3
|
+
title: OKF::Bundle
|
|
4
|
+
description: The pure in-memory collection of concepts that validate, lint, and graph run over.
|
|
5
|
+
resource: gems/okf/lib/okf/bundle.rb
|
|
6
|
+
tags: [pure]
|
|
7
|
+
generated:
|
|
8
|
+
by: human:maintainer
|
|
9
|
+
at: 2026-08-13T12:00:00Z
|
|
10
|
+
sources:
|
|
11
|
+
- title: gems/okf/lib/okf/bundle.rb
|
|
12
|
+
resource: https://github.com/serradura/okf/blob/main/gems/okf/lib/okf/bundle.rb
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Overview
|
|
16
|
+
|
|
17
|
+
`OKF::Bundle` is a set of [concepts](concept.md) held together in memory, with no
|
|
18
|
+
disk involved. It is the object the three judging capabilities operate on:
|
|
19
|
+
`#validate`, `#lint`, and `#graph` each hand the bundle to a dedicated pure
|
|
20
|
+
class and return a result. A bundle also carries the reserved files
|
|
21
|
+
(`index.md`, `log.md`) and — importantly — an `unparseable` list.
|
|
22
|
+
|
|
23
|
+
# Best-effort by construction
|
|
24
|
+
|
|
25
|
+
When a bundle is built from disk, files the reader cannot use do not vanish and do
|
|
26
|
+
not abort the build: they are collected in `bundle.unparseable` — frontmatter that
|
|
27
|
+
would not parse, and files that would not open, since a locked file is one file's
|
|
28
|
+
problem and not the bundle's. That is what
|
|
29
|
+
lets [graph](graph.md), the [server](../capabilities/graph-server.md), and the
|
|
30
|
+
[read views](../capabilities/read-views.md) render everything that *is* valid
|
|
31
|
+
while the [CLI](../cli.md) notes the skips on stderr — §11's best-effort posture,
|
|
32
|
+
made structural.
|
|
33
|
+
|
|
34
|
+
# Build it from data, not only from files
|
|
35
|
+
|
|
36
|
+
Because the bundle is pure, an embedding application can construct concepts
|
|
37
|
+
straight from its own records — no Markdown round-trip — and still get validate,
|
|
38
|
+
lint, and graph for free. This is the surface the
|
|
39
|
+
[library API](../capabilities/library-api.md) exposes to, say, a Rails store that
|
|
40
|
+
already holds knowledge as rows. It also feeds the shared `#catalog`, the data
|
|
41
|
+
behind every read view — and the rollups beside it, each kept in one home
|
|
42
|
+
after a hand copy diverged: `#stats` (whose `by_dir` reads the directory
|
|
43
|
+
index, so an empty directory reports its honest zero), `#tag_groups` (the
|
|
44
|
+
vocabulary-curation cut, within-group counts beside cross-set totals), and
|
|
45
|
+
`Bundle::References` (the §6.3 inventory — the one model that sees a bundle's
|
|
46
|
+
non-markdown files, fed a manifest by the shell). The CLI verbs and the MCP
|
|
47
|
+
tools consume the same three.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Component
|
|
3
|
+
title: OKF::Concept
|
|
4
|
+
description: The pure in-memory model of a single OKF file — frontmatter, body, and a stable id.
|
|
5
|
+
resource: gems/okf/lib/okf/concept.rb
|
|
6
|
+
tags: [pure]
|
|
7
|
+
generated:
|
|
8
|
+
by: human:maintainer
|
|
9
|
+
at: 2026-08-14T12:00:00Z
|
|
10
|
+
sources:
|
|
11
|
+
- title: gems/okf/lib/okf/concept.rb
|
|
12
|
+
resource: https://github.com/serradura/okf/blob/main/gems/okf/lib/okf/concept.rb
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Overview
|
|
16
|
+
|
|
17
|
+
`OKF::Concept` is the atomic node: a `path`, a parsed
|
|
18
|
+
`frontmatter` (`@okf-eco format/frontmatter`) hash, and a Markdown `body`. It is
|
|
19
|
+
[pure](../design/core-shell-split.md) — it holds no file handle and does no I/O.
|
|
20
|
+
The on-disk counterpart is `OKF::Concept::File`, part of the
|
|
21
|
+
[library API](../capabilities/library-api.md).
|
|
22
|
+
|
|
23
|
+
# The id is the concept's identity
|
|
24
|
+
|
|
25
|
+
`#id` is the concept's **stable identifier** across the whole system — the graph
|
|
26
|
+
node key, the link target, and the thing you name a concept for. By default it is
|
|
27
|
+
the `path` minus `.md` (e.g. `model/graph.md` → `model/graph`), which is why you
|
|
28
|
+
name a file for what it *is*, not where it sits. A frontmatter `id`, when set,
|
|
29
|
+
pins the identity explicitly — the path-derived name is the fallback, not the only
|
|
30
|
+
source — so a concept can keep its id across a move.
|
|
31
|
+
|
|
32
|
+
The override is this gem's **extension, not spec**: §2 defines the concept id
|
|
33
|
+
as the path minus `.md`, full stop. Pinning one puts the concept in two worlds
|
|
34
|
+
on purpose — the identity views ([catalog, hubs, `--dir`,
|
|
35
|
+
search](../capabilities/read-views.md)) follow the id, because the edges do,
|
|
36
|
+
while the physical views (`index`, `dirs`, stats' `by_dir`) keep the file where
|
|
37
|
+
it lives, because an index is a physical listing. An integration test holds a
|
|
38
|
+
concept whose id leaves its directory and asserts both worlds at once, so the
|
|
39
|
+
split stays a decision; the authoring advice is the default's — rename the
|
|
40
|
+
file, not the id.
|
|
41
|
+
|
|
42
|
+
# What it derives from its own content
|
|
43
|
+
|
|
44
|
+
The concept parses its body on demand into the structural facts the rest of the
|
|
45
|
+
gem consumes:
|
|
46
|
+
|
|
47
|
+
- `#type`, `#title`, `#description`, `#resource`, `#tags` — typed reads over
|
|
48
|
+
the frontmatter;
|
|
49
|
+
- the §5 families, each carrying §13.1's fallbacks inline: `#generated` /
|
|
50
|
+
`#generated_at` / `#generated_by` (a legacy `timestamp` lifts into `at`,
|
|
51
|
+
per-key, with no actor ever invented), `#sources` (the native list, or the
|
|
52
|
+
legacy `# Citations` (`@okf-eco format/citations`) body list whenever the native
|
|
53
|
+
value yields zero mappings), `#verified` (a bare mapping reads as a
|
|
54
|
+
one-element list; degenerate shapes fold to unverified), `#trust_tier` /
|
|
55
|
+
`#trust` (derived per §5.3, never stored), `#status`/`#declared_status`
|
|
56
|
+
(absent reads stable; both keep the producer's spelling, because every
|
|
57
|
+
surface that *displays* a status prints what was written — the fold belongs
|
|
58
|
+
to `.effective_status`, which is what narrowing compares through), `#stale_after_date`/`#stale_on?(today)` (§5.5 — stale
|
|
59
|
+
on the day itself; the clock is always an argument, never read);
|
|
60
|
+
- the §10 contract of an Attested Computation: `#runtime`, `#parameters`,
|
|
61
|
+
`#computation`, `#executor`, `#attester`, `#attested_computation?`;
|
|
62
|
+
- `#usage_window` — validated for shape, deliberately consumed by nothing: no
|
|
63
|
+
gem surface computes over usage counts, so an effective-window resolver
|
|
64
|
+
would be speculative;
|
|
65
|
+
- `#declared_generated?`, `#legacy_timestamp?`, `#legacy_citations?` — raw-key
|
|
66
|
+
detection for lint and the surfaces; detection never influences reading;
|
|
67
|
+
- `#links` — every raw cross-link (`@okf-eco format/cross-links`) target in the body, in order; the bundle-relative ones become graph edges;
|
|
68
|
+
- `#external_links` — the subset of those that are URLs or `mailto:` (not edges);
|
|
69
|
+
- `#to_markdown` — the inverse of the frontmatter parser (`#citations` is gone,
|
|
70
|
+
subsumed by `#sources`);
|
|
71
|
+
- `#lint` — the concept-scoped [lint](../capabilities/linter.md) checks in isolation.
|
|
72
|
+
|
|
73
|
+
A concept never decides conformance alone; a [bundle](bundle.md) does, because
|
|
74
|
+
some checks (duplicate titles, missing link targets) are only meaningful across
|
|
75
|
+
the set.
|
data/.okf/model/graph.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Component
|
|
3
|
+
title: OKF::Bundle::Graph
|
|
4
|
+
description: The in-memory knowledge graph — concepts as nodes, cross-links as directed edges, with type and tag indexes.
|
|
5
|
+
resource: gems/okf/lib/okf/bundle/graph.rb
|
|
6
|
+
tags: [graph, pure]
|
|
7
|
+
generated:
|
|
8
|
+
by: human:maintainer
|
|
9
|
+
at: 2026-08-13T12:00:00Z
|
|
10
|
+
sources:
|
|
11
|
+
- title: gems/okf/lib/okf/bundle/graph.rb
|
|
12
|
+
resource: https://github.com/serradura/okf/blob/main/gems/okf/lib/okf/bundle/graph.rb
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Overview
|
|
16
|
+
|
|
17
|
+
`OKF::Bundle::Graph` turns a [bundle](bundle.md) into nodes and edges:
|
|
18
|
+
[concepts](concept.md) become nodes keyed by id, and bundle-relative
|
|
19
|
+
cross-links (`@okf-eco format/cross-links`) become directed edges. It is pure — it
|
|
20
|
+
carries no presentation concerns; sizing and colour belong to a renderer like
|
|
21
|
+
the [graph server](../capabilities/graph-server.md).
|
|
22
|
+
|
|
23
|
+
# Fidelity is a build option
|
|
24
|
+
|
|
25
|
+
The same graph ships at three weights, so a client downloads only what it needs
|
|
26
|
+
and fetches the rest on demand:
|
|
27
|
+
|
|
28
|
+
| Build | Node payload |
|
|
29
|
+
|-------|--------------|
|
|
30
|
+
| default (`body: true`) | id, type, title, description, tags, **body** |
|
|
31
|
+
| `body: false` | everything but the body |
|
|
32
|
+
| `minimal: true` | just id and title — the leanest payload to draw |
|
|
33
|
+
|
|
34
|
+
# Indexes come free at every weight
|
|
35
|
+
|
|
36
|
+
Regardless of node fidelity, the graph exposes two inverted indexes computed from
|
|
37
|
+
every concept:
|
|
38
|
+
|
|
39
|
+
- `type_index` — `{ type => [id, …] }`, so even a minimal client can colour nodes
|
|
40
|
+
by [`type`](concept.md). A concept whose type is missing *or blank* indexes
|
|
41
|
+
under `Untyped`: §11 condition 2 rejects the two identically (the
|
|
42
|
+
[validator](../capabilities/validator.md) asks `OKF.blank?`, not `empty?`), so
|
|
43
|
+
sorting them into different buckets would give `type: " "` a row of its own,
|
|
44
|
+
labelled with spaces;
|
|
45
|
+
- `tag_index` — `{ tag => [id, …] }`, so it can filter by tag.
|
|
46
|
+
|
|
47
|
+
Those indexes, plus `unlinked_ids` (degree-0 nodes), are what the
|
|
48
|
+
[read views](../capabilities/read-views.md) — `types`, `tags`, `stats`, `loose`
|
|
49
|
+
— are built from, and what their `--type`/`--dir`/`--tag` filters match against.
|
|
50
|
+
|
|
51
|
+
# Reduced to a skeleton
|
|
52
|
+
|
|
53
|
+
Where this graph is the full wiring, the [skeleton](skeleton.md) is the same
|
|
54
|
+
graph made holdable: concepts collapsed into their directory, the links between
|
|
55
|
+
two directories collapsed into one weighted arc, and every link tagged with the
|
|
56
|
+
cut it survives. It is the reduction [`graph --traffic`](../capabilities/read-views.md)
|
|
57
|
+
reads for cohesion and the [graph page](../capabilities/graph-server.md) lays a
|
|
58
|
+
large bundle out on — built from this graph's own nodes and edges, and just as
|
|
59
|
+
pure.
|
data/.okf/model/index.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# The model
|
|
2
|
+
|
|
3
|
+
The pure, in-memory data structures the gem builds a bundle out of — no disk, no
|
|
4
|
+
stdio. Everything else reads or renders these.
|
|
5
|
+
|
|
6
|
+
* [Concept](concept.md) - one file's worth of knowledge: frontmatter plus body, with a stable id.
|
|
7
|
+
* [Bundle](bundle.md) - a collection of concepts you validate, lint, and graph.
|
|
8
|
+
* [Graph](graph.md) - concepts as nodes, cross-links as edges, plus type and tag indexes.
|
|
9
|
+
* [Skeleton](skeleton.md) - the graph reduced: directories, the weighted arcs between them, and each link with the cut it survives.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Component
|
|
3
|
+
title: OKF::Bundle::Skeleton
|
|
4
|
+
description: The graph reduced to what a reader can hold — directories, the weighted arcs between them, and each link with the cut it survives.
|
|
5
|
+
resource: gems/okf/lib/okf/bundle/skeleton.rb
|
|
6
|
+
tags: [graph, pure]
|
|
7
|
+
generated:
|
|
8
|
+
by: human:maintainer
|
|
9
|
+
at: 2026-07-23T12:00:00Z
|
|
10
|
+
sources:
|
|
11
|
+
- title: gems/okf/lib/okf/bundle/skeleton.rb
|
|
12
|
+
resource: https://github.com/serradura/okf/blob/main/gems/okf/lib/okf/bundle/skeleton.rb
|
|
13
|
+
- title: gems/okf/lib/okf/cli/graph.rb
|
|
14
|
+
resource: https://github.com/serradura/okf/blob/main/gems/okf/lib/okf/cli/graph.rb
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Overview
|
|
18
|
+
|
|
19
|
+
`OKF::Bundle::Skeleton` is the [graph](graph.md) reduced to what a reader can
|
|
20
|
+
hold in their head. It is built from a graph's nodes and edges, does no I/O, and
|
|
21
|
+
decides nothing about how any of it is drawn — the same purity the graph keeps,
|
|
22
|
+
one level of abstraction up. Two consumers read it: [`graph
|
|
23
|
+
--traffic`](../capabilities/read-views.md) prints its directory reduction, and
|
|
24
|
+
the [graph page](../capabilities/graph-server.md)'s link layer lays a large
|
|
25
|
+
bundle out on the backbone it names.
|
|
26
|
+
|
|
27
|
+
A dense bundle is not dense the way a hub-and-spoke picture is. Measured on a
|
|
28
|
+
47-concept bundle with 227 links, the top hub takes 13 inbound and the median 4 —
|
|
29
|
+
no 80/20 to exploit, so dropping two-thirds of the *concepts* still leaves 53
|
|
30
|
+
edges. The density lives **between directories**: 173 of those 227 links (76%)
|
|
31
|
+
cross a directory boundary. That is the reduction worth drawing, and it is why
|
|
32
|
+
this class exists at all.
|
|
33
|
+
|
|
34
|
+
# The two things it produces
|
|
35
|
+
|
|
36
|
+
- **`dirs` + `arcs`** — the reduction as counts: one row per directory, one
|
|
37
|
+
weighted arc per ordered pair of directories. This is what `graph --traffic`
|
|
38
|
+
prints, with **cohesion** (a directory's internal share of its own traffic)
|
|
39
|
+
derived from them. Directories come off the concept *id* (`OKF.dir_of`), not
|
|
40
|
+
the file path, so this agrees with the graph's own `catalog` and `--dir`
|
|
41
|
+
filter — the side that follows the id, because the edges do.
|
|
42
|
+
- **`edges`, each with its `keep_at`** — the smallest cut at which a link
|
|
43
|
+
survives. Nothing prints these; they are what lets the graph page lay a large
|
|
44
|
+
bundle out on its strongest links first, inlined into the page as `EDGE_CUT`
|
|
45
|
+
because the layout needs them before any `fetch()` could answer.
|
|
46
|
+
|
|
47
|
+
Both are emitted **unthresholded**, and `#suggested_cut` *names* where to cut
|
|
48
|
+
rather than cutting — so a caller narrows the picture without this class ever
|
|
49
|
+
having to know what a picture is.
|
|
50
|
+
|
|
51
|
+
# The cut is fitted, not fixed
|
|
52
|
+
|
|
53
|
+
A fixed arc cut cannot serve both ends of the size range: measured at weight 3
|
|
54
|
+
across ten bundles, it left **2 arcs on one and 136 on another** — too tight to
|
|
55
|
+
be a picture at one end, no reduction at all at the other. What stays roughly
|
|
56
|
+
constant as a bundle grows is not the arc count but the arcs *per box*, since a
|
|
57
|
+
node-link diagram reads at about one to two edges per node regardless of size. So
|
|
58
|
+
`#suggested_cut` targets 1.5 arcs per directory and reports the weight that
|
|
59
|
+
delivers it, floored at 8 for the small end. Cohesion is computed over **every**
|
|
60
|
+
arc regardless of the cut, so narrowing the drawn picture never moves the
|
|
61
|
+
evidence under it.
|
|
62
|
+
|
|
63
|
+
# The spine is a sparsifier, not a sample
|
|
64
|
+
|
|
65
|
+
The `keep_at === 0` set is the **spine**: each concept's single most-connected
|
|
66
|
+
neighbour. It is chosen, not sampled, and the property that earns it the name is
|
|
67
|
+
that it **touches every linked concept**, so a layout run over it alone strands
|
|
68
|
+
nothing and the arrangement is a real one rather than a sketch to be redone.
|
|
69
|
+
|
|
70
|
+
It is the local-degree sparsifier (Lindner et al.) with a union rule — an edge
|
|
71
|
+
survives if *either* endpoint kept it — which is what stops it from stranding the
|
|
72
|
+
quiet half of a bundle the way a global "drop the weakest edges" rule does. It is
|
|
73
|
+
**not** the disparity filter, the usual name in this territory: that reads an
|
|
74
|
+
edge's weight against its endpoint's total, and every link here weighs exactly 1,
|
|
75
|
+
which makes every proportion identical and the filter a coin toss. Weighted-graph
|
|
76
|
+
tools do not transfer to an unweighted graph just because both are graphs.
|
data/.okf/overview.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Overview
|
|
3
|
+
title: okf at a glance
|
|
4
|
+
description: A light Ruby gem that reads, searches, validates, lints, and serves Open Knowledge Format v0.2 bundles.
|
|
5
|
+
tags: [okf, gem, diagram]
|
|
6
|
+
generated:
|
|
7
|
+
by: human:maintainer
|
|
8
|
+
at: 2026-08-13T12:00:00Z
|
|
9
|
+
sources:
|
|
10
|
+
- title: README.md
|
|
11
|
+
resource: https://github.com/serradura/okf/blob/main/README.md
|
|
12
|
+
- title: AGENTS.md
|
|
13
|
+
resource: https://github.com/serradura/okf/blob/main/AGENTS.md
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Overview
|
|
17
|
+
|
|
18
|
+
**okf** — the gem on RubyGems — operates on OKF v0.2 (`@okf-eco format/okf-format`)
|
|
19
|
+
bundles: directories of Markdown files with YAML frontmatter that humans and
|
|
20
|
+
agents both read from one source. It does not define new knowledge storage; it
|
|
21
|
+
gives you leverage over knowledge that already lives as Markdown.
|
|
22
|
+
|
|
23
|
+
```mermaid
|
|
24
|
+
flowchart LR
|
|
25
|
+
skill["companion<br/>agent skill"] -. authors/curate .-> bundle[("OKF v0.2 bundle<br/>Markdown + YAML")]
|
|
26
|
+
bundle --> model["pure model<br/>Concept · Bundle · Graph"]
|
|
27
|
+
skill -. execute .-> cli
|
|
28
|
+
subgraph cli ["okf CLI"]
|
|
29
|
+
validate["validate — legal? §11"]
|
|
30
|
+
lint["lint — well-curated?"]
|
|
31
|
+
search["search — which concept?"]
|
|
32
|
+
server["server — explore"]
|
|
33
|
+
end
|
|
34
|
+
model --> cli
|
|
35
|
+
model --> library["library API<br/>embed in Ruby"]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Over such a bundle the gem gives you seven capabilities behind one
|
|
39
|
+
[command-line tool](cli.md):
|
|
40
|
+
|
|
41
|
+
| Capability | What it answers | Verb |
|
|
42
|
+
| -------------------------------------------------------- | --------------------------------- | ---------------- |
|
|
43
|
+
| [Companion agent skill](capabilities/agent-skill.md) | Can an agent author it? | `skill` |
|
|
44
|
+
| [Conformance validator](capabilities/validator.md) | Is this a legal OKF bundle? (§11) | `validate` |
|
|
45
|
+
| [Curation linter](capabilities/linter.md) | Is it navigable, complete, fresh? | `lint` / `loose` |
|
|
46
|
+
| [Ranked text search](capabilities/search.md) | Which concept covers X? | `search` |
|
|
47
|
+
| [Interactive graph server](capabilities/graph-server.md) | Can I explore it visually? | `server` |
|
|
48
|
+
| [Static render](capabilities/render.md) | Can I ship a serverless snapshot? | `render` |
|
|
49
|
+
| [Library API](capabilities/library-api.md) | Can my Ruby program use it? | (in-process) |
|
|
50
|
+
|
|
51
|
+
Beside the gem's seven, the sibling surfaces. The
|
|
52
|
+
MCP server (`@okf-mcp design/the-tool-set`) (`okf-mcp`) projects the same kernel
|
|
53
|
+
onto the Model Context Protocol so any MCP-capable agent host reads these
|
|
54
|
+
bundles without a terminal — ten read-only tools, concepts as resources a host
|
|
55
|
+
can attach on its own, and the [skill's](capabilities/agent-skill.md) playbooks
|
|
56
|
+
as prompts. The enforcement layer (`@okf-eco gems/okf-pro`) (`okf-pro`)
|
|
57
|
+
goes the other way and is the only surface here that **writes**: it generates an
|
|
58
|
+
agent's knowledge repository — bundle, hooks, pre-commit, CI, skill — and then
|
|
59
|
+
holds it to a few invariants at all three doors, under a contract where a gate
|
|
60
|
+
that cannot check refuses rather than shrugs.
|
|
61
|
+
|
|
62
|
+
Alongside those, a family of [read views](capabilities/read-views.md) —
|
|
63
|
+
`index`, `catalog`, `files`, `types`, `tags`, `stats`, `graph` — print the bundle at a
|
|
64
|
+
glance so an agent reads it without a browser.
|
|
65
|
+
|
|
66
|
+
Knowledge rarely lives in one bundle, so `okf server` hosts one, several, or every
|
|
67
|
+
bundle in a per-user [registry](registry.md) — one hub, one switcher, no per-repo
|
|
68
|
+
server to remember.
|
|
69
|
+
|
|
70
|
+
# The two ideas it inherits from the format
|
|
71
|
+
|
|
72
|
+
- **Dual audience.** Every file serves a human skimming it _and_ an agent
|
|
73
|
+
extracting from it, so bodies are structural Markdown and
|
|
74
|
+
links (`@okf-eco format/cross-links`) are plain Markdown links — both readers already
|
|
75
|
+
understand them.
|
|
76
|
+
- **The graph is emergent.** Files are nodes, Markdown links are edges. You never
|
|
77
|
+
declare a graph; the gem [builds one](model/graph.md) from how concepts link.
|
|
78
|
+
|
|
79
|
+
# Design ethos
|
|
80
|
+
|
|
81
|
+
The gem is deliberately light so it runs on the Ruby an OS already ships. That
|
|
82
|
+
ethos is not incidental — it is enforced by [hard constraints](design/):
|
|
83
|
+
a [Ruby 2.4 floor](design/ruby-floor.md), exactly
|
|
84
|
+
[three runtime dependencies](design/runtime-dependencies.md), and a
|
|
85
|
+
[core/shell split](design/core-shell-split.md) that keeps all logic pure and
|
|
86
|
+
testable without disk. Everything else — no ActiveSupport, no build step, no
|
|
87
|
+
JavaScript toolchain — follows from those.
|