okf 1.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 (65) hide show
  1. checksums.yaml +7 -0
  2. data/.okf/capabilities/agent-skill.md +46 -0
  3. data/.okf/capabilities/graph-server.md +60 -0
  4. data/.okf/capabilities/index.md +20 -0
  5. data/.okf/capabilities/library-api.md +67 -0
  6. data/.okf/capabilities/linter.md +49 -0
  7. data/.okf/capabilities/read-views.md +84 -0
  8. data/.okf/capabilities/validator.md +40 -0
  9. data/.okf/cli.md +52 -0
  10. data/.okf/design/core-shell-split.md +58 -0
  11. data/.okf/design/index.md +10 -0
  12. data/.okf/design/ruby-floor.md +45 -0
  13. data/.okf/design/runtime-dependencies.md +44 -0
  14. data/.okf/design/server-trust-boundary.md +35 -0
  15. data/.okf/format/citations.md +33 -0
  16. data/.okf/format/cross-links.md +52 -0
  17. data/.okf/format/frontmatter.md +38 -0
  18. data/.okf/format/index.md +9 -0
  19. data/.okf/format/okf-format.md +43 -0
  20. data/.okf/index.md +18 -0
  21. data/.okf/log.md +9 -0
  22. data/.okf/model/bundle.md +38 -0
  23. data/.okf/model/concept.md +44 -0
  24. data/.okf/model/graph.md +44 -0
  25. data/.okf/model/index.md +8 -0
  26. data/.okf/overview.md +66 -0
  27. data/CHANGELOG.md +54 -0
  28. data/CODE_OF_CONDUCT.md +10 -0
  29. data/LICENSE.txt +201 -0
  30. data/NOTICE +10 -0
  31. data/README.md +276 -0
  32. data/exe/okf +6 -0
  33. data/lib/okf/bundle/folder.rb +94 -0
  34. data/lib/okf/bundle/graph.rb +118 -0
  35. data/lib/okf/bundle/linter/report.rb +56 -0
  36. data/lib/okf/bundle/linter.rb +416 -0
  37. data/lib/okf/bundle/reader.rb +60 -0
  38. data/lib/okf/bundle/validator/result.rb +35 -0
  39. data/lib/okf/bundle/validator.rb +131 -0
  40. data/lib/okf/bundle/writer.rb +137 -0
  41. data/lib/okf/bundle.rb +216 -0
  42. data/lib/okf/cli.rb +910 -0
  43. data/lib/okf/concept/file.rb +63 -0
  44. data/lib/okf/concept.rb +101 -0
  45. data/lib/okf/markdown/citations.rb +49 -0
  46. data/lib/okf/markdown/frontmatter.rb +55 -0
  47. data/lib/okf/markdown/links.rb +98 -0
  48. data/lib/okf/path.rb +34 -0
  49. data/lib/okf/server/app.rb +120 -0
  50. data/lib/okf/server/graph.rb +112 -0
  51. data/lib/okf/server/runner.rb +78 -0
  52. data/lib/okf/server/templates/graph.html.erb +803 -0
  53. data/lib/okf/skill/SKILL.md +133 -0
  54. data/lib/okf/skill/reference/APACHE-2.0.txt +202 -0
  55. data/lib/okf/skill/reference/SPEC.md +460 -0
  56. data/lib/okf/skill/reference/authoring.md +218 -0
  57. data/lib/okf/skill/reference/cli.md +196 -0
  58. data/lib/okf/skill/templates/concept.md +24 -0
  59. data/lib/okf/skill/templates/index.md +8 -0
  60. data/lib/okf/skill/templates/log.md +6 -0
  61. data/lib/okf/skill/templates/root-index.md +12 -0
  62. data/lib/okf/skill.rb +82 -0
  63. data/lib/okf/version.rb +5 -0
  64. data/lib/okf.rb +55 -0
  65. metadata +142 -0
