Skip to main content

orbitr

CI PyPI version Python versions License: MIT

Academic literature search and reference management for the terminal. Search arXiv and Semantic Scholar concurrently, inspect papers and their citations, get recommendations, export bibliographies, and manage your Zotero library — all without leaving the shell.

Contents


Installation

With uv (fastest):

uv tool install orbitr
orbitr --version

With pip:

pip install orbitr
orbitr --version

Requirements: Python ≥ 3.10

From source

git clone https://github.com/francojc/orbitr
cd orbitr
uv tool install .
orbitr --version

Development setup

orbitr uses a Nix flake to pin the development environment (Python 3.12, uv, ruff, pyright) and just as a task runner.

Prerequisites: Nix with flakes enabled, direnv, just.

git clone <repo-url> orbitr
cd orbitr          # direnv activates the flake shell automatically
just setup        # uv sync inside the pinned environment
just run -- --help

Without direnv: nix develop && just setup.

Common tasks:

just test        # full test suite
just cov         # tests with coverage report
just check       # lint + format check (no writes)
just qa          # check + type check
just fmt         # auto-format source files

API credentials

orbitr works without credentials; providing them increases rate limits, enables Zotero integration, or connects a private Karakeep bookmark server.

Credential Purpose
Semantic Scholar API key Higher rate limits (get one at semanticscholar.org/product/api)
Zotero User ID + API key orbitr zotero commands
Karakeep API key + server URL orbitr karakeep search (private bookmarks)
orbitr init      # guided interactive setup

Or set environment variables directly — see Configuration.


Quick start

# Search across arXiv and Semantic Scholar
orbitr search "retrieval augmented generation"

# Field filters and date range
orbitr search "scaling laws" --from 2022 --sort citations

# Full metadata for a specific paper (arXiv ID, DOI, or SS ID accepted)
orbitr paper 2005.14165

# Papers citing the Transformer paper
orbitr cite 1706.03762 --limit 20

# Papers by an author
orbitr author "Percy Liang"

# Recommendations from a seed paper
orbitr recommend 1706.03762

# Export search results as BibTeX
orbitr search "in-context learning" --format json \
  | orbitr export --format bibtex --output refs.bib

# Add a paper to Zotero
orbitr zotero add 2503.19260 --collection "Reading List" --tags "llm,linguistics"

# Browse a Zotero collection
orbitr zotero list -c "Reading List"

# Search a private Karakeep bookmark library (not part of academic search)
orbitr karakeep search "retrieval augmented generation" --limit 20

# Inspect a single Zotero item (use a key from zotero list)
orbitr zotero get ABCD1234

# Bulk export a collection as Markdown files
orbitr zotero list -c "Reading List" --format keys \
  | xargs -I{} orbitr zotero export-md {} -o notes/

Global flags

These flags work with every command.

Flag Short Description
--help Show help for any command
--version -V Print version and exit
--verbose -v Show debug output and request details
--quiet -q Suppress informational output; only results and errors
--no-color Disable ANSI color (also: NO_COLOR env var)
--config <path> Use an alternate config file

Commands

Search for papers across arXiv and Semantic Scholar concurrently. Results are deduplicated by DOI, arXiv ID, and title similarity, then ranked by the chosen criterion.

orbitr search QUERY [OPTIONS]

Field filters can be given as CLI flags or embedded directly in the query string using field:value syntax (e.g. "title:attention author:Vaswani").

Options:

Flag Short Default Description
--sources -s arxiv,semantic_scholar Comma-separated sources
--limit -n 10 Max results (1–200)
--title -T Filter by title keywords
--author -a Filter by author name
--venue -j Filter by journal or conference
--from Earliest publication year
--to Latest publication year
--sort relevance relevance, citations, date, impact, combined
--format -f table table, list, detail, json
--no-cache Bypass the local result cache
# Keyword search
orbitr search "diffusion models image generation"

# Field-filter flags
orbitr search "RLHF" --author "Ouyang" --from 2022 --to 2023

# Inline field syntax
orbitr search "title:contrastive learning author:Chen"

# Single source, sorted by citations
orbitr search "vision transformer" --sources semantic_scholar \
  --limit 25 --sort citations

# Machine-readable output
orbitr search "federated learning" --format json

orbitr paper

Fetch full metadata for a single paper. Accepts arXiv IDs, DOIs, and Semantic Scholar paper IDs — the source is detected automatically.

orbitr paper PAPER_ID [OPTIONS]

Options:

