okf-cli 0.1.2__tar.gz → 0.4.1__tar.gz

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 (67) hide show
  1. okf_cli-0.4.1/.github/workflows/test.yml +17 -0
  2. okf_cli-0.4.1/.last-update.json +5 -0
  3. okf_cli-0.4.1/AGENTS.md +205 -0
  4. {okf_cli-0.1.2 → okf_cli-0.4.1}/OKF_SPEC.md +27 -27
  5. okf_cli-0.4.1/PKG-INFO +257 -0
  6. okf_cli-0.4.1/README.md +226 -0
  7. okf_cli-0.4.1/example/.okfignore +3 -0
  8. okf_cli-0.4.1/example/loose/deep/no-heading.md +4 -0
  9. okf_cli-0.4.1/example/loose/no-desc.md +6 -0
  10. okf_cli-0.4.1/example/loose/no-title.md +5 -0
  11. {okf_cli-0.1.2 → okf_cli-0.4.1}/example/playbooks/incident-response.md +3 -3
  12. okf_cli-0.4.1/example/smoke-ignore.md +5 -0
  13. okf_cli-0.4.1/example/tables/customers.md +16 -0
  14. okf_cli-0.4.1/example/tables/orders.md +17 -0
  15. okf_cli-0.4.1/example/tables/partitions/daily.md +12 -0
  16. okf_cli-0.4.1/openwiki/architecture.md +72 -0
  17. okf_cli-0.4.1/openwiki/domain-model.md +108 -0
  18. okf_cli-0.4.1/openwiki/operations.md +60 -0
  19. okf_cli-0.4.1/openwiki/quickstart.md +40 -0
  20. okf_cli-0.4.1/openwiki/testing.md +61 -0
  21. okf_cli-0.4.1/openwiki/workflows.md +104 -0
  22. {okf_cli-0.1.2 → okf_cli-0.4.1}/pyproject.toml +10 -4
  23. okf_cli-0.4.1/skills/okf-cli-manual/SKILL.md +110 -0
  24. okf_cli-0.4.1/skills/writing-knowledge-base/SKILL.md +127 -0
  25. okf_cli-0.4.1/skills/writing-knowledge-base/reference/example/README.md +12 -0
  26. okf_cli-0.4.1/skills/writing-knowledge-base/reference/example/datasets/sales.md +7 -0
  27. okf_cli-0.4.1/skills/writing-knowledge-base/reference/example/domain.md +6 -0
  28. okf_cli-0.4.1/skills/writing-knowledge-base/reference/example/loose/deep/no-heading.md +4 -0
  29. okf_cli-0.4.1/skills/writing-knowledge-base/reference/example/loose/no-desc.md +6 -0
  30. okf_cli-0.4.1/skills/writing-knowledge-base/reference/example/loose/no-title.md +5 -0
  31. okf_cli-0.4.1/skills/writing-knowledge-base/reference/example/playbooks/incident-response.md +14 -0
  32. okf_cli-0.4.1/skills/writing-knowledge-base/reference/example/playbooks/oncall-guide.md +13 -0
  33. okf_cli-0.4.1/skills/writing-knowledge-base/reference/example/tables/customers.md +16 -0
  34. okf_cli-0.4.1/skills/writing-knowledge-base/reference/example/tables/orders.md +16 -0
  35. okf_cli-0.4.1/skills/writing-knowledge-base/reference/example/tables/partitions/2026/q1/jan/january.md +5 -0
  36. okf_cli-0.4.1/skills/writing-knowledge-base/reference/example/tables/partitions/daily.md +12 -0
  37. okf_cli-0.4.1/skills/writing-knowledge-base/reference/knowledge-base.md +65 -0
  38. okf_cli-0.4.1/src/okf/cli.py +45 -0
  39. okf_cli-0.4.1/src/okf/commands/__init__.py +0 -0
  40. okf_cli-0.4.1/src/okf/commands/bundle.py +307 -0
  41. okf_cli-0.4.1/src/okf/commands/list.py +41 -0
  42. okf_cli-0.4.1/src/okf/commands/show.py +53 -0
  43. okf_cli-0.4.1/src/okf/commands/validate.py +47 -0
  44. okf_cli-0.4.1/src/okf/core.py +188 -0
  45. okf_cli-0.4.1/tests/cli/test_bundle.py +459 -0
  46. okf_cli-0.4.1/tests/cli/test_list.py +93 -0
  47. okf_cli-0.4.1/tests/cli/test_show.py +90 -0
  48. okf_cli-0.4.1/tests/cli/test_validate.py +225 -0
  49. okf_cli-0.4.1/tests/e2e/test_e2e.py +840 -0
  50. okf_cli-0.4.1/tests/test_core.py +216 -0
  51. okf_cli-0.4.1/uv.lock +238 -0
  52. okf_cli-0.1.2/PKG-INFO +0 -156
  53. okf_cli-0.1.2/README.md +0 -126
  54. okf_cli-0.1.2/example/tables/customers.md +0 -16
  55. okf_cli-0.1.2/example/tables/orders.md +0 -16
  56. okf_cli-0.1.2/example/tables/partitions/daily.md +0 -12
  57. okf_cli-0.1.2/src/okf/cli.py +0 -233
  58. okf_cli-0.1.2/tests/test_cli.py +0 -304
  59. okf_cli-0.1.2/uv.lock +0 -150
  60. {okf_cli-0.1.2 → okf_cli-0.4.1}/.gitignore +0 -0
  61. {okf_cli-0.1.2 → okf_cli-0.4.1}/LICENSE +0 -0
  62. {okf_cli-0.1.2 → okf_cli-0.4.1}/example/README.md +0 -0
  63. {okf_cli-0.1.2 → okf_cli-0.4.1}/example/datasets/sales.md +0 -0
  64. {okf_cli-0.1.2 → okf_cli-0.4.1}/example/domain.md +0 -0
  65. {okf_cli-0.1.2 → okf_cli-0.4.1}/example/playbooks/oncall-guide.md +0 -0
  66. {okf_cli-0.1.2 → okf_cli-0.4.1}/example/tables/partitions/2026/q1/jan/january.md +0 -0
  67. {okf_cli-0.1.2 → okf_cli-0.4.1}/src/okf/__init__.py +0 -0