@@ -0,0 +1,196 @@
1
+ # OKF tool verbs — the `okf` CLI
2
+
3
+ `validate`, `lint`, `loose`, `index`, `catalog`, `files`, `tags`, `types`, `stats`,
4
+ `server`, and `graph` are **not** eyeball passes and are not
5
+ reimplemented in this skill. They run the deterministic `okf` executable shipped by
6
+ the companion gem — the single source of truth for OKF mechanics. Your job is to
7
+ invoke it correctly and interpret the result, not to reason out conformance by hand.
8
+
9
+ ## Presence guard
10
+
11
+ Check the tool exists before relying on it. If it is missing, the gem is not
12
+ installed — say so and stop; never fabricate a result:
13
+
14
+ ```bash
15
+ command -v okf >/dev/null || echo "okf CLI not found — install it: 'gem install okf' (or from a checkout: 'cd gem && bundle exec rake install')"
16
+ ```
17
+
18
+ ## Invocation
19
+
20
+ The surface is self-describing — `okf --help` maps every verb, `okf <verb> --help`
21
+ its flags. Ask the tool for what exists; this file carries only what `--help`
22
+ cannot: each verb's semantics, its traps, and its JSON shape.
23
+
24
+ **`--json` is compact by design.** Every emitting verb prints single-line JSON —
25
+ the token-efficient substrate you consume; `--pretty` (which implies `--json`)
26
+ indents it for a human. The bytes differ, the JSON is identical, so parse either.
27
+ When you only need to *scan* a bundle, the plain text views are lighter still than
28
+ JSON (they print each key once, not per row) — reach for `--json` when you need to
29
+ extract structure, not merely read it.
30
+
31
+ **Project the JSON to what you'll read.** On `index`, `catalog`, and `files`,
32
+ `--fields a,b` keeps only those properties and `--except a,b` drops them
33
+ (mutually exclusive; both imply `--json`; an unknown name is a usage error that
34
+ lists the valid ones). Projection happens before emission, so you pay no tokens
35
+ for a field you dropped — e.g. `okf index <dir> --except body,listing` is the lean
36
+ directory *skeleton* (structure + rollups), and on a large bundle that is the
37
+ difference between a few hundred bytes and hundreds of KB, since the per-item rows
38
+ (`listing`) dominate at scale. `okf index --no-body` is shorthand for dropping just
39
+ `body`.
40
+
41
+ **Exit codes:** `0` success · `1` non-conformant bundle (or a `lint --fail-on`
42
+ threshold crossed) · `2` usage error. `graph` and `server` are best-effort
43
+ (§9): a file with invalid frontmatter is skipped and noted on stderr, never fatal.
44
+
45
+ ## validate — the hard gate (§9)
46
+
47
+ Implements the spec's §9 conformance definition exactly:
48
+
49
+ - **§9.1** every non-reserved file has a parseable YAML frontmatter block;
50
+ - **§9.2** every such block has a non-empty `type`;
51
+ - **§9.3** any `index.md`/`log.md` present follows §6/§7 (a nested `index.md` has
52
+ no frontmatter, a root `index.md` carries only `okf_version`, `log.md` date
53
+ headings are ISO `YYYY-MM-DD`).
54
+
55
+ `ERROR`s are the three conditions above; the bundle is non-conformant until every
56
+ one is fixed. `warn`s are soft — missing recommended fields, non-list tags, an
57
+ unparseable timestamp, and **broken cross-links, which §5.3 explicitly tolerates**.
58
+ Fix warnings when cheap; never block on them. Use `--json` in CI.
59
+
60
+ ## lint — curation quality (advisory)
61
+
62
+ Asks the complementary question to `validate`: not "is this legal OKF?" but "is
63
+ this well-curated, navigable, trustworthy?" — precisely over the things §9 forbids
64
+ `validate` from rejecting. It has its own report, never emits conformance errors,
65
+ and **exits `0` even with findings** unless you pass `--fail-on warn`.
66
+
67
+ Six conceptual categories, each backed by individual checks (names in parens):
68
+
69
+ - **reachability** — orphans, concepts not in any index, disconnected islands,
70
+ and unlinked (degree-0) files
71
+ (`orphan`, `not_in_index`, `disconnected_component`, `unlinked`)
72
+ - **backlog** — demand-ranked missing concepts (linked-to but absent), broken index entries
73
+ (`missing_concept`, `broken_index_entry`)
74
+ - **completeness** — stubs, missing `title` / `description` / `timestamp`
75
+ (`stub`, `missing_title`, `missing_description`, `missing_timestamp`)
76
+ - **freshness** — concepts older than a cutoff (`stale`) — **only computed when you
77
+ pass `--stale-after`; a plain `okf lint` never reports staleness at all**
78
+ - **provenance** — uncited external claims, broken citations, spec §8
79
+ (`uncited_external`, `broken_citation`)
80
+ - **hygiene** — duplicate titles, unused/undefined reference links, self-links
81
+ (`duplicate_title`, `unused_reference_def`, `undefined_reference`, `self_link`)
82
+
83
+ `--only` / `--except` filter by the **individual check names above**, not the
84
+ category labels — `okf lint <dir> --only orphan,stub` works; `--only reachability`
85
+ is an error. Two knobs tune specific checks: `--min-body N` sets the `stub` body
86
+ threshold in characters (default 50), and `--stale-after DUR` sets the `stale`
87
+ cutoff — a duration like `90d` or `12w`, or an ISO date like `2026-01-01` (a bare
88
+ number is rejected).
89
+
90
+ `lint --json` is the structured substrate you consume to reason about the two
91
+ things lint deliberately does **not** compute — contradictions and *semantic*
92
+ staleness — which need understanding of meaning.
93
+
94
+ ## loose — files with no graph connections (by folder)
95
+
96
+ Lists the **loose** files — concepts with graph **degree 0**: no cross-links in
97
+ *or* out — grouped by folder. It is a focused, folder-organized view over `lint`'s
98
+ `unlinked` check (`okf loose <dir>` ≈ `okf lint <dir> --only unlinked`, regrouped),
99
+ for the "which files float in the graph?" question. Advisory: **exits `0`**; `--json`
100
+ emits `{ bundle, count, loose: [{ id, title, dir }] }`.
101
+
102
+ **Loose ≠ orphan** — the trap. `lint`'s `orphan` is about *reachability*, and an
103
+ `index.md` listing makes a file reachable, so an indexed file is never an orphan.
104
+ But an index listing is **not a graph edge**: a file can be listed in an index yet
105
+ have no cross-links, so it floats in the graph while `lint` reports it as reachable.
106
+ `loose`/`unlinked` catch exactly that gap. A loose file is not automatically a
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).
109
+
110
+ ## index — the progressive-disclosure map (§6)
111
+
112
+ The "orient before you read" view, and the one read verb that sees the layer the
113
+ others can't: `index.md` files are reserved/structural, so `catalog`/`files`/… (all
114
+ concept views) never show them. `okf index <dir>` prints one entry per directory
115
+ that holds concepts or carries an `index.md`, root first — the authored index body
116
+ (frontmatter stripped), a `type`/`tag` rollup over the concepts that live directly
117
+ there, its child directories, and the concept listing. Run it first when picking up
118
+ an existing bundle: it is the cheapest high-signal orientation, and it surfaces
119
+ enumeration drift a grep can't (you can't grep for a listing entry that is *missing*).
120
+
121
+ `--area A` narrows to a directory and is **repeatable** — `--area model --area
122
+ format` shows both; `root` names the bundle root. `--no-body` drops the prose to a
123
+ skeleton (headers, rollups, child pointers). For a directory that has concepts but
124
+ **no `index.md`**, the listing is **synthesized** from the concepts' descriptions
125
+ and tagged `(no index.md)` — §6 explicitly permits synthesizing a map on the fly.
126
+
127
+ It is a **read view**: advisory, always exit 0. A synthesized directory is a
128
+ *signal* (a map worth writing), never a defect — `index` emits no lint findings and
129
+ never fails a bundle. JSON: `{ bundle, count, directories: [{ dir, index_path,
130
+ present, synthesized, count, types, tags, subdirs, body, listing: [{ id, title,
131
+ description, type, tags }] }] }`.
132
+
133
+ ## catalog / files / tags / types / stats — the server views, as text
134
+
135
+ The browser server (below) has Catalog, Files, Tags and Stats panels; these
136
+ verbs reproduce them on the CLI so an agent can read a bundle without a browser.
137
+ All are advisory reads (exit 0) sharing one data source (per-concept metadata plus
138
+ in/out link degree). Add `--json` to any for a machine substrate.
139
+
140
+ - **`catalog`** — every concept with its metadata (type, status, tags, timestamp,
141
+ in/out link degree, description), grouped by top-level area. The "what's here, in
142
+ detail" view. JSON: `{ bundle, count, concepts: [{ id, title, type, description,
143
+ tags, timestamp, status, backlog_ref, dir, area, links_out, links_in }] }`.
144
+ - **`files`** — the folder tree: each concept's filename + title, grouped by
145
+ directory. The "how it's organised" view. JSON: `{ bundle, count, files: [{ path,
146
+ id, dir, type, title, description }] }`.
147
+ - **`tags`** — every tag with the concepts that carry it, ordered by count
148
+ descending. The "what themes dominate" view. JSON: `{ bundle, count, tags: [{ tag,
149
+ count, concepts: [id, …] }] }`. `--by type|area` regroups the list per concept
150
+ 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,
153
+ groups: [{ <dim>, count, tags: […] }] }`.
154
+ - **`types`** — every type with the concepts that carry it, ordered by count
155
+ descending. The "what kinds of knowledge" view. JSON: `{ bundle, count, types:
156
+ [{ type, count, concepts: [id, …] }] }`.
157
+ - **`stats`** — bundle rollups: concept / area / type / cross-link / distinct-tag
158
+ totals plus per-type and per-area breakdowns. The "shape at a glance" view. JSON:
159
+ `{ bundle, concepts, areas, concept_types, cross_links, distinct_tags, by_type, by_area }`.
160
+
161
+ The four list views narrow with the same filters the browser panels offer —
162
+ `--type TYPE`, `--area AREA`, `--tag TAG`; each takes the ones orthogonal to
163
+ itself (`tags` can't filter by tag). Matching is case-insensitive and exact; a
164
+ concept at the bundle root lives in the `(root)` area, which `--area` also accepts
165
+ as plain `root` (no shell quoting). A filter that matches nothing is an empty view,
166
+ not an error: `okf tags <dir> --area billing --json` answers "which tags does the
167
+ billing area use?", `okf catalog <dir> --tag auth` answers "what carries the auth
168
+ tag?".
169
+
170
+ Reach for `stats` first to size a bundle, `catalog`/`files` to enumerate it, `tags`
171
+ to find thematic clusters — all without standing up the server.
172
+
173
+ ## server — interactive graph server
174
+
175
+ Starts a local HTTP server (`okf server <dir>`; `-p`/`--port`, default 8808, and
176
+ `--bind`) and prints its URL — stop it with Ctrl-C. The page boots from a lean
177
+ payload (nodes carry only `id` and `title`, plus compact type/tag indexes) and
178
+ fetches each concept's markdown body **live from disk** as you click it, so the
179
+ initial load stays small and edits show without a restart. Concepts render as nodes
180
+ coloured by `type` and sized by degree, links as edges, with a detail panel
181
+ (rendered markdown, "Links to" / "Linked from" backlinks), layout switching,
182
+ type/area/tag filters on every view, and search. It is a Rack app, so the same
183
+ server can be mounted in a host app (e.g. Rails).
184
+
185
+ **Trust boundary:** the page loads Cytoscape and marked from a CDN and
186
+ renders each concept's markdown body **without sanitization**, so only serve
187
+ bundles you trust. Inlined graph data cannot break out of its `<script>` (every
188
+ `<` is escaped), but the fetched markdown is rendered unsanitized.
189
+
190
+ ## graph — the raw structure
191
+
192
+ Prints the node/edge graph. `--json` emits a machine-readable dump (`nodes` with
193
+ `id`/`type`/`title`/`description`/`tags`, and `edges`) you can pipe into other
194
+ analysis or use to plan a traversal before consuming a large bundle. `--no-body`
195
+ drops each node's body; `--minimal` ships only `id`/`title` plus the type/tag
196
+ indexes — the lean shape the `server` page boots from.
@@ -0,0 +1,24 @@
1
+ ---
2
+ type: <Concept type, e.g. Service, BigQuery Table, Metric, Playbook, Decision>
3
+ title: <Human-readable display name>
4
+ description: <Single sentence summarizing the concept.>
5
+ resource: <Canonical URI of the underlying asset — omit for abstract concepts>
6
+ tags: [<tag>, <tag>]
7
+ timestamp: <ISO 8601, e.g. 2026-06-14T10:00:00Z>
8
+ ---
9
+
10
+ # Overview
11
+
12
+ <What this concept is and why it matters.>
13
+
14
+ # Schema
15
+
16
+ <Use for assets with fields/columns; otherwise replace with relevant sections.>
17
+
18
+ | Field | Type | Description |
19
+ |-------|------|-------------|
20
+ | | | |
21
+
22
+ # Citations
23
+
24
+ [1] [<source title>](<url>)
@@ -0,0 +1,8 @@
1
+ # <Directory / Group Heading>
2
+
3
+ * [<Title>](<relative-url>) - <short description from the concept's frontmatter>
4
+ * [<Title>](<relative-url>) - <short description>
5
+
6
+ # <Another Group>
7
+
8
+ * [<Subdirectory>](<subdir>/) - <short description of the subdirectory>
@@ -0,0 +1,6 @@
1
+ # Update Log
2
+
3
+ ## <YYYY-MM-DD>
4
+ * **Creation**: <what was created> — [<concept>](<bundle-relative-path>).
5
+ * **Update**: <what changed> — [<concept>](<bundle-relative-path>).
6
+ * **Deprecation**: <what was retired> — [<concept>](<bundle-relative-path>).
@@ -0,0 +1,12 @@
1
+ ---
2
+ okf_version: "0.1"
3
+ ---
4
+
5
+ # <Directory / Group Heading>
6
+
7
+ * [<Title>](<relative-url>) - <short description from the concept's frontmatter>
8
+ * [<Title>](<relative-url>) - <short description>
9
+
10
+ # <Another Group>
11
+
12
+ * [<Subdirectory>](<subdir>/) - <short description of the subdirectory>
data/lib/okf/skill.rb ADDED
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OKF
4
+ # Installs this gem's companion agent skill — the SKILL.md + reference/ +
5
+ # templates/ that teach an agent to author, maintain, and consume OKF bundles
6
+ # and to drive the `okf` executable — into a destination directory.
7
+ #
8
+ # The skill ships *inside* the gem (under lib/okf/skill), so `gem install okf`
9
+ # provides both the CLI and the skill that uses it, and the two can never drift
10
+ # apart in version: the skill's own reference/cli.md always matches the CLI it
11
+ # was released with.
12
+ class Skill
13
+ class Error < OKF::Error
14
+ end
15
+
16
+ # The canonical skill tree, bundled in the sibling skill/ directory.
17
+ ASSETS = File.expand_path("skill", __dir__)
18
+
19
+ # An agent discovers a skill as <skills-dir>/<name>/SKILL.md, so by default
20
+ # (nest: true) the tree lands in a skills/okf/ folder under the destination:
21
+ #
22
+ # okf skill .claude -> .claude/skills/okf (adds skills/ then okf/)
23
+ # okf skill .agents/skills -> .agents/skills/okf (already a skills dir)
24
+ # okf skill .../skills/okf -> .../skills/okf (already the skill dir)
25
+ #
26
+ # Point it at a project or skills directory and the skill settles in its own
27
+ # folder instead of splattering its files loose among the others. Pass
28
+ # nest: false (`--here`) to install straight into the destination, wherever it
29
+ # is.
30
+ NAME = "okf"
31
+ SKILLS_DIR = "skills"
32
+
33
+ def self.install(dest, force: false, nest: true)
34
+ new(dest, force: force, nest: nest).install
35
+ end
36
+
37
+ attr_reader :dest
38
+
39
+ def initialize(dest, force: false, nest: true)
40
+ @dest = nest ? resolve(dest.to_s) : dest.to_s
41
+ @path = File.expand_path(@dest)
42
+ @force = force
43
+ end
44
+
45
+ # Copy the skill tree into dest, creating it if needed. Refuses to write over
46
+ # a non-empty directory unless forced, so an existing (possibly customized)
47
+ # skill is never silently clobbered. Returns the relative paths written.
48
+ def install
49
+ if File.exist?(@path) && !File.directory?(@path)
50
+ raise Error, "destination #{@dest} exists and is not a directory"
51
+ end
52
+ if File.directory?(@path) && !Dir.empty?(@path) && !@force
53
+ raise Error, "destination #{@dest} is not empty (pass --force to overwrite)"
54
+ end
55
+
56
+ FileUtils.mkdir_p(@path)
57
+ FileUtils.cp_r(File.join(ASSETS, "."), @path)
58
+ files
59
+ end
60
+
61
+ # Relative paths of every file in the bundled skill, sorted for stable output.
62
+ def files
63
+ Dir.glob(File.join(ASSETS, "**", "*"))
64
+ .select { |path| File.file?(path) }
65
+ .map { |path| path[(ASSETS.length + 1)..-1] }
66
+ .sort
67
+ end
68
+
69
+ private
70
+
71
+ # Resolve the destination to a skills/okf leaf, so the skill always sits in its
72
+ # own folder under whatever the user pointed at. A destination already named
73
+ # okf is the skill dir itself (idempotent); one named skills only needs okf/.
74
+ def resolve(dest)
75
+ case File.basename(dest)
76
+ when NAME then dest
77
+ when SKILLS_DIR then File.join(dest, NAME)
78
+ else File.join(dest, SKILLS_DIR, NAME)
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OKF
4
+ VERSION = "1.0.0"
5
+ end
data/lib/okf.rb ADDED
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "fileutils"
5
+ require "date"
6
+ require "json"
7
+ require "optparse"
8
+ require "pathname"
9
+ require "securerandom"
10
+ require "set"
11
+ require "time"
12
+ require "yaml"
13
+
14
+ module OKF
15
+ class Error < StandardError
16
+ end
17
+
18
+ # Blank in the frontmatter sense: nil, false, an empty/whitespace-only string,
19
+ # or an empty collection. Numbers and other scalars are never blank. The one
20
+ # domain-wide predicate behind "non-empty type" (§9.2) and the recommended-field
21
+ # warnings, kept here so the gem needs no ActiveSupport.
22
+ def self.blank?(value)
23
+ return true if value.nil? || value == false
24
+ return value.strip.empty? if value.is_a?(String)
25
+
26
+ value.respond_to?(:empty?) ? value.empty? : false
27
+ end
28
+
29
+ require "okf/version"
30
+
31
+ # ── kernel: cross-cutting primitives ──
32
+ require "okf/path"
33
+
34
+ # ── Markdown: parse structure out of a markdown document (§4/§5/§8) ──
35
+ require "okf/markdown/frontmatter"
36
+ require "okf/markdown/links"
37
+ require "okf/markdown/citations"
38
+
39
+ # ── domain: pure representations + analyzers (no disk, no CLI) ──
40
+ require "okf/concept"
41
+ require "okf/bundle"
42
+ require "okf/bundle/graph"
43
+ require "okf/bundle/validator"
44
+ require "okf/bundle/validator/result"
45
+ require "okf/bundle/linter"
46
+ require "okf/bundle/linter/report"
47
+
48
+ # ── shell: everything that touches the outside world ──
49
+ require "okf/concept/file"
50
+ require "okf/bundle/reader"
51
+ require "okf/bundle/writer"
52
+ require "okf/bundle/folder"
53
+ require "okf/skill"
54
+ require "okf/cli"
55
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: okf
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Rodrigo Serradura
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rack
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '2.2'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '2.2'
26
+ - !ruby/object:Gem::Dependency
27
+ name: webrick
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '1.4'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '1.4'
40
+ description: |
41
+ OKF is portable knowledge — Markdown files with YAML frontmatter that both
42
+ humans and agents read. This gem reads OKF bundles, checks them for v0.1 (§9)
43
+ conformance, and serves them as an interactive graph (a mountable Rack app).
44
+ It ships a library API (OKF::Bundle and friends) plus an `okf` command-line
45
+ tool (validate / lint / loose / server / graph / skill).
46
+ email:
47
+ - rodrigo.serradura@gmail.com
48
+ executables:
49
+ - okf
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - ".okf/capabilities/agent-skill.md"
54
+ - ".okf/capabilities/graph-server.md"
55
+ - ".okf/capabilities/index.md"
56
+ - ".okf/capabilities/library-api.md"
57
+ - ".okf/capabilities/linter.md"
58
+ - ".okf/capabilities/read-views.md"
59
+ - ".okf/capabilities/validator.md"
60
+ - ".okf/cli.md"
61
+ - ".okf/design/core-shell-split.md"
62
+ - ".okf/design/index.md"
63
+ - ".okf/design/ruby-floor.md"
64
+ - ".okf/design/runtime-dependencies.md"
65
+ - ".okf/design/server-trust-boundary.md"
66
+ - ".okf/format/citations.md"
67
+ - ".okf/format/cross-links.md"
68
+ - ".okf/format/frontmatter.md"
69
+ - ".okf/format/index.md"
70
+ - ".okf/format/okf-format.md"
71
+ - ".okf/index.md"
72
+ - ".okf/log.md"
73
+ - ".okf/model/bundle.md"
74
+ - ".okf/model/concept.md"
75
+ - ".okf/model/graph.md"
76
+ - ".okf/model/index.md"
77
+ - ".okf/overview.md"
78
+ - CHANGELOG.md
79
+ - CODE_OF_CONDUCT.md
80
+ - LICENSE.txt
81
+ - NOTICE
82
+ - README.md
83
+ - exe/okf
84
+ - lib/okf.rb
85
+ - lib/okf/bundle.rb
86
+ - lib/okf/bundle/folder.rb
87
+ - lib/okf/bundle/graph.rb
88
+ - lib/okf/bundle/linter.rb
89
+ - lib/okf/bundle/linter/report.rb
90
+ - lib/okf/bundle/reader.rb
91
+ - lib/okf/bundle/validator.rb
92
+ - lib/okf/bundle/validator/result.rb
93
+ - lib/okf/bundle/writer.rb
94
+ - lib/okf/cli.rb
95
+ - lib/okf/concept.rb
96
+ - lib/okf/concept/file.rb
97
+ - lib/okf/markdown/citations.rb
98
+ - lib/okf/markdown/frontmatter.rb
99
+ - lib/okf/markdown/links.rb
100
+ - lib/okf/path.rb
101
+ - lib/okf/server/app.rb
102
+ - lib/okf/server/graph.rb
103
+ - lib/okf/server/runner.rb
104
+ - lib/okf/server/templates/graph.html.erb
105
+ - lib/okf/skill.rb
106
+ - lib/okf/skill/SKILL.md
107
+ - lib/okf/skill/reference/APACHE-2.0.txt
108
+ - lib/okf/skill/reference/SPEC.md
109
+ - lib/okf/skill/reference/authoring.md
110
+ - lib/okf/skill/reference/cli.md
111
+ - lib/okf/skill/templates/concept.md
112
+ - lib/okf/skill/templates/index.md
113
+ - lib/okf/skill/templates/log.md
114
+ - lib/okf/skill/templates/root-index.md
115
+ - lib/okf/version.rb
116
+ homepage: https://github.com/serradura/okf-gem
117
+ licenses:
118
+ - Apache-2.0
119
+ metadata:
120
+ allowed_push_host: https://rubygems.org
121
+ homepage_uri: https://github.com/serradura/okf-gem
122
+ source_code_uri: https://github.com/serradura/okf-gem
123
+ changelog_uri: https://github.com/serradura/okf-gem/blob/main/CHANGELOG.md
124
+ rubygems_mfa_required: 'true'
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: 2.4.0
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubygems_version: 4.0.16
140
+ specification_version: 4
141
+ summary: Read, validate, and serve Open Knowledge Format (OKF) v0.1 bundles.
142
+ test_files: []