Skip to main content

Academic literature search CLI for arXiv, Semantic Scholar, and Zotero

Project description

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

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 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

Project details


Download files

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

Source Distribution

orbitr-0.2.0.tar.gz (175.0 kB view details)

Uploaded Source

Built Distribution

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

orbitr-0.2.0-py3-none-any.whl (69.9 kB view details)

Uploaded Python 3

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

Hashes for orbitr-0.2.0.tar.gz
Algorithm Hash digest
SHA256 b7020562e2eba1309ea9cd0756711b66f83fa7e3195d875bff626c20850a96be
MD5 401715c0c92b64cf4db9c2f28eb7aa10
BLAKE2b-256 518e58b6fc955ff39166095fc020e82fba428dd2e2f1cebc534a800e986a2825

See more details on using hashes here.

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

Hashes for orbitr-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f8bc6a9913d8299a3fc5c44ba24bf8e87042cbee912e4d931570bb76a4d905f1
MD5 7965bb080984aa30f70cb415ce419d5d
BLAKE2b-256 13f04c0528e8cdcab46bf8873a547771c5d9ef37db9623ce6008a8991f1697e6

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