-
Notifications
You must be signed in to change notification settings - Fork 282
feat(cli): export and validate OKF v0.2 bundles #1554
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
phernandez
wants to merge
29
commits into
main
Choose a base branch
from
feat/1550-okf-export
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
4215eaf
feat(cli): export and validate OKF v0.2 bundles
phernandez 286c68f
fix(cli): address OKF export compatibility review
phernandez 0fcf890
fix(cli): tighten OKF concept and entry boundaries
phernandez 64a0be9
fix(cli): preserve BM source frontmatter conventions
phernandez 73a1f83
fix(cli): narrow export history schema dependencies
phernandez 68cc8c9
fix(cli): preserve indented source fence content
phernandez a16b65f
fix(cli): resolve unique BM filename aliases in exports
phernandez 540b76e
fix(cli): reuse BM source frontmatter classification
phernandez 753ee70
fix(cli): normalize OKF export project references
phernandez 2072488
fix(cli): preserve export indentation and link policy
phernandez a53c548
fix(cli): preserve canonical title lookup and ambiguity
phernandez 9bb9fae
fix(cli): reuse Wiki ownership and canonical note types
phernandez a3765de
fix(cli): keep bare filename aliases project scoped
phernandez eb82d9f
fix(cli): preserve Markdown labels and literal OKF paths
phernandez 45b92be
fix(cli): resolve nested manual commands and scalar OKF aliases
phernandez 5c46f90
fix(cli): honor escaped OKF wikilink delimiters
phernandez 9bacc52
fix(cli): preserve OKF permalink resolution precedence
phernandez 961ff85
fix(cli): reject duplicate offline OKF permalinks
phernandez 5d2f07a
fix(cli): separate OKF title and path resolution
phernandez 1aee8d2
fix(cli): keep OKF filename fallback source-specific
phernandez ec0b373
fix(cli): preserve unresolved paths and deterministic YAML sets
phernandez d0b9b4c
fix(cli): honor explicit OKF project qualifiers
phernandez 4e38727
fix(cli): abort OKF export on incomplete file scans
phernandez d97b053
fix(cli): include generated OKF identities and reject stage collisions
phernandez 1bb4dc6
fix(cli): reject ambiguous source identity and network link rewrites
phernandez 111154e
fix(cli): guard export source identity and exact project selection
phernandez b71487e
test(cli): model case-insensitive existence on Python 3.14
phernandez c5dc3f5
fix(cli): honor strict ignore rules and resource title links
phernandez 0f4fc77
fix(cli): preserve external ID wikilinks during export
phernandez File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| """Export and check static OKF v0.2 directory bundles.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from pathlib import Path | ||
| from typing import TYPE_CHECKING | ||
|
|
||
| import typer | ||
|
|
||
| from basic_memory.cli.app import app | ||
|
|
||
| if TYPE_CHECKING: | ||
| from basic_memory.okf.validation import CheckReport | ||
|
|
||
| okf_app = typer.Typer(help="Export and check OKF v0.2-compatible directory bundles") | ||
| app.add_typer(okf_app, name="okf") | ||
|
|
||
|
|
||
| def print_report(report: CheckReport, json_output: bool) -> None: | ||
| if json_output: | ||
| typer.echo(report.model_dump_json()) | ||
| else: | ||
| typer.echo( | ||
| f"{'Valid' if report.success else 'Invalid'} OKF bundle: {report.concepts} concepts" | ||
| ) | ||
| for diagnostic in report.diagnostics: | ||
| typer.echo(f"{diagnostic.path}: {diagnostic.rule}: {diagnostic.message}") | ||
| if not report.success: | ||
| raise typer.Exit(1) | ||
|
|
||
|
|
||
| @okf_app.command("check") | ||
| def check( | ||
| bundle_path: Path = typer.Argument(..., help="Directory bundle to validate"), | ||
| json_output: bool = typer.Option(False, "--json", help="Output machine-readable diagnostics"), | ||
| ) -> None: | ||
| """Validate OKF v0.2 structural rules; exit nonzero on violations.""" | ||
| from basic_memory.okf.validation import check_bundle | ||
|
|
||
| print_report(check_bundle(bundle_path), json_output) | ||
|
|
||
|
|
||
| @okf_app.command("export") | ||
| def export( | ||
| destination: Path = typer.Argument(..., help="Destination outside the source project"), | ||
| project: str = typer.Option(..., "--project", "-p", help="Configured local project to export"), | ||
| replace: bool = typer.Option(False, "--replace", help="Replace an existing destination bundle"), | ||
| json_output: bool = typer.Option(False, "--json", help="Output machine-readable diagnostics"), | ||
| ) -> None: | ||
| """Stage, validate, and publish a static OKF v0.2-compatible bundle. | ||
|
|
||
| Preserves source files and non-Markdown assets. Links become standard Markdown; | ||
| BM semantics use the bm.okf_export extension. History is best-effort recorded history. | ||
| """ | ||
| from basic_memory.cli.commands.command_utils import run_with_cleanup | ||
| from basic_memory.cli.container import get_or_create_container | ||
| from basic_memory.db import maybe_install_uvloop | ||
| from basic_memory.okf.export import export_project | ||
| from basic_memory.okf.validation import CheckReport, Diagnostic | ||
|
|
||
| try: | ||
| config = get_or_create_container().config | ||
| # PostgreSQL needs the guarded policy before run_with_cleanup creates its loop. | ||
| maybe_install_uvloop(config) | ||
| report = run_with_cleanup(export_project(config, project, destination, replace=replace)) | ||
| except (ValueError, OSError, UnicodeError) as error: | ||
| report = CheckReport( | ||
| diagnostics=[Diagnostic(path=str(destination), rule="export", message=str(error))] | ||
| ) | ||
| print_report(report, json_output) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| --- | ||
| title: okf-check(1) | ||
| type: manpage | ||
| section: 1 | ||
| name: okf-check | ||
| summary: check OKF v0.2 structural conformance without a project database | ||
| generated: cli | ||
| --- | ||
|
|
||
| # okf-check(1) | ||
|
|
||
| ## NAME | ||
|
|
||
| **okf-check** — check OKF v0.2 structural conformance without a project database | ||
|
|
||
| ## SYNOPSIS | ||
|
|
||
| ``` | ||
| bm okf check BUNDLE_PATH [--json] | ||
| ``` | ||
|
|
||
| ## DESCRIPTION | ||
|
|
||
| Walk a directory bundle without Basic Memory configuration, indexing, or ignore | ||
| rules. Every non-reserved .md file must be UTF-8, have parseable YAML mapping | ||
| frontmatter, and carry a non-empty string `type`. Only root index.md may have | ||
| frontmatter, containing only `okf_version`. Index sections have headings and | ||
| entries use standard Markdown links. log.md has no frontmatter and groups | ||
| recorded entries under `## YYYY-MM-DD` headings, newest first. | ||
|
|
||
| Diagnostics identify the file, rule, and problem. Exit status is 0 for a valid | ||
| bundle and 1 for violations or unreadable files. JSON contains `concepts` and | ||
| `diagnostics`; reserved files and assets are not counted as concepts. | ||
|
|
||
| Unknown types, unknown keys, missing optional fields, broken cross-links, | ||
| missing indexes, and non-Markdown assets are accepted. Version declarations | ||
| are advisory. Symlinks are diagnosed as non-portable. This checks the structural | ||
| contract, not trust, attestation execution, or every optional field convention. | ||
|
|
||
| The contract follows OKF v0.2 §11: | ||
| https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/e6d34fd29c1c6c75ec23078e7a8191a9c8209620/okf/SPEC.md | ||
|
|
||
| ## OPTIONS | ||
|
|
||
| - **--json** — Output machine-readable diagnostics | ||
|
|
||
| ## EXAMPLES | ||
|
|
||
| ``` | ||
| bm okf check ~/exports/research | ||
| bm okf check ~/exports/research --json | ||
| ``` | ||
|
|
||
| ## SEE ALSO | ||
|
|
||
| - see_also [[okf-export(1)]] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| --- | ||
| title: okf-export(1) | ||
| type: manpage | ||
| section: 1 | ||
| name: okf-export | ||
| summary: export a local project as an OKF v0.2-compatible bundle | ||
| generated: cli | ||
| --- | ||
|
|
||
| # okf-export(1) | ||
|
|
||
| ## NAME | ||
|
|
||
| **okf-export** — export a local project as an OKF v0.2-compatible bundle | ||
|
|
||
| ## SYNOPSIS | ||
|
|
||
| ``` | ||
| bm okf export DESTINATION --project PROJECT [--replace] [--json] | ||
| ``` | ||
|
|
||
| ## DESCRIPTION | ||
|
|
||
| Export a configured local project to a static directory outside the project. | ||
| Source files remain unchanged. Cloud projects must first be pulled locally. | ||
| The export follows Basic Memory's project ignore rules; non-Markdown assets | ||
| such as PDFs retain their relative paths. Symlinks are not exported. | ||
| Concept filenames must use lowercase `.md`; supported BM alternatives such as | ||
| `.markdown` or `.MD` must be renamed before export so OKF readers cannot skip them. | ||
|
|
||
| Concept frontmatter is retained, with `type` using BM's canonical string value | ||
| and defaulting to `note` when absent or null. Absent `tags` default to an empty | ||
| list. Other metadata values are preserved. Wikilinks become standard Markdown links. | ||
| Exact file paths, titles, and permalinks resolve within the exported snapshot; | ||
| unresolved links remain broken links. Ambiguous aliases are not guessed. | ||
| Code examples retain literal wikilinks. | ||
|
|
||
| Generated index.md files contain standard links and only the root carries | ||
| `okf_version: "0.2"` frontmatter. The root log.md has no frontmatter and | ||
| records accepted Basic Memory journal history under ISO date headings. | ||
| File materialization may lag recorded acceptance; the log does not claim | ||
| every recorded version is represented by the exported files. | ||
| It does not reconstruct offline edits. Live Wiki bytes are not copied. | ||
| Unmarked files at reserved filenames must be renamed before export, even without | ||
| frontmatter; only recognized Wiki artifacts or marked OKF indexes are replaced. | ||
| Databases predating the accepted-change journal produce an empty history without | ||
| being migrated by export. | ||
|
|
||
| The destination is staged and checked before publication. Existing destinations | ||
| are refused unless `--replace` is explicit. A failed publication restores the | ||
| previous bundle; if restoration also fails, its bytes remain in a sibling | ||
| `.NAME.bm-okf-backup-*` directory. Source changes detected during export cause | ||
| failure. Export is intended for a quiescent project, not as a transaction over | ||
| concurrent filesystem edits. Unchanged project state produces identical bytes. | ||
|
|
||
| ## BM EXTENSION | ||
|
|
||
| The YAML `bm.okf_export` mapping has `version: 1` and `relations`, an ordered | ||
| list of original BM wikilink relations with `type`, `target`, and `context`. | ||
| This preserves typed edges and authored target spelling after links become | ||
| ordinary Markdown. Existing `bm` keys are preserved; an existing `okf_export` | ||
| key or non-mapping `bm` is a collision and fails export. | ||
|
|
||
| Categorized observations retain their human-readable `[category] content` | ||
| syntax, tags, context, and temporal qualifiers in the body. They are not copied | ||
| into a second metadata list. The extension declares this BM interpretation of | ||
| the body; generic OKF consumers can read it as ordinary Markdown. Relations | ||
| in metadata are authoritative for recovering BM edge types; ordinary Markdown | ||
| links alone only express untyped edges. This command does not add an importer | ||
| or switch Basic Memory's canonical syntax. | ||
|
|
||
| ## OPTIONS | ||
|
|
||
| - **-p, --project** — Configured local project to export | ||
| - **--replace** — Replace an existing destination bundle | ||
| - **--json** — Output machine-readable diagnostics | ||
|
|
||
| ## EXAMPLES | ||
|
|
||
| ``` | ||
| bm okf export ~/exports/research --project research | ||
| bm okf export ~/exports/research --project research --replace --json | ||
| bm okf check ~/exports/research | ||
| ``` | ||
|
|
||
| ## SEE ALSO | ||
|
|
||
| - see_also [[okf-check(1)]] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| """Static Open Knowledge Format export and filesystem conformance checks.""" |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.