logoxide
Bibles, commentaries, lexicons, books, and media as versioned packages. A package is a git
repository (or a registry's release archive) with a logoxide.toml and its text in one or more
formats; logoxide reads it, caches it, and tells
topos the translation's name, aliases, and verse
counts, so references like John 3:16 KJV are checked against that translation. lx is the
command line.
Quick start
logoxide.toml says which packages a vault uses and logoxide.lock pins their exact text; commit
or sync both with your notes. doc/workflow.md walks through a vault and a
package of your own, start to finish.
Licenses are shown, never enforced. lx search and lx show print each text's license as
its publisher states it, but logoxide installs and reads a text whatever it says. Before you
redistribute a text (in a shared vault, a registry, a mirror, or an app), check that you have the
right to: many translations are under copyright and allow only personal use.
What works
For someone with notes (a vault, an editor, Obsidian) who wants John 3:16 KJV to resolve, show
its text, and still point at the same words after the translation is re-edited:
- A vault:
lx initwrites alogoxide.toml(a manifest without[package]);lx import ebible:<id>,fetch:<id>,ccel:<id>, orsword:<repository>/<module>makes a publisher's download into a package kept in the shared library, andlx add github:owner/repoadds one published as a git repository.logoxide.lockpins each package's exact text (its commit or archive hash, and a checksum of every file), solx installon another device gets the same bytes or fails. Forks sit side by side (package =, their own abbreviation); a package can be turned off without removing it (enabled = false) - Finding texts:
lx searchlooks through your own catalogs and five publishers' lists by default: eBible.org's and fetch.bible's (about 2,900 translations), CCEL's Bibles and commentaries (ThML), and CrossWire's SWORD repository (Bibles, commentaries, and dictionaries, Strong's among them), grouped by the work each is an edition of. Catalogs are kept in the cache for a week (--refresh,--offline);lx import --updatebrings imports up to date - Reading:
lx read "John 3:16 KJV", andlx compare "Psalm 51:1" --bibles KJV,BSBwith each Bible in its own numbering through the vault's versification maps, saying what one lacks. Commentaries' notes on a passage (lx show --notes), a dictionary's entry (--entry G25), and a verse's cross-references (--xref); text or JSON - Links that survive updates: every release ships
logoxide.verses.bin, a hash of each verse's words, so a link made against one version (&ver=1.0.2&vh=9f86d081) finds its verse again after a renumbering and says when the words changed.lx diffandlx verifyread the same hashes - Formats read: USX, USFM, OSIS, ThML, GBF (a book a file, or a whole Bible in one);
dictionaries (
entries/*.xml) and cross-references (xref/*.tsv); books as EPUBs, with the references topos finds in them; Paratext.vrsversification maps (lx map "Psalm 51:1" --from English --to Original) - Front ends on the same code:
logoxide-lsp(hover, completion, references, and whole books in any editor;crates/logoxide-lsp/README.md),logoxide-mcp(an MCP server: catalogs, passages with their licenses, notes, entries; read-only unless--allow-writes;crates/logoxide-mcp/README.md),logoxide-ffi(npm and PyPIlogoxide, with topos's API in the same package; packages opened from bytes and installed without git, so WebAssembly and Obsidian too;crates/logoxide-ffi/README.md), and the Obsidian pluginobsidian-logoxide, whose Bibles live in its vault'sLogoxide/folder. All of them are argument parsing and display onlogoxide-app(crates/logoxide-app/README.md) - Licenses are shown with every text, never enforced: each package's SPDX license and rights as its publisher states them, and the MCP server attaches them to every passage
Also: publishing
For someone making or hosting packages. These work and are specified in doc/, but nobody hosts
one yet, so they're kept as they are until someone asks:
- Packages:
lx new(--from book.epubfills[package]from the file;--kind collectionfor a package of packages),lx release(writes the summary, checks the version against what changed since the last release: patch for notes and markup, minor for wording, additions, or titles, major for verses removed, renumbered, or joined; then commits and tags),lx check,lx show --git URL(a release's summary without its text) - Registries: each release as an archive listed with its SHA-256 in a
catalog.toml, so any static host or GitHub's releases serves thousands of books without a repository each:lx registry init,lx publish,lx yank,lx catalog build,lx add --registry; a folder of package repositories works as a registry too (lx catalog add <folder> --name <registry>) - Works (
work = "kjv"): editions of one work are grouped in search;lx workslists what logoxide's table and your catalogs name - Media: audio and video listed in
[media]by URL, size, and SHA-256, never stored; WebVTT timings per recording name where each verse is;lx media add,lx media check - Every command:
init,new,add,remove,enable,disable,install,update,list,show,check,release,diff,verify,info,clean,search,works,import,catalog,registry,publish,yank,media,map,read,compare, with completion (source <(COMPLETE=bash lx))
Specifications
For anyone writing another implementation, or publishing packages and catalogs by hand:
- doc/manifest.md:
logoxide.toml, every key, kinds, formats, features, dependencies,[media],[titles], categories, and what a package is made of - doc/catalog.md:
catalog.toml, registries,[[package.release]], how release archives are packed, and the checksum - doc/lock.md:
logoxide.lock - doc/summaries.md:
logoxide.summary.toml,logoxide.verses.bin(LXV2),logoxide.references.bin(LXR1), and how changes decide version numbers - doc/trust.md: what is checked, what is trusted on first use, and what isn't
Using it
The library is LOGOXIDE_HOME (else $XDG_DATA_HOME/logoxide), or --library DIR: any folder,
including inside a vault's .obsidian/ so it syncs. The cache is per device: LOGOXIDE_CACHE,
else $XDG_CACHE_HOME/logoxide. ~/.config/logoxide/config.toml can set both, and catalogs and
registries for every project. Catalogs downloaded over HTTP are kept in the cache for
catalog-max-age (7 days by default; "12h", "30m", or seconds; 0 keeps none): lx search --refresh or lx catalog refresh downloads them again, lx search --offline uses only what's
kept. Fetching git packages runs the git command; where it isn't
installed, lx reads repositories over HTTPS instead (their refs, and archives of commits).
A package
[]
= "kjv"
= "King James Version (1769)"
= "KJV"
= ["AV", "King James"]
= "1.0.0"
= "en"
= "LicenseRef-PublicDomain"
[]
= { = "usx/", = "usx" }
= { = "usfm/", = "usfm" }
[]
= ["usfm"]
= []
= []
Every key is in doc/manifest.md.
Install
Rust 1.89 or later. Until the crates are published, build from this repository with topos and sword-modules checked out beside it (see Development).
Development
cargo test, cargo clippy --all-targets -- -D warnings, cargo fmt. The bindings
(crates/logoxide-ffi) are a workspace of their own that builds against a topos checkout beside
this one (../topos): BoltFFI only exports the items of path dependencies, and they re-export
topos's API.
- Versions: the workspace's version, its
logoxide,logoxide-markup,logoxide-text,logoxide-import, andlogoxide-appdependencies', and logoxide-ffi's must be the same (scripts/check-versions.sh, run by CI, and by the release with its tag), now 0.1.0. - topos: the topos tag the bindings build against is
vand topos-bible's version inCargo.toml(scripts/topos-ref.sh); both workflows read it from there. - Unpublished dependencies: until topos 0.6 and sword-modules 0.1 are on crates.io, CI builds
against checkouts of them (
scripts/patch-unpublished.shwrites a[patch.crates-io]into an ignored.cargo/config.toml). sword-modules has no public repository yet, so CI needs theSWORD_MODULES_REPOrepository variable (a git URL it can clone) until it is published. - Releases:
cargo publish --workspacefor the crates. Pushing av*tag runs.github/workflows/release.yml: it checks the versions against the tag, runs the workspace's and the bindings' tests, builds the wheels and the npm package, installs a wheel in a fresh environment and imports it (crates/logoxide-ffi/scripts/smoke-test.py), runs the Node example against the npm package, and then publishes to PyPI and npm. - Third-party notices: the wheels and the npm package contain logoxide-ffi compiled with its
dependencies, so each carries a
THIRD-PARTY-NOTICESfile: every crate linked into it for that target, with its license and license files, fromcargo metadata(crates/logoxide-ffi/scripts/third-party-notices.py, run bynpm run pack:wasmandnpm run pack:python; the release checks the file is in both).
License: CC0-1.0