Skip to main content

openakb-validate

openakb-validate is the pure Python reference validator library for the OpenAKB descriptor format, spec major v1. It is a library only: no CLI, no network access, no background services, and no storage, search, freshness, authentication, or transport mechanism.

The package validates caller-provided descriptor data and reports stable findings. It does not fetch referenced resources unless the caller supplies an explicit resolver. Source, issues, and the normative specification live in the openakb/spec repository.

Install

Install from the package index into Python 3.12 or newer:

python -m pip install openakb-validate

For repository development:

cd packages/python
uv sync

Validate a descriptor

Use validate for descriptor-only validation. The input is already-parsed JSON data; callers own file reading and output formatting.

import json
from pathlib import Path

from openakb_validate import ValidationResult, validate

descriptor = json.loads(Path("openakb.json").read_text(encoding="utf-8"))
result: ValidationResult = validate(descriptor)

if not result.ok:
    for finding in result.findings:
        print(f"{finding.code}: {finding.message}")

Each Finding has a stable code, RFC 6901 JSON Pointer path, and message. Its .name property derives the public finding name from the code catalog and, for a code outside the catalog, echoes the code back rather than raising. Advisory diagnostics use Advisory and appear in warnings; they never affect the validation verdict. The re-exported json_pointer helper builds the same canonical pointers the validator emits, for callers that construct or match against finding.path.

The stable validation codes for spec major v1 are AKB001 through AKB012, defined in spec §7, Validation and error codes. Those code meanings are part of the public contract for v1 and only change through the spec process.

Extract citations

Use extract_citations to read normative [cite:] markers from Markdown prose. The parser follows CommonMark structure, so markers in code and HTML constructs remain literal text. Each returned Citation contains source ids in written order, including duplicates.

from openakb_validate import Citation, extract_citations

citations: list[Citation] = extract_citations("See [cite: source_a, source_b].")
ids = [citation.ids for citation in citations]

Strict mode

Strict mode adds AKB006 unknown-core-property findings for unknown core members outside extension payloads:

import json
from pathlib import Path

from openakb_validate import validate

descriptor = json.loads(Path("openakb.json").read_text(encoding="utf-8"))
result = validate(descriptor, strict=True)
unknown_core_findings = [
    finding for finding in result.findings if finding.code == "AKB006"
]

Strict mode remains local and deterministic. It does not make network requests or freshness decisions. Advisory warnings describe MAY-warn surfaces and never affect result.ok.

Check content

Content checks are opt-in: check_content only fetches a descriptor's referenced resources through a resolver you supply, then verifies hashes, provenance sidecars, citation markers, and claim quotes. LocalFileResolver(base_dir=...) reads files under a caller-controlled directory.

import json
from pathlib import Path

from openakb_validate import ContentReport, LocalFileResolver, check_content

descriptor = json.loads(Path("openakb.json").read_text(encoding="utf-8"))
resolver = LocalFileResolver(base_dir="example-akb")
report: ContentReport = check_content(descriptor, resolver=resolver)

if report.failed:
    for check in report.failed:
        print(f"FAILED {check.kind} {check.path}: {check.detail}")
elif not report.verified:
    print("nothing verified: no content was fetched or there was nothing to check")
else:
    print(f"verified {len(report.verified)} content reference(s)")

for finding in report.findings:
    print(f"{finding.code}: {finding.message}")

Three outcomes, and why ok can be silent

Every content check reports one of three outcomes, exposed as the module constants VERIFIED, FAILED, and UNVERIFIABLE:

  • verified — the resource was fetched and matched: a hash matched, a quote was found in its capture, or citation markers resolved.
  • failed — the resource was fetched and did not match: a hash mismatch, an absent quote, or malformed fetched content. Tampering surfaces here.
  • unverifiable — the resource could not be fetched, or there was nothing to check it against. Nothing was proven either way; this is never an error.

report.ok is True when no check failed and no structural finding was raised. It is deliberately not "everything verified": a report in which every check is unverifiable — because nothing was fetched — is still ok. To tell "all good" from "nothing checked", read the outcome accessors, which mirror report.failed:

  • report.verified, report.failed, report.unverifiable collect the checks with each outcome.
  • report.findings carries only the structural findings raised inside content (for example, a citation marker that points at a missing source). A hash or quote mismatch is not a structural finding — it appears in report.failed. Consuming code that watches only report.findings will therefore miss a corrupted capture; key on report.failed (and report.ok) to catch tampering.

Filter checks by their kind using the exported constants rather than hard-coding strings: KIND_GUIDE_HASH, KIND_CONTENT_HASH, KIND_CITATIONS, KIND_SIDECAR, KIND_CAPTURE, and KIND_QUOTE.

import json
from pathlib import Path

from openakb_validate import KIND_CAPTURE, LocalFileResolver, check_content