Flag Short Default Description
--format -f table table, list, detail, json
--no-cache Bypass the local paper cache
orbitr paper 1706.03762                          # arXiv ID
orbitr paper arxiv:2503.19260                    # arXiv ID with prefix
orbitr paper 10.18653/v1/2020.acl-main.196       # DOI
orbitr paper 1706.03762 --format detail          # full single-paper view
orbitr paper 1706.03762 --format json            # machine-readable

orbitr cite

List papers that cite a given paper via Semantic Scholar. Accepts arXiv IDs, DOIs, and Semantic Scholar paper IDs.

orbitr cite PAPER_ID [OPTIONS]

Options:

Flag Short Default Description
--limit -n 10 Max citing papers (1–200)
--format -f table table, list, detail, json
--no-cache Bypass the local citation cache
orbitr cite 1706.03762
orbitr cite 1706.03762 --limit 50 --format list
orbitr cite 10.18653/v1/2020.acl-main.196 --format json

orbitr author

Search for an author by name and list their papers via Semantic Scholar. Returns publications from the best-matching author result.

orbitr author NAME [OPTIONS]

Options:

Flag Short Default Description
--limit -n 10 Max papers to list (1–200)
--format -f table table, list, detail, json
--no-cache Bypass the local cache
orbitr author "Emily M. Bender"
orbitr author "LeCun" --limit 20 --format list
orbitr author "Percy Liang" --format json | jq '.[].title'

orbitr recommend

Get papers similar to a seed paper via Semantic Scholar's recommendation API. The seed is any paper ID — arXiv ID, DOI, or Semantic Scholar ID.

orbitr recommend SEED [OPTIONS]

Options:

Flag Short Default Description
--method -m hybrid content, citation, or hybrid
--limit -n 10 Number of recommendations (1–50)
--format -f table table, list, detail, json
--no-cache Bypass the local cache
orbitr recommend 1706.03762
orbitr recommend 1706.03762 --method citation --limit 20
orbitr recommend 10.18653/v1/2020.acl-main.196 --format json

orbitr export

Export papers to a bibliography format. Reads paper JSON piped from another orbitr command, or runs a fresh search with --query.

orbitr export [OPTIONS]

Options:

Flag Short Default Description
--format -f bibtex bibtex, ris, csl-json
--output -o stdout Output file path
--query -q Run a fresh search and export results
# Pipe from search
orbitr search "sparse attention" --limit 10 --format json \
  | orbitr export --format bibtex --output sparse.bib

# Single paper via pipe
orbitr paper 1706.03762 --format json \
  | orbitr export --format csl-json

# Direct query (no pipe needed)
orbitr export --query "BERT language model" --format ris --output bert.ris

# RIS to stdout for inspection
orbitr search "contrastive learning" --format json | orbitr export --format ris

orbitr query

Translate a plain-language description into a orbitr search command. Extracts year, author, and keywords heuristically.

orbitr query NATURAL [OPTIONS]

Options:

Flag Short Description
--run -r Execute the generated command immediately
# Show the generated command
orbitr query "recent papers on contrastive learning in NLP"

# Show and run immediately
orbitr query "Vaswani attention transformer 2017" --run

orbitr zotero

Manage your Zotero library. Requires zotero_user_id and zotero_api_key — run orbitr init to configure them, then orbitr doctor to verify.


orbitr zotero add

Add a paper to your Zotero library by ID. Fetches full metadata from arXiv or Semantic Scholar and creates a journalArticle item.

orbitr zotero add PAPER_ID [OPTIONS]

Options:

Flag Short Description
--collection -c Target collection name or key
--tags -t Comma-separated tags
--no-cache Bypass the local paper cache
orbitr zotero add 1706.03762
orbitr zotero add arxiv:2503.19260 --collection "Reading List" --tags "llm,linguistics"
orbitr zotero add 10.18653/v1/2020.acl-main.196 --collection "NLP Papers"

orbitr zotero collections

List all collections in your Zotero library.

orbitr zotero collections [OPTIONS]

Options:

Flag Short Default Description
--format -f table table or json
orbitr zotero collections
orbitr zotero collections --format json | jq '.[].name'

orbitr zotero new

Create a new collection in your Zotero library.

orbitr zotero new NAME [OPTIONS]

Options:

Flag Short Description
--parent -p Parent collection name or key
orbitr zotero new "PhD Research"
orbitr zotero new "Chapter 3" --parent "PhD Research"

orbitr zotero list

Browse items in your Zotero library or a specific collection. --format keys outputs bare item keys one-per-line for use with xargs.

