A Markdown knowledge graph for academic paper reading notes, with exporters back to LaTeX and BibTeX.
gloss maintains an Obsidian vault in which papers,
authors, institutions, venues and projects are linked notes. It resolves
metadata from a DOI, an arXiv identifier, a publisher URL or a title; keeps
the entity notes consistent as papers are added; and exports any subset of
the graph as a compilable LaTeX document or a .bib file for a paper draft.
gloss is deliberately two uncoupled things:
| The code | this directory. Shareable. Knows nothing about anyone's notes. |
| The vault | a directory of Markdown notes, elsewhere. Private. Readable without this tool. |
Nothing here hardcodes a vault path, and a test enforces that. The separation exists so the system can be given to someone else without handing over one's reading notes along with it. See ADR 0002.
$ uv sync
$ uv run gloss --version$ uv run gloss init ~/papers-vault --name "Your Name" --mailto you@example.edu
$ export GLOSS_VAULT=~/papers-vault
$ uv run gloss checkgloss finds the vault by, in order: the --vault flag, the $GLOSS_VAULT
environment variable, then the nearest ancestor directory containing a
.gloss/ directory.
Implemented:
| Command | Does |
|---|---|
gloss init |
Create a vault: directories, configuration, alias table. |
gloss new |
Resolve a work from a DOI, arXiv id, URL or title; confirm; write the note and its entity notes. |
gloss new --blank |
Same, for unpublished or unindexed work, entered by hand. |
gloss check |
Lint for duplicate citekeys, dangling wikilinks, filename/citekey mismatch, missing venue short names. |
gloss list |
List the papers matching a selection. |
gloss bib export |
Write a .bib for a selection, for a paper draft. |
gloss sync |
Create and refresh the author, institution, venue and project notes. |
gloss merge |
Merge two entity notes that name the same thing. |
gloss latex build |
Render a selection as a compilable LaTeX project. |
gloss migrate |
Import an existing LaTeX Chapters/ corpus and its papers.bib. |
gloss import |
Import legacy Markdown notes or a plain-text reading queue. |
All planned commands are built. The milestone sequence that produced them is in docs/DESIGN.md.
$ gloss new 10.1145/1294261.1294281 --project a project
title Dynamo: Amazon's Highly Available Key… [crossref]
authors Zhiyuan Jiang; Shuitao Gan; +7 more [openalex]
institutions* Amazon; Westmere University; +3 more [openalex]
venue Proceedings of the 21st Symposium… [crossref]
series CCS [crossref]
year 2022 [crossref]
citekey decandia:2007:dynamo [proposed]
accept / edit <field> / abort [accept]:Each field shows the source that supplied it, because no source is trustworthy for every field — see docs/RESOLUTION.md. Accepting writes the paper note plus any author, institution, venue and project notes it needs.
For work that is unpublished, embargoed, or simply not indexed yet:
$ gloss new --blank --title "..." --authors "Jane Roe; Richard Roe" \
--institutions "UC Berkeley; Anthropic" --year 2026Each author, institution, venue and project note carries a query listing the
papers that reference it, which the
Dataview plugin renders
as a live table. gloss init writes a vault README naming that dependency,
so an unrendered query is a documented requirement rather than a puzzle.
gloss sync maintains that region and nothing else — prose written around it
is never touched.
For a vault that must read without plugins, set entity_index = "list" under
[notes] in .gloss/config.toml. The papers are then written out as
Markdown lists; they can go stale after a hand-edit, and gloss check
reports that as stale-index.
One selection language, shared by list, bib export and latex build:
$ gloss list --project a project --status read
$ gloss list --institution CMU --year 2020-2025 --sort year
$ gloss bib export --project "another project" --with-references -o related.bibRepeated values within a dimension are OR; different dimensions are AND. So
--project A --project B --status read means papers you have read belonging
to either project, and a paper in both is returned once.
Matching is case-insensitive and follows aliases, so --institution CMU
finds papers linking [[Westmere University]].
$ gloss latex build builds/all.toml --compileProduces a complete LaTeX project — regenerated Macros/, a filtered
bibliography, \section{\syllabuscite{key}} headings — and a PDF. A link to
a paper outside the build degrades to a citation rather than a broken
reference, so any subset compiles.
| Document | Covers |
|---|---|
| docs/DESIGN.md | What the system is for and why it is shaped this way. |
| docs/MODULES.md | Every module's responsibility and permitted dependencies. |
| docs/RESOLUTION.md | Which metadata source is trusted for what, with the evidence. |
| docs/MIGRATION.md | Importing a LaTeX corpus, and what conversion preserves. |
| docs/LATEX.md | Build specifications, what is generated, and the round trip. |
| docs/IMPORT.md | Importing earlier notes and reading queues. |
| docs/SCHEMA.md | The vault data contract. Read this first if adopting the system. |
| docs/decisions/ | Architecture decision records, with their consequences. |
$ uv run pytest # unit suite
$ uv run pytest -m integration # tests that reach the network