okf-parser 0.1.0__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.
@@ -0,0 +1,111 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ci-${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ version-bump:
17
+ name: Version bump and changelog
18
+ if: github.event_name == 'pull_request'
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - name: Check out repository history
22
+ uses: actions/checkout@v4
23
+ with:
24
+ fetch-depth: 0
25
+
26
+ - name: Require a version bump and matching changelog
27
+ shell: bash
28
+ env:
29
+ BASE: ${{ github.base_ref }}
30
+ run: |
31
+ set -euo pipefail
32
+ read_version() {
33
+ sed -n 's/^version = "\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)"$/\1/p'
34
+ }
35
+
36
+ git fetch --quiet origin "$BASE"
37
+ head_version=$(read_version < pyproject.toml)
38
+ if git cat-file -e "origin/$BASE:pyproject.toml" 2>/dev/null; then
39
+ base_version=$(git show "origin/$BASE:pyproject.toml" | read_version)
40
+ else
41
+ base_version="0.0.0"
42
+ fi
43
+
44
+ if [[ -z "$head_version" ]]; then
45
+ echo "::error file=pyproject.toml::A versão SemVer não foi encontrada."
46
+ exit 1
47
+ fi
48
+ if [[ "$head_version" == "$base_version" ]]; then
49
+ echo "::error file=pyproject.toml::A versão continua $head_version; faça o bump."
50
+ exit 1
51
+ fi
52
+ highest=$(printf '%s\n%s\n' "$base_version" "$head_version" | sort -V | tail -1)
53
+ if [[ "$highest" != "$head_version" ]]; then
54
+ echo "::error file=pyproject.toml::A versão $head_version não supera $base_version."
55
+ exit 1
56
+ fi
57
+
58
+ expected_changelog="changelog/$head_version.md"
59
+ mapfile -t added_changelogs < <(
60
+ git diff --diff-filter=A --name-only "origin/$BASE...HEAD" -- "changelog/*.md"
61
+ )
62
+ if [[ "${#added_changelogs[@]}" -ne 1 ]]; then
63
+ echo "::error file=changelog::Cada PR deve adicionar exatamente um changelog."
64
+ printf 'Encontrado: %s\n' "${added_changelogs[@]}"
65
+ exit 1
66
+ fi
67
+ if [[ "${added_changelogs[0]}" != "$expected_changelog" ]]; then
68
+ echo "::error file=${added_changelogs[0]}::Esperado $expected_changelog."
69
+ exit 1
70
+ fi
71
+
72
+ echo "OK: $base_version -> $head_version; $expected_changelog presente."
73
+
74
+ quality:
75
+ runs-on: ubuntu-latest
76
+ steps:
77
+ - name: Check out repository
78
+ uses: actions/checkout@v4
79
+
80
+ - name: Install uv
81
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
82
+ with:
83
+ version: "0.11.21"
84
+ python-version: "3.12"
85
+
86
+ - name: Install locked dependencies
87
+ run: uv sync --frozen --all-groups
88
+
89
+ - name: Check lockfile
90
+ run: uv lock --check
91
+
92
+ - name: Check Python formatting
93
+ run: uv run ruff format --check .
94
+
95
+ - name: Lint Python
96
+ run: uv run ruff check .
97
+
98
+ - name: Check types
99
+ run: uv run ty check src tests
100
+
101
+ - name: Find dead code
102
+ run: uv run vulture src --min-confidence 90
103
+
104
+ - name: Run tests
105
+ run: uv run pytest
106
+
107
+ - name: Validate this repository with okf-parser
108
+ run: uv run okf-parser check .
109
+
110
+ - name: Build distributions
111
+ run: uv build
@@ -0,0 +1,53 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: Check out release
15
+ uses: actions/checkout@v4
16
+
17
+ - name: Install uv
18
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
19
+ with:
20
+ version: "0.11.21"
21
+ python-version: "3.12"
22
+
23
+ - name: Verify release version
24
+ shell: bash
25
+ run: test "v$(uv version --short)" = "$GITHUB_REF_NAME"
26
+
27
+ - name: Build distributions
28
+ run: uv build
29
+
30
+ - name: Upload distributions
31
+ uses: actions/upload-artifact@v4
32
+ with:
33
+ name: python-package-distributions
34
+ path: dist/
35
+ if-no-files-found: error
36
+
37
+ publish:
38
+ needs: build
39
+ runs-on: ubuntu-latest
40
+ environment:
41
+ name: pypi
42
+ url: https://pypi.org/project/okf-parser/
43
+ permissions:
44
+ id-token: write
45
+ steps:
46
+ - name: Download distributions
47
+ uses: actions/download-artifact@v4
48
+ with:
49
+ name: python-package-distributions
50
+ path: dist/
51
+
52
+ - name: Publish distributions with attestations
53
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,7 @@
1
+ .venv/
2
+ .pytest_cache/
3
+ .ruff_cache/
4
+ __pycache__/
5
+ *.py[cod]
6
+ dist/
7
+ build/
@@ -0,0 +1,165 @@
1
+ Metadata-Version: 2.4
2
+ Name: okf-parser
3
+ Version: 0.1.0
4
+ Summary: Relational inspection and validation for Open Knowledge Format bundles
5
+ Requires-Python: >=3.12
6
+ Requires-Dist: cyclopts<5,>=4.22
7
+ Requires-Dist: duckdb<2,>=1.4
8
+ Requires-Dist: fastmcp<4,>=3.4
9
+ Requires-Dist: ibis-framework[duckdb]<13,>=12
10
+ Requires-Dist: markdown-it-py<5,>=4
11
+ Requires-Dist: mdformat-frontmatter<3,>=2
12
+ Requires-Dist: mdformat-gfm<2,>=1
13
+ Requires-Dist: mdformat<2,>=1
14
+ Requires-Dist: networkx<4,>=3.4
15
+ Requires-Dist: pyyaml<7,>=6
16
+ Description-Content-Type: text/markdown
17
+
18
+ ---
19
+ type: Project
20
+ title: okf-parser
21
+ description: Relational inspection and validation for Open Knowledge Format bundles
22
+ ---
23
+
24
+ # okf-parser
25
+
26
+ Relational inspection and validation for
27
+ [Open Knowledge Format (OKF) v0.2](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
28
+ bundles.
29
+
30
+ `okf-parser` reads an OKF bundle without imposing a domain taxonomy, preserves
31
+ unknown frontmatter fields, and exposes concepts and links as
32
+ [Ibis](https://ibis-project.org/) tables. This makes bundle-wide rules—identity,
33
+ lineage, cardinality, provenance, and profile-specific constraints—expressible
34
+ as deterministic relational checks.
35
+
36
+ ## Why another OKF tool?
37
+
38
+ The ecosystem already has good static linters and generators, including
39
+ `okflint`, `okf-cli`, and `google-okf`. This project focuses on a different
40
+ layer:
41
+
42
+ - compile a bundle into queryable relational tables;
43
+ - project those same relations into a NetworkX graph;
44
+ - validate OKF v0.2 conformance without rejecting extensions;
45
+ - distinguish normative errors from advisory diagnostics;
46
+ - let projects add cross-concept rules as Ibis expressions;
47
+ - produce stable human-readable and JSON reports for CI and agents.
48
+
49
+ The parser and validation model are inspired by
50
+ [`franklinbaldo/sisprev`](https://github.com/franklinbaldo/sisprev): parse
51
+ documents independently from semantic validation, aggregate violations instead
52
+ of failing at the first bad concept, preserve authored bodies, and test
53
+ filesystem identity explicitly. No Sisprev-specific legal types are copied into
54
+ the core.
55
+
56
+ [`mrorigo/rust-okf`](https://github.com/mrorigo/rust-okf) inspired the stable
57
+ logical key, conservative metadata preservation, BOM/CRLF handling, and clean
58
+ separation between bundle parsing and downstream query surfaces. Its BM25,
59
+ vector index, storage format, and HTTP server are intentionally outside this
60
+ project's scope.
61
+
62
+ ## Quick start
63
+
64
+ ```bash
65
+ uv sync
66
+ uv run okf-parser check path/to/bundle
67
+ uv run okf-parser inventory path/to/bundle
68
+ uv run okf-parser graph path/to/bundle
69
+ uv run okf-parser format path/to/bundle
70
+ uv run okf-parser format path/to/bundle --write
71
+ uv run okf-parser duckdb path/to/bundle knowledge.duckdb
72
+ ```
73
+
74
+ The command exits with status `1` only when normative errors exist. Broken
75
+ cross-links are warnings because OKF v0.2 explicitly says they do not make a
76
+ bundle non-conformant.
77
+
78
+ ## GitHub Actions
79
+
80
+ Add the repository as a CI check:
81
+
82
+ ```yaml
83
+ steps:
84
+ - uses: actions/checkout@v4
85
+ - uses: franklinbaldo/okf-parser@v1
86
+ with:
87
+ path: knowledge
88
+ ```
89
+
90
+ The composite action installs a pinned uv version and executes the same
91
+ `validate_path()` function used by the Python API, CLI, and MCP server.
92
+
93
+ Releases are published to PyPI from GitHub Releases through OIDC Trusted
94
+ Publishing. No long-lived PyPI token is stored in the repository.
95
+
96
+ Every pull request must increase the SemVer version in `pyproject.toml` and add
97
+ exactly one matching `changelog/<version>.md` entry. CI compares both against
98
+ the target branch before allowing merge.
99
+
100
+ ## MCP
101
+
102
+ ```bash
103
+ uv run okf-parser serve
104
+ uv run okf-parser-mcp
105
+ uv run fastmcp run
106
+ ```
107
+
108
+ Read-only tools: `check`, `inventory`, `graph`, and `format_check`.
109
+
110
+ ## DuckDB
111
+
112
+ `okf-parser` is a regular uv-managed Python app; the DuckDB integration is part
113
+ of the same package, not a native C++ subproject:
114
+
115
+ ```python
116
+ import duckdb
117
+
118
+ from okf_parser.duckdb import attach_okf
119
+
120
+ connection = duckdb.connect("knowledge.duckdb")
121
+ attach_okf(connection, "knowledge/")
122
+
123
+ connection.sql("""
124
+ SELECT concept_type, count(*)
125
+ FROM okf.concepts
126
+ GROUP BY concept_type
127
+ """).show()
128
+ ```
129
+
130
+ The call creates `okf.concepts`, `okf.links`, `okf.reserved`, and
131
+ `okf.diagnostics` as ordinary DuckDB tables. Use a new database or schema for
132
+ each materialization.
133
+
134
+ ## Python API
135
+
136
+ ```python
137
+ from pathlib import Path
138
+
139
+ from okf_parser import load_bundle, validate_path
140
+
141
+ bundle = load_bundle(Path("knowledge"))
142
+ print(bundle.concepts.execute())
143
+ print(bundle.links.execute())
144
+ print(bundle.to_networkx())
145
+ print(bundle.validate())
146
+
147
+ report = validate_path(Path("knowledge"))
148
+ assert report.markdown_count == report.concept_count + report.reserved_count
149
+ assert report.is_conformant
150
+ ```
151
+
152
+ ## Current scope
153
+
154
+ - UTF-8 Markdown discovery;
155
+ - reserved `index.md` and `log.md` handling;
156
+ - strict YAML-frontmatter parsing for concept documents;
157
+ - required non-empty `type`;
158
+ - stable concept IDs derived from paths;
159
+ - Markdown-link extraction and resolution;
160
+ - Ibis tables for concepts, reserved documents, and links;
161
+ - NetworkX graph projection for traversal, cycles, components, and impact;
162
+ - aggregated validation reports.
163
+
164
+ Profiles, lifecycle/provenance family validation, external resources, and
165
+ pluggable Ibis rules are the next milestones.
@@ -0,0 +1,148 @@
1
+ ---
2
+ type: Project
3
+ title: okf-parser
4
+ description: Relational inspection and validation for Open Knowledge Format bundles
5
+ ---
6
+
7
+ # okf-parser
8
+
9
+ Relational inspection and validation for
10
+ [Open Knowledge Format (OKF) v0.2](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
11
+ bundles.
12
+
13
+ `okf-parser` reads an OKF bundle without imposing a domain taxonomy, preserves
14
+ unknown frontmatter fields, and exposes concepts and links as
15
+ [Ibis](https://ibis-project.org/) tables. This makes bundle-wide rules—identity,
16
+ lineage, cardinality, provenance, and profile-specific constraints—expressible
17
+ as deterministic relational checks.
18
+
19
+ ## Why another OKF tool?
20
+
21
+ The ecosystem already has good static linters and generators, including
22
+ `okflint`, `okf-cli`, and `google-okf`. This project focuses on a different
23
+ layer:
24
+
25
+ - compile a bundle into queryable relational tables;
26
+ - project those same relations into a NetworkX graph;
27
+ - validate OKF v0.2 conformance without rejecting extensions;
28
+ - distinguish normative errors from advisory diagnostics;
29
+ - let projects add cross-concept rules as Ibis expressions;
30
+ - produce stable human-readable and JSON reports for CI and agents.
31
+
32
+ The parser and validation model are inspired by
33
+ [`franklinbaldo/sisprev`](https://github.com/franklinbaldo/sisprev): parse
34
+ documents independently from semantic validation, aggregate violations instead
35
+ of failing at the first bad concept, preserve authored bodies, and test
36
+ filesystem identity explicitly. No Sisprev-specific legal types are copied into
37
+ the core.
38
+
39
+ [`mrorigo/rust-okf`](https://github.com/mrorigo/rust-okf) inspired the stable
40
+ logical key, conservative metadata preservation, BOM/CRLF handling, and clean
41
+ separation between bundle parsing and downstream query surfaces. Its BM25,
42
+ vector index, storage format, and HTTP server are intentionally outside this
43
+ project's scope.
44
+
45
+ ## Quick start
46
+
47
+ ```bash
48
+ uv sync
49
+ uv run okf-parser check path/to/bundle
50
+ uv run okf-parser inventory path/to/bundle
51
+ uv run okf-parser graph path/to/bundle
52
+ uv run okf-parser format path/to/bundle
53
+ uv run okf-parser format path/to/bundle --write
54
+ uv run okf-parser duckdb path/to/bundle knowledge.duckdb
55
+ ```
56
+
57
+ The command exits with status `1` only when normative errors exist. Broken
58
+ cross-links are warnings because OKF v0.2 explicitly says they do not make a
59
+ bundle non-conformant.
60
+
61
+ ## GitHub Actions
62
+
63
+ Add the repository as a CI check:
64
+
65
+ ```yaml
66
+ steps:
67
+ - uses: actions/checkout@v4
68
+ - uses: franklinbaldo/okf-parser@v1
69
+ with:
70
+ path: knowledge
71
+ ```
72
+
73
+ The composite action installs a pinned uv version and executes the same
74
+ `validate_path()` function used by the Python API, CLI, and MCP server.
75
+
76
+ Releases are published to PyPI from GitHub Releases through OIDC Trusted
77
+ Publishing. No long-lived PyPI token is stored in the repository.
78
+
79
+ Every pull request must increase the SemVer version in `pyproject.toml` and add
80
+ exactly one matching `changelog/<version>.md` entry. CI compares both against
81
+ the target branch before allowing merge.
82
+
83
+ ## MCP
84
+
85
+ ```bash
86
+ uv run okf-parser serve
87
+ uv run okf-parser-mcp
88
+ uv run fastmcp run
89
+ ```
90
+
91
+ Read-only tools: `check`, `inventory`, `graph`, and `format_check`.
92
+
93
+ ## DuckDB
94
+
95
+ `okf-parser` is a regular uv-managed Python app; the DuckDB integration is part
96
+ of the same package, not a native C++ subproject:
97
+
98
+ ```python
99
+ import duckdb
100
+
101
+ from okf_parser.duckdb import attach_okf
102
+
103
+ connection = duckdb.connect("knowledge.duckdb")
104
+ attach_okf(connection, "knowledge/")
105
+
106
+ connection.sql("""
107
+ SELECT concept_type, count(*)
108
+ FROM okf.concepts
109
+ GROUP BY concept_type
110
+ """).show()
111
+ ```
112
+
113
+ The call creates `okf.concepts`, `okf.links`, `okf.reserved`, and
114
+ `okf.diagnostics` as ordinary DuckDB tables. Use a new database or schema for
115
+ each materialization.
116
+
117
+ ## Python API
118
+
119
+ ```python
120
+ from pathlib import Path
121
+
122
+ from okf_parser import load_bundle, validate_path
123
+
124
+ bundle = load_bundle(Path("knowledge"))
125
+ print(bundle.concepts.execute())
126
+ print(bundle.links.execute())
127
+ print(bundle.to_networkx())
128
+ print(bundle.validate())
129
+
130
+ report = validate_path(Path("knowledge"))
131
+ assert report.markdown_count == report.concept_count + report.reserved_count
132
+ assert report.is_conformant
133
+ ```
134
+
135
+ ## Current scope
136
+
137
+ - UTF-8 Markdown discovery;
138
+ - reserved `index.md` and `log.md` handling;
139
+ - strict YAML-frontmatter parsing for concept documents;
140
+ - required non-empty `type`;
141
+ - stable concept IDs derived from paths;
142
+ - Markdown-link extraction and resolution;
143
+ - Ibis tables for concepts, reserved documents, and links;
144
+ - NetworkX graph projection for traversal, cycles, components, and impact;
145
+ - aggregated validation reports.
146
+
147
+ Profiles, lifecycle/provenance family validation, external resources, and
148
+ pluggable Ibis rules are the next milestones.
@@ -0,0 +1,20 @@
1
+ name: Validate OKF bundle
2
+ description: Validate every Markdown file below a path as Open Knowledge Format v0.2
3
+ inputs:
4
+ path:
5
+ description: Bundle directory to validate
6
+ required: false
7
+ default: .
8
+ runs:
9
+ using: composite
10
+ steps:
11
+ - name: Install uv
12
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
13
+ with:
14
+ version: "0.11.21"
15
+ - name: Validate OKF
16
+ shell: bash
17
+ env:
18
+ OKF_PATH: ${{ inputs.path }}
19
+ run: |
20
+ uv run --project "$GITHUB_ACTION_PATH" --frozen okf-parser check "$OKF_PATH"
@@ -0,0 +1,20 @@
1
+ ---
2
+ type: ChangelogEntry
3
+ title: okf-parser 0.1.0
4
+ description: Initial release of the relational OKF validation toolkit
5
+ ---
6
+
7
+ # okf-parser 0.1.0
8
+
9
+ - Validate complete OKF v0.2 bundles with aggregated diagnostics.
10
+ - Query concepts and links through Ibis and materialize them in DuckDB.
11
+ - Project bundle relationships into NetworkX graphs.
12
+ - Expose Cyclopts CLI commands and read-only FastMCP tools.
13
+ - Check or apply Markdown formatting with mdformat.
14
+ - Reuse validation through a composite GitHub Action.
15
+ - Publish signed PyPI releases through OIDC Trusted Publishing.
16
+ - Validate the repository with `okf-parser` itself in CI.
17
+ - Propose bidirectional code generation between OKF profiles and Python models.
18
+ - Reserve only normative `index.md` and `log.md` documents.
19
+ - Discover Markdown consistently without traversing environments or symlinks.
20
+ - Extract links through CommonMark tokens and use portable concept keys.
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://gofastmcp.com/public/schemas/fastmcp.json/v1.json",
3
+ "source": {
4
+ "type": "filesystem",
5
+ "path": "src/okf_parser/cli.py",
6
+ "entrypoint": "mcp"
7
+ },
8
+ "environment": {
9
+ "type": "uv",
10
+ "python": "3.12",
11
+ "project": "."
12
+ },
13
+ "deployment": {
14
+ "transport": "stdio",
15
+ "log_level": "INFO"
16
+ }
17
+ }
@@ -0,0 +1,55 @@
1
+ [project]
2
+ name = "okf-parser"
3
+ version = "0.1.0"
4
+ description = "Relational inspection and validation for Open Knowledge Format bundles"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "cyclopts>=4.22,<5",
9
+ "duckdb>=1.4,<2",
10
+ "fastmcp>=3.4,<4",
11
+ "ibis-framework[duckdb]>=12,<13",
12
+ "markdown-it-py>=4,<5",
13
+ "mdformat>=1,<2",
14
+ "mdformat-frontmatter>=2,<3",
15
+ "mdformat-gfm>=1,<2",
16
+ "networkx>=3.4,<4",
17
+ "pyyaml>=6,<7",
18
+ ]
19
+
20
+ [project.scripts]
21
+ okf-parser = "okf_parser.cli:main"
22
+ okf-parser-mcp = "okf_parser.cli:run_mcp_stdio"
23
+
24
+ [dependency-groups]
25
+ dev = [
26
+ "pytest>=8,<10",
27
+ "ruff>=0.15,<0.16",
28
+ "ty>=0.0.1a20,<0.1",
29
+ "vulture>=2.14,<3",
30
+ ]
31
+
32
+ [build-system]
33
+ requires = ["hatchling"]
34
+ build-backend = "hatchling.build"
35
+
36
+ [tool.pytest.ini_options]
37
+ testpaths = ["tests"]
38
+
39
+ [tool.ruff]
40
+ line-length = 100
41
+ target-version = "py312"
42
+
43
+ [tool.ruff.lint]
44
+ select = ["ALL"]
45
+ ignore = [
46
+ "COM812",
47
+ "ISC001",
48
+ ]
49
+
50
+ [tool.ruff.lint.per-file-ignores]
51
+ "src/okf_parser/cli.py" = ["T201"]
52
+ "tests/*" = ["D103", "PLR2004", "S101"]
53
+
54
+ [tool.ruff.lint.pydocstyle]
55
+ convention = "google"