Skip to content

Python API

The supported entry point is intentionally small.

from citekeep import Citekeep

app = Citekeep.open("~/bibliography/master.bib")
results = app.search("adaptive estimation", project_bib="refs.bib")
plan = app.plan_project(".")
app.apply(plan)

Parsing, fingerprint indexes and lossless text patches are implementation modules rather than a compatibility promise. What follows is.

citekeep.app.Citekeep

Configured access to one canonical BibTeX library.

open classmethod

open(library)

Open the canonical library at library, expanding ~.

Nothing is read here. Every method reads the file afresh, so an edit made in a text editor between two calls is seen.

master_records

master_records()

The records the library holds, in the order they appear in it.

search

search(query, project_bib=None)

Search the project and the library, without touching the network.

Parameters:

Name Type Description Default
query str

words matched against title, authors, journal, citation key, DOI and arXiv identifier. Every word must appear.

required
project_bib str | Path | None

a project bibliography to search as well.

None

Returns:

Type Description
SearchResults

Project hits first, since their keys are the ones valid in that

SearchResults

document; library hits omit works the project already holds, so

SearchResults

that nothing is offered twice.

search_online

search_online(
    query, limit=10, source_modules=sources.DEFAULT
)

Search the online sources, zbMATH first.

Parameters:

Name Type Description Default
query str

a DOI, an arXiv identifier, or free text.

required
limit int

how many results to ask the source for.

10
source_modules tuple

the sources to try, in order.

DEFAULT

Returns:

Type Description
str

The source that answered, and the records it returned. A source

tuple[Record, ...]

with nothing to say is passed over rather than reported as a

tuple[str, tuple[Record, ...]]

failure.

verify

verify(record, source_modules=sources.DEFAULT)

Ask every source about record, and report what they answer.

Nothing is written: the caller arbitrates. One service failing does not hide the evidence of the others.

plan_refresh

plan_refresh(
    record, candidate, mode="complete", fields=None
)

Plan an update of record from one verified candidate.

Parameters:

Name Type Description Default
record Record

the record as currently held.

required
candidate SourceCandidate

a candidate returned by verify.

required
mode str

complete fills only the empty fields, selected takes the fields named in fields, replace takes the bibliographic metadata whole.

'complete'
fields list[str] | None

the fields to take, when mode is selected.

None

Raises:

Type Description
ValueError

the candidate identity is not trusted, or the mode is unknown.

The local citation key and every project-only field survive all three modes; the plan is not applied here.

plan_materialize

plan_materialize(master_key, project_bib)

Plan copying one library record into a project bibliography.

Raises:

Type Description
KeyError

no record in the library carries master_key.

plan_project

plan_project(
    root,
    project_bib=None,
    field_resolutions=None,
    identity_resolutions=None,
)

Plan one complete synchronisation of the project under root.

Reads the \cite commands in the project's TeX files and pairs them with the library both ways: records the document needs are copied down, records only the project holds are offered up.

Parameters:

Name Type Description Default
root str | Path

the project directory.

required
project_bib str | Path | None

its bibliography, when the document declares none or declares several.

None
field_resolutions dict | None

decisions on fields where a reviewed local value contradicts the library.

None
identity_resolutions dict | None

decisions on records whose identity the evidence does not settle.

None

Raises:

Type Description
ValueError

no bibliography is declared, several are, or the one given is the library itself.

The plan records a digest of both files, so that apply can refuse to act on a file that has changed since. Nothing is written here.

apply

apply(plan)

Write a plan to disk, atomically.

Raises:

Type Description
ValueError

the plan carries unresolved conflicts, or was not built against files.

ConcurrentModification

the library or the project bibliography changed since the plan was made.

Returns:

Type Description
ProjectPlan

The plan that was applied.

The editor protocol

The citekeep editor … command namespace is an implementation protocol for editor extensions, not a second everyday CLI. It carries the small stdin/JSON operations needed to materialise, add or refresh one record after an interactive choice has been made — the choosing itself belongs to the editor.

Its JSON carries a schema_version. An extension should refuse to run against a version it does not know, rather than misread the output; citekeep.el does exactly that.

Building an extension for another editor

There is no VS Code or Neovim extension today, and the API above is what one would be built on. The shape that works, as learned from the Emacs one:

  1. call search with what the user typed, and show project hits before library hits;
  2. offer an explicit online action rather than searching the network implicitly;
  3. call plan_materialize when a library record is chosen, and insert the key the plan reports — not the library's key, which may differ from the project's;
  4. never write while the user has unsaved changes in the buffer you are about to touch.