Metadata-Version: 2.4
Name: scholar-paper-cli
Version: 0.1.0
Summary: spm: CLI for Semantic Scholar with persistent cache and offline fallback
Project-URL: Homepage, https://github.com/TudeOrangBiasa/scholar-paper-cli
Project-URL: Repository, https://github.com/TudeOrangBiasa/scholar-paper-cli
Author: TudeStillLearning!
License: MIT
License-File: LICENSE
Requires-Python: >=3.13
Requires-Dist: httpx
Requires-Dist: numpy>=2.0
Requires-Dist: onnxruntime>=1.27.0
Requires-Dist: pydantic-settings>=2.7
Requires-Dist: pydantic>=2.10
Requires-Dist: sqlite-vec>=0.1.9
Requires-Dist: tokenizers>=0.23.1
Description-Content-Type: text/markdown

# scholar-paper-cli

spm — CLI for Semantic Scholar. 15 commands, persistent SQLite cache, offline fallback, multilingual semantic search.

Pairs with the `writing-for-agents` skill for hackathon, proposal, thesis, and article workflows.

## Features

- 15 commands: paper/author search, details, citations, references, recommendations, related, session tracking, BibTeX export
- Persistent SQLite cache with 30-day TTL. Repeat queries cost zero.
- Offline fallback: when Semantic Scholar is unreachable, return cached data with offline flag.
- Multilingual semantic search via `intfloat/multilingual-e5-small` (100+ languages including Indonesian).
- Portable CLI: JSON on stdout, pipeable, scriptable, works in any agent that can run bash and in a plain terminal.

## Install

Requires Python 3.13 and uv.

```bash
git clone https://github.com/TudeOrangBiasa/scholar-paper-cli
cd scholar-paper-cli
uv sync

# Download embedding model (~118MB, one time)
# See models/README.md for details
```

## Run

```bash
spm --help
spm search "quantum entanglement" --limit 2
```

Every command prints a JSON `{"data": ..., "meta": ...}` envelope on stdout. Errors print `{"error": {"type", "message"}}` with a non-zero exit code.

## Skill

Teach your agent the CLI by installing the skill:

```bash
mkdir -p ~/.config/opencode/skills/spm
cp skills/spm/SKILL.md ~/.config/opencode/skills/spm/
```

The skill documents every command, the output contract, caching semantics, embeddings, and workflow recipes.

## Commands (15)

| Command | Flags (defaults) | Description |
|---------|------------------|-------------|
| `spm search <query>` | `--limit` (10), `--offset` (0) | Search papers by query |
| `spm paper <id>` | `--embed` | Get paper by ID, persists + embeds |
| `spm citations <id>` | `--limit` (100), `--offset` (0) | Papers that cite this paper |
| `spm references <id>` | `--limit` (100), `--offset` (0) | Papers referenced by this paper |
| `spm author-search <query>` | `--limit` (10), `--offset` (0) | Search authors by name |
| `spm author <id>` | — | Get author by ID, persists |
| `spm author-top <id>` | `--limit` (10) | Top papers by citation count |
| `spm author-duplicates <query>` | `--limit` (50), `--threshold` (0.8) | Group authors by name similarity |
| `spm consolidate <canonical> <dup>...` | — | Merge duplicate authors in storage |
| `spm recommend <id>` | `--limit` (100) | SS API recommendations |
| `spm related <id>` | `--k` (10) | Local KNN via semantic embeddings |
| `spm session add <session> <id>` | — | Track paper in working session |
| `spm session list <session>` | — | List papers in session |
| `spm session remove <session> <id>` | — | Remove paper from session |
| `spm bibtex <session>` | — | Export session as BibTeX |

Every command returns a `ToolResponse` with `data` and `meta` (cache metadata: source, cached, offline, fetched_at, ttl_until).

## Configuration

See [docs/CONFIGURATION.md](docs/CONFIGURATION.md) for all `SPM_*` environment variables.

## Command call flow

A command follows this sequence:

1. **Shell/agent** runs `spm <command>`.
2. **cli.py** parses args and assembles state (cache dir, SQLite, API client, optional embedder).
3. **Tool function** composes `CachedSemanticScholarClient` + storage CRUD + (optionally) embedder.
4. **Cache check**: fresh hit returns cached data. Stale or miss triggers step 5.
5. **API call** (if online): SS API via rate-limited, circuit-broken, offline-aware client.
6. **Persist**: paper, author, citation, session rows written to SQLite. Embedding stored in `embeddings_vec`.
7. **Wrap**: response enveloped as `ToolResponse[data, meta]`, printed as JSON on stdout.

See [docs/PLAN.md](docs/PLAN.md) for the full design rationale.

## Development

```bash
uv run pytest           # all tests
uv run ruff check       # lint
uv run ty check         # type check
uv run ruff format      # auto-format
```

See [docs/PLAN.md](docs/PLAN.md) for the full plan, [docs/WORKFLOW.md](docs/WORKFLOW.md) for document-writing integration, [docs/CONFIGURATION.md](docs/CONFIGURATION.md) for env vars.

## Status

v0.1.0 feature-complete. 14 of 14 planned issues done. Security review applied: 0 CRITICAL, 0 HIGH, 0 MEDIUM.

Future work is open-ended. See [docs/PLAN.md](docs/PLAN.md) for the original plan and the one deferred item: cross-encoder rerank (v3 in the plan, blocked by bundle size and missing Indonesian benchmark for any small multilingual cross-encoder).

## Acknowledgments

- **Semantic Scholar** (Allen AI) for the Graph API and the public dataset of ~200M academic papers.
- **[akapet00/semantic-scholar-mcp](https://github.com/akapet00/semantic-scholar-mcp)** for the upstream reference. The 15 command set mirrors the original 15 tools.
- **argparse (stdlib)** for the CLI interface.
- Open source libraries: Pydantic, httpx, sqlite-vec, ONNX Runtime, tokenizers, pytest, ruff, ty.
- Embedding model: [intfloat/multilingual-e5-small](https://huggingface.co/intfloat/multilingual-e5-small) (MIT license).

## How to contribute

1. Check [docs/PLAN.md](docs/PLAN.md) for the project plan and any open work.
2. Read [AGENTS.md](AGENTS.md) for conventions (TDD, ponytail, anti-AI-slop rules).
3. Open an issue describing the change.
4. Write tests first, then minimum code, then verify all checks pass:
   ```bash
   uv run pytest
   uv run ruff check src tests
   uv run ty check src tests
   uv run ruff format --check src tests
   ```
5. Open a PR. Title format: `type(scope): short description` (e.g. `feat(api): add batch search endpoint`).

## License

MIT. See [LICENSE](LICENSE).
