okf 1.9.0 → 1.10.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.
@@ -13,7 +13,7 @@ description: >-
13
13
  working in a repo that already carries an OKF bundle — a `.okf/` directory or a
14
14
  root `index.md` carrying `okf_version`.
15
15
  user-invocable: true
16
- argument-hint: "[search|produce|migrate|maintain|consume|curate|doctor|<okf-cli-verb>] [dir|@slug] [--flags]"
16
+ argument-hint: "[search|produce|migrate|maintain|refine|consume|curate|doctor|<okf-cli-verb>] [dir|@slug] [--flags]"
17
17
  allowed-tools: Read Write Edit Grep Glob Bash
18
18
  ---
19
19
 
@@ -123,10 +123,12 @@ when you need chapter and verse.
123
123
 
124
124
  **No subcommand?** Infer intent: "document this / capture X" → `produce`;
125
125
  "convert / migrate / OKFy these existing docs into a bundle" → `migrate`; "the
126
- code changed, update the docs" → `maintain`; "what do we know about X / where
127
- is X documented" → `search`; a repo already carrying a bundle plus a task
128
- needing its knowledge → `consume`; "check / graph / preview it" → run the
129
- matching CLI verb and interpret the result. When genuinely ambiguous, ask.
126
+ code changed, update the docs" → `maintain`; "restructure / rebalance the
127
+ bundle / is the structure right / get more out of it" → `refine`; "what do we
128
+ know about X / where is X documented" → `search`; a repo already carrying a
129
+ bundle plus a task needing its knowledge → `consume`; "check / graph / preview
130
+ it" → run the matching CLI verb and interpret the result. When genuinely
131
+ ambiguous, ask.
130
132
 
131
133
  **Which target?** A leading `@` is a *registry ref*, not a path: `@slug` names a
132
134
  bundle registered with `okf registry set`, bare `@` the default — route it
@@ -158,15 +160,17 @@ Read the referenced playbook before executing — it *is* the procedure.
158
160
  | `produce` | Author | create or extend a bundle | [playbooks/produce.md](playbooks/produce.md) |
159
161
  | `migrate` | Author | convert existing docs in place: frontmatter + reserved files, bodies verbatim | [playbooks/migrate.md](playbooks/migrate.md) |
160
162
  | `maintain` | Author | sync the bundle's content with reality after a change | [playbooks/maintain.md](playbooks/maintain.md) |
163
+ | `refine` | Author | optimize the bundle's structure: evidence-driven, cohesion-first; proposes, never auto-applies | [playbooks/refine.md](playbooks/refine.md) |
161
164
  | `consume` | Use | use the bundle as context for a task | [playbooks/consume.md](playbooks/consume.md) |
162
165
  | `curate` | Curate | structural upkeep as it stands: validate + lint + loose | [playbooks/curate.md](playbooks/curate.md) |
163
166
  | `doctor` | Setup | install and verify the CLI, then doctor the bundle | [playbooks/doctor.md](playbooks/doctor.md) |
164
- | `<okf-cli-verb>` | Read | validate, lint, loose, index, catalog, files, tags, types, stats, graph, server, render, registry, skill | `okf <verb> --help` + [reference/cli.md](reference/cli.md) |
167
+ | `<okf-cli-verb>` | Read | validate, lint, loose, index, catalog, files, tags, types, stats, graph, server, render, registry, skill — **plus any verb an installed extension adds** (`okf help` is authoritative, this list is not) | `okf <verb> --help` + [reference/cli.md](reference/cli.md) |
165
168
 
166
- Two boundaries worth keeping sharp: `curate` is structural upkeep only — when
167
- the *content* no longer matches reality, that is `maintain` — and `doctor` is
168
- the one playbook that does not assume the CLI is installed. In Claude Code with
169
- the okf plugin, `/okf:gem` routes these same verbs.
169
+ Three boundaries worth keeping sharp: `curate` is structural upkeep only — when
170
+ the *content* no longer matches reality, that is `maintain`, and when the
171
+ content is right but the *shape* underserves retrieval, that is `refine` — and
172
+ `doctor` is the one playbook that does not assume the CLI is installed. In
173
+ Claude Code with the okf plugin, `/okf:gem` routes these same verbs.
170
174
 
171
175
  ## The lifecycle is a flywheel, not phases
172
176
 
@@ -9,7 +9,9 @@ reachability, backlog, completeness, hygiene. It is not `maintain`, the
9
9
  skill's workflow for when the project changed and the bundle's *content*
10
10
  must catch up with reality; reach for that one when what is written stopped
11
11
  being true. Curating can surface semantic staleness, and when it does,
