--- name: papyrus-cli description: "Ground agent reasoning in the arxiv ML-research corpus via the installed `papyrus` command. Use when the user mentions an arxiv paper, wants a literature sweep, current SOTA, related work, BibTeX/CSV export, or asks you to find papers instead of reasoning from training. Free direct endpoints: search (BM25), semantic-search (embeddings), paper, related, excerpts, cite, pdf, lists. Paid chat-backed: ask, exec, ask-batch." --- # Papyrus CLI Your training has a cutoff; the arxiv corpus doesn't. Every "what papers exist on X?" answer from training alone is a partial, stale, often fabricated answer. Use this CLI. ## Install / discovery This skill is documentation only. It does **not** bundle the binary. The CLI is the installed `papyrus` command on `PATH`: ```bash command -v papyrus >/dev/null 2>&1 || { curl -sSL https://api.rapidreview.io/cli/install | bash export PATH="$HOME/.local/bin:$PATH" } papyrus --help >/dev/null ``` If install fails, report the full stderr plus `uname -s` and `uname -m`; that usually means the release bucket is missing a build for the current OS/arch. After install, `papyrus doctor` prints PATH, platform, backend, config, and auth diagnostics without leaking secrets. ## Auth Set once, never think about it: ```bash export RAPIDREVIEW_KEY="rr_sk_..." ``` API keys don't rotate, don't refresh, and are safe to parallelize. (Bare `papyrus` with no args opens an interactive TUI + onboarding picker for humans. Agents never call bare.) ## Output contract - **stdout** = payload (JSON / BibTeX / CSV / text). - **stderr** = session id, usage footer, errors. - **Exit codes**: `0` ok · `1` error · `124` `--timeout` hit · `130` SIGINT · `141` broken pipe. - Paid commands **always emit JSON** with `ok: bool`, `session_id`, `answer`, `arxiv_ids`, `tokens.cost_usd`, `duration_ms` — even on failure. ## Command families **Direct — fast, deterministic, compose first.** `search`, `semantic-search`, `paper`, `related`, `excerpts`, `cite`, `pdf`, `lists`, `list-papers`, `usage`, `keys`. DB / index lookups; responses in ~1 s. **Chat-backed — reserve for synthesis.** `ask` (one-shot), `exec` (multi-turn stream), `ask-batch` (sequential NDJSON), `wait`. Spin up an agent turn; typically 30–120 s. Worth it when the question genuinely requires judgment, comparison, or long-horizon research across many papers. If you're reaching for `ask` to *find* papers, you're one `search` + one `related` away from a better — and faster — answer. Synthesis commands are for decisions, not lookups. > **Pricing**: all commands are currently **free** on this backend. The `ask --estimate` projection and `ask-batch --max-cost` ceiling are forward-looking — they'll activate when billing comes online. Treat them as dry-run affordances for now. ## Search (BM25, list-capable) ```bash papyrus search "flash attention" --max-results 10 papyrus search --query "test-time compute" --query "inference scaling" --max-results 20 papyrus search --stdin --max-results 20 < queries.txt ``` - `--query` repeatable up to **8**; list form fans out, dedupes by arxiv_id (max score), merges sorted, paginates with `--offset` / `--max-results`. - Filters: `--author "Vaswani"`, `--date-from 2024-01-01`, `--date-to 2025-12-31`. - Output: `--format json|bibtex|csv`. Response: `{query | queries, papers: [{arxiv_id, title, year, authors, citation_count, score, snippets}], count, offset, limit, truncated}`. ## Semantic search (embeddings, list-capable) Same contract, cap **4** (per-query embedding cost): ```bash papyrus semantic-search "networks that process sequences without recurrence" papyrus semantic-search --query "attention without recurrence" --query "parallelizable sequence models" ``` Use for conceptual / paraphrastic queries. Prefer `search` when a specific term must appear literally. ## Paper intel ```bash papyrus paper 1706.03762 # full metadata papyrus related 1706.03762 --n 10 # SOTA related-work (hybrid) papyrus excerpts 2504.08066 --query "tree search" --max 5 papyrus cite 1706.03762 # BibTeX papyrus pdf 1706.03762 [--out paper.pdf] # URL or bytes ``` **`related` is the golden-standard "find related work" tool.** It's a tuned hybrid that blends citation-graph proximity with semantic similarity — not pure embedding neighbours. For any task that starts "given paper X, find relevant adjacent work," reach for `related` first. Returns papers with `similarity_score` (NOT `score`). Run it without `--min-score` first; recent or niche papers often have top scores below 50. Add `--min-score` only after seeing the score range. `excerpts` returns `[{index, text}]`; PDF-extracted whitespace can be mangled — normalize before quoting. ## Chat-backed — `ask` / `exec` / `ask-batch` ```bash papyrus ask "Compare DPO vs PPO for LLM alignment. 3 arxiv ids." papyrus ask --schema '{"picks":[{"id":"string","why":"string"}]}' "Pick 3 best..." papyrus exec "Survey post-Mamba SSM work." # stream papyrus exec --continue "And which extend SSD?" # multi-turn papyrus ask-batch < questions.txt # sequential NDJSON ``` Attached human terminals get live response streaming. Use `--headless` (or run with non-TTY stderr) for the stable agent contract: no prompts and no live progress mixed into machine-facing paths. **Safety valves** (always set one unattended — chat-backed calls are slow): - `--timeout N` aborts with exit 124. - `ask --estimate` prints `{estimated_cost_usd, ...}` without running; forward-looking, treat as a dry-run affordance until billing goes live. - `ask-batch --max-cost $USD` gates the batch on a cumulative ceiling (remaining questions return `{ok: false, skipped: true}`); forward-looking — no charges apply today. **Rate limit.** The CLI refuses more than **10 chat-backed calls per minute** or **100 per hour** (rolling windows, per machine, covers `ask` / `exec` / `ask-batch` / `wait`). Hitting the cap exits `1` with a message like `rate limit: 11 chat calls in the last 60s …`. `ask --estimate` bypasses the limit (no LLM call). Use `ask-batch` for intentional many-question runs. ## Recipes **Current-topic sweep ($0).** One search call, many phrasings: ```bash papyrus search \ --query "mechanistic interpretability diffusion" \ --query "concept unlearning diffusion" \ --query "SAE diffusion" \ --max-results 25 \ | jq '.papers | map(select(.year >= 2024))' ``` **Deep-dive from an anchor ($0).** The most effective pattern — don't jump to `ask`: ```bash papyrus related 2407.08608 --n 15 # SOTA related-work (hybrid) papyrus excerpts 2407.08608 --query "async copy" --max 5 papyrus paper 2407.08608 && papyrus cite 2407.08608 ``` **Explicit forward-citation lookup ($0).** `related` gives you *relevant related work* but won't enumerate "papers that literally cite X." For that, BM25-search the anchor's distinctive coinages (terms the paper itself introduced): ```bash papyrus search "Mamba-2 State Space Duality" papyrus excerpts --query "Mamba-2" --max 2 # verify body mention ``` Use this only when you need explicit citers. For "what should I read next from this paper?" → `related`. **Bounded batch with fail triage.** ```bash papyrus ask-batch --timeout 90 < qs.txt > out.jsonl jq -c 'select(.ok == false)' out.jsonl # failures jq -s 'map(.tokens.completion_tokens) | add' out.jsonl # total tokens produced ``` ## Decision tree ``` user asks → you call ────────────────────────────────────── ─────────────────────────────────── "paper X / arxiv id X …" paper → excerpts → related → cite "from paper X, what else should I read?" related X --n 15 "find papers about Y / recent work on Y" search (list form, 3–5 phrasings) "who literally cites X?" search "" + excerpts verify "compare A vs B at claim level" paper A, paper B, excerpts on both "rank / pick / decide the best of N" ask --schema (chat-backed, slow) "long synthesis across many papers" exec (chat-backed, multi-turn, slow) ``` ## Common flags - `--envelope` (global): wrap direct-endpoint JSON in `{meta, data}` for uniform agent parsing. - `--headless` (global): explicit agent mode, no interactive prompts. Non-TTY stderr infers this automatically. - `--format json|bibtex|csv` (paper-list commands). ## Diagnostics ```bash papyrus doctor papyrus doctor --json ``` Use this before concluding the CLI is unavailable. It reports the installed binary path, whether that directory is on `PATH`, the detected release target, backend URL, config directory writability, and auth source (`RAPIDREVIEW_KEY`, stored API key, OAuth credentials, or none). ## Local bridge / TUI permissions Humans can expose their local workspace to a chat session from the CLI. The permission source of truth is always the CLI: - Bare `papyrus` TUI automatically attaches local tools to the current session while local access is on. - Web chat mints a short-lived token; paste `/connect ` into the TUI to attach this CLI to that web session. - `/permissions` shows current local access; `/approvals` is an alias. Use `/permissions off`, `/permissions read-only`, `/permissions workspace-write`, `/permissions shell-exec`, `/permissions writes on`, `/permissions exec on`, `/permissions terminal on`, `/permissions terminal off`, or `/permissions workspace `. - `/status` shows the current session, explicit bridge connection, and local access state. - `/connect ` inherits the current `/permissions` settings. It also accepts one-shot overrides: `--allow-writes`, `--allow-exec`, `--no-terminal`, and `--workspace `. - `/disconnect` detaches an explicit `/connect` bridge. It does not close the current TUI chat. - In the TUI or web chat, `!` runs a user-initiated local shell command through the live CLI. Use `!!` to send a normal chat message that starts with `!`. Default TUI local access is current directory, read-only agent tools, and user-initiated `!cmd` enabled. Agent-initiated writes and `shell.exec` require explicit CLI opt-in; `!cmd` is controlled separately by `/permissions terminal on|off`. Current local tool surface: - Read-only: `fs.read_file`, `fs.list_dir`, `fs.glob`, `fs.grep`. - Workspace writes: `fs.write_file` for create/overwrite and `fs.edit_file` for exact text replacement. Existing-file changes require a prior `fs.read_file` in the same bridge/TUI stream or an `expected_hash` from a recent read result. - Concurrent writes/edits to the same file are rejected on the CLI side. If two local write requests overlap on one path, both return an error and the agent should retry them serially. - Legacy write compatibility: `fs.apply_patch` is still accepted from older clients, but new clients advertise `fs.write_file` / `fs.edit_file` instead. - OS escape hatch: `shell.exec` runs through the user's shell with credential-shaped environment variables scrubbed. Its cwd is clamped inside the workspace, but it is not a filesystem sandbox; only expose it for trusted sessions or explicit command approval flows. - User shell: `user_shell.exec` backs `!cmd`. It is not exposed as an agent tool; it is advertised only when terminal access is enabled and records the command/result as model-visible user context without starting an assistant turn. Agent-facing local tool results: - Filesystem tools return structured dicts to the agent. The bridge transport still keeps pretty JSON in `output` for previews, but the canonical result is carried in `metadata` and unwrapped by the backend. - Filesystem errors include `status`, `error`, and where known `error_code` / `retryable` (for example `stale_write`, `concurrent_write`, `path_escape`, `unsupported_tool`, `tool_unavailable`, `timeout`). - `shell.exec` intentionally keeps its transport shape: `output` is stdout, `stderr` and `exit_code` are separate fields, and metadata carries `timed_out`, truncation flags, and the explicit non-sandbox boundary. ## Caveats - **Query-to-paper mapping is lost** in list-form search — all queries merge into one ranked list. Need per-query attribution? Call multiple times. - **Shared contract across surfaces**: `string_search` / `semantic_search` agent tools, the SDK routes, and this CLI all accept `query: str | list[str]`. What you learn here applies to `ask` / `exec` calls too. - **BM25 undercovers fragmented terminology.** For topics with unstable naming, do `search` then `related` — don't trust a single sweep. - **Parallel calls** need `RAPIDREVIEW_KEY` for robustness. OAuth refresh is serialized via file-lock but the API key path has zero lock contention. - **Billing**: everything is currently free. `cost_usd` fields in responses still populate (for observability) but you're not charged. `--estimate` / `--max-cost` exist as forward-looking guardrails. ## Invocation modes - `papyrus --headless ` — explicit agent path; non-TTY stderr infers the same mode. - `papyrus ` in an attached terminal — human one-shot, with live streaming where supported. - `papyrus` (bare) — interactive TUI for humans. - `papyrus login` — explicit OAuth flow (dev-container bootstrap).