okf 1.9.0 → 1.11.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/CHANGELOG.md +696 -133
- data/README.md +250 -334
- data/lib/okf/bundle/folder.rb +24 -5
- data/lib/okf/bundle/linter.rb +1 -1
- data/lib/okf/bundle/search/index.rb +13 -3
- data/lib/okf/bundle/search.rb +91 -11
- data/lib/okf/bundle.rb +26 -2
- data/lib/okf/cli/catalog.rb +66 -0
- data/lib/okf/cli/command.rb +657 -0
- data/lib/okf/cli/dirs.rb +118 -0
- data/lib/okf/cli/files.rb +68 -0
- data/lib/okf/cli/graph.rb +82 -0
- data/lib/okf/cli/index.rb +169 -0
- data/lib/okf/cli/lint.rb +139 -0
- data/lib/okf/cli/loose.rb +78 -0
- data/lib/okf/cli/registry.rb +229 -0
- data/lib/okf/cli/render.rb +66 -0
- data/lib/okf/cli/search.rb +285 -0
- data/lib/okf/cli/server.rb +186 -0
- data/lib/okf/cli/skill.rb +57 -0
- data/lib/okf/cli/stats.rb +113 -0
- data/lib/okf/cli/tags.rb +144 -0
- data/lib/okf/cli/types.rb +37 -0
- data/lib/okf/cli/validate.rb +66 -0
- data/lib/okf/cli.rb +425 -1706
- data/lib/okf/render/graph/template.html.erb +1285 -129
- data/lib/okf/render/graph.rb +46 -2
- data/lib/okf/server/app.rb +71 -4
- data/lib/okf/server/hub/not_found.rb +663 -0
- data/lib/okf/server/hub.rb +512 -38
- data/lib/okf/skill/SKILL.md +26 -19
- data/lib/okf/skill/playbooks/consume.md +3 -3
- data/lib/okf/skill/playbooks/curate.md +3 -1
- data/lib/okf/skill/playbooks/maintain.md +7 -5
- data/lib/okf/skill/playbooks/menu.md +5 -0
- data/lib/okf/skill/playbooks/refine.md +93 -0
- data/lib/okf/skill/playbooks/search.md +7 -7
- data/lib/okf/skill/reference/cli.md +122 -22
- data/lib/okf/version.rb +1 -1
- data/lib/okf.rb +9 -0
- metadata +38 -8
data/lib/okf/skill/SKILL.md
CHANGED
|
@@ -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
|
|
|
@@ -83,10 +83,10 @@ flags. The division of labour is the whole game:
|
|
|
83
83
|
|
|
84
84
|
- **Shell out — never eyeball —** anything a verb computes: conformance (§9), what
|
|
85
85
|
exists, what links where, where a term lives, what's stale, the map. Every read
|
|
86
|
-
verb takes `--json` and the list views filter by type/
|
|
86
|
+
verb takes `--json` and the list views filter by type/dir/tag, so ask the narrow
|
|
87
87
|
question instead of paging the bundle.
|
|
88
|
-
- **Skeleton first, bodies last.** `
|
|
89
|
-
|
|
88
|
+
- **Skeleton first, bodies last.** `dirs`, `search`, `graph --minimal`, and
|
|
89
|
+
`--fields` projections each answer for a fraction of a dump's bytes; full
|
|
90
90
|
bodies are the final step of a retrieval, never the first. <!-- rule:okf-skeleton-first -->
|
|
91
91
|
- **You judge — the CLI can't —** meaning: contradictions, semantic staleness
|
|
92
92
|
(parses fine, no longer true), whether a loose file is terminal-by-design, whether
|
|
@@ -102,12 +102,15 @@ shapes, the tag-curation views, the server's trust boundary.
|
|
|
102
102
|
|
|
103
103
|
## Orient before you touch anything
|
|
104
104
|
|
|
105
|
-
Picking up a bundle you don't already know — to consume or maintain —
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
105
|
+
Picking up a bundle you don't already know — to consume or maintain — start with
|
|
106
|
+
`okf dirs <dir|@slug>`: one row per *directory*, so it stays small on a bundle of
|
|
107
|
+
any size and it names the branches every other view narrows to. Then open the one
|
|
108
|
+
you want with `okf index <dir|@slug> --dir <branch>` (the §6 map: that directory's
|
|
109
|
+
index body, rollups, and listing), and read `log.md` (the §7 baseline of what
|
|
110
|
+
changed last) — all of it **before** greping or opening leaves. Reach for `index`
|
|
111
|
+
rather than grep for the one reason that outranks convenience: **grep cannot find
|
|
112
|
+
an index entry that is missing**, so enumeration drift is invisible to it — you
|
|
113
|
+
can't search for the word that should be there but isn't. <!-- rule:okf-orient-index -->
|
|
111
114
|
Per-verb steps are in the
|
|
112
115
|
playbooks (the Commands table below; no `okf` installed? read the root
|
|
113
116
|
`index.md` plus each area's `index.md`).
|
|
@@ -123,10 +126,12 @@ when you need chapter and verse.
|
|
|
123
126
|
|
|
124
127
|
**No subcommand?** Infer intent: "document this / capture X" → `produce`;
|
|
125
128
|
"convert / migrate / OKFy these existing docs into a bundle" → `migrate`; "the
|
|
126
|
-
code changed, update the docs" → `maintain`; "
|
|
127
|
-
is
|
|
128
|
-
|
|
129
|
-
|
|
129
|
+
code changed, update the docs" → `maintain`; "restructure / rebalance the
|
|
130
|
+
bundle / is the structure right / get more out of it" → `refine`; "what do we
|
|
131
|
+
know about X / where is X documented" → `search`; a repo already carrying a
|
|
132
|
+
bundle plus a task needing its knowledge → `consume`; "check / graph / preview
|
|
133
|
+
it" → run the matching CLI verb and interpret the result. When genuinely
|
|
134
|
+
ambiguous, ask.
|
|
130
135
|
|
|
131
136
|
**Which target?** A leading `@` is a *registry ref*, not a path: `@slug` names a
|
|
132
137
|
bundle registered with `okf registry set`, bare `@` the default — route it
|
|
@@ -158,15 +163,17 @@ Read the referenced playbook before executing — it *is* the procedure.
|
|
|
158
163
|
| `produce` | Author | create or extend a bundle | [playbooks/produce.md](playbooks/produce.md) |
|
|
159
164
|
| `migrate` | Author | convert existing docs in place: frontmatter + reserved files, bodies verbatim | [playbooks/migrate.md](playbooks/migrate.md) |
|
|
160
165
|
| `maintain` | Author | sync the bundle's content with reality after a change | [playbooks/maintain.md](playbooks/maintain.md) |
|
|
166
|
+
| `refine` | Author | optimize the bundle's structure: evidence-driven, cohesion-first; proposes, never auto-applies | [playbooks/refine.md](playbooks/refine.md) |
|
|
161
167
|
| `consume` | Use | use the bundle as context for a task | [playbooks/consume.md](playbooks/consume.md) |
|
|
162
168
|
| `curate` | Curate | structural upkeep as it stands: validate + lint + loose | [playbooks/curate.md](playbooks/curate.md) |
|
|
163
169
|
| `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) |
|
|
170
|
+
| `<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
171
|
|
|
166
|
-
|
|
167
|
-
the *content* no longer matches reality, that is `maintain
|
|
168
|
-
|
|
169
|
-
the
|
|
172
|
+
Three boundaries worth keeping sharp: `curate` is structural upkeep only — when
|
|
173
|
+
the *content* no longer matches reality, that is `maintain`, and when the
|
|
174
|
+
content is right but the *shape* underserves retrieval, that is `refine` — and
|
|
175
|
+
`doctor` is the one playbook that does not assume the CLI is installed. In
|
|
176
|
+
Claude Code with the okf plugin, `/okf:gem` routes these same verbs.
|
|
170
177
|
|
|
171
178
|
## The lifecycle is a flywheel, not phases
|
|
172
179
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Playbook: consume — use a bundle as context
|
|
2
2
|
|
|
3
|
-
1. **Orient first** (the [SKILL.md](../SKILL.md) reflex): `okf
|
|
4
|
-
the
|
|
5
|
-
and `log.md` gives recent history. Address a registered bundle by `@slug` (bare
|
|
3
|
+
1. **Orient first** (the [SKILL.md](../SKILL.md) reflex): `okf dirs <dir|@slug>`
|
|
4
|
+
gives the shape, `okf index <dir|@slug> --dir <branch>` opens the branch you
|
|
5
|
+
want — its index body, rollups and listing — and `log.md` gives recent history. Address a registered bundle by `@slug` (bare
|
|
6
6
|
`@` = the default); if the cwd carries no bundle, `okf registry list` finds one
|
|
7
7
|
instead of a directory hunt. Then follow links only into the concepts the
|
|
8
8
|
task needs. For a *pointed question* rather than broad context, switch to the
|
|
@@ -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,11 +1,13 @@
|
|
|
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.
|
|
5
|
-
[
|
|
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
|
-
1. **Orient before hunting.** Run `okf
|
|
8
|
-
|
|
8
|
+
1. **Orient before hunting.** Run `okf dirs <dir>` (the shape), then `okf index
|
|
9
|
+
<dir> --dir <branch>` on the branch the change touches (the §6 map: its index
|
|
10
|
+
body, rollups and listing), read `log.md` (the §7 baseline: what changed
|
|
9
11
|
last), and `okf stats <dir>` (size and shape) *before* you grep. It is the
|
|
10
12
|
cheapest context and it primes the hunt — and it is the only reliable way to
|
|
11
13
|
catch enumeration drift, because **grep cannot find an index entry that is
|
|
@@ -44,7 +46,7 @@ up. The modelling craft behind steps 3 and 7 lives in
|
|
|
44
46
|
defect.** Loose ≠ orphan: an index listing makes a file *reachable* (not an
|
|
45
47
|
orphan) but is not a graph edge, so an indexed file can still float here.
|
|
46
48
|
7. **Curate the tag vocabulary** when the pass
|
|
47
|
-
touched tags, or when `okf tags <dir>` shows a long tail of singletons. Run `okf tags <dir> --by
|
|
49
|
+
touched tags, or when `okf tags <dir>` shows a long tail of singletons. Run `okf tags <dir> --by dir` and
|
|
48
50
|
`--by type` — the grouped view is the analysis; read each group top-down:
|
|
49
51
|
- **twins** — two tags riding the exact same concepts (equal counts sort them
|
|
50
52
|
adjacent). Merge into one unless each genuinely names a different theme.
|
|
@@ -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 dirs in `okf tags --by dir`, 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,93 @@
|
|
|
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 dirs <dir|@slug>` (directories, fan-out, depth — and
|
|
23
|
+
`subtree` says where the weight sits), `log.md` (how the bundle grew), `okf
|
|
24
|
+
stats` (totals). Additive growth
|
|
25
|
+
optimizes each pass locally, never the whole — that is the drift this
|
|
26
|
+
playbook corrects.
|
|
27
|
+
2. **Measure — the CLI is the evidence.** Baseline `validate` / `lint
|
|
28
|
+
--stale-after` / `loose` first: refine assumes a sound bundle, and hard
|
|
29
|
+
errors are [curate](curate.md)'s job. Then the two structural reads:
|
|
30
|
+
- `okf tags <dir> --by dir` — each row carries `count/total`, so a tag's
|
|
31
|
+
**locality** reads directly: a tag wholly inside one area names a *domain*
|
|
32
|
+
(the directories are right); one spread across areas names a *concern*.
|
|
33
|
+
- `okf graph <dir> --hubs` — concepts ranked by inbound links, each with
|
|
34
|
+
the areas those links come from: the **origin test** for every hub.
|
|
35
|
+
3. **Diagnose — you are the judgment.** The measurements are evidence, never
|
|
36
|
+
verdicts:
|
|
37
|
+
- **Concerns never become containers.** A directory built around a spread
|
|
38
|
+
tag ("everything async") prunes nothing — most needs would enter it.
|
|
39
|
+
The cross-cut stays a tag. <!-- rule:okf-concern-not-container -->
|
|
40
|
+
- **A directory must prune.** The positive test for any area, existing or
|
|
41
|
+
proposed: does knowing "it's in there" eliminate a large, even slice? A
|
|
42
|
+
good node splits its parent into chunks that are nameable, mutually
|
|
43
|
+
exclusive, and roughly comparable in size. And small is not merge-worthy
|
|
44
|
+
on its own — a two-concept area that is a genuinely distinct domain
|
|
45
|
+
stays. <!-- rule:okf-directory-prunes -->
|
|
46
|
+
- **The hub origin test.** Inbound majority from the hub's own area:
|
|
47
|
+
well-homed, leave it. A dominant *foreign* area: that area is the better
|
|
48
|
+
home. Foreign majority with *no* dominant area: a shared primitive — the
|
|
49
|
+
only admission ticket into a shared-core area (without that test, a
|
|
50
|
+
`foundation/` rots into a `misc/`). Two comparable strong ties, one of
|
|
51
|
+
them home: stay and carry the other as a tag — moving trades one
|
|
52
|
+
imbalance for another. And in a design bundle expect the central
|
|
53
|
+
decisions to fail this test wholesale: that is centrality, not
|
|
54
|
+
mis-homing.
|
|
55
|
+
- **Fatness alarm, not fatness rule.** A fat area (≳20–25 concepts) wants
|
|
56
|
+
**heading sections inside its `index.md`** first — the same prune as
|
|
57
|
+
sub-directories, for zero extra hops and no new enumeration to keep
|
|
58
|
+
sound. Directory nesting pays only at hundreds of concepts, and only
|
|
59
|
+
where the index's own headings already form separable, nameable
|
|
60
|
+
sub-groups — fatness alone never justifies depth; the sections that
|
|
61
|
+
formed are the evidence the split exists.
|
|
62
|
+
- **Duplication.** Read the area overviews for a fact re-explained in
|
|
63
|
+
several (drifting tables are the tell); capture-once-link-many says
|
|
64
|
+
extract it into one concept and link from the rest. Extraction is the one
|
|
65
|
+
refine move that touches bodies, and it redistributes rather than
|
|
66
|
+
rewrites: assemble the canonical concept from the copies, keep every
|
|
67
|
+
copy's unique domain-specific detail (in the extract, or in the one-line
|
|
68
|
+
note left beside each link), and where the copies *disagree*, which is
|
|
69
|
+
true is a [maintain](maintain.md) question — verify against reality or
|
|
70
|
+
flag the conflict in the proposal, never silently pick a winner while
|
|
71
|
+
merging. <!-- rule:okf-extract-not-rewrite -->
|
|
72
|
+
- **Vocabulary twins.** The [maintain](maintain.md) tag-curation recipe
|
|
73
|
+
(twins, echoes, singletons) applies to `type` too — `okf types <dir>`.
|
|
74
|
+
4. **Plan — tier by leverage ÷ churn, free levers first.** Tag curation,
|
|
75
|
+
index heading-sectioning, and extraction before any file move; a move only
|
|
76
|
+
when the origin test demands one, and each gated by **do-nothing**: skip it
|
|
77
|
+
unless its value beats its churn. Record what you *declined* and why — the
|
|
78
|
+
decline list is what stops the next pass from re-proposing it.
|
|
79
|
+
5. **Propose — never auto-apply.** Refine's output is a short report (the
|
|
80
|
+
evidence, the tiers, the declines) plus a ready-to-run execution prompt the
|
|
81
|
+
user can hand back later: a scope line, the governing principles above, the
|
|
82
|
+
explicit prohibitions, the closeout gate as acceptance. Analysis and
|
|
83
|
+
execution are separate on purpose — the judgment is spent once, frozen, and
|
|
84
|
+
then executed without re-derivation. <!-- rule:okf-refine-proposes -->
|
|
85
|
+
6. **Execute only on approval**, then walk the
|
|
86
|
+
[Closeout gate](../reference/authoring.md#closeout--the-finishing-gate):
|
|
87
|
+
every touched `index.md` re-enumerated, links absolute bundle-relative so
|
|
88
|
+
they survived the moves, a dated `log.md` entry carrying the *why*,
|
|
89
|
+
validate/lint/loose clean, and a before/after of step 2's evidence.
|
|
90
|
+
|
|
91
|
+
Two traps: never split a cohesive cluster (a deliberately paired mirror flow)
|
|
92
|
+
to hit a size band, and never tag a concept with its own directory's name — a
|
|
93
|
+
group-name echo adds no edge.
|
|
@@ -12,12 +12,12 @@ reads, and full bodies are read last, and only the winners.
|
|
|
12
12
|
the root `index.md` then each relevant area's `index.md` by hand. No bundle in
|
|
13
13
|
the cwd? `okf registry list` names the registered ones — address them by
|
|
14
14
|
`@slug`, don't hunt sibling directories.
|
|
15
|
-
2. **Ingest the map and decide where to look.** `okf
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
2. **Ingest the map and decide where to look.** `okf dirs <dir|@slug>` is the
|
|
16
|
+
skeleton: every directory with what lives under it. *You* do the semantic
|
|
17
|
+
matching here — the question names a meaning, the map names directories;
|
|
18
|
+
connect them by judgment, not string equality. When one looks right, `okf
|
|
19
|
+
index <dir|@slug> --dir <name>` buys its authored index body and listing
|
|
20
|
+
(titles + descriptions) for the price of one directory.
|
|
21
21
|
<!-- rule:okf-search-map-first -->
|
|
22
22
|
3. **Cut across with the finder when the question is lexical.** An exact
|
|
23
23
|
symbol, an error code, a column name, a phrase — things structure won't
|
|
@@ -52,7 +52,7 @@ reads, and full bodies are read last, and only the winners.
|
|
|
52
52
|
default when you can. <!-- rule:okf-search-fuzzy-is-a-switch -->
|
|
53
53
|
|
|
54
54
|
Scope any of them with what the map taught you:
|
|
55
|
-
`--
|
|
55
|
+
`--dir billing`, `--type Decision`, `--tag idempotency`, `--in body`.
|
|
56
56
|
Matches rank by where they hit, and the snippet often *is* the answer.
|
|
57
57
|
When the answer may live in another registered bundle, span them — leading
|
|
58
58
|
@slugs (`okf search @handbook @notes <terms>`) or `@all` for every registered
|
|
@@ -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.
|
|
@@ -144,7 +150,7 @@ as Ruby regular expressions with `--regexp`/`-e` (an invalid pattern is a usage
|
|
|
144
150
|
error, exit 2). `--fuzzy` forgives typos; pairing it with `-e` is a usage error,
|
|
145
151
|
since a pattern is matched literally rather than by edit distance.
|
|
146
152
|
`--in a,b` restricts the searched fields (title, id, tags, type, description,
|
|
147
|
-
body); the shared `--type/--
|
|
153
|
+
body); the shared `--type/--dir/--tag` filters narrow the candidates *first*,
|
|
148
154
|
so a search scoped by what `index` taught you stays surgical.
|
|
149
155
|
|
|
150
156
|
**The default is exact, so an exact query means what it looks like.** A phrase in
|
|
@@ -267,8 +273,30 @@ there, its child directories, and the concept listing. Run it first when picking
|
|
|
267
273
|
an existing bundle: it is the cheapest high-signal orientation, and it surfaces
|
|
268
274
|
enumeration drift a grep can't (you can't grep for a listing entry that is *missing*).
|
|
269
275
|
|
|
270
|
-
`--
|
|
271
|
-
format` shows both; `root`
|
|
276
|
+
`--dir PATH` narrows to a directory **and everything below it**, and is
|
|
277
|
+
**repeatable** — `--dir model --dir format` shows both; `root` (or `.`) names the
|
|
278
|
+
bundle root. A `--dir` also brings the **chain from the root down to it**, so a branch is
|
|
279
|
+
never shown adrift of the authored context that says what it is — the root
|
|
280
|
+
`index.md`'s prose first among it. Those rows print with a leading `↑` and carry
|
|
281
|
+
`ancestor: true`; `--no-ancestors` drops them. Ascent and descent are separate
|
|
282
|
+
axes, so `--depth` never bounds the chain: `--dir X --depth 0` is X alone, plus
|
|
283
|
+
how you get to X. A `--dir` that names nothing gains no chain — a lone root row
|
|
284
|
+
would read as a partial answer to a query that matched nothing.
|
|
285
|
+
|
|
286
|
+
`--depth N` bounds how far below the starting point the map reaches
|
|
287
|
+
(the `--dir` when one is given, else the bundle root), counted **relatively**:
|
|
288
|
+
`--depth 1` is the top of the tree, `--dir X --depth 1` is one branch of it, and
|
|
289
|
+
the pair walks down a level at a time.
|
|
290
|
+
|
|
291
|
+
**On a bundle of any size the map is unreadable whole** — every directory is a
|
|
292
|
+
section, and even `--no-body` keeps one listing row per *concept* — so narrow
|
|
293
|
+
rather than paging it: `okf dirs` is the orientation, `--dir <branch> --depth 1`
|
|
294
|
+
is the step down into it,
|
|
295
|
+
and `--except body,listing` on top of either is the lean JSON skeleton. Full
|
|
296
|
+
`index` output on a few hundred concepts runs to hundreds of KB; the same map at
|
|
297
|
+
`--depth 1` is a couple of KB.
|
|
298
|
+
|
|
299
|
+
`--no-body` drops the prose to a
|
|
272
300
|
skeleton (headers, rollups, child pointers). For a directory that has concepts but
|
|
273
301
|
**no `index.md`**, the listing is **synthesized** from the concepts' descriptions
|
|
274
302
|
and tagged `(no index.md)` — §6 explicitly permits synthesizing a map on the fly.
|
|
@@ -277,7 +305,49 @@ It is a **read view**: advisory, always exit 0. A synthesized directory is a
|
|
|
277
305
|
*signal* (a map worth writing), never a defect — `index` emits no lint findings and
|
|
278
306
|
never fails a bundle. JSON: `{ bundle, count, directories: [{ dir, index_path,
|
|
279
307
|
present, synthesized, count, types, tags, subdirs, body, listing: [{ id, title,
|
|
280
|
-
description, type, tags }] }] }
|
|
308
|
+
description, type, tags }] }] }` — `ancestor` marks a row that is there to place
|
|
309
|
+
the branch rather than to answer about it.
|
|
310
|
+
|
|
311
|
+
## dirs — the bundle's clusters and their sizes
|
|
312
|
+
|
|
313
|
+
`okf dirs <dir>` lists every directory the bundle has — the ones holding
|
|
314
|
+
concepts, the ones carrying an `index.md`, and the empty intermediates that only
|
|
315
|
+
exist to connect the tree — with the number of concepts living **directly** in
|
|
316
|
+
each and the number in its **subtree**. A cluster *is* a directory here, so this
|
|
317
|
+
is the view that tells you what `--dir` can be pointed at and how much sits
|
|
318
|
+
behind each choice.
|
|
319
|
+
|
|
320
|
+
Two numbers, because one cannot answer the question. `count` is direct, so the
|
|
321
|
+
column sums to the bundle's concept total and a dir holding only sub-directories
|
|
322
|
+
reads `0` rather than a hidden rollup. `subtree` is defined as *exactly what
|
|
323
|
+
`--dir <that row>` returns*, so the row and the flag can never disagree — which
|
|
324
|
+
is also why the root's subtree is its own direct count (`.` is a prefix of
|
|
325
|
+
nothing). Without it a truncated listing is all zeroes at the top of a deep tree,
|
|
326
|
+
which is where you most need to know where the mass is. The human table shows the
|
|
327
|
+
second column only where some dir actually nests.
|
|
328
|
+
|
|
329
|
+
`--dir PATH` (repeatable) narrows to a directory and its subtree, and brings the
|
|
330
|
+
**chain up to the root** with it so the branch is placed rather than shown
|
|
331
|
+
adrift — those rows are marked `↑`, carry `ancestor: true`, and stay out of
|
|
332
|
+
`total` (`--no-ancestors` drops them). `--depth N` keeps only N levels below the
|
|
333
|
+
starting point — the `--dir` when one is given,
|
|
334
|
+
the bundle root otherwise. Relative, not absolute, so `--dir a/b --depth 1`
|
|
335
|
+
reads "a/b and one level under it" without your first working out how deep `a/b`
|
|
336
|
+
is. `--depth 0` is the starting point alone. A `--depth` that is not a whole
|
|
337
|
+
number is a usage error (exit 2).
|
|
338
|
+
|
|
339
|
+
**This is the first command to run on a bundle you do not know** — the same first
|
|
340
|
+
move [SKILL.md](../SKILL.md) prescribes. `okf dirs <dir>` is one row per
|
|
341
|
+
directory, so its size tracks the tree rather than the concept count: it tells
|
|
342
|
+
you the shape and where the weight sits, `--depth 1` trims it further on a deep
|
|
343
|
+
bundle, and you then descend with `okf index --dir`, one level at a time.
|
|
344
|
+
|
|
345
|
+
The root prints `(root)` and stores `.` — the split every grouped view keeps, so
|
|
346
|
+
a table and its `--json` never disagree about which spelling is the data. JSON:
|
|
347
|
+
`{ bundle, total, count, dirs: [{ dir, ancestor, count, subtree, subdirs }] }`,
|
|
348
|
+
root first. `count` is rows printed, chain included; `total` sums the direct
|
|
349
|
+
counts of the rows you actually asked for, which is what keeps a row's `subtree`
|
|
350
|
+
equal to the `total` that `--dir` on that row returns.
|
|
281
351
|
|
|
282
352
|
## catalog / files / tags / types / stats — the server views, as text
|
|
283
353
|
|
|
@@ -287,7 +357,8 @@ All are advisory reads (exit 0) sharing one data source (per-concept metadata pl
|
|
|
287
357
|
in/out link degree). Add `--json` to any for a machine substrate.
|
|
288
358
|
|
|
289
359
|
- **`catalog`** — every concept with its metadata (type, status, tags, timestamp,
|
|
290
|
-
in/out link degree, description), grouped by top-level area
|
|
360
|
+
in/out link degree, description), grouped by top-level area (`dir` on every row
|
|
361
|
+
carries the full path). The "what's here, in
|
|
291
362
|
detail" view. JSON: `{ bundle, count, concepts: [{ id, title, type, description,
|
|
292
363
|
tags, timestamp, status, backlog_ref, dir, area, links_out, links_in }] }`.
|
|
293
364
|
- **`files`** — the folder tree: each concept's filename + title, grouped by
|
|
@@ -295,26 +366,44 @@ in/out link degree). Add `--json` to any for a machine substrate.
|
|
|
295
366
|
id, dir, type, title, description }] }`.
|
|
296
367
|
- **`tags`** — every tag with the concepts that carry it, ordered by count
|
|
297
368
|
descending. The "what themes dominate" view. JSON: `{ bundle, count, tags: [{ tag,
|
|
298
|
-
count, concepts: [id, …] }] }`. `--by type|
|
|
299
|
-
dimension with **within-group** counts (a tag spanning groups appears in each)
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
369
|
+
count, concepts: [id, …] }] }`. `--by type|dir` regroups the list per concept
|
|
370
|
+
dimension with **within-group** counts (a tag spanning groups appears in each);
|
|
371
|
+
each row also carries the tag's **total** across the narrowed set, printed
|
|
372
|
+
`count/total` when they differ — so a tag's locality reads per row (a plain
|
|
373
|
+
count = wholly local; `2/7` = a cross-cutting spread). The substrate for tag
|
|
374
|
+
curation and for [refine](../playbooks/refine.md)'s domain-vs-concern read;
|
|
375
|
+
the judgment recipes live in the [maintain playbook](../playbooks/maintain.md)
|
|
376
|
+
and the [refine playbook](../playbooks/refine.md). JSON: `{ bundle, count, by,
|
|
377
|
+
groups: [{ <dim>, count, tags: [{ tag, count, total, concepts }] }] }`.
|
|
303
378
|
- **`types`** — every type with the concepts that carry it, ordered by count
|
|
304
379
|
descending. The "what kinds of knowledge" view. JSON: `{ bundle, count, types:
|
|
305
380
|
[{ type, count, concepts: [id, …] }] }`.
|
|
306
|
-
- **`stats`** — bundle rollups: concept /
|
|
307
|
-
totals plus per-type and per-
|
|
308
|
-
`{ bundle, concepts, areas, concept_types, cross_links, distinct_tags,
|
|
381
|
+
- **`stats`** — bundle rollups: concept / dir / type / cross-link / distinct-tag
|
|
382
|
+
totals plus per-type and per-dir breakdowns. The "shape at a glance" view. JSON:
|
|
383
|
+
`{ bundle, concepts, dirs, areas, concept_types, cross_links, distinct_tags,
|
|
384
|
+
by_type, by_dir, by_area }` (`areas`/`by_area` are the deprecated first-segment
|
|
385
|
+
cut, kept for one release). `dirs`/`by_dir` cover every directory `okf dirs`
|
|
386
|
+
lists — counts are direct, so a directory holding nothing itself is present at
|
|
387
|
+
`0` rather than missing, and `by_dir.keys` is a complete list of what `--dir`
|
|
388
|
+
can address.
|
|
309
389
|
|
|
310
390
|
The four list views narrow with the same filters the browser panels offer —
|
|
311
|
-
`--type TYPE`, `--
|
|
312
|
-
itself (`tags` can't filter by tag). Matching is case-insensitive and
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
391
|
+
`--type TYPE`, `--dir PATH`, `--tag TAG`; each takes the ones orthogonal to
|
|
392
|
+
itself (`tags` can't filter by tag). Matching is case-insensitive; `--type` and
|
|
393
|
+
`--tag` are exact, `--dir` takes the named directory **and everything below it**
|
|
394
|
+
(`--dir platform` reaches `platform/services/api`). A concept at the bundle root
|
|
395
|
+
lives in `.`, which `--dir` also accepts as plain `root` (no shell quoting). A
|
|
396
|
+
filter that matches nothing is an empty view, not an error: `okf tags <dir> --dir
|
|
397
|
+
billing --json` answers "which tags does the billing cluster use?",
|
|
398
|
+
`okf catalog <dir> --tag auth` answers "what carries the auth tag?".
|
|
399
|
+
|
|
400
|
+
**`--area` is deprecated.** It still works — matching the *first path segment*
|
|
401
|
+
only, its old behavior unchanged — and prints `warning: --area is deprecated, use
|
|
402
|
+
--dir` on stderr (stdout stays clean, so a `--json` consumer is unaffected). Same
|
|
403
|
+
for `tags --by area`. Both go in a later release; write `--dir` in anything new.
|
|
404
|
+
On `index` it combines with neither `--depth` nor `--dir` — exit 2, because it is
|
|
405
|
+
*exact* and both of those select a range, so the pair used to return the area
|
|
406
|
+
plus whatever the other flag selected: an answer to neither question.
|
|
318
407
|
|
|
319
408
|
Reach for `stats` first to size a bundle, `catalog`/`files` to enumerate it, `tags`
|
|
320
409
|
to find thematic clusters — all without standing up the server.
|
|
@@ -330,10 +419,13 @@ in a body render as diagrams, and a click (or tap) opens the diagram full
|
|
|
330
419
|
screen with drag-to-pan and wheel/pinch zoom. Concepts render as nodes
|
|
331
420
|
coloured by `type` and sized by degree, links as edges, with a detail panel
|
|
332
421
|
(rendered markdown, "Links to" / "Linked from" backlinks), layout switching,
|
|
333
|
-
type/
|
|
422
|
+
type/dir/tag filters on every view (the dir chips take a directory *and* its
|
|
423
|
+
subtree, the same rule `--dir` uses), and search. Cluster mode groups the
|
|
424
|
+
concepts into one box per directory, nested to a depth picked beside the layout
|
|
425
|
+
select — depth 1 is the flat view, and a flat bundle is offered no control. The authored layer is in the
|
|
334
426
|
UI too: the Files view carries **Files | Indexes** tabs — the Indexes tab
|
|
335
427
|
lists the log first (the chronological index), then every `index.md` — and
|
|
336
|
-
folder nodes in file-tree mode and
|
|
428
|
+
folder nodes in file-tree mode and directory boxes in cluster mode open a
|
|
337
429
|
directory's §6 map in the inspector (authored, or synthesized when none
|
|
338
430
|
exists). Links to an `index.md`, `log.md`, or bare directory navigate instead
|
|
339
431
|
of dead-ending, and the log is fetched fresh on every read, so a
|
|
@@ -427,3 +519,11 @@ drops each node's body, and `--minimal` ships only `id`/`title` plus the type/ta
|
|
|
427
519
|
indexes — the lean shape the `server` page boots from. Reach for the full dump
|
|
428
520
|
only when the task truly consumes every body; for one question, the
|
|
429
521
|
[search verb](#search--ranked-text-retrieval-metadata--body) is orders cheaper.
|
|
522
|
+
|
|
523
|
+
`--hubs` swaps the dump for the **inbound ranking**: every concept with at
|
|
524
|
+
least one inbound link, ranked by inbound degree, each with its links grouped
|
|
525
|
+
by *source area* (`core/status ×3 flows 2, billing 1`) — the evidence for
|
|
526
|
+
[refine](../playbooks/refine.md)'s hub origin test ("is this hub well-homed?").
|
|
527
|
+
A source at the bundle root counts under `(root)`. JSON: `{ bundle, count,
|
|
528
|
+
hubs: [{ id, area, inbound, by_area: { <area>: n } }] }`. Advisory read, exit 0;
|
|
529
|
+
`--minimal`/`--no-body` shape node payloads and change nothing here.
|
data/lib/okf/version.rb
CHANGED
data/lib/okf.rb
CHANGED
|
@@ -25,6 +25,15 @@ module OKF
|
|
|
25
25
|
value.respond_to?(:empty?) ? value.empty? : false
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
# The directory a concept lives in, derived from its §2 id: the id *is* the
|
|
29
|
+
# path minus `.md`, so putting the suffix back and taking the dirname is the
|
|
30
|
+
# definition rather than a parse of it. One home for it because three views
|
|
31
|
+
# answer with a `dir` — the catalog, the search rows, the linter's per-directory
|
|
32
|
+
# checks — and a rule spelled three times is three things to keep in step.
|
|
33
|
+
def self.dir_of(id)
|
|
34
|
+
File.dirname("#{id}.md")
|
|
35
|
+
end
|
|
36
|
+
|
|
28
37
|
require "okf/version"
|
|
29
38
|
|
|
30
39
|
# ── kernel: cross-cutting primitives ──
|
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.
|
|
4
|
+
version: 1.11.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rodrigo Serradura
|
|
@@ -54,11 +54,22 @@ dependencies:
|
|
|
54
54
|
description: |
|
|
55
55
|
OKF (Open Knowledge Format) is portable knowledge: Markdown files with YAML
|
|
56
56
|
frontmatter that both humans and agents read from one source. This gem is the
|
|
57
|
-
Ruby-native way to work with it.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
Ruby-native way to work with it.
|
|
58
|
+
|
|
59
|
+
Its companion agent skill authors and curates a bundle. The `okf` command-line
|
|
60
|
+
tool validates the result for v0.1 (§9) conformance, lints its curation
|
|
61
|
+
quality, and answers questions about it: ranked full-text search, and a
|
|
62
|
+
progressive-disclosure map that reads a large bundle a directory at a time
|
|
63
|
+
rather than loading it whole. `okf server` opens it as an interactive
|
|
64
|
+
knowledge graph and `okf render` bakes that same page into one self-contained
|
|
65
|
+
HTML file you can host anywhere. A per-user registry names your bundles, so
|
|
66
|
+
every verb reaches them by @slug from any directory and one search can span
|
|
67
|
+
them all.
|
|
68
|
+
|
|
69
|
+
Everything the CLI does also runs in-process through a library API
|
|
70
|
+
(OKF::Bundle and friends), and the graph server is a mountable Rack app. It
|
|
71
|
+
adds no service to your stack: rack, webrick and minifts are the only runtime
|
|
72
|
+
dependencies, and it runs on every Ruby since 2.4.
|
|
62
73
|
email:
|
|
63
74
|
- rodrigo.serradura@gmail.com
|
|
64
75
|
executables:
|
|
@@ -86,6 +97,23 @@ files:
|
|
|
86
97
|
- lib/okf/bundle/validator/result.rb
|
|
87
98
|
- lib/okf/bundle/writer.rb
|
|
88
99
|
- lib/okf/cli.rb
|
|
100
|
+
- lib/okf/cli/catalog.rb
|
|
101
|
+
- lib/okf/cli/command.rb
|
|
102
|
+
- lib/okf/cli/dirs.rb
|
|
103
|
+
- lib/okf/cli/files.rb
|
|
104
|
+
- lib/okf/cli/graph.rb
|
|
105
|
+
- lib/okf/cli/index.rb
|
|
106
|
+
- lib/okf/cli/lint.rb
|
|
107
|
+
- lib/okf/cli/loose.rb
|
|
108
|
+
- lib/okf/cli/registry.rb
|
|
109
|
+
- lib/okf/cli/render.rb
|
|
110
|
+
- lib/okf/cli/search.rb
|
|
111
|
+
- lib/okf/cli/server.rb
|
|
112
|
+
- lib/okf/cli/skill.rb
|
|
113
|
+
- lib/okf/cli/stats.rb
|
|
114
|
+
- lib/okf/cli/tags.rb
|
|
115
|
+
- lib/okf/cli/types.rb
|
|
116
|
+
- lib/okf/cli/validate.rb
|
|
89
117
|
- lib/okf/concept.rb
|
|
90
118
|
- lib/okf/concept/file.rb
|
|
91
119
|
- lib/okf/markdown/citations.rb
|
|
@@ -97,6 +125,7 @@ files:
|
|
|
97
125
|
- lib/okf/render/graph/template.html.erb
|
|
98
126
|
- lib/okf/server/app.rb
|
|
99
127
|
- lib/okf/server/hub.rb
|
|
128
|
+
- lib/okf/server/hub/not_found.rb
|
|
100
129
|
- lib/okf/server/runner.rb
|
|
101
130
|
- lib/okf/skill.rb
|
|
102
131
|
- lib/okf/skill/SKILL.md
|
|
@@ -107,6 +136,7 @@ files:
|
|
|
107
136
|
- lib/okf/skill/playbooks/menu.md
|
|
108
137
|
- lib/okf/skill/playbooks/migrate.md
|
|
109
138
|
- lib/okf/skill/playbooks/produce.md
|
|
139
|
+
- lib/okf/skill/playbooks/refine.md
|
|
110
140
|
- lib/okf/skill/playbooks/search.md
|
|
111
141
|
- lib/okf/skill/reference/APACHE-2.0.txt
|
|
112
142
|
- lib/okf/skill/reference/SPEC.md
|
|
@@ -142,6 +172,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
142
172
|
requirements: []
|
|
143
173
|
rubygems_version: 4.0.16
|
|
144
174
|
specification_version: 4
|
|
145
|
-
summary: 'The complete
|
|
146
|
-
|
|
175
|
+
summary: 'The complete Open Knowledge Format toolkit: an agent skill, a CLI and library,
|
|
176
|
+
ranked search, and a live knowledge graph. 100% local.'
|
|
147
177
|
test_files: []
|