@@ -0,0 +1,17 @@
1
+ name: Test
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ runs-on: ubuntu-latest
8
+ strategy:
9
+ matrix:
10
+ python-version: ["3.11"]
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: astral-sh/setup-uv@v3
14
+ with:
15
+ python-version: ${{ matrix.python-version }}
16
+ - run: uv sync
17
+ - run: uv run pytest -q
@@ -0,0 +1,5 @@
1
+ {
2
+ "lastHead": "ddca03b",
3
+ "lastRun": "2026-07-11",
4
+ "mode": "update"
5
+ }
@@ -0,0 +1,205 @@
1
+ # AGENTS.md — okf-cli contributor context
2
+
3
+ This file is for AI agents (and humans) picking up work on `okf-cli`.
4
+
5
+ ## OpenWiki (read first)
6
+
7
+ This repository has docs in `openwiki/`.
8
+
9
+ Start here:
10
+
11
+ - [OpenWiki quickstart](openwiki/quickstart.md)
12
+
13
+ Then follow links to architecture, workflows, domain model, operations, and testing notes relevant to task.
14
+
15
+ ## Project overview
16
+
17
+ `okf-cli` is a Python CLI that converts plain markdown directories into
18
+ [Open Knowledge Format (OKF)](OKF_SPEC.md) bundles and provides tools to
19
+ inspect/validate them.
20
+
21
+ - **Input:** plain `.md` files starting with `# Title` and a `>` description block.
22
+ `bundle` also supports optional `.okfignore` in input root.
23
+ - **Output:** OKF-conformant markdown with YAML frontmatter, per-directory `index.md` files.
24
+ - **Operations:** `bundle`, `list`, `show`, `validate`.
25
+
26
+ ## Tech stack
27
+
28
+ - Python 3.11+
29
+ - Package/venv manager: **uv**
30
+ - CLI framework: **typer**
31
+ - YAML parsing: **pyyaml**
32
+ - Tests: **pytest**
33
+ - Lint/format: **ruff** (via `uvx ruff check .` / `uvx ruff format .`)
34
+ - Build: hatchling (configured in `pyproject.toml`)
35
+
36
+ Always use `uv` for dependency sync and running commands:
37
+
38
+ ```bash
39
+ uv sync # install/sync deps
40
+ uv run pytest -q # run tests
41
+ uv run okf --help # run CLI
42
+ uv run okf bundle example bundled --default-type reference --force
43
+ ```
44
+
45
+ ## Project layout
46
+
47
+ ```
48
+ okf-cli
49
+ ├── .github/workflows/test.yml # CI (pytest on 3.11)
50
+ ├── OKF_SPEC.md # OKF v0.1 specification
51
+ ├── README.md # user-facing docs
52
+ ├── AGENTS.md # this file
53
+ ├── pyproject.toml # project metadata + deps
54
+ ├── uv.lock # uv lockfile
55
+ ├── src/okf/
56
+ │ ├── cli.py # Typer entrypoint, registers commands
57
+ │ ├── core.py # shared parsing/formatting/conformance
58
+ │ └── commands/
59
+ │ ├── bundle.py # plain markdown → OKF bundle
60
+ │ ├── list.py # list concept IDs
61
+ │ ├── show.py # print concept by ID
62
+ │ └── validate.py # conformance check
63
+ └── tests/test_cli.py # pytest suite
64
+ ```
65
+
66
+ ## Architecture
67
+
68
+ ### `src/okf/cli.py`
69
+
70
+ - Creates the `typer.Typer` app named `okf`.
71
+ - Registers `bundle`, `list`, `show`, `validate`.
72
+ - No business logic here.
73
+
74
+ ### `src/okf/core.py`
75
+
76
+ - `RESERVED` — filenames `bundle` skips: `index.md`, `log.md`, `README.md`.
77
+ - `SPEC_RESERVED` — filenames reserved by the OKF spec: `index.md`, `log.md`.
78
+ - `build_frontmatter(...)` — generates YAML frontmatter using JSON-escaped strings.
79
+ - `parse_md(...)` — extracts title/description/body from plain markdown. Tries strict format first (line 1 `# Title`, `>` block); falls back leniently (title from line 0 only, description from first 80 chars of body). Never raises.
80
+ - `parse_frontmatter(...)` — parses YAML frontmatter with `yaml.safe_load`.
81
+ - `check_conformance(...)` — validates a directory against OKF §9, returns `(errors, warnings)`. Now enforces:
82
+ - §9.1: Non-reserved `.md` must have parseable frontmatter.
83
+ - §9.2: Frontmatter must have non-empty `type`.
84
+ - §9.3: `index.md` must not contain frontmatter (§6), except root `index.md` may have only `okf_version` (§11). `log.md` must not contain frontmatter (§7).
85
+ - Non-UTF-8 files are flagged as errors.
86
+
87
+ ### Commands
88
+
89
+ | Command | Input expected | Behavior |
90
+ | ---------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
91
+ | `bundle` | non-conformant plain markdown dir | generates OKF bundle; skips `index.md`, `log.md`, `README.md` with warnings; skips `.okfignore`-matched files; checks local `.md` links (warn by default, fail with `--strict-links`); root files need `--default-type`; requires `--force` to overwrite existing output |
92
+ | `list` | OKF-conformant bundle | prints concept IDs; exits 1 if dir is not conformant |
93
+ | `show` | OKF-conformant bundle | prints concept file by ID; exits 1 if dir is not conformant |
94
+ | `validate` | any directory | prints conformance errors and summary per §9 |
95
+
96
+ ## Key conventions
97
+
98
+ ### Reserved filenames
99
+
100
+ - `bundle` treats `index.md`, `log.md`, `README.md` as reserved because it
101
+ often runs against raw repo directories that may contain these files.
102
+ - `list`, `show`, `validate` operate on already-conformant OKF bundles, so
103
+ they only treat `index.md` and `log.md` as reserved per the spec.
104
+ - `README.md` can be a valid concept in an OKF bundle.
105
+
106
+ ### Link checks in `bundle`
107
+
108
+ - `bundle` scans markdown body links for local `.md` targets.
109
+ - Supports relative (`./x.md`, `../x.md`) and bundle-root (`/dir/x.md`) links.
110
+ - Ignores external links (scheme URLs like `https:`/`mailto:`), fragment-only links, directory links, and non-`.md` targets.
111
+ - Default behavior: emit warnings for missing local targets or targets outside bundle.
112
+ - `--strict-links`: treat those link issues as fatal and exit non-zero.
113
+
114
+ ### `.okfignore` (bundle only)
115
+
116
+ - Location: input directory root (`<input-dir>/.okfignore`).
117
+ - Format: one bundle-relative markdown path per line.
118
+ - Example: `tables/orders.md`, `smoke-ignore.md`
119
+ - Blank lines and lines starting with `#` are ignored.
120
+ - Matching is exact path match only (no glob, no negation).
121
+ - If `.okfignore` is non-UTF-8, `bundle` exits with error.
122
+
123
+ ### OKF conformance (§9)
124
+
125
+ 1. Every non-reserved `.md` must have parseable YAML frontmatter.
126
+ 1. Every frontmatter must contain a non-empty `type` string.
127
+ 1. Reserved filenames (`index.md`, `log.md`) follow structure per §6/§7 when present.
128
+ - `index.md` must not contain frontmatter (§6), except root `index.md` may contain only `okf_version` (§11).
129
+ - `log.md` must not contain frontmatter (§7).
130
+ 1. All files must be valid UTF-8.
131
+
132
+ `check_conformance()` is the source of truth for this logic.
133
+
134
+ ### Frontmatter
135
+
136
+ `build_frontmatter()` outputs JSON-escaped YAML values, e.g.:
137
+
138
+ ```yaml
139
+ ---
140
+ type: "tables"
141
+ title: "Customer Orders"
142
+ ---
143
+ ```
144
+
145
+ `parse_frontmatter()` uses `yaml.safe_load()` and returns `None` for missing,
146
+ malformed, or non-dict frontmatter.
147
+
148
+ ## Testing
149
+
150
+ Run the full suite before finishing:
151
+
152
+ ```bash
153
+ uv run pytest -q
154
+ ```
155
+
156
+ Add tests for new behavior in `tests/test_cli.py`. Existing patterns:
157
+
158
+ - Unit tests for `core.py` helpers.
159
+ - CLI integration tests using `typer.testing.CliRunner` and `tmp_path`.
160
+ - Conformance tests for `validate`, `list`, `show`.
161
+
162
+ ## Common tasks
163
+
164
+ ### Regenerate the example bundle
165
+
166
+ ```bash
167
+ uv run okf bundle example bundled --default-type reference --force
168
+ uv run okf bundle example bundled --default-type reference --force --strict-links
169
+ uv run okf validate bundled
170
+ uv run okf list bundled
171
+ ```
172
+
173
+ `bundled/` is gitignored; it is only a local artifact. Use `--force` for re-runs.
174
+ If `example/.okfignore` exists, `bundle` will skip matched files.
175
+
176
+ ### Add a new CLI command
177
+
178
+ 1. Create `src/okf/commands/<name>.py` with a function taking `typer` arguments.
179
+ 1. Import and register it in `src/okf/cli.py` with `app.command()(fn)` or
180
+ `app.command("alias")(fn)`.
181
+ 1. Add tests in `tests/test_cli.py`.
182
+
183
+ ### Modify conformance behavior
184
+
185
+ Update `check_conformance()` in `src/okf/core.py`, then ensure
186
+ `validate`, `list`, and `show` all behave consistently.
187
+
188
+ ## Style guidelines
189
+
190
+ - Keep changes minimal. Prefer stdlib/installed dependencies over new ones.
191
+ - Do not add abstractions "for later".
192
+ - Use `Path` from `pathlib`, not string path manipulation.
193
+ - Use `uv` for all package/runtime commands.
194
+
195
+ ## OpenWiki
196
+
197
+ This repository has documentation located in the /openwiki directory.
198
+
199
+ Start here:
200
+
201
+ - [OpenWiki quickstart](openwiki/quickstart.md)
202
+
203
+ OpenWiki includes repository overview, architecture notes, workflows, domain concepts, operations, integrations, testing guidance, and source maps.
204
+
205
+ When working in this repository, read the OpenWiki quickstart first, then follow its links to the relevant architecture, workflow, domain, operation, and testing notes.
@@ -12,7 +12,7 @@ YAML frontmatter. There is no schema registry, no central authority, and
12
12
  no required tooling. If you can `cat` a file, you can read OKF; if you