12
- switch to `maintain` for those concepts.
12
+ switch to `maintain` for those concepts. And it never moves knowledge: when
13
+ the content is right but the shape underserves retrieval — fat areas,
14
+ mis-homed hubs, an uncurated tag layer — that is [refine](refine.md).
13
15
 
14
16
  1. Locate the bundle: the directory you were given, if any; otherwise a
15
17
  `.okf/` directory or a root `index.md` whose frontmatter carries
@@ -1,8 +1,9 @@
1
1
  # Playbook: maintain — keep a bundle in sync with reality
2
2
 
3
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).
4
+ up. Restructuring the bundle itself — moving concepts, adding areas — is
5
+ [refine](refine.md), not maintain. The modelling craft behind steps 3 and 7
6
+ lives in [authoring.md](../reference/authoring.md).
6
7
 
7
8
  1. **Orient before hunting.** Run `okf index <dir>` (the §6 map — every directory's
8
9
  index body, rollups, and listings), read `log.md` (the §7 baseline: what changed
@@ -33,6 +33,11 @@ is the lede.
33
33
  the working tree has uncommitted changes to the code the bundle describes
34
34
  (`git status`), prefer **`maintain`**: that is exactly the drift it exists
35
35
  to close.
36
+ - **clean, but the shape strains** — one area dwarfing the rest in
37
+ `okf stats`, tags spread thin across areas in `okf tags --by area`, hubs
38
+ whose inbound links are mostly foreign in `okf graph --hubs` → offer
39
+ **`refine`** (evidence-driven restructuring; it proposes before it
40
+ touches anything).
36
41
  4. **Freshness is off by default.** If the bundle carries timestamps, note that a
37
42
  plain `lint` said nothing about staleness and `okf lint <root> --stale-after
38
43
  90d` is the check that would.
@@ -0,0 +1,92 @@
1
+ # Playbook: refine — restructure a bundle to get the most from OKF
2
+
3
+ Reach for this when the bundle's *content* is right but its *shape* may not be:
4
+ areas grown fat by additive passes, hubs homed by history, a tag layer that
5
+ never became the second index. Refine optimizes the projection — the same
6
+ knowledge, arranged to serve progressive disclosure, the emergent graph,
7
+ cross-cutting tags, and capture-once-link-many. It is not [curate](curate.md)
8
+ (upkeep of the structure as it stands) and not [maintain](maintain.md) (content
9
+ catching up with reality): refine changes where knowledge lives, never what it
10
+ says. Its permitted edits are structural — move a concept, extract a duplicated
11
+ fact to one home, section an index, retag, relink, and write the connective
12
+ sentence a link lives in; summarizing, updating, or correcting a body is
13
+ maintain's job, reached by switching verbs, not by stretching this one.
14
+
15
+ The frame that governs every move: the directory tree is a **lossy projection
16
+ of the link graph**. A tree gives each concept one parent, so the tree encodes
17
+ only the single dominant decomposition; every genuinely many-to-many
18
+ relationship rides links and tags, never new directories. And cohesion outranks
19
+ balance — a move has semantic cost, so balance is a tiebreaker and a fatness
20
+ alarm, never the objective. <!-- rule:okf-cohesion-over-balance -->
21
+
22
+ 1. **Orient.** `okf index <dir|@slug> --no-body` (areas, fan-out, depth),
23
+ `log.md` (how the bundle grew), `okf stats` (totals). Additive growth
24
+ optimizes each pass locally, never the whole — that is the drift this
25
+ playbook corrects.
26
+ 2. **Measure — the CLI is the evidence.** Baseline `validate` / `lint
27
+ --stale-after` / `loose` first: refine assumes a sound bundle, and hard
28
+ errors are [curate](curate.md)'s job. Then the two structural reads:
29
+ - `okf tags <dir> --by area` — each row carries `count/total`, so a tag's
30
+ **locality** reads directly: a tag wholly inside one area names a *domain*
31
+ (the directories are right); one spread across areas names a *concern*.
32
+ - `okf graph <dir> --hubs` — concepts ranked by inbound links, each with
33
+ the areas those links come from: the **origin test** for every hub.
34
+ 3. **Diagnose — you are the judgment.** The measurements are evidence, never
35
+ verdicts:
36
+ - **Concerns never become containers.** A directory built around a spread
37
+ tag ("everything async") prunes nothing — most needs would enter it.
38
+ The cross-cut stays a tag. <!-- rule:okf-concern-not-container -->
39
+ - **A directory must prune.** The positive test for any area, existing or
40
+ proposed: does knowing "it's in there" eliminate a large, even slice? A
41
+ good node splits its parent into chunks that are nameable, mutually
42
+ exclusive, and roughly comparable in size. And small is not merge-worthy
43
+ on its own — a two-concept area that is a genuinely distinct domain
44
+ stays. <!-- rule:okf-directory-prunes -->
45
+ - **The hub origin test.** Inbound majority from the hub's own area:
46
+ well-homed, leave it. A dominant *foreign* area: that area is the better
47
+ home. Foreign majority with *no* dominant area: a shared primitive — the
48
+ only admission ticket into a shared-core area (without that test, a
49
+ `foundation/` rots into a `misc/`). Two comparable strong ties, one of
50
+ them home: stay and carry the other as a tag — moving trades one
51
+ imbalance for another. And in a design bundle expect the central
52
+ decisions to fail this test wholesale: that is centrality, not
53
+ mis-homing.
54
+ - **Fatness alarm, not fatness rule.** A fat area (≳20–25 concepts) wants
55
+ **heading sections inside its `index.md`** first — the same prune as
56
+ sub-directories, for zero extra hops and no new enumeration to keep
57
+ sound. Directory nesting pays only at hundreds of concepts, and only
58
+ where the index's own headings already form separable, nameable
59
+ sub-groups — fatness alone never justifies depth; the sections that
60
+ formed are the evidence the split exists.
61
+ - **Duplication.** Read the area overviews for a fact re-explained in
62
+ several (drifting tables are the tell); capture-once-link-many says
63
+ extract it into one concept and link from the rest. Extraction is the one
64
+ refine move that touches bodies, and it redistributes rather than
65
+ rewrites: assemble the canonical concept from the copies, keep every
66
+ copy's unique domain-specific detail (in the extract, or in the one-line
67
+ note left beside each link), and where the copies *disagree*, which is
68
+ true is a [maintain](maintain.md) question — verify against reality or
69
+ flag the conflict in the proposal, never silently pick a winner while
70
+ merging. <!-- rule:okf-extract-not-rewrite -->
71
+ - **Vocabulary twins.** The [maintain](maintain.md) tag-curation recipe
72
+ (twins, echoes, singletons) applies to `type` too — `okf types <dir>`.
73
+ 4. **Plan — tier by leverage ÷ churn, free levers first.** Tag curation,
74
+ index heading-sectioning, and extraction before any file move; a move only
75
+ when the origin test demands one, and each gated by **do-nothing**: skip it
76
+ unless its value beats its churn. Record what you *declined* and why — the
77
+ decline list is what stops the next pass from re-proposing it.
78
+ 5. **Propose — never auto-apply.** Refine's output is a short report (the
79
+ evidence, the tiers, the declines) plus a ready-to-run execution prompt the
80
+ user can hand back later: a scope line, the governing principles above, the
81
+ explicit prohibitions, the closeout gate as acceptance. Analysis and
82
+ execution are separate on purpose — the judgment is spent once, frozen, and
83
+ then executed without re-derivation. <!-- rule:okf-refine-proposes -->
84
+ 6. **Execute only on approval**, then walk the
85
+ [Closeout gate](../reference/authoring.md#closeout--the-finishing-gate):
86
+ every touched `index.md` re-enumerated, links absolute bundle-relative so
87
+ they survived the moves, a dated `log.md` entry carrying the *why*,
88
+ validate/lint/loose clean, and a before/after of step 2's evidence.
89
+
90
+ Two traps: never split a cohesive cluster (a deliberately paired mirror flow)
91
+ to hit a size band, and never tag a concept with its own directory's name — a
92
+ group-name echo adds no edge.
@@ -20,6 +20,12 @@ The surface is self-describing — `okf --help` maps every verb, `okf <verb> --h
20
20
  its flags. Ask the tool for what exists; this file carries only what `--help`
21
21
  cannot: each verb's semantics, its traps, and its JSON shape.
22
22
 
23
+ **The verb list is open, not closed.** An installed extension gem adds verbs of
24
+ its own, listed under `installed extensions:` in `okf help`. So a verb that
25
+ `--help` shows and this file does not document is **normal, not a documentation
26
+ error** — ask `okf <verb> --help` for it, and expect nothing here about its
27
+ semantics or JSON. Everything below documents the built-ins only.
28
+
23
29
  **`--json` is compact by design.** Every emitting verb prints single-line JSON —
24
30
  the token-efficient substrate you consume; `--pretty` (which implies `--json`)
25
31
  indents it for a human. The bytes differ, the JSON is identical, so parse either.
@@ -296,10 +302,14 @@ in/out link degree). Add `--json` to any for a machine substrate.
296
302
  - **`tags`** — every tag with the concepts that carry it, ordered by count
297
303
  descending. The "what themes dominate" view. JSON: `{ bundle, count, tags: [{ tag,
298
304
  count, concepts: [id, …] }] }`. `--by type|area` regroups the list per concept
299
- dimension with **within-group** counts (a tag spanning groups appears in each) —
300
- the substrate for tag curation; the judgment recipe lives in the
301
- [maintain playbook](../playbooks/maintain.md). JSON: `{ bundle, count, by,
302
- groups: [{ <dim>, count, tags: […] }] }`.
305
+ dimension with **within-group** counts (a tag spanning groups appears in each);
306
+ each row also carries the tag's **total** across the narrowed set, printed
307
+ `count/total` when they differ — so a tag's locality reads per row (a plain
308
+ count = wholly local; `2/7` = a cross-cutting spread). The substrate for tag
309
+ curation and for [refine](../playbooks/refine.md)'s domain-vs-concern read;
310
+ the judgment recipes live in the [maintain playbook](../playbooks/maintain.md)
311
+ and the [refine playbook](../playbooks/refine.md). JSON: `{ bundle, count, by,
312
+ groups: [{ <dim>, count, tags: [{ tag, count, total, concepts }] }] }`.
303
313
  - **`types`** — every type with the concepts that carry it, ordered by count
304
314
  descending. The "what kinds of knowledge" view. JSON: `{ bundle, count, types:
305
315
  [{ type, count, concepts: [id, …] }] }`.
@@ -427,3 +437,11 @@ drops each node's body, and `--minimal` ships only `id`/`title` plus the type/ta
427
437
  indexes — the lean shape the `server` page boots from. Reach for the full dump
428
438
  only when the task truly consumes every body; for one question, the
429
439
  [search verb](#search--ranked-text-retrieval-metadata--body) is orders cheaper.
440
+
441
+ `--hubs` swaps the dump for the **inbound ranking**: every concept with at
442
+ least one inbound link, ranked by inbound degree, each with its links grouped
443
+ by *source area* (`core/status ×3 flows 2, billing 1`) — the evidence for
444
+ [refine](../playbooks/refine.md)'s hub origin test ("is this hub well-homed?").
445
+ A source at the bundle root counts under `(root)`. JSON: `{ bundle, count,
446
+ hubs: [{ id, area, inbound, by_area: { <area>: n } }] }`. Advisory read, exit 0;
447
+ `--minimal`/`--no-body` shape node payloads and change nothing here.
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.9.0"
4
+ VERSION = "1.10.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.9.0
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura
@@ -86,6 +86,22 @@ files:
86
86
  - lib/okf/bundle/validator/result.rb
87
87
  - lib/okf/bundle/writer.rb
88
88
  - lib/okf/cli.rb
89
+ - lib/okf/cli/catalog.rb
90
+ - lib/okf/cli/command.rb
91
+ - lib/okf/cli/files.rb
92
+ - lib/okf/cli/graph.rb
93
+ - lib/okf/cli/index.rb
94
+ - lib/okf/cli/lint.rb
95
+ - lib/okf/cli/loose.rb
96
+ - lib/okf/cli/registry.rb
97
+ - lib/okf/cli/render.rb
98
+ - lib/okf/cli/search.rb
99
+ - lib/okf/cli/server.rb
100
+ - lib/okf/cli/skill.rb
101
+ - lib/okf/cli/stats.rb
102
+ - lib/okf/cli/tags.rb
103
+ - lib/okf/cli/types.rb
104
+ - lib/okf/cli/validate.rb
89
105
  - lib/okf/concept.rb
90
106
  - lib/okf/concept/file.rb
91
107
  - lib/okf/markdown/citations.rb
@@ -97,6 +113,7 @@ files:
97
113
  - lib/okf/render/graph/template.html.erb
98
114
  - lib/okf/server/app.rb
99
115
  - lib/okf/server/hub.rb
116
+ - lib/okf/server/hub/not_found.rb
100
117
  - lib/okf/server/runner.rb
101
118
  - lib/okf/skill.rb
102
119
  - lib/okf/skill/SKILL.md
@@ -107,6 +124,7 @@ files:
107
124
  - lib/okf/skill/playbooks/menu.md
108
125
  - lib/okf/skill/playbooks/migrate.md
109
126
  - lib/okf/skill/playbooks/produce.md
127
+ - lib/okf/skill/playbooks/refine.md
110
128
  - lib/okf/skill/playbooks/search.md
111
129
  - lib/okf/skill/reference/APACHE-2.0.txt
112
130
  - lib/okf/skill/reference/SPEC.md