okf-cli 0.4.5__tar.gz → 0.4.7__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 (59) hide show
  1. okf_cli-0.4.7/.last-update.json +1 -0
  2. okf_cli-0.4.7/AGENTS.md +82 -0
  3. okf_cli-0.4.7/PKG-INFO +169 -0
  4. okf_cli-0.4.7/README.md +138 -0
  5. okf_cli-0.4.7/openwiki/architecture.md +96 -0
  6. {okf_cli-0.4.5 → okf_cli-0.4.7}/openwiki/domain-model.md +10 -2
  7. {okf_cli-0.4.5 → okf_cli-0.4.7}/openwiki/operations.md +1 -0
  8. {okf_cli-0.4.5 → okf_cli-0.4.7}/openwiki/quickstart.md +28 -1
  9. okf_cli-0.4.7/openwiki/testing.md +75 -0
  10. {okf_cli-0.4.5 → okf_cli-0.4.7}/openwiki/workflows.md +13 -10
  11. {okf_cli-0.4.5 → okf_cli-0.4.7}/pyproject.toml +1 -1
  12. okf_cli-0.4.7/src/okf/api.py +541 -0
  13. okf_cli-0.4.7/src/okf/commands/bundle.py +59 -0
  14. okf_cli-0.4.7/src/okf/commands/list.py +23 -0
  15. okf_cli-0.4.7/src/okf/commands/show.py +21 -0
  16. okf_cli-0.4.7/src/okf/commands/validate.py +32 -0
  17. okf_cli-0.4.7/tests/test_api.py +1041 -0
  18. okf_cli-0.4.7/tests/test_cli.py +195 -0
  19. {okf_cli-0.4.5 → okf_cli-0.4.7}/uv.lock +1 -1
  20. okf_cli-0.4.5/.last-update.json +0 -1
  21. okf_cli-0.4.5/AGENTS.md +0 -205
  22. okf_cli-0.4.5/PKG-INFO +0 -257
  23. okf_cli-0.4.5/README.md +0 -226
  24. okf_cli-0.4.5/openwiki/architecture.md +0 -72
  25. okf_cli-0.4.5/openwiki/testing.md +0 -62
  26. okf_cli-0.4.5/src/okf/commands/bundle.py +0 -321
  27. okf_cli-0.4.5/src/okf/commands/list.py +0 -41
  28. okf_cli-0.4.5/src/okf/commands/show.py +0 -53
  29. okf_cli-0.4.5/src/okf/commands/validate.py +0 -47
  30. okf_cli-0.4.5/tests/cli/test_bundle.py +0 -482
  31. okf_cli-0.4.5/tests/cli/test_list.py +0 -93
  32. okf_cli-0.4.5/tests/cli/test_show.py +0 -90
  33. okf_cli-0.4.5/tests/cli/test_validate.py +0 -225
  34. okf_cli-0.4.5/tests/e2e/test_e2e.py +0 -849
  35. {okf_cli-0.4.5 → okf_cli-0.4.7}/.github/workflows/test.yml +0 -0
  36. {okf_cli-0.4.5 → okf_cli-0.4.7}/.gitignore +0 -0
  37. {okf_cli-0.4.5 → okf_cli-0.4.7}/LICENSE +0 -0
  38. {okf_cli-0.4.5 → okf_cli-0.4.7}/OKF_SPEC.md +0 -0
  39. {okf_cli-0.4.5 → okf_cli-0.4.7}/example/.okfignore +0 -0
  40. {okf_cli-0.4.5 → okf_cli-0.4.7}/example/README.md +0 -0
  41. {okf_cli-0.4.5 → okf_cli-0.4.7}/example/datasets/sales.md +0 -0
  42. {okf_cli-0.4.5 → okf_cli-0.4.7}/example/domain.md +0 -0
  43. {okf_cli-0.4.5 → okf_cli-0.4.7}/example/loose/deep/no-heading.md +0 -0
  44. {okf_cli-0.4.5 → okf_cli-0.4.7}/example/loose/no-desc.md +0 -0
  45. {okf_cli-0.4.5 → okf_cli-0.4.7}/example/loose/no-title.md +0 -0
  46. {okf_cli-0.4.5 → okf_cli-0.4.7}/example/playbooks/incident-response.md +0 -0
  47. {okf_cli-0.4.5 → okf_cli-0.4.7}/example/playbooks/oncall-guide.md +0 -0
  48. {okf_cli-0.4.5 → okf_cli-0.4.7}/example/smoke-ignore.md +0 -0
  49. {okf_cli-0.4.5 → okf_cli-0.4.7}/example/tables/customers.md +0 -0
  50. {okf_cli-0.4.5 → okf_cli-0.4.7}/example/tables/orders.md +0 -0
  51. {okf_cli-0.4.5 → okf_cli-0.4.7}/example/tables/partitions/2026/q1/jan/january.md +0 -0
  52. {okf_cli-0.4.5 → okf_cli-0.4.7}/example/tables/partitions/daily.md +0 -0
  53. {okf_cli-0.4.5 → okf_cli-0.4.7}/skills/okf-cli-manual/SKILL.md +0 -0
  54. {okf_cli-0.4.5 → okf_cli-0.4.7}/skills/writing-knowledge-base/SKILL.md +0 -0
  55. {okf_cli-0.4.5 → okf_cli-0.4.7}/src/okf/__init__.py +0 -0
  56. {okf_cli-0.4.5 → okf_cli-0.4.7}/src/okf/cli.py +0 -0
  57. {okf_cli-0.4.5 → okf_cli-0.4.7}/src/okf/commands/__init__.py +0 -0
  58. {okf_cli-0.4.5 → okf_cli-0.4.7}/src/okf/core.py +0 -0
  59. {okf_cli-0.4.5 → okf_cli-0.4.7}/tests/test_core.py +0 -0