13
13
  can `git clone` a repo, you can ship it.
14
14
 
15
- ---
15
+ ______________________________________________________________________
16
16
 
17
17
  ## 1. Motivation
18
18
 
@@ -33,9 +33,9 @@ of structural conventions needed to make a knowledge corpus
33
33
  ### Goals
34
34
 
35
35
  1. Define a universal format that **enrichment agents** can write into.
36
- 2. Inform how **consumption agents** should read and traverse it.
37
- 3. Facilitate **exchange** of knowledge across systems and organizations.
38
- 4. Standardize the small number of **required** fields that must be
36
+ 1. Inform how **consumption agents** should read and traverse it.
37
+ 1. Facilitate **exchange** of knowledge across systems and organizations.
38
+ 1. Standardize the small number of **required** fields that must be
39
39
  present for content to be meaningfully consumed.
40
40
 
41
41
  ### Non-goals
@@ -45,7 +45,7 @@ of structural conventions needed to make a knowledge corpus
45
45
  - Replacing domain-specific schemas (Avro, Protobuf, OpenAPI, etc.) —
46
46
  OKF *references* them; it does not subsume them.
47
47
 
48
- ---
48
+ ______________________________________________________________________
49
49
 
50
50
  ## 2. Terminology
51
51
 
@@ -66,7 +66,7 @@ of structural conventions needed to make a knowledge corpus
66
66
  - **Citation** — A link from a concept to an external source that
