Academic literature search CLI for arXiv, Semantic Scholar, and Zotero
Project description
orbitr
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
- Quick start
- Global flags
- Commands
- Configuration
- Output formats
- Piping and scripting
- Exit codes
- Shell completions
- Project layout
- Dependencies
Installation
Requirements: Python ≥ 3.10, uv
git clone <repo-url> 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 and
enables Zotero integration.
| Credential | Purpose |
|---|---|
| Semantic Scholar API key | Higher rate limits (get one at semanticscholar.org/product/api) |
| Zotero User ID + API key | orbitr zotero commands |
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"
# 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
orbitr search
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
orbitr zotero search
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 API key, Zotero credentials, and default preferences. All values are optional and can be skipped.
orbitr doctor
Check configuration and connectivity to arXiv and Semantic Scholar (and Zotero
if credentials are configured). Exits 0 if all checks pass, 1 if any
connectivity check fails.
orbitr doctor
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 = ""
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 |
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 jsonalways produces newline-delimited JSON regardless of TTY.orbitr exportreads piped JSON from anyorbitrcommand.- Use
-q/--quietto 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 |
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file orbitr-0.2.0.tar.gz.
File metadata
- Download URL: orbitr-0.2.0.tar.gz
- Upload date:
- Size: 175.0 kB
- Tags: Source
- Uploaded using 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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b7020562e2eba1309ea9cd0756711b66f83fa7e3195d875bff626c20850a96be
|
|
| MD5 |
401715c0c92b64cf4db9c2f28eb7aa10
|
|
| BLAKE2b-256 |
518e58b6fc955ff39166095fc020e82fba428dd2e2f1cebc534a800e986a2825
|
File details
Details for the file orbitr-0.2.0-py3-none-any.whl.
File metadata
- Download URL: orbitr-0.2.0-py3-none-any.whl
- Upload date:
- Size: 69.9 kB
- Tags: Python 3
- Uploaded using 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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8bc6a9913d8299a3fc5c44ba24bf8e87042cbee912e4d931570bb76a4d905f1
|
|
| MD5 |
7965bb080984aa30f70cb415ce419d5d
|
|
| BLAKE2b-256 |
13f04c0528e8cdcab46bf8873a547771c5d9ef37db9623ce6008a8991f1697e6
|