Skip to content

Python reference

Generated from the installed lokf package. Every entry below is the real signature and docstring of the shipped code.

Load and represent LOKF knowledge bundles.

A bundle is a directory of markdown concept files (OKF layout). This module lifts it into Python objects and, via the published JSON-LD context, into an RDF graph:

import lokf
bundle = lokf.load_bundle("examples/acme-knowledge")
g = bundle.graph() # rdflib.Graph of the whole bundle

load_bundle(path: 'str | pathlib.Path') -> 'Bundle'

Section titled “load_bundle(path: 'str | pathlib.Path') -> 'Bundle'”

Load a bundle directory into a Bundle.

index.md/log.md are reserved (OKF §3) and not parsed as concepts; the root index.md frontmatter becomes Bundle.meta.

One concept document: frontmatter data (with body) plus its file.

A knowledge bundle: root index.md metadata plus its concepts.

Resolve a Concept ID or IRI to an absolute Concept IRI.

Bundle.iri(self, concept: 'Concept') -> 'str'

Section titled “Bundle.iri(self, concept: 'Concept') -> 'str'”

A concept’s IRI: explicit id or base_iri + Concept ID.

Bundle.by_iri(self) -> 'dict[str, Concept]'

Section titled “Bundle.by_iri(self) -> 'dict[str, Concept]'”

IRI -> Concept index (built once, cached).

Bundle.get(self, ref: 'str') -> 'Concept | None'

Section titled “Bundle.get(self, ref: 'str') -> 'Concept | None'”

Look up a concept by IRI, Concept ID, or bundle-relative path.

Each concept’s frontmatter with its IRI injected as id.

Bundle.to_jsonld(self, context: 'dict | None' = None) -> 'list[dict]'

Section titled “Bundle.to_jsonld(self, context: 'dict | None' = None) -> 'list[dict]'”

Each concept’s frontmatter as a JSON-LD document (context attached).

Bundle.graph(self, context: 'dict | None' = None)

Section titled “Bundle.graph(self, context: 'dict | None' = None)”

The whole bundle as one rdflib.Graph.

All concepts are parsed in a single pass (one @graph document) so the JSON-LD context is compiled once, not once per concept.

Programmatic access to the LOKF LinkML schema and its vocabulary.

The schema (lokf.yaml) and the published JSON-LD context are the single source of truth for LOKF’s types, typed-relation slots, and relation vocabulary. This module reads them so tools never hardcode the vocabulary.

Both files are resolved in this order: an explicit path argument, a walk up from the current directory for a repo checkout (so local edits always win), then the copies packaged under lokf/data/ (regenerated by lokf-build) so installed wheels work outside a checkout.

load_schema(path: 'str | pathlib.Path | None' = None) -> 'dict'

Section titled “load_schema(path: 'str | pathlib.Path | None' = None) -> 'dict'”

Return the LOKF LinkML schema as a plain dict (cached per file).

load_context(path: 'str | pathlib.Path | None' = None) -> 'dict'

Section titled “load_context(path: 'str | pathlib.Path | None' = None) -> 'dict'”

Return the published JSON-LD @context mapping (cached per file).

vocabulary(schema_path: 'str | pathlib.Path | None' = None) -> 'Vocabulary'

Section titled “vocabulary(schema_path: 'str | pathlib.Path | None' = None) -> 'Vocabulary'”

Load the schema and return its Vocabulary (cached per file).

One relationship predicate: a frontmatter name bound to an RDF IRI.

A JSON-serializable row (the lokf vocab --json / MCP shape).

The LOKF vocabulary derived from the LinkML schema.

Vocabulary.subclasses_of(self, ancestor: 'str') -> 'set[str]'

Section titled “Vocabulary.subclasses_of(self, ancestor: 'str') -> 'set[str]'”

Class names descending from ancestor (inclusive), via is_a.

Vocabulary.expand(self, curie: 'str') -> 'str'

Section titled “Vocabulary.expand(self, curie: 'str') -> 'str'”

Expand a prefix:local CURIE to a full IRI.