orbitr zotero list [OPTIONS]

Options:

Flag Short Default Description
--collection -c Collection name or key; omit for the whole library
--limit -n 25 Maximum items to return
--sort dateModified dateModified, title, or date
--format -f table table, json, or keys
# Browse the 25 most recently modified items
orbitr zotero list

# Scope to a collection, sorted by title
orbitr zotero list -c "NLP" --sort title

# Pipeable keys output
orbitr zotero list -c "NLP" --format keys

# JSON for scripting
orbitr zotero list --limit 50 --format json | jq '.[].title'

orbitr zotero get

Show full metadata, abstract, notes, and attachment info for a single Zotero item. Displays a PDF URI line (zotero://open-pdf/...) when a PDF attachment is linked, which opens the file directly in Zotero's built-in viewer.

orbitr zotero get ITEM_KEY [OPTIONS]

Options:

Flag Short Default Description
--format -f detail detail or json
--notes/--no-notes --notes Include or suppress Zotero notes
orbitr zotero get ABCD1234
orbitr zotero get ABCD1234 --no-notes
orbitr zotero get ABCD1234 --format json

Full-text search within your Zotero library. Optionally scoped to a collection. Supports the same --format keys pipeline pattern as zotero list.

orbitr zotero search QUERY [OPTIONS]

Options:

Flag Short Default Description
--collection -c Scope search to this collection
--limit -n 25 Maximum results
--format -f table table, json, or keys
orbitr zotero search "language model"
orbitr zotero search "attention" -c "Transformers"
orbitr zotero search "RLHF" --format keys

orbitr zotero export-md

Export a single Zotero item as a Markdown file with YAML frontmatter. When a PDF attachment is linked, pdf_uri is included in the frontmatter and a clickable zotero://open-pdf/... link appears in the body.

Outputs to stdout by default. Pass --output with a file path or a directory; when a directory is given, the filename is auto-generated as YYYY-Author-Short-Title.md.

orbitr zotero export-md ITEM_KEY [OPTIONS]

Options:

Flag Short Description
--output -o Output file or directory (default: stdout)

Output format:

---
title: "Paper Title"
authors: [First Last, First Last]
year: 2024
doi: "10.xxxx/yyyy"
zotero_key: ABCD1234
zotero_url: "zotero://select/items/0_ABCD1234"
pdf_uri: "zotero://open-pdf/library/items/EFGH5678"
tags: [tag1, tag2]
type: source
---

# Paper Title

**Authors:** First Last, First Last  **Year:** 2024  **Venue:** Journal Name
**DOI:** [10.xxxx/yyyy](https://doi.org/10.xxxx/yyyy)
**PDF:** [zotero://open-pdf/...](zotero://open-pdf/...)

## Abstract

Abstract text.

## Notes

Zotero note content (if any).
# Preview to stdout
orbitr zotero export-md ABCD1234

# Write to a file
orbitr zotero export-md ABCD1234 -o kb/sources/raw/paper.md

# Auto-generated filename in a directory
orbitr zotero export-md ABCD1234 -o kb/sources/raw/

# Bulk export an entire collection
orbitr zotero list -c "NLP" --format keys \
  | xargs -I{} orbitr zotero export-md {} -o kb/sources/raw/

orbitr cache

Manage the local SQLite result cache. Three tiers are maintained independently: search (1 h TTL), paper (24 h), citations (6 h).

orbitr cache COMMAND
Subcommand Description
stats Entry counts per tier, disk usage, and cache path
clean [--tier T] Remove expired entries; optional tier filter
clear [--tier T] [--yes] Delete all entries; prompts unless --yes
orbitr cache stats
orbitr cache clean
orbitr cache clean --tier search
orbitr cache clear --yes
orbitr cache clear --tier paper --yes

orbitr init

Interactive first-time setup. Writes ~/.config/orbitr/config.toml with mode 0600. Run once after installing, or again to rotate credentials.

orbitr init

Prompts for Semantic Scholar, Zotero, and optional Karakeep credentials plus default preferences. All values are optional and can be skipped. Karakeep uses KARAKEEP_API_KEY and KARAKEEP_SERVER_URL when configured through the environment.


orbitr doctor

Check configuration and connectivity to arXiv, Semantic Scholar, Zotero, and Karakeep when credentials are configured. Exits 0 if all checks pass, 1 if any connectivity check fails.

orbitr doctor

Searches a private Karakeep bookmark corpus using the configured Bearer token and server URL. This is deliberately a dedicated workflow; Karakeep is not a default orbitr academic-search source and does not affect academic ranking or deduplication.

orbitr karakeep search "transformer"
orbitr karakeep search "reading list" --limit 20 --format json | jq .title
orbitr karakeep search "papers" --server https://karakeep.example.org

Configure with orbitr init, or set KARAKEEP_API_KEY and KARAKEEP_SERVER_URL. The server URL must be an http or https URL without embedded credentials. orbitr uses Karakeep API v1 endpoint /api/v1/bookmarks/search.


Configuration

Settings are resolved in this order (earlier sources win):

CLI flags  >  environment variables  >  config file  >  built-in defaults

Config file

Location: ~/.config/orbitr/config.toml (XDG; override with --config).

[defaults]
sources     = ["arxiv", "semantic_scholar"]
max_results = 10
format      = "table"
no_cache    = false
no_pager    = false

[credentials]
semantic_scholar_api_key = ""
zotero_user_id           = ""
zotero_api_key           = ""
karakeep_api_key         = ""
karakeep_server_url      = ""

Environment variables

Variable Description
ORBITR_SOURCES Default sources (comma-separated)
ORBITR_MAX_RESULTS Default result limit
ORBITR_FORMAT Default output format
ORBITR_CACHE_DIR Override cache directory
ORBITR_NO_CACHE Disable caching (1 = true)
ORBITR_NO_PAGER Disable pager (1 = true)
SEMANTIC_SCHOLAR_API_KEY Semantic Scholar API key
ZOTERO_USER_ID Zotero user ID
ZOTERO_API_KEY Zotero API key
KARAKEEP_API_KEY Karakeep Bearer API key
KARAKEEP_SERVER_URL Karakeep server base URL
NO_COLOR Disable all ANSI color output

A template is provided in .env.example.


Output formats

All paper-returning commands support --format / -f:

Format Description Best for
table Compact multi-column table (truncated fields) Interactive browsing
list One labeled block per paper, abstract snippet Skimming results
detail Full single-paper view with wrapped abstract orbitr paper
json Newline-delimited JSON objects Piping, jq, scripting

Auto-detection: when stdout is not a TTY (pipe or redirect), --format defaults to json automatically unless set explicitly.

Pager: long output is paged through $PAGER (default: less -R) when stdout is a TTY. Disable with ORBITR_NO_PAGER=1 or --no-color.


Piping and scripting

  • Results → stdout; warnings and errors → stderr.
  • --format json always produces newline-delimited JSON regardless of TTY.
  • orbitr export reads piped JSON from any orbitr command.
  • Use -q / --quiet to suppress progress output in scripts.
# Search → BibTeX file
orbitr search "in-context learning" --sort citations --limit 10 --format json \
  | orbitr export --format bibtex --output icl.bib

# Extract titles with jq
orbitr search "model merging" --format json | jq -r '.[].title'

# Author publication list as CSV
orbitr author "Danqi Chen" --format json \
  | jq -r '.[] | [.title, (.published_date // ""), (.citation_count // 0)] | @csv' \
  > danqi_chen.csv

# Pipe into a custom script
orbitr search "continual learning" --limit 20 --format json | python triage.py

# Bulk-export a Zotero collection as Markdown files
orbitr zotero list -c "Reading List" --format keys \
  | xargs -I{} orbitr zotero export-md {} -o kb/sources/

# Find Zotero items matching a keyword, export each as Markdown
orbitr zotero search "transformer" --format keys \
  | xargs -I{} orbitr zotero export-md {} -o kb/sources/

Exit codes

Code Meaning
0 Success
1 Source error (network failure, API error)
2 Usage error (bad argument, invalid flag value)
3 Config error (missing credentials)
4 No results found

Shell completions

orbitr supports tab-completion for Zsh, Bash, and Fish via Click's completion system. The simplest method is the built-in flag (works when run directly from an interactive shell):

orbitr --install-completion   # detects your shell and installs automatically

If auto-detection fails, generate the script manually with the _ORBITR_COMPLETE environment variable:

Zsh:

_ORBITR_COMPLETE=source_zsh orbitr > ~/.zfunc/_orbitr
# Add to ~/.zshrc (if not already present):
#   fpath=(~/.zfunc $fpath)
#   autoload -Uz compinit && compinit

Bash:

_ORBITR_COMPLETE=source_bash orbitr > ~/.bash_completion.d/orbitr
# Add to ~/.bashrc:
#   source ~/.bash_completion.d/orbitr

Fish:

_ORBITR_COMPLETE=source_fish orbitr > ~/.config/fish/completions/orbitr.fish

Project layout

orbitr/
├── pyproject.toml
├── flake.nix
├── .env.example
├── README.md
├── src/
│   └── orbitr/
│       ├── __init__.py
│       ├── cli.py              # Typer app root; global flags; command registration
│       ├── config.py           # Layered config: flags > env vars > file > defaults
│       ├── _async.py           # asyncio.run() helper
│       ├── exceptions.py       # OrbitrError hierarchy with exit codes
│       ├── commands/
│       │   ├── search.py       # orbitr search
│       │   ├── paper.py        # orbitr paper, orbitr cite
│       │   ├── author.py       # orbitr author
│       │   ├── recommend.py    # orbitr recommend
│       │   ├── export.py       # orbitr export
│       │   ├── query.py        # orbitr query
│       │   ├── zotero.py       # orbitr zotero add / collections / new / list / get / search / export-md
│       │   ├── cache.py        # orbitr cache stats / clean / clear
│       │   ├── init.py         # orbitr init
│       │   └── doctor.py       # orbitr doctor
│       ├── clients/
│       │   ├── base.py         # Retry, backoff, circuit-break; HTTPError → SourceError
│       │   ├── arxiv.py        # arXiv Atom feed client
│       │   └── semantic_scholar.py  # Semantic Scholar Graph API client
│       ├── core/
│       │   ├── models.py       # Paper, Author, SearchResult (Pydantic v2)
│       │   ├── deduplication.py # DOI / arXiv ID / fuzzy-title dedup
│       │   ├── ranking.py      # relevance, citations, date, impact, combined
│       │   ├── cache.py        # SQLite TTL cache (3 tiers)
│       │   ├── export.py       # BibTeX, RIS, CSL-JSON formatters
│       │   └── query.py        # field:value parsing; per-source query builders
│       ├── zotero/
│       │   └── client.py       # pyzotero wrapper: add, list/get/search items, collections
│       └── display/
│           ├── __init__.py     # render() dispatcher; effective_format(); pager
│           ├── table.py        # Rich Table renderer
│           ├── list.py         # Rich Panel renderer
│           ├── detail.py       # Full single-paper Rich layout
│           └── json_fmt.py     # Newline-delimited JSON serialiser
└── tests/
    ├── conftest.py
    ├── fixtures/               # Recorded API responses for offline testing
    ├── test_models.py
    ├── test_arxiv.py
    ├── test_semantic_scholar.py
    ├── test_deduplication.py
    ├── test_ranking.py
    ├── test_cache.py
    ├── test_search.py
    ├── test_cache_cmd.py
    ├── test_paper.py
    ├── test_recommend.py
    ├── test_author.py
    ├── test_export.py
    ├── test_init.py
    ├── test_doctor.py
    ├── test_query.py
    ├── test_zotero.py
    ├── test_zotero_client.py
    ├── test_display_phase4.py
    └── test_base_client.py

Dependencies

Package Purpose
typer CLI framework; command tree, flags, completions
rich Tables, panels, color, pager integration
httpx Async HTTP client
pydantic Data models and validation
feedparser arXiv Atom feed parsing
rapidfuzz Fuzzy title matching for deduplication
pyzotero Zotero Web API client
python-dateutil Flexible date parsing
python-dotenv .env file loading

Metadata

Release files for orbitr 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for orbitr 0.4.0
File Size Uploaded
orbitr-0.4.0.tar.gz 183.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for orbitr 0.4.0
File Interpreter ABI Platform
orbitr-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 260.1 kB

Release files / orbitr-0.4.0.tar.gz

Download URL orbitr-0.4.0.tar.gz
Size 183.3 kB
Tags Source
SHA-256 checksum
How to use checksums
b36e1a09298aaec2ebc5e4604089b3a181cfe913184b515178efbafa4eda7a19
BLAKE2b-256 checksum
How to use checksums
b7d0c32080740c24b3f8bf91a49fcbc308e36b81a9ab9c4a440ec944107cfa6c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / orbitr-0.4.0-py3-none-any.whl

Download URL orbitr-0.4.0-py3-none-any.whl
Size 76.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4784befdb7362d755b4e48bd9eb424d10ec056ac5fa2aed1d9aa6c8affd04261
BLAKE2b-256 checksum
How to use checksums
b5e8a0c8cf755a56492d2cf79414e136a8a33a64f67450dc5da7f91a64b8318a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page