67
67
  supports a claim in the body.
68
68
 
69
- ---
69
+ ______________________________________________________________________
70
70
 
71
71
  ## 3. Bundle Structure
72
72
 
@@ -97,10 +97,10 @@ A bundle MAY be distributed as:
97
97
  The following filenames have defined meaning at any level of the
98
98
  hierarchy and MUST NOT be used for concept documents:
99
99
 
100
- | Filename | Purpose |
101
- |--------------|--------------------------------------------------------|
102
- | `index.md` | Directory listing. See §6. |
103
- | `log.md` | Update history. See §7. |
100
+ | Filename | Purpose |
101
+ | ---------- | -------------------------- |
102
+ | `index.md` | Directory listing. See §6. |
103
+ | `log.md` | Update history. See §7. |
104
104
 
105
105
  All other `.md` files are concept documents.
106
106
 
@@ -109,7 +109,7 @@ frontmatter field in §4.1. OKF does not specify a separate file format
109
109
  for aggregating documents by tag; producers that want a tag-browsing
110
110
  view can synthesize one at consumption time by scanning frontmatter.
111
111
 
112
- ---
112
+ ______________________________________________________________________
113
113
 
114
114
  ## 4. Concept Documents
115
115
 
@@ -117,7 +117,7 @@ Every concept is a UTF-8 markdown file. It has two parts:
117
117
 