Vocabulary.compact(self, uri: 'str') -> 'str'

Section titled “Vocabulary.compact(self, uri: 'str') -> 'str'”

Compact a full IRI to a CURIE where a prefix matches.

Parse OKF/LOKF concept markdown into JSON-LD-ready dictionaries.

These helpers are the seed of the LOKF toolkit’s parser: parse_concept splits a concept file into frontmatter + body, and isoify normalizes YAML-parsed dates to the ISO-8601 Z form used by the committed RDF projections.

Recursively convert datetime/date values to ISO-8601 strings.

+00:00 offsets are normalized to Z so JSON/RDF output matches the committed examples/*.nt projections byte-for-byte.

Read one concept markdown file into a dict of frontmatter + body.

Raises ValueError with a clear message if the file has no --- delimited YAML frontmatter (e.g. a plain markdown or reserved file).

Convert LOKF markdown (a single concept or a whole bundle) to RDF.

This is the engine behind lokf convert. A concept file is lifted to JSON-LD via the published context and parsed with rdflib, so it serializes to any format rdflib supports.

from lokf import rdf
print(rdf.serialize("examples/acme-knowledge/metrics/weekly-active-users.md"))
print(rdf.serialize("examples/acme-knowledge", fmt="nt"))

docs_to_graph(docs: 'list[dict]', context: 'dict | None' = None)

Section titled “docs_to_graph(docs: 'list[dict]', context: 'dict | None' = None)”

Parse a list of concept docs into one rdflib.Graph.

The docs are wrapped in a single @graph JSON-LD document so the context is compiled once. This is the shared seam behind lokf.model.Bundle.graph and graph_of.

graph_of(source: 'str | pathlib.Path', context: 'dict | None' = None)

Section titled “graph_of(source: 'str | pathlib.Path', context: 'dict | None' = None)”

RDF graph for a concept file or a bundle directory.

A directory is projected as a whole bundle. A single .md file is resolved against its enclosing bundle when one exists (so id follows the bundle’s base_iri); a standalone file falls back to its explicit id or a file:// IRI derived from its path.

serialize(source: 'str | pathlib.Path', fmt: 'str' = 'ttl', context: 'dict | None' = None) -> 'str'

Section titled “serialize(source: 'str | pathlib.Path', fmt: 'str' = 'ttl', context: 'dict | None' = None) -> 'str'”

Serialize a concept file or bundle to RDF text in fmt (default Turtle).

A pyoxigraph-backed RDF store for querying a LOKF knowledge base.

Load a bundle (or any RDF graph) into an in-memory Oxigraph store and run SPARQL over it — the knowledge-retrieval layer of the toolkit.

from lokf.store import GraphStore
store = GraphStore.from_bundle("examples/acme-knowledge")
for row in store.select("SELECT ?s WHERE { ?s a lokf:Metric }"):
print(row["s"])

The SPARQL query form: ‘select’, ‘ask’, ‘construct’, or ‘describe’.

Leading comments and PREFIX/BASE lines are skipped. Defaults to ‘select’ when no form keyword is found. Shared by the CLI, server, and MCP so all three classify a query identically.

An in-memory SPARQL store over a LOKF knowledge base.

prefixes (the schema’s namespace table) are prepended to every query and update, so lokf:/schema:/prov: and friends work without a per-query PREFIX block.

GraphStore.query(self, sparql: 'str', **kw)

Section titled “GraphStore.query(self, sparql: 'str', **kw)”

Run a SPARQL query with the schema prefixes in scope.

Returns pyoxigraph’s native result: QuerySolutions (SELECT), QueryBoolean (ASK), or QueryTriples (CONSTRUCT/DESCRIBE).

Federated SERVICE queries are rejected: the engine would issue an outbound request to a query-controlled host, which is an SSRF vector for the local lokf serve endpoint. (LOAD/INSERT/DELETE are already rejected by pyoxigraph’s read-only query.)

GraphStore.select(self, sparql: 'str', **kw) -> 'list[dict]'

Section titled “GraphStore.select(self, sparql: 'str', **kw) -> 'list[dict]'”

Run a SELECT and return rows as {var: python value} dicts.

Every selected variable is a key in every row (None when unbound), so the column set is complete even when a variable is unbound in all rows; bound bindings are reduced to their lexical value.

GraphStore.ask(self, sparql: 'str', **kw) -> 'bool'

Section titled “GraphStore.ask(self, sparql: 'str', **kw) -> 'bool'”

Run an ASK query and return the boolean.

GraphStore.construct(self, sparql: 'str', fmt: 'str' = 'ttl', **kw) -> 'str'

Section titled “GraphStore.construct(self, sparql: 'str', fmt: 'str' = 'ttl', **kw) -> 'str'”

Run a CONSTRUCT/DESCRIBE and serialize the resulting graph.

GraphStore.serialize_results(self, sparql: 'str', fmt: 'str' = 'json', **kw) -> 'bytes'

Section titled “GraphStore.serialize_results(self, sparql: 'str', fmt: 'str' = 'json', **kw) -> 'bytes'”

Run a SELECT/ASK and serialize results in the SPARQL results format.

GraphStore.rdflib_graph(self, sparql: 'str | None' = None)

Section titled “GraphStore.rdflib_graph(self, sparql: 'str | None' = None)”

The store (or a CONSTRUCT/DESCRIBE result) as an rdflib.Graph.

With no query, the whole store is returned. This backs the live graph visualization, which projects the graph to cytoscape elements.

GraphStore.dump(self, fmt=<RdfFormat Turtle>) -> 'bytes'

Section titled “GraphStore.dump(self, fmt=<RdfFormat Turtle>) -> 'bytes'”

Serialize the whole store (default graph) as RDF text.

A local SPARQL endpoint + live graph visualization for a knowledge base.

lokf serve <bundle> loads the bundle into a ~lokf.store.GraphStore and publishes it over HTTP so agents (and people) can query and explore it locally — no external services, entirely offline:

  • GET|POST /sparql — the SPARQL 1.1 protocol. SELECT/ASK return application/sparql-results+json; CONSTRUCT/DESCRIBE return Turtle.
  • GET /graph.json — cytoscape.js elements for the whole graph.
  • GET / — an interactive cytoscape view with a live SPARQL box.

The server is stdlib-only (http.server); cytoscape.js ships in the package.

build_server(store: 'GraphStore', host: 'str' = '127.0.0.1', port: 'int' = 8000)

Section titled “build_server(store: 'GraphStore', host: 'str' = '127.0.0.1', port: 'int' = 8000)”

A ThreadingHTTPServer serving store (start/stop it yourself).

serve(source, host: 'str' = '127.0.0.1', port: 'int' = 8000) -> 'None'

Section titled “serve(source, host: 'str' = '127.0.0.1', port: 'int' = 8000) -> 'None'”

Load source and serve it until interrupted.

Propose typed relations from the markdown links in concept bodies.

Concept prose often links to other concepts without asserting the relationship in frontmatter. This module extracts those links (extract_links), classifies each one against a cue-phrase table (propose), and can write accepted proposals back into the source files’ frontmatter without disturbing formatting (apply).

Section titled “extract_links(concept: 'Concept', bundle: 'Bundle') -> 'list[Link]'”

Markdown prose links in concept.body (code blocks/spans excluded).

propose(bundle: 'Bundle', vocab: 'Vocabulary | None' = None, concept: 'Concept | None' = None) -> 'list[Proposal]'

Section titled “propose(bundle: 'Bundle', vocab: 'Vocabulary | None' = None, concept: 'Concept | None' = None) -> 'list[Proposal]'”

Propose relations for prose links not already asserted in frontmatter.

proposal_row(proposal: 'Proposal', applied_ids: 'set[int] | None' = None) -> 'dict'

Section titled “proposal_row(proposal: 'Proposal', applied_ids: 'set[int] | None' = None) -> 'dict'”

A JSON-serializable row for a proposal.

Shared wire shape for lokf propose --json and the MCP propose_relations tool. When applied_ids is given (apply mode), the row gains an applied flag; in dry-run mode it is omitted.

apply(proposals: 'list[Proposal]', min_confidence: 'float' = 0.0) -> 'list[Proposal]'

Section titled “apply(proposals: 'list[Proposal]', min_confidence: 'float' = 0.0) -> 'list[Proposal]'”

Write accepted proposals into source frontmatter; return those written.

Slot relations append the target IRI under the slot key; non-slot relations append {predicate, target} to relations. Files are edited with round-trip YAML so comments, key order, and quoting survive; duplicates are never written, and everything outside the frontmatter block (any preamble before the first --- and the whole body after the second) is preserved byte-for-byte.

One markdown prose link, resolved (where possible) to a bundle concept.

A proposed relation from source to link.target.

Graph and search projections of a bundle, derived without rdflib.

The knowledge-graph page and JSON-LD blocks in the docs are built in a CI environment that has neither rdflib nor the installed lokf package, so everything here is derived from concept frontmatter and the Vocabulary alone. to_cytoscape projects typed relations to edges (RDF predicates from typed relation slots and reified relations entries, never plain markdown body links); dataset_search_jsonld emits schema.org Dataset documents for Google Dataset Search.

to_cytoscape(bundle, vocab=None) -> 'dict'

Section titled “to_cytoscape(bundle, vocab=None) -> 'dict'”

Bundle as cytoscape.js elements (nodes + typed-relation edges).

Nodes are the bundle’s concepts; edges are RDF predicates drawn from each concept’s typed relation slots and reified relations entries, keeping only those whose target resolves to another concept in the bundle.

Named-slot edges match the concept-to-concept subset of Bundle.graph one-to-one and carry data.reified = False. Reified relations entries are flattened to direct labeled edges for display (in the RDF projection they remain reified statements, not direct concept-to-concept triples) and are marked data.reified = True. Non-dict relations entries are skipped; validation reports them.

graph_to_cytoscape(graph, vocab=None) -> 'dict'

Section titled “graph_to_cytoscape(graph, vocab=None) -> 'dict'”

Any rdflib.Graph as cytoscape.js elements.

Nodes are resources that carry an rdf:type in the graph (labelled by schema:name/rdfs:label when present, else the local IRI part); edges are triples whose predicate is a LOKF relation predicate and whose object is itself a node. This drives the live server’s visualization of a SPARQL CONSTRUCT result, mirroring to_cytoscape for a store.

dataset_search_jsonld(bundle, vocab=None) -> 'list[dict]'

Section titled “dataset_search_jsonld(bundle, vocab=None) -> 'list[dict]'”

schema.org Dataset JSON-LD docs for each Dataset/Table concept.

Shaped for Google Dataset Search; only keys with values are emitted, and bundle-relative references (url/isPartOf/hasPart) are resolved to absolute IRIs through Bundle.resolve.

Access and install the Claude Code agent skills bundled with LOKF.

The skills live under lokf/skills/<name>/SKILL.md, each a directory with a SKILL.md carrying YAML frontmatter (name/description) and a markdown body of instructions that drive the real lokf CLI. This module locates them (zip-safe, like lokf.schema), lists their frontmatter, and copies the tree into a project’s .claude/skills so an agent can use them.

Return the packaged skills directory (lokf/skills).

Return (name, description) from each skill’s SKILL.md frontmatter.

install(dest: 'str | pathlib.Path | None' = None) -> 'pathlib.Path'

Section titled “install(dest: 'str | pathlib.Path | None' = None) -> 'pathlib.Path'”

Copy the skills tree into dest (default .claude/skills); return it.

Parents are created and same-named skills are overwritten in place.

A FastMCP stdio server that exposes the LOKF toolkit to agents.

LOKF is a semantic profile of the Open Knowledge Framework: a knowledge base is a bundle of markdown concepts (frontmatter + prose) that projects to RDF and is queryable with SPARQL. The tools here let an agent list and inspect concepts, run SPARQL, convert markdown to RDF, propose typed relations from prose links, read the relation vocabulary, and summarize a bundle. Point tools at a bundle directory (e.g. examples/acme-knowledge) unless noted.

list_concepts(bundle: 'str') -> 'list[dict]'

Section titled “list_concepts(bundle: 'str') -> 'list[dict]'”

List every concept in a bundle as {concept_id, type, title, iri}.

bundle is a LOKF bundle directory. A fast index of what the knowledge base contains; use describe_concept for the full record of any one.

describe_concept(bundle: 'str', concept_id: 'str') -> 'dict'

Section titled “describe_concept(bundle: 'str', concept_id: 'str') -> 'dict'”

Describe one concept: {iri, type, title, body, frontmatter, turtle}.

concept_id is a bundle-relative id (e.g. metrics/weekly-active-users, with or without .md). turtle is the concept’s RDF projection. Returns {error: …} if no concept matches.

sparql_query(bundle: 'str', query: 'str') -> 'dict'

Section titled “sparql_query(bundle: 'str', query: 'str') -> 'dict'”

Run a SPARQL query over a bundle’s in-memory graph.

Schema prefixes (lokf/schema/prov/dcterms/skos/foaf/rdf/rdfs/owl/xsd/dcat) are preset, so queries need no PREFIX block. SELECT returns {columns: […], rows: [{…}]}; ASK returns {boolean: bool}; CONSTRUCT/DESCRIBE returns {turtle: ‘…’}. Returns {error: …} on a bad query.

convert(source: 'str', format: 'str' = 'ttl') -> 'dict'

Section titled “convert(source: 'str', format: 'str' = 'ttl') -> 'dict'”

Convert LOKF markdown to RDF: {format, rdf}.

source is a concept .md file or a bundle directory; format is one of ttl | nt | jsonld | xml | n3 | trig. Returns {error: …} for a bad format.

propose_relations(bundle: 'str', min_confidence: 'float' = 0.0, apply: 'bool' = False) -> 'list[dict]'

Section titled “propose_relations(bundle: 'str', min_confidence: 'float' = 0.0, apply: 'bool' = False) -> 'list[dict]'”

Propose typed relations from the markdown links in concept prose.

Each proposal is {source, link_text, target, predicate, curie, confidence, rationale}. Proposals below min_confidence are dropped. When apply is True the accepted proposals are written into the source files’ frontmatter and each carries an applied flag.

Return the LOKF vocabulary: {classes, relations}.

classes maps class name -> CURIE. relations is a list of {name, curie, uri, frontmatter_key, description}, where frontmatter_key is True when the relation can be asserted as a frontmatter slot (else it is used via a relations: entry).

Summarize a bundle for quick orientation.

Returns {concept_count, types, triple_count, relation_edge_count}: the number of concepts, a per-type count, the size of the RDF projection, and the number of typed-relation edges between concepts.

Run the LOKF MCP server over stdio.

Reproduce every generated LOKF artifact from the single source of truth (lokf.yaml), then assemble the reference bundle, validate it against the schema, and project it to RDF.

Run from anywhere inside the repository:

uv sync
uv run lokf-build # or: just build

Outputs (regenerated in place): lokf.context.jsonld JSON-LD context (+ type->@type, id->@id aliases) lokf.schema.json JSON Schema lokf.shacl.ttl SHACL shapes lokf.owl.ttl OWL ontology examples/acme-knowledge.bundle.json assembled bundle (git-ignored) examples/acme-knowledge.nt RDF triples for the whole bundle examples/weekly-active-users.nt RDF triples for one concept

Echo cmd, then run it with subprocess.run(..., check=True).

Run the four LinkML generators, then publish the authoring context.

Assemble all concept files (+ root index.md metadata) into one bundle.

Validate the assembled bundle against the schema’s KnowledgeBundle root.

to_rdf(root: 'pathlib.Path', bundle: 'dict') -> 'None'

Section titled “to_rdf(root: 'pathlib.Path', bundle: 'dict') -> 'None'”

Project the bundle (and its Metric concept) to N-Triples in examples/.

Entry point for the lokf-build console script.