descriptor = json.loads(Path("openakb.json").read_text(encoding="utf-8"))
report = check_content(descriptor, resolver=LocalFileResolver(base_dir="example-akb"))

capture_checks = [check for check in report.checks if check.kind == KIND_CAPTURE]

Resolvers

LocalFileResolver accepts a str or os.PathLike[str] base_dir and confines reads to files beneath it, rejecting absolute paths, .. traversal, queries, and path parameters before any read. That path policing is specific to LocalFileResolver.

Implement the Resolver protocol when content lives somewhere other than a local directory:

from openakb_validate import Resolver, Unfetchable


class MappingResolver(Resolver):
    """Resolve references from an in-memory mapping."""

    def __init__(self, files: dict[str, bytes]) -> None:
        self._files = files

    def fetch(self, uri: str) -> bytes:
        try:
            return self._files[uri]
        except KeyError as error:
            raise Unfetchable(uri) from error

check_content calls fetch(uri) with the effective reference: the descriptor reference (a content_uri, capture_uri, guide_uri, or provenance_uri) already joined onto the descriptor's base_uri when one is present, with any #fragment stripped. A resolver returns the resource bytes or raises Unfetchable; anything it cannot fetch becomes an unverifiable outcome, never an error. A custom resolver receives none of LocalFileResolver's path guards and owns its own safety.

Validate everything in one call

Use validate_with_content when a caller wants descriptor validation, strict-mode advisories, provenance checks, and content checks through one API.

import json
from pathlib import Path

from openakb_validate import FullReport, LocalFileResolver, validate_with_content

descriptor = json.loads(Path("openakb.json").read_text(encoding="utf-8"))
report: FullReport = validate_with_content(
    descriptor,
    resolver=LocalFileResolver(base_dir="example-akb"),
    strict=True,
)

if not report.ok:
    for finding in report.validation.findings:
        print(f"{finding.code}: {finding.message}")
    for check in report.content.failed:
        print(f"FAILED {check.kind} {check.path}: {check.detail}")

report.ok combines structural validity and content checks (validation.ok and content.ok), so it carries the same caveat: it does not require that anything was verified. This is still a pure library call — callers choose where data comes from, how findings are displayed, and whether any finding blocks their workflow.

Conformance

The package participates in the shared OpenAKB conformance suite for spec major v1. Conformance fixtures are the cross-language contract for validation behavior, including the stable AKB001 through AKB012 code mapping.

Package development emits and checks a conformance report with:

cd packages/python
uv run python tests/conformance_report.py > conformance-report.json
node ../../scripts/ci/check-conformance-report.mjs conformance-report.json

These commands are the package conformance/report gate used by CI and release checks.

Development and contributing

Use uv for package work:

cd packages/python
uv sync
uv run pytest
uv run ruff format --check .
uv run ruff check .
uv run mypy

The package vendors byte-identical copies of the published schemas from schema/v1/ so they are available through importlib.resources. Check drift from the repository root:

bash scripts/ci/check-schema-sync.sh

Follow the package conventions in AGENTS.md and the repository conventions in the root AGENTS.md, and see CONTRIBUTING.md for the contribution process. Public artifacts must remain vendor-neutral.

License

Apache-2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openakb_validate-0.2.0.tar.gz (56.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openakb_validate-0.2.0-py3-none-any.whl (38.7 kB view details)

Uploaded Python 3

File details

Details for the file openakb_validate-0.2.0.tar.gz.

File metadata

  • Download URL: openakb_validate-0.2.0.tar.gz
  • Upload date:
  • Size: 56.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for openakb_validate-0.2.0.tar.gz
Algorithm Hash digest
SHA256 60d825a845d9c5909a898cd0253b65135f8e957512fc0ad4e7b3ffb735a31261
MD5 4d3bd0a1efb49a26ff0d741b7dc2e705
BLAKE2b-256 c8c529cba1d5e31c8ac8695257dad5f3d0d3a669fe870dd85a005bda2711e25b

See more details on using hashes here.

Provenance

The following attestation bundles were made for openakb_validate-0.2.0.tar.gz:

Publisher: publish-python.yml on openakb/spec

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file openakb_validate-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for openakb_validate-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c88b8769d851d016ac8cfc26cdf2ffb1946c50815ada0ca22636091a2e2bf254
MD5 3373233603c1c982fc890ffa9b896c5e
BLAKE2b-256 5e8fafb2bd8e030e8d0e810bbfc2ee298bb1112b8e7ca4cc787fbfa372392425

See more details on using hashes here.

Provenance

The following attestation bundles were made for openakb_validate-0.2.0-py3-none-any.whl:

Publisher: publish-python.yml on openakb/spec

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.3.0

2 files

This release

0.2.0 This release

2 files

0.1.2

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page