118
118
  1. A **YAML frontmatter block**, delimited by `---` on its own line at
119
119
  the start of the file and a closing `---` on its own line.
120
- 2. A **markdown body**, containing free-form content.
120
+ 1. A **markdown body**, containing free-form content.
121
121
 
122
122
  ### 4.1 Frontmatter
123
123
 
@@ -170,11 +170,11 @@ prose, since structure aids both human reading and agent retrieval.
170
170
  There are no required body sections. The following section headings have
171
171
  **conventional** meaning and SHOULD be used when applicable:
172
172
 
173
- | Heading | Purpose |
174
- |----------------|--------------------------------------------------------|
175
- | `# Schema` | Structured description of an asset's columns/fields. |
176
- | `# Examples` | Concrete usage examples, often as fenced code blocks. |
177
- | `# Citations` | External sources backing claims in the body. See §8. |
173
+ | Heading | Purpose |
174
+ | ------------- | ----------------------------------------------------- |
175
+ | `# Schema` | Structured description of an asset's columns/fields. |
176
+ | `# Examples` | Concrete usage examples, often as fenced code blocks. |
177
+ | `# Citations` | External sources backing claims in the body. See §8. |
178
178
 
179
179
  ### 4.3 Example: a concept bound to a resource
180
180
 
@@ -228,7 +228,7 @@ its expected SLA. See the [orders table](/tables/orders.md).
228
228
  2. …
229
229
  ```
230
230
 
231
- ---
231
+ ______________________________________________________________________
232
232
 
233
233
  ## 5. Cross-linking
234
234
 
@@ -266,7 +266,7 @@ Consumers MUST tolerate broken links — a link whose target does not
266
266
  exist in the bundle is not malformed; it may simply represent
267
267
  not-yet-written knowledge.
268
268
 
269
- ---
269
+ ______________________________________________________________________
270
270
 
271
271
  ## 6. Index Files
272
272
 
@@ -293,7 +293,7 @@ Entries SHOULD include the description from the linked concept's
293
293
  frontmatter. Producers MAY generate `index.md` automatically; consumers
294
294
  MAY synthesize one on the fly when none is present.
295
295
 
296
- ---
296
+ ______________________________________________________________________
297
297
 
298
298
  ## 7. Log Files (optional)
299
299
 
@@ -317,7 +317,7 @@ Date headings MUST use ISO 8601 `YYYY-MM-DD` form. Log entries are
317
317
  prose; the leading bold word (`**Update**`, `**Creation**`,
318
318
  `**Deprecation**`, etc.) is a convention, not a requirement.
319
319
 
320
- ---
320
+ ______________________________________________________________________
321
321
 
322
322
  ## 8. Citations
323
323
 
@@ -336,7 +336,7 @@ Citation links MAY be absolute URLs, bundle-relative paths, or paths
336
336
  into a `references/` subdirectory that mirrors external material as
337
337
  first-class OKF concepts.
338
338
 
339
- ---
339
+ ______________________________________________________________________
340
340
 
341
341
  ## 9. Conformance
342
342
 
@@ -344,8 +344,8 @@ A bundle is **conformant** with OKF v0.1 if:
344
344
 
345
345
  1. Every non-reserved `.md` file in the tree contains a parseable YAML
346
346
  frontmatter block.
347
- 2. Every frontmatter block contains a non-empty `type` field.
348
- 3. Every reserved filename (`index.md`, `log.md`) follows the structure
347
+ 1. Every frontmatter block contains a non-empty `type` field.
348
+ 1. Every reserved filename (`index.md`, `log.md`) follows the structure
349
349
  described in §6 and §7 respectively when present.
350
350
 
351
351
  Consumers SHOULD treat all other constraints as soft guidance. In
@@ -361,7 +361,7 @@ This permissive consumption model is intentional: OKF is meant to
361
361
  remain useful as bundles grow, get refactored, and are partially
362
362
  generated by agents.
363
363
 
364
- ---
364
+ ______________________________________________________________________
365
365
 
366
366
  ## 10. Relationship to other formats
367
367
 
@@ -377,7 +377,7 @@ OKF is intentionally close to several established patterns:
377
377
  OKF differs primarily in being **specified** — pinning down the small
378
378
  set of rules needed for interoperability without dictating tooling.
379
379
 
380
- ---
380
+ ______________________________________________________________________
381
381
 
382
382
  ## 11. Versioning
383
383
 
@@ -395,7 +395,7 @@ only place frontmatter is permitted in an `index.md`). Consumers that
395
395
  do not understand the declared version SHOULD attempt best-effort
396
396
  consumption rather than refusing the bundle.
397
397
 
398
- ---
398
+ ______________________________________________________________________
399
399
 
400
400
  ## Appendix A — Minimal example bundle
401
401
 
okf_cli-0.4.1/PKG-INFO ADDED
@@ -0,0 +1,257 @@
1
+ Metadata-Version: 2.4
2
+ Name: okf-cli
3
+ Version: 0.4.1
4
+ Summary: Open Knowledge Format tooling
5
+ License: MIT License
6
+
7
+ Copyright (c) 2026 Dheerapat Tookkane
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
26
+ License-File: LICENSE
27
+ Requires-Python: >=3.11
28
+ Requires-Dist: pyyaml>=6
29
+ Requires-Dist: typer>=0.15
30
+ Description-Content-Type: text/markdown
31
+
32
+ # okf-cli — Open Knowledge Format tooling
33
+
34
+ Converts plain markdown into [OKF](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)-conformant knowledge bundles. Domain experts write `# Title` then `> description` — `okf bundle` generates frontmatter, type, timestamps, and index files. Files without strict formatting are parsed leniently: title from line 0 if present, description from body text.
35
+
36
+ Also validates bundles and lists concept IDs for consumption by other tools.
37
+
38
+ ## Install
39
+
40
+ ```bash
41
+ uv tool install okf-cli
42
+ ```
43
+
44
+ ### Dev quickstart
45
+
46
+ ```bash
47
+ uv sync
48
+ uv run okf --help
49
+ ```
50
+
51
+ ## Commands
52
+
53
+ ### `okf bundle` — convert plain markdown to OKF bundle
54
+
55
+ ```
56
+ okf bundle <input-dir> [output-dir] [--default-type <name>] [--force] [--strict-links]
57
+ ```
58
+
59
+ | Argument | Description |
60
+ | ---------------- | ---------------------------------------------------------------------------- |
61
+ | `input-dir` | Directory of plain `.md` files |
62
+ | `output-dir` | Target directory (default: `bundled`) |
63
+ | `--default-type` | Type for root-level files (skip root files if omitted) |
64
+ | `--force`, `-f` | Overwrite output directory if it exists |
65
+ | `--strict-links` | Fail if local markdown links point outside bundle or to missing `.md` target |
66
+
67
+ ```bash
68
+ okf bundle example --default-type reference # first run → bundled/
69
+ okf bundle example --default-type reference --force # re-run
70
+ okf bundle example --default-type reference --force --strict-links # fail on broken local .md links
71
+ cat bundled/tables/orders.md
72
+ ```
73
+
74
+ `.okfignore` (bundle only):
75
+
76
+ - Put `.okfignore` in `input-dir`.
77
+ - Add bundle-relative markdown paths to skip, one per line.
78
+ - Blank lines and `#` comments ignored.
79
+ - Matching is exact path match (no glob, no negation).
80
+
81
+ ```text
82
+ # example/.okfignore
83
+ smoke-ignore.md
84
+ tables/orders.md
85
+ ```
86
+
87
+ Local link checks during `bundle`:
88
+
89
+ - Scans markdown body links to local `.md` targets.
90
+ - Supports relative links (`./x.md`, `../x.md`) and bundle-root links (`/tables/x.md`).
91
+ - Ignores external links (`https:`, `mailto:`), fragment-only links (`#section`), directory links, and non-`.md` targets.
92
+ - Default mode prints warnings for missing targets or links resolving outside bundle.
93
+ - `--strict-links` turns those warnings into a non-zero exit (`Error: strict link check failed`).
94
+
95
+ ### `okf list` — list concept IDs in a bundle
96
+
97
+ ```
98
+ okf list <directory>
99
+ ```
100
+
101
+ Prints concept IDs (bundle-relative path with `.md` stripped) for every
102
+ concept file in the bundle. Reserved filenames (`index.md`, `log.md`)
103
+ are excluded. `README.md` is not reserved by the OKF spec and is listed
104
+ as a concept if present.
105
+
106
+ Requires the directory to be a valid OKF bundle; fails if any
107
+ non-reserved `.md` is missing frontmatter or a non-empty `type`.
108
+
109
+ ```bash
110
+ okf list bundled/
111
+ # datasets/sales
112
+ # playbooks/incident-response
113
+ # tables/orders
114
+ # …
115
+ ```
116
+
117
+ Useful for piping OKF bundles into other tooling:
118
+
119
+ ```bash
120
+ okf list bundled/ | xargs -I{} okf show bundled/ {}
121
+ ```
122
+
123
+ ### `okf show` — read a concept by ID
124
+
125
+ ```
126
+ okf show <directory> <concept-id>
127
+ ```
128
+
129
+ Prints the full contents (frontmatter + body) of a concept file.
130
+ Concept IDs are the bundle-relative path with `.md` stripped — exactly
131
+ as printed by `okf list`.
132
+
133
+ Requires the directory to be a valid OKF bundle.
134
+
135
+ ```bash
136
+ okf show bundled/ tables/orders
137
+ # ---
138
+ # type: "tables"
139
+ # title: "Customer Orders"
140
+ # ...
141
+ ```
142
+
143
+ Guards against path traversal and rejects reserved filenames.
144
+
145
+ ### `okf validate` — check OKF conformance
146
+
147
+ ```
148
+ okf validate <directory>
149
+ ```
150
+
151
+ Checks OKF v0.1 §9 conformance:
152
+
153
+ - Every non-reserved `.md` has parseable YAML frontmatter with non-empty `type`.
154
+ - Reserved filenames (`index.md`, `log.md`) follow spec structure (§6/§7).
155
+ - Non-UTF-8 files are flagged.
156
+
157
+ ```bash
158
+ okf validate bundled/
159
+ # 16 files: 16 ok
160
+ ```
161
+
162
+ ## Writing input files (for `bundle`)
163
+
164
+ ### Strict format (recommended)
165
+
166
+ Every `.md` file starts with:
167
+
168
+ ```markdown
169
+ # Title
170
+
171
+ > Description
172
+ > Second optional description line.
173
+ ```
174
+
175
+ Everything after the description block is preserved unchanged.
176
+
177
+ ### Lenient fallback
178
+
179
+ Files that don't follow the strict format are still bundled best-effort:
180
+
181
+ | Condition | Behavior |
182
+ | ---------------------------------------- | ------------------------------------------------------------------ |
183
+ | No `# Title` on line 1 | Title omitted from frontmatter |
184
+ | No `>` description block | Description derived from first 80 chars of body ("…" if truncated) |
185
+ | Root-level file without `--default-type` | Skip file, warn, continue |
186
+
187
+ **Rules:**
188
+
189
+ | Rule | Why |
190
+ | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
191
+ | Folder name = concept type | `tables/orders.md` → `type: "tables"` |
192
+ | Only `.md` files processed | Non-`.md` files ignored |
193
+ | `index.md`, `log.md`, `README.md` skipped in `bundle` | Input may contain repo artifacts; these are not concepts. `bundle` warns when it skips them. Other commands (`list`, `show`, `validate`) operate on conformant OKF bundles where only `index.md` and `log.md` are reserved. |
194
+ | `.okfignore` entries skipped in `bundle` | Add bundle-relative markdown paths (e.g. `tables/orders.md`) to skip conversion for selected files. Blank lines and `#` comments are ignored. |
195
+
196
+ Root files need `--default-type`. Otherwise put files in named folders.
197
+
198
+ See the [`example/`](example/) directory for a sample of how to structure files.
199
+
200
+ ## How `bundle` works
201
+
202
+ 1. Walk `input-dir` for `.md` files (skip `.okfignore` matches and reserved names)
203
+ 1. Extract `title` from `#` on line 1, `description` from `>` block. If strict format not met, falls back: title omitted if absent, description from first 80 chars of body
204
+ 1. Check local markdown links against planned bundle targets (warn by default, or fail with `--strict-links`)
205
+ 1. Set `type` from parent dir name, `timestamp` from file mtime
206
+ 1. Write concept files with YAML frontmatter (title field omitted if empty)
207
+ 1. Generate `index.md` per directory — `# Contents` for files, `# Directories` for subdirs (recursive)
208
+
209
+ ## Output
210
+
211
+ Each concept becomes a markdown file with YAML frontmatter:
212
+
213
+ ```yaml
214
+ ---
215
+ type: "tables"
216
+ title: "Customer Orders"
217
+ description: "One row per completed customer order across all channels."
218
+ timestamp: "2026-07-04T15:06:51+00:00"
219
+ ---
220
+
221
+ Original body preserved as-is.
222
+ ```
223
+
224
+ Every directory gets its own `index.md`:
225
+
226
+ ```markdown
227
+ # Contents
228
+
229
+ * [Customer Orders](orders.md) - One row per completed customer order across all channels.
230
+
231
+ # Directories
232
+
233
+ * [partitions](partitions/)
234
+ ```
235
+
236
+ ## OKF Conformance
237
+
238
+ Generated bundles conform to [OKF v0.1](OKF_SPEC.md) (§9):
239
+
240
+ - Every non-reserved `.md` has parseable YAML frontmatter with non-empty `type` ✓
241
+ - Reserved filenames follow spec structure ✓
242
+ - Consumers MUST tolerate missing optional fields, unknown types, broken links ✓
243
+
244
+ ## Project layout
245
+
246
+ ```
247
+ okf-cli
248
+ ├── .github/workflows/test.yml # CI
249
+ ├── OKF_SPEC.md # OKF specification
250
+ ├── pyproject.toml # uv-managed Python project
251
+ ├── src/okf/
252
+ │ ├── cli.py # Typer entrypoint
253
+ │ ├── core.py # Shared parsing/formatting
254
+ │ └── commands/ # bundle, list, show, validate
255
+ ├── tests/test_cli.py # Tests
256
+ └── example/ # Sample input markdown
257
+ ```