OxiVault
Vault-LD knowledge graph store on object storage.
oxivault converts Obsidian-style Markdown vaults to and from RDF using in-process Vault-LD reference algorithms and RDFLib. It supports local files, in-memory stores, Git repositories, and S3-compatible object storage, with CLI, Python, and HTTP API interfaces.
Upstream specification and reference credit
OxiVault builds on the original Vault-LD work from The Knowledge Graph Guys:
- Specification: Vault-LD SPEC.md
- Reference implementation:
This project adapts those reference conversion algorithms for in-process library use under src/oxivault/_reference/vault_ld/.
Features
- Vault ↔ RDF conversion
vault2rdf: export vault content toschema.ttlanddata.ttlrdf2vault: ingest RDF into Markdown notes with frontmatter
- Graph access and querying
- Canonical triples table via
Vault.triples()(Polars DataFrame) - SPARQL querying via
Vault.query()andoxivault query - Graph exploration via
neighbors(),backlinks(),search(),search_body()
- Canonical triples table via
- Note CRUD with optimistic concurrency
get_note(),put_note(),delete_note(),list_notes(),exists_note()
- ObjectStore backends
LocalDirStore,MemoryStore,S3Store,GitStore
- Sync engine
- Two-way sync between local vaults and S3-compatible storage (
oxivault sync)
- Two-way sync between local vaults and S3-compatible storage (
- HTTP API server (FastAPI)
- Endpoints for notes, graph querying, search, and reindexing
Requirements
- Python 3.14+
- For S3 sync/backends: credentials configured for your AWS or S3-compatible provider (through boto3/client configuration)
Installation
pip install oxivault
With uv:
uv add oxivault
CLI quick start
Export a vault to RDF:
oxivault vault2rdf ./my-vault --out-dir ./dist --source
Ingest RDF into a vault:
oxivault rdf2vault ./my-vault ./graph.ttl
Run a SPARQL query:
oxivault query ./my-vault "SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10"
Sync local vault with S3:
oxivault sync ./my-vault --bucket my-s3-vault --direction both
Start the HTTP API server:
oxivault serve ./my-vault --host 127.0.0.1 --port 8000
Python quick start
from oxivault.models import RdfDocument
from oxivault.store.memory import MemoryStore
from oxivault.vault import Vault
store = MemoryStore()
vault = Vault(store)
rdf = b"""@prefix ex: <https://example.org/> .
@prefix data: <https://example.org/data/> .
data:item1 a ex:Thing .
"""
vault.rdf2vault([RdfDocument(content=rdf, format="turtle")])
triples = vault.triples()
print(triples.select(["subject", "predicate", "object"]))
HTTP API
Run:
oxivault serve ./my-vault --port 8000
Then use:
GET /vaultGET /notesGET /notes/{path}PUT /notes/{path}DELETE /notes/{path}POST /graph/sparqlGET /graph/edges?subject=...GET /graph/issuesGET /search?q=...POST /reindex
Interactive docs are available at /docs.
API auth, CORS, presigned URLs, and publication helper
The FastAPI app now supports OAuth2 bearer tokens and session-cookie authentication with two roles.
Use read for audience and published-content access and editor for librarian write operations.
Read-only SPARQL filtering remains in place as defense-in-depth behind authentication and authorization.
CORS uses an explicit allow-list of front-end origins.
Presigned URLs support browser-direct uploads and temporary private downloads.
The publication helper updates note publication metadata and can optionally perform verified copy-based publication to a public bucket or prefix.
Authentication is opt-in for backward compatibility, so set auth_enabled=True in ApiServerConfig to enforce auth.
Example app wiring:
from oxivault.server import ApiServerConfig, create_app
app = create_app(
vault,
config=ApiServerConfig(
auth_enabled=True,
read_tokens={"read-token"},
editor_tokens={"editor-token"},
users={
"audience": {"password": "audience-password", "role": "read"},
"librarian": {"password": "librarian-password", "role": "editor"},
},
cors_allowed_origins=["https://app.nalandabodhi.org"],
),
)
Additional endpoints:
POST /auth/tokenPOST /auth/session/loginPOST /auth/session/logoutPOST /objects/presign-putPOST /objects/presign-getPOST /publication/notes/{path}
Conversion behavior and constraints
- Not all RDF graphs are representable as vault notes. Check reported conversion issues when ingesting/exporting.
- CLI RDF ingest accepts
.ttl(Turtle) and.nt(N-Triples) files. Vault.vault2rdf()andoxivault vault2rdfdefault to query-oriented export. Usesource=True(Python) or--source(CLI) to include placement metadata for roundtrip location fidelity.Vault.rdf2vault([])is invalid (empty sequence). Passing a non-empty sequence with an empty RDF document is valid.
Examples
Runnable examples are in examples/:
examples/local_store_demo.pyexamples/roundtrip_demo.pyexamples/graph_query_demo.pyexamples/server_and_backends_demo.py
Run an example:
uv run python examples/roundtrip_demo.py
Development
uv sync --group dev
tara check
Release and PyPI publishing
Publishing is automated with GitHub tags through .github/workflows/publish.yml.
Create and push an annotated SemVer tag to publish, for example:
git tag -a v0.1.0 -m "Release 0.1.0"
git push origin v0.1.0
The publish workflow builds source and wheel distributions and uploads them to PyPI with GitHub OIDC trusted publishing.
Configure a PyPI trusted publisher for dkapitan/oxivault that points to workflow publish.yml and environment pypi.
License
Licensed under the Apache License 2.0. See LICENSE.
Project links
- Source: https://github.com/dkapitan/oxivault
- Issue tracker: https://github.com/dkapitan/oxivault/issues
- Changelog: CHANGELOG.md
Metadata
Release files for oxivault 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| oxivault-0.2.1.tar.gz | 46.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| oxivault-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 103.6 kB
Release files / oxivault-0.2.1.tar.gz
| Download URL | oxivault-0.2.1.tar.gz |
|---|---|
| Size | 46.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f710f6157fc2e4f6fa57c6b76d6283407d520d69addcec4a34df8e07afefa91b
|
|
BLAKE2b-256 checksum How to use checksums |
89683aeda3475e15fcb887eb65d628260a8b9a13cf66c6e8e592491a45e320fa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency logRelease files / oxivault-0.2.1-py3-none-any.whl
| Download URL | oxivault-0.2.1-py3-none-any.whl |
|---|---|
| Size | 56.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1edd2b16a69bfd7bf59799f6d6f1ca42f2ce0f605d090dfd6f0f3771180bc844
|
|
BLAKE2b-256 checksum How to use checksums |
d7adb5df04218fbb09cbb444a7d32236f915f731b05d776f16cc70be405a67f2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency log