Skip to main content

astrobib

A terminal-based literature manager for astrophysics research

PyPI License: MIT

astrobib connects to the NASA/Harvard ADS to search, fetch, and organize papers as plain BibTeX files, with a fast terminal UI. It ships as a single native binary: instant startup, instant quit, no runtime dependencies.

Your library is just a directory of .bib files, indistinguishable from hand-written BibTeX, and cite keys derive from each paper's stable identity (arXiv ID or bibcode) — so any two copies of a paper, fetched by anyone at any time, agree on the key forever. Libraries from all earlier astrobib versions work unchanged.


Installation

uv tool install astrobib     # or: pipx install astrobib

Binary wheels cover macOS (arm64, x86_64) and Linux (x86_64, aarch64). Building from source needs a Rust toolchain: cargo install --git https://github.com/clemson-cal/astrobib.


Quick start

# set your ADS token (https://ui.adsabs.harvard.edu/user/settings/token)
export ADS_API_TOKEN=...

astrobib                     # launch the TUI
astrobib list                # CLI: newest papers
astrobib search '^andersson OR kw:"compact objects"'
astrobib add 2020ApJ...123..456Z
astrobib import refs.bib     # resolve a foreign .bib against ADS

The two-tier library model

astrobib always works on up to two libraries: a local bib directory (tier 2) and your global personal library (tier 1, at ~/.local/share/astrobib/library/). astrobib [LIBRARY_DIR] points tier 2 at any directory holding bib/; with no argument, the nearest ancestor of the current directory with a bib/ is used. A .tex or .md manuscript alongside activates citation tracking, but any bib directory works. With the global tier enabled (the default), reads merge both tiers and imports write to both — the paper repo stands alone for coauthors while your collection accrues. Press t (or click the global badge) to hide the global tier: reads and writes become purely local. Removing a local paper never destroys a sole copy — it is rescued into the global library. Both stores are plain bib/*.bib files, one paper per file, indistinguishable from hand-written BibTeX. Nothing else is ever written into your repos.


TUI overview

Scope capsules at the top switch between your library, saved ADS query tabs, and the manuscript view. A query's tab appears the moment it is sent — an ADS query can take a minute — and the page says what it is waiting for, then how it ended: results, nothing found, or why it failed. Each keeps its own sort, and remembers it. An optional one-cell colour swatch column shows a metric — your own decaying priority, or ADS citation counts; switch it on from the table panel (|), like any other column. The pub card on the right shows the highlighted paper (hover the citekey column to preview others); an event log and clickable view badges sit at the bottom. Most things are clickable; every action has a key (? shows the cheat-sheet).

Keys

  • / — live filter (query language below); S — new ADS query (/ sets the result count, ⌃r what ADS returns — both also clickable; pasting a DOI or ADS URL imports directly)
  • j k g G — move; [ ] — switch scope (] past the last one composes a new query); ctrl+w — close query scope; r — refresh; + - — result count
  • Space — select row (iOS-style selection mode); a — select visible; A — select all; Esc — done
  • i — import ADS result(s); m — toggle manuscript/local membership; — remove (with confirmation)
  • p — download PDFs (ADS open-access, then arXiv); B — browser download (watches ~/Downloads); o — open PDF; X — clear PDF; double-click a row — open its PDF
  • y — copy chord: yy cite key, yY full key, yb bibcode, ya/yx/yd ADS/arXiv/DOI URL, yp PDF path, yt title, yA abstract; card title/abstract/key are click-to-copy
  • y q — copy the active query's whole configuration: its text, its result count and what ADS returns, as an ADS search URL. P — open the query configuration on the clipboard (it says so if the clipboard holds something else). Both round-trip, so a query pasted to a colleague arrives as the query you sent
  • In any prompt: ⌃k / ⌃u / ⌃w kill to end of line, to start of line, and the previous word, and ⌃y yanks the last of them back; ⌥w copies what you are composing (from a query, the same URL as y q)
  • E — edit the active query in place (text, result count and what ADS returns); S always composes a new one
  • N — name the active query (the capsule label; persists across edits to the query, empty restores the derived name)
  • C / R — open a citations / references query for the shown paper; v — pub view (the raw .bib); e — export the selection to a .bib file
  • M — pick the metric the swatch column shows (priority or citations, distinct colormaps; show the column itself from |); . — priority 1.0, 0 — clear, < > — scale it (decays weekly); the wheel over a swatch does the same for that row
  • | — table panel: show/hide columns, / to resize, s to sort by any of them (shown or not); Tab swaps the arrow keys between the panel and the table, Esc hands them back
  • t — show/hide the global tier; D — pub card; L — event log; ? — keys; @ — about; q — quit

The side panels, the pub card and the footer are separated from the table by a faint tint rather than by border lines, and the tint is chosen from your terminal's own background: darker than it on a light theme, lighter on a dark one. astrobib asks the terminal at startup (OSC 11) and falls back to dark for terminals that do not answer — set ASTROBIB_THEME=light or dark to decide it yourself.


Filtering the library

Press / to filter as you type. Whitespace-separated terms AND together; each term is a case-insensitive partial match. Bare terms match author, title, abstract, key, keywords, and year; field prefixes narrow:

author:cabrera         author anywhere in the list
^andersson             first-author papers (= author:^andersson)
title:magnetar         word in title
abs:"fast radio burst" phrase in abstract
kw:"compact objects"   keyword
year:2015-2020         ranges; year:2020- open-ended
is:ms                  local/manuscript members;  is:pdf  cached PDFs
pri:>0.5  cit:>100    metric comparisons (> < or bare for ≥); no metric never matches
-abs:neutrino          leading - negates (NOT works too)
^andersson OR ^baxter  uppercase OR separates alternatives; AND binds tighter

Long queries wrap across as many rows as they need rather than scrolling out of sight; the text stays one line, and ⏎ still runs it. A half-typed query never errors. With a filter active, S pre-fills the equivalent ADS query — filter locally, escalate in one keystroke.

Pressing / offers these four as a starting point; click one to load it into an empty filter.

^andersson year:2019-                 first author, open-ended years
abs:"fast radio burst"                phrase in the abstract
is:pdf pri:>0.5                       has a PDF, high priority
kw:"compact objects" -abs:neutrino    keyword, and a negation

ADS queries

S passes your query to the ADS API unmodified, so the full Solr language works (bibstem:ApJL, citations(...), boolean grouping, …). Each query becomes a scope capsule, persisted per library context in tabs.json. The pub card walks the citation graph directly: click "cited by N" (or the citations/references affordances) to open a citations(...) or references(...) scope for the shown paper.

Pressing S offers these four as a starting point; click one to load it into an empty prompt.

abs:"little red dot" -doctype:abstract    phrase, minus meeting abstracts
author:"^Andersson, K." year:2020-        first author, from a year on
bibstem:ApJL abs:"magnetar"               one journal
arxiv_class:astro-ph.HE                   an arXiv subject class

Samples never carry an absolute upper year: recency is the prompt's own control (⌃r), and a baked-in end year would silently exclude the newest work once it passed.

A saved query reads as a feed: ADS is asked for the newest records by entry date — when it indexed them — not by publication date, so r brings back what has appeared since you last looked rather than what was published most recently. The Entered column shows that date beside Year; the table panel picks which of the four selection sorts a query uses. That sort chooses which records come back, so ordering a feed by citations gives the most cited among the newest n, not the most cited overall.


Markdown manuscripts

Literature reviews and notes work as manuscripts too: any .md files beside bib/ are scanned for citations (main.md is the sole root when present; Obsidian ![[embeds]] pull in more files, like \input). Cite pandoc-style — bare @Andersson2021 or bracketed [@Andersson2021; @Baxter2019] — or with Obsidian wikilinks: [[Andersson2021]] counts as a citation when it resolves in the library, and stays an ordinary note link when it doesn't. An unresolved @cite shows as missing in the Manuscript view, same as LaTeX. astrobib refs renders the bibliography of everything cited into the manuscript — a sorted, linked reference list (authors, year, italic title, journal, ADS/arXiv/DOI links) kept between <!-- astrobib:references --> markers, appended as a ## References section the first time. Regenerate any time; your prose is never touched.


Building with make

The dependency graph of a paper is acyclic, and astrobib refs implements the middle of it:

main.pdf  <-  main.tex, refs.bib
bib/      <-  main.tex          (citing a paper pulls it out of your library)
refs.bib  <-  main.tex, bib/

astrobib refs — copy newly cited papers into bib/, then write refs.bib from what is there. It stamps refs.bib's mtime even when the content is unchanged, so a make rule settles instead of re-running every build; no touch $@ is needed. astrobib refs --check — verify only: writes nothing, exits nonzero if refs.bib is stale or a cited paper is still missing from bib/. For CI and pre-commit hooks. astrobib refs --no-sync — write refs.bib from what bib/ already holds and fetch nothing, for a CI job that must not modify tracked files.

A complete Makefile is in docs/examples/Makefile.


refs.bib and co-authors

For TeX manuscripts, refs.bib regenerates silently whenever the TUI rescans — and the TUI rescans itself when you edit sources externally (mtimes are polled, like the original app): every cited manuscript-db member, emitted under the string you actually cited (full key or unambiguous prefix), so hash suffixes never need to appear in your .tex. astrobib refs [--prune] does the same from the CLI, first copying cited-but-missing entries into the manuscript db (--prune also removes uncited ones, rescuing sole copies). Co-authors don't need astrobib. They add a reference by pasting BibTeX from the ADS website into bib/any-name.bib (and, if they like, appending it to refs.bib by hand so the paper still compiles). Next time you check out the repo, astrobib tidy canonicalizes those files — re-keys them through ADS when needed, renames them to {Key}.bib, dedupes, rewrites the old keys inside your sources — and regenerates refs.bib for the commit. Migrating a manuscript that predates astrobib works the same way: in a directory with sources and its own loose .bib files but no bib/, astrobib tidy adopts it wholesale — builds bib/, resolves everything against ADS, rewrites your \cite keys in place, and regenerates refs.bib.


CLI

list, search [--ads], add <bibcode|ADS URL>, show <key>, rm <key> [--local-only] (sole copies rescued), import <file.bib> [--global-only|--local-only], refs [FILE] [--prune|--no-sync|--check] [--dry-run], tidy [--dry-run], convert bibcode|full|short (uniform cite keys, rewritten in your sources), update [--all] (arXiv → published refresh, same key forever), config [ads_token|email <value>] (show or set the environment), gc (report what the machine-local caches cost), plus --library PATH (relocate the global tier) and --no-global. import resolves each entry against ADS (arXiv ID → DOI → exact title+author+year) unless its cite key is already reproducible from its own data — canonical astrobib entries import byte-identically — and prints copy-pasteable key replacements for your .tex files.


See docs/DESIGN.md for the data-format contract. Bugs and feature requests: github.com/clemson-cal/astrobib/issues.

© 2026 Jonathan Zrake · MIT license · Clemson University Physics and Astronomy · Supported by NSF award number 2408034 Development assisted by Claude (Fable 5).

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

astrobib-0.14.0.tar.gz (314.2 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

astrobib-0.14.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.8 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

astrobib-0.14.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.6 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

astrobib-0.14.0-py3-none-macosx_11_0_arm64.whl (2.5 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

astrobib-0.14.0-py3-none-macosx_10_12_x86_64.whl (2.7 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file astrobib-0.14.0.tar.gz.

File metadata

  • Download URL: astrobib-0.14.0.tar.gz
  • Upload date:
  • Size: 314.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.14.1

File hashes

Hashes for astrobib-0.14.0.tar.gz
Algorithm Hash digest
SHA256 4f312ca9710e83efdc8a56cd89bd62648cc8491951e3cccbac815b7aff6443a0
MD5 f9504d56ca092ae3f537db2e4255083d
BLAKE2b-256 b3e510b70cff9f6ec8f407004f15ecabf5244ccc89f71485f94e4b1e0e4c50b4

See more details on using hashes here.

File details

Details for the file astrobib-0.14.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for astrobib-0.14.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c32135bcde48c72d6433e763e02d39cc1dcb376f543f4bea685c40d2e257a3c6
MD5 c279787049fee14c2dbb19cc9d9acb5b
BLAKE2b-256 11589478da092ebb3adb7442fd85888f13ae7d09a0decfb06e716e9cd55e8ce2

See more details on using hashes here.

File details

Details for the file astrobib-0.14.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for astrobib-0.14.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 fba4abe886a33930ac3a76b7cbb7d1ebf001a1a12e5a749b22708a240822b969
MD5 445f56b7abb31eff7b4a680449548968
BLAKE2b-256 7b4260c0af2ed435d39608e6871799a7d56d078bc8c5f3a97269cacb7e70baed

See more details on using hashes here.

File details

Details for the file astrobib-0.14.0-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for astrobib-0.14.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 ed6e7e680a4550e2aa42a3f8229d544c901bb0218934c65dd7a0fbc64639ac2d
MD5 c2cc8b687ef6d82f5e670c62307e4d1c
BLAKE2b-256 79953848eb45ace98ea05eaedf3786630fc3924dab71a1ed27e979702da96b18

See more details on using hashes here.

File details

Details for the file astrobib-0.14.0-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for astrobib-0.14.0-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 f3a69c3f8f399e029a35109f7b1c675ac87ff29f3bf02d6431a9f71c5f159674
MD5 8369de8285f2c2356098c840b5156f87
BLAKE2b-256 1211c942a6842499b48bb9b8f63356b26240ae3d50773296c6d8bdaa9cc5746d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page