@@ -0,0 +1 @@
1
+ {"head": "b0a76b5d97d2d46ab19d4fc4149be3efb4dc0228", "timestamp": "2025-07-15T19:10:00Z"}
@@ -0,0 +1,82 @@
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 documentation 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
+ ## Tech stack
16
+
17
+ - Python 3.11+
18
+ - Package/venv manager: **uv**
19
+ - CLI framework: **typer**
20
+ - YAML parsing: **pyyaml**
21
+ - Tests: **pytest**
22
+ - Lint/format: **ruff** (via `uvx ruff check .` / `uvx ruff format .`)
23
+ - Build: hatchling (configured in `pyproject.toml`)
24
+
25
+ Always use `uv` for dependency sync and running commands:
26
+
27
+ ```bash
28
+ uv sync # install/sync deps
29
+ uv run pytest -q # run tests
30
+ uv run okf --help # run CLI
31
+ ```
32
+
33
+ ## Project layout
34
+
35
+ ```
36
+ okf-cli
37
+ ├── .github/workflows/test.yml # CI (pytest on 3.11)
38
+ ├── OKF_SPEC.md # OKF v0.1 specification
39
+ ├── pyproject.toml # project metadata + deps
40
+ ├── uv.lock # uv lockfile
41
+ ├── src/okf/
42
+ │ ├── cli.py # Typer entrypoint, registers commands
43
+ │ ├── api.py # programmatic Python API (all business logic)
44
+ │ ├── core.py # shared parsing/formatting/conformance
45
+ │ └── commands/
46
+ │ ├── bundle.py # thin wrapper → api.bundle()
47
+ │ ├── list.py # thin wrapper → api.list_concepts()
48
+ │ ├── show.py # thin wrapper → api.show_concept()
49
+ │ └── validate.py # thin wrapper → api.validate()
50
+ └── tests/
51
+ ├── test_api.py # API unit/integration tests
52
+ ├── test_cli.py # CLI exit code/error message tests
53
+ └── test_core.py # core helper unit tests
54
+ ```
55
+
56
+ ## Common tasks
57
+
58
+ ### Regenerate the example bundle
59
+
60
+ ```bash
61
+ uv run okf bundle example bundled --default-type reference --force
62
+ uv run okf validate bundled
63
+ ```
64
+
65
+ `bundled/` is gitignored. Use `--force` for re-runs.
66
+
67
+ ### Add a new CLI command
68
+
69
+ 1. Create `src/okf/commands/<name>.py` with a function taking `typer` arguments.
70
+ 1. Import and register it in `src/okf/cli.py` with `app.command()(fn)`.
71
+ 1. Add tests in `tests/test_cli.py`.
72
+
73
+ ### Modify conformance behavior
74
+
75
+ Update `check_conformance()` in `src/okf/core.py`, then ensure `validate`, `list`, and `show` all behave consistently.
76
+
77
+ ## Style guidelines
78
+
79
+ - Keep changes minimal. Prefer stdlib/installed dependencies over new ones.
80
+ - Do not add abstractions "for later".
81
+ - Use `Path` from `pathlib`, not string path manipulation.
82
+ - Use `uv` for all package/runtime commands.
okf_cli-0.4.7/PKG-INFO ADDED
@@ -0,0 +1,169 @@
1
+ Metadata-Version: 2.4
2
+ Name: okf-cli
3
+ Version: 0.4.7
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 the content, `okf bundle` generates frontmatter, type, timestamps, and index files.
35
+
36
+ Also validates bundles, lists concept IDs, and reads concepts by ID.
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 # → bundled/
69
+ okf bundle example --default-type reference --force --strict-links
70
+ ```
71
+
72
+ **`.okfignore`**: put in `input-dir` root; one bundle-relative `.md` path per line. Exact match only (no glob).
73
+
74
+ **Link checking**: scans body links to local `.md` targets. Missing or out-of-bundle links warn by default, fail with `--strict-links`.
75
+
76
+ ### `okf list` — list concept IDs in a bundle
77
+
78
+ ```
79
+ okf list <directory>
80
+ ```
81
+
82
+ Prints concept IDs (path without `.md`). Requires valid OKF bundle.
83
+
84
+ ```bash
85
+ okf list bundled/
86
+ # datasets/sales
87
+ # tables/orders
88
+ ```
89
+
90
+ ### `okf show` — read a concept by ID
91
+
92
+ ```
93
+ okf show <directory> <concept-id>
94
+ ```
95
+
96
+ Prints full concept contents (frontmatter + body). Concept IDs as printed by `okf list`. Guards against path traversal.
97
+
98
+ ### `okf validate` — check OKF conformance
99
+
100
+ ```
101
+ okf validate <directory>
102
+ ```
103
+
104
+ Checks OKF v0.1 §9 conformance: frontmatter required, `type` required, reserved filenames follow spec structure, UTF-8 required.
105
+
106
+ ```bash
107
+ okf validate bundled/
108
+ # 16 files: 16 ok
109
+ ```
110
+
111
+ ## Input format
112
+
113
+ ### Strict (recommended)
114
+
115
+ ```markdown
116
+ # Title
117
+
118
+ > Description
119
+ ```
120
+
121
+ ### Lenient fallback
122
+
123
+ Files without strict format are bundled best-effort: title omitted if absent, description synthesized from first 80 chars of body.
124
+
125
+ | Rule | Why |
126
+ | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
127
+ | Folder name = concept type | `tables/orders.md` → `type: "tables"` |
128
+ | Only `.md` files processed | Non-`.md` files ignored |
129
+ | `index.md`, `log.md`, `README.md` skipped in `bundle` | Repo artifacts; not OKF concepts. `list`/`show`/`validate` only reserve `index.md` and `log.md`. |
130
+ | `.okfignore` entries skipped | Skip selected files without moving them. |
131
+
132
+ Root files need `--default-type`. See [`example/`](example/) for sample structure.
133
+
134
+ ## Output
135
+
136
+ Each concept becomes a markdown file with YAML frontmatter:
137
+
138
+ ```yaml
139
+ ---
140
+ type: "tables"
141
+ title: "Customer Orders"
142
+ description: "One row per completed customer order across all channels."
143
+ timestamp: "2026-07-04T15:06:51+00:00"
144
+ ---
145
+
146
+ Original body preserved as-is.
147
+ ```
148
+
149
+ Every directory gets an `index.md` listing files and subdirs.
150
+
151
+ ## OKF Conformance
152
+
153
+ Generated bundles conform to [OKF v0.1](OKF_SPEC.md) (§9): frontmatter required, non-empty `type`, reserved filenames follow spec structure.
154
+
155
+ ## Project layout
156
+
157
+ ```
158
+ okf-cli
159
+ ├── .github/workflows/test.yml # CI
160
+ ├── OKF_SPEC.md # OKF specification
161
+ ├── pyproject.toml # uv-managed Python project
162
+ ├── src/okf/
163
+ │ ├── cli.py # Typer entrypoint
164
+ │ ├── api.py # Programmatic Python API
165
+ │ ├── core.py # Shared parsing/formatting
166
+ │ └── commands/ # bundle, list, show, validate
167
+ ├── tests/ # pytest suite
168
+ └── example/ # Sample input markdown
169
+ ```
@@ -0,0 +1,138 @@
1
+ # okf-cli — Open Knowledge Format tooling
2
+
3
+ Converts plain markdown into [OKF](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)-conformant knowledge bundles. Domain experts write the content, `okf bundle` generates frontmatter, type, timestamps, and index files.
4
+
5
+ Also validates bundles, lists concept IDs, and reads concepts by ID.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ uv tool install okf-cli
11
+ ```
12
+
13
+ ### Dev quickstart
14
+
15
+ ```bash
16
+ uv sync
17
+ uv run okf --help
18
+ ```
19
+
20
+ ## Commands
21
+
22
+ ### `okf bundle` — convert plain markdown to OKF bundle
23
+
24
+ ```
25
+ okf bundle <input-dir> [output-dir] [--default-type <name>] [--force] [--strict-links]
26
+ ```
27
+
28
+ | Argument | Description |
29
+ | ---------------- | ---------------------------------------------------------------------------- |
30
+ | `input-dir` | Directory of plain `.md` files |
31
+ | `output-dir` | Target directory (default: `bundled`) |
32
+ | `--default-type` | Type for root-level files (skip root files if omitted) |
33
+ | `--force`, `-f` | Overwrite output directory if it exists |
34
+ | `--strict-links` | Fail if local markdown links point outside bundle or to missing `.md` target |
35
+
36
+ ```bash
37
+ okf bundle example --default-type reference # → bundled/
38
+ okf bundle example --default-type reference --force --strict-links
39
+ ```
40
+
41
+ **`.okfignore`**: put in `input-dir` root; one bundle-relative `.md` path per line. Exact match only (no glob).
42
+
43
+ **Link checking**: scans body links to local `.md` targets. Missing or out-of-bundle links warn by default, fail with `--strict-links`.
44
+
45
+ ### `okf list` — list concept IDs in a bundle
46
+
47
+ ```
48
+ okf list <directory>
49
+ ```
50
+
51
+ Prints concept IDs (path without `.md`). Requires valid OKF bundle.
52
+
53
+ ```bash
54
+ okf list bundled/
55
+ # datasets/sales
56
+ # tables/orders
57
+ ```
58
+
59
+ ### `okf show` — read a concept by ID
60
+
61
+ ```
62
+ okf show <directory> <concept-id>
63
+ ```
64
+
65
+ Prints full concept contents (frontmatter + body). Concept IDs as printed by `okf list`. Guards against path traversal.
66
+
67
+ ### `okf validate` — check OKF conformance
68
+
69
+ ```
70
+ okf validate <directory>
71
+ ```
72
+
73
+ Checks OKF v0.1 §9 conformance: frontmatter required, `type` required, reserved filenames follow spec structure, UTF-8 required.
74
+
75
+ ```bash
76
+ okf validate bundled/
77
+ # 16 files: 16 ok
78
+ ```
79
+
80
+ ## Input format
81
+
82
+ ### Strict (recommended)
83
+
84
+ ```markdown
85
+ # Title
86
+
87
+ > Description
88
+ ```
89
+
90
+ ### Lenient fallback
91
+
92
+ Files without strict format are bundled best-effort: title omitted if absent, description synthesized from first 80 chars of body.
93
+
94
+ | Rule | Why |
95
+ | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
96
+ | Folder name = concept type | `tables/orders.md` → `type: "tables"` |
97
+ | Only `.md` files processed | Non-`.md` files ignored |
98
+ | `index.md`, `log.md`, `README.md` skipped in `bundle` | Repo artifacts; not OKF concepts. `list`/`show`/`validate` only reserve `index.md` and `log.md`. |
99
+ | `.okfignore` entries skipped | Skip selected files without moving them. |
100
+
101
+ Root files need `--default-type`. See [`example/`](example/) for sample structure.
102
+
103
+ ## Output
104
+
105
+ Each concept becomes a markdown file with YAML frontmatter:
106
+
107
+ ```yaml
108
+ ---
109
+ type: "tables"
110
+ title: "Customer Orders"
111
+ description: "One row per completed customer order across all channels."
112
+ timestamp: "2026-07-04T15:06:51+00:00"
113
+ ---
114
+
115
+ Original body preserved as-is.
116
+ ```
117
+
118
+ Every directory gets an `index.md` listing files and subdirs.
119
+
120
+ ## OKF Conformance
121
+
122
+ Generated bundles conform to [OKF v0.1](OKF_SPEC.md) (§9): frontmatter required, non-empty `type`, reserved filenames follow spec structure.
123
+
124
+ ## Project layout
125
+
126
+ ```
127
+ okf-cli
128
+ ├── .github/workflows/test.yml # CI
129
+ ├── OKF_SPEC.md # OKF specification
130
+ ├── pyproject.toml # uv-managed Python project
131
+ ├── src/okf/
132
+ │ ├── cli.py # Typer entrypoint
133
+ │ ├── api.py # Programmatic Python API
134
+ │ ├── core.py # Shared parsing/formatting
135
+ │ └── commands/ # bundle, list, show, validate
136
+ ├── tests/ # pytest suite
137
+ └── example/ # Sample input markdown
138
+ ```
@@ -0,0 +1,96 @@
1
+ # Architecture
2
+
3
+ ## Runtime shape
4
+
5
+ `okf-cli` has a three-layer architecture:
6
+
7
+ - **CLI layer** (`src/okf/cli.py`) — Typer app creation, command registration, `--version` callback.
8
+ - **API layer** (`src/okf/api.py`) — programmatic Python functions, all business logic lives here.
9
+ - **Core layer** (`src/okf/core.py`) — shared parsing, formatting, conformance helpers.
10
+ - **Command wrappers** (`src/okf/commands/`) — thin IO/error bridges from CLI args to API calls.
11
+
12
+ Why this split: the API layer is the canonical home for all logic. Commands handle only Typer argument parsing, error display, and exit codes. `core.py` is pure utility with no side effects.
13
+
14
+ ## Key modules
15
+
16
+ ### `src/okf/api.py` — programmatic API
17
+
18
+ Public functions and return types:
19
+
20
+ | Function | Returns | Key behavior |
21
+ | ---------------------------------------------- | ---------------- | ----------------------------------------------------------------------------- |
22
+ | `bundle(input_dir, output_dir, ...)` | `BundleResult` | Full bundle pipeline with link checking, `.okfignore`, `AGENTS.md` generation |
23
+ | `convert_file(input_file, output_file, type_)` | `BundleResult` | Convert single markdown file to OKF concept (timestamp from mtime) |
24
+ | `convert_content(content, output_file, type_)` | `BundleResult` | Convert raw markdown string to OKF concept (no timestamp) |
25
+ | `list_concepts(bundle_dir)` | `list[str]` | Conformance-gated concept ID listing |
26
+ | `show_concept(bundle_dir, concept_id)` | `ConceptContent` | Conformance-gated concept read with path traversal guard |
27
+ | `validate(bundle_dir)` | `ValidateResult` | Conformance check with `.ok` property |
28
+
29
+ Internal helpers (not public API): `_iter_links`, `_resolve_md_target`, `_load_okfignore`, `_generate_indexes`, `_write_concept`.
30
+
31
+ ### `src/okf/core.py` — shared utilities
32
+
33
+ - `RESERVED` — filenames `bundle` skips: `index.md`, `log.md`, `readme.md`.
34
+ - `SPEC_RESERVED` — spec-level reserved names: `index.md`, `log.md`, `agents.md`.
35
+ - `build_frontmatter(type_, title, description, timestamp)` — YAML frontmatter via JSON-escaped values.
36
+ - `parse_md(text)` — extracts title/description/body; strict first, lenient fallback.
37
+ - `parse_frontmatter(text)` — parses YAML frontmatter, returns `None` for invalid.
38
+ - `check_conformance(directory)` — validates OKF §9, returns `(errors, warnings)`.
39
+
40
+ ### Command wrappers (`src/okf/commands/`)
41
+
42
+ Each file imports from `okf.api` and calls the corresponding function, translating exceptions to Typer exit codes. No business logic.
43
+
44
+ ## Command execution flow
45
+
46
+ ### `okf bundle` (via `api.bundle()`)
47
+
48
+ 1. Read source directory + optional `.okfignore` (`_load_okfignore`).
49
+ 1. Walk `*.md`, skipping reserved names and ignored paths.
50
+ 1. Parse each markdown file via `parse_md` (strict first, lenient fallback).
51
+ 1. Scan markdown body links via `_iter_links` / `_resolve_md_target` — warns on missing or out-of-bundle targets; `--strict-links` makes these fatal.
52
+ 1. Build YAML frontmatter via `build_frontmatter`.
53
+ 1. Write transformed files and generate `index.md` per directory.
54
+ 1. Write `AGENTS.md` at output root with navigation guidance for the knowledge base.
55
+
56
+ ### `okf validate` (via `api.validate()`)
57
+
58
+ 1. Ensure target directory exists and has markdown files.
59
+ 1. Call `check_conformance` once.
60
+ 1. Return `ValidateResult` with file count, errors, and warnings.
61
+
62
+ ### `okf list` and `okf show` (via `api.list_concepts()` / `api.show_concept()`)
63
+
64
+ Both functions first run `check_conformance`. If directory is non-conformant, they raise `ValueError`.
65
+
66
+ Reason: reading APIs should not return misleading data from broken bundles.
67
+
68
+ ## Shared invariants
69
+
70
+ - Reserved name handling differs by phase:
71
+ - Bundling phase skips `index.md`, `log.md`, `README.md` (`RESERVED`).
72
+ - Spec-conformance phase reserves `index.md`, `log.md`, `agents.md` (`SPEC_RESERVED`). `agents.md` is reserved but skipped during conformance checks (not an error).
73
+ - Non-UTF-8 markdown is a conformance error.
74
+ - `type` frontmatter is required and must be non-empty for non-reserved concept files.
75
+
76
+ Source: `src/okf/core.py` (constants), `src/okf/api.py` (enforcement).
77
+
78
+ ## Evolution notes (from git history)
79
+
80
+ Major behavior shifts:
81
+
82
+ - project started bundling-focused, then added `validate`/`list`/`show` workflow;
83
+ - frontmatter parsing/conformance matured to real YAML parsing and shared conformance gating;
84
+ - markdown parsing in bundling became lenient to tolerate imperfect source docs;
85
+ - `.okfignore` added to allow selective exclusions without moving/deleting source files;
86
+ - single-file conversion (`convert_file`, `convert_content`) added for programmatic use without full directory bundling;
87
+ - `bundle()` internal logic refactored to use shared `_write_concept` helper.
88
+
89
+ Evidence: `git log -- src/okf/core.py`, `git log -- src/okf/commands/bundle.py`, top-level `git log --oneline`.
90
+
91
+ ## Extension points
92
+
93
+ - New API function: add to `src/okf/api.py` with typed return, add tests in `tests/test_api.py`.
94
+ - New command: add thin wrapper in `src/okf/commands/`, register in `src/okf/cli.py`, add CLI tests in `tests/test_cli.py`.
95
+ - New conformance rule: implement in `check_conformance` (`src/okf/core.py`) and update API/validate expectations.
96
+ - New metadata field support: no schema migration required; parser already tolerates extra YAML keys.
@@ -19,7 +19,7 @@ Markdown file with YAML frontmatter at top:
19
19
  - required for non-reserved files: `type` (non-empty string)
20
20
  - optional but common: `title`, `description`, `timestamp`, plus arbitrary producer-defined keys
21
21
 
22
- Implementation: `parse_frontmatter`, `check_conformance` in `src/okf/core.py`.
22
+ Implementation: `parse_frontmatter`, `check_conformance` in `src/okf/core.py`. API returns parsed data via `ConceptContent` dataclass.
23
23
 
24
24
  ### Concept ID
25
25
 
@@ -27,7 +27,15 @@ Bundle-relative path without `.md` suffix.
27
27
 
28
28
  - Example: `tables/orders.md` -> `tables/orders`.
29
29
 
30
- Implementation: `src/okf/commands/list.py`, `src/okf/commands/show.py`.
30
+ Implementation: `api.list_concepts()`, `api.show_concept()` in `src/okf/api.py`.
31
+
32
+ ### Result types (API)
33
+
34
+ `src/okf/api.py` defines typed return values:
35
+
36
+ - `BundleResult` — `files_written`, `output_dir`, `warnings`, `errors`
37
+ - `ValidateResult` — `total_files`, `errors`, `warnings`, `ok` (property)
38
+ - `ConceptContent` — `frontmatter` (dict), `body`, `raw`
31
39
 
32
40
  ### Reserved filenames
33
41
 
@@ -14,6 +14,7 @@ Packaging and runtime metadata: `pyproject.toml`.
14
14
  Key points:
15
15
 
16
16
  - CLI script entrypoint: `okf = "okf.cli:app"`
17
+ - Python API: `from okf.api import bundle, list_concepts, show_concept, validate`
17
18
  - Runtime deps: `typer`, `pyyaml`
18
19
  - Dev deps include `pytest`, `ruff`
19
20
 
@@ -3,11 +3,14 @@
3
3
  `okf-cli` converts plain markdown directories into Open Knowledge Format (OKF) bundles, then validates and reads those bundles.
4
4
 
5
5
  - CLI entrypoint: `src/okf/cli.py`
6
+ - Programmatic Python API: `src/okf/api.py`
6
7
  - Shared parsing/conformance logic: `src/okf/core.py`
7
- - Commands: `src/okf/commands/bundle.py`, `src/okf/commands/validate.py`, `src/okf/commands/list.py`, `src/okf/commands/show.py`
8
+ - Commands (thin wrappers): `src/okf/commands/bundle.py`, `src/okf/commands/validate.py`, `src/okf/commands/list.py`, `src/okf/commands/show.py`
8
9
 
9
10
  ## Start in 5 minutes
10
11
 
12
+ ### CLI
13
+
11
14
  ```bash
12
15
  uv sync
13
16
  uv run okf --help
@@ -18,6 +21,30 @@ uv run okf show example_knowledge_base tables/customers
18
21
  uv run okf bundle example --default-type reference --force --strict-links
19
22
  ```
20
23
 
24
+ ### Python API
25
+
26
+ ```python
27
+ from okf.api import (
28
+ bundle, convert_file, convert_content,
29
+ list_concepts, show_concept, validate,
30
+ )
31
+
32
+ # Full directory bundle
33
+ result = bundle("example", "out", default_type="reference", force=True)
34
+ assert result.errors == []
35
+
36
+ # Single-file conversions
37
+ convert_file("example/tables/orders.md", "out/tables/orders.md", type_="tables")
38
+ convert_content("# Title\n\n> Desc\n\nBody.", "out/single.md", type_="reference")
39
+
40
+ concepts = list_concepts("out")
41
+ concept = show_concept("out", "tables/customers")
42
+ print(concept.body)
43
+
44
+ report = validate("out")
45
+ assert report.ok
46
+ ```
47
+
21
48
  Why this sequence:
22
49
 
23
50
  1. `bundle` transforms raw markdown into OKF structure.
@@ -0,0 +1,75 @@
1
+ # Testing
2
+
3
+ ## Test suite map
4
+
5
+ - API unit/integration tests: `tests/test_api.py`
6
+ - `TestBundle` — bundling via `api.bundle()`, link checking, `.okfignore`, lenient parsing, `AGENTS.md` generation
7
+ - `TestListConcepts` — listing via `api.list_concepts()`, reserved file handling
8
+ - `TestShowConcept` — reading via `api.show_concept()`, path traversal guard
9
+ - `TestValidate` — conformance checks via `api.validate()`, all §9 rule variants
10
+ - `TestWorkflow` — cross-command pipeline (bundle → validate/list/show)
11
+ - Core unit tests: `tests/test_core.py`
12
+ - parsing helpers (`parse_md`, `parse_frontmatter`)
13
+ - frontmatter generation (`build_frontmatter`)
14
+ - conformance engine (`check_conformance`)
15
+ - CLI integration tests: `tests/test_cli.py`
16
+ - exit codes and error message formatting for all commands
17
+ - Typer-specific behavior (argument parsing, `--force`, `--strict-links`)
18
+
19
+ ## Run tests
20
+
21
+ ```bash
22
+ uv run pytest -q
23
+ ```
24
+
25
+ ## Change-oriented guidance
26
+
27
+ ### If editing `src/okf/api.py`
28
+
29
+ Run at minimum:
30
+
31
+ ```bash
32
+ uv run pytest -q tests/test_api.py tests/test_cli.py
33
+ ```
34
+
35
+ Reason: API functions are the business logic; CLI tests verify the wrapper layer.
36
+
37
+ ### If editing `src/okf/core.py`
38
+
39
+ Run at minimum:
40
+
41
+ ```bash
42
+ uv run pytest -q tests/test_core.py tests/test_api.py
43
+ ```
44
+
45
+ Reason: core helpers are used by the API layer.
46
+
47
+ ### If editing command wrappers (`src/okf/commands/*.py`)
48
+
49
+ Run at minimum:
50
+
51
+ ```bash
52
+ uv run pytest -q tests/test_cli.py
53
+ ```
54
+
55
+ Reason: commands are thin wrappers — CLI tests verify exit codes and error output.
56
+
57
+ ### If editing CLI registration (`src/okf/cli.py`)
58
+
59
+ Run full suite:
60
+
61
+ ```bash
62
+ uv run pytest -q
63
+ ```
64
+
65
+ ## Behaviors with dedicated regression coverage
66
+
67
+ - `.okfignore` parsing and skip semantics, including non-UTF-8 failure.
68
+ - Lenient parsing fallback when strict markdown format is missing.
69
+ - Reserved filename differences between bundling and spec conformance.
70
+ - Root `index.md` special allowance for `okf_version` only.
71
+ - `list`/`show` hard failure on non-conformant bundles.
72
+ - `show` path traversal guard.
73
+ - Link checking: `_resolve_md_target` path resolution, `--strict-links` fatal mode, missing/out-of-bundle targets.
74
+
75
+ Primary evidence: `tests/test_api.py`, `tests/test_core.py`, `tests/test_cli.py`.