Functions not in the linxiv CLI¶
What the web server provides that the linxiv CLI does not.
Compares the linxiv CLI that the web server wraps with the web server code in server/app/. Not an exhaustive diff.
Server-only code with no CLI command behind it¶
- Auth:
routes/auth.pyhas login, setup, logout and "me", plus the remember-me option (app/auth.py). - Knowledge graph:
routes/graph.pybuilds the payload in Python, because the CLI has no graph command. - AI features:
app/ai.pyandroutes/ai.pycall Gemini, OpenAI, Anthropic or a generic provider overhttpx. They cover tag suggestions, summaries (saved as a note) and metadata cleanup, with write-only keys stored in settings. - MCP over HTTP at
/mcp:app/mcp_bridge.pyandroutes/mcp.pyrunlinxiv-mcpas a subprocess per session. It has a bearer token that is shown once, stored as a sha256 hash under web-onlyweb_mcp_token_*keys, and can be rotated or revoked. The tool profile is read-only or read+write. - Background full-text worker:
app/fulltext_worker.pyruns as an asyncio task in the FastAPI lifespan.routes/sources.pyexposes the job queue (/jobs,/jobs/{id}/cancel,/sources/worker,/sources/pending). The "Index now" button also goes through this. - PDF layout and folder moves:
app/pdf_layout.pyandapp/pdf_text.py. Files are moved andPAPER_META.PDF_PATHis written straight into SQLite, because the CLI has no command to set a PDF location. - Direct external calls: PubMed via NCBI E-utilities (
routes/metadata.py), and bioRxiv/medRxiv as a source (DOI-only, 2 MB cap). POST /api/add:routes/add.pyclassifies the input (arXiv ID, DOI, publisher article link, PDF URL) on the server and then picks the CLI command. Publisher links (Nature, Springer, Wiley, ACS, APS, IOP, Science, PNAS and others) map to their DOI with the table from linXiv v0.7.0'srecognize.rs, which only the linXiv app andlinxiv-headlessuse. The publisher PDF is fetched on a best-effort basis: the server checks that the link returns a real PDF beforelinxiv pdf downloadstores it, because that command keeps whatever the link returns.- Metadata from the PDF's file name:
app/pdf_name.pyreads a title and a year folder from the stored PDF path.GET /papersandGET /papers/{id}flag titles that look like junk read from the PDF (title_suspect), andGET /papers/{id}/lookup?by=filenamesearches Crossref, OpenAlex, arXiv or PubMed with the file name's title instead of the stored DOI. - PDF full text:
routes/sources.pyextracts a saved PDF's text with pypdf and stores it withlinxiv paper set-text(linXiv v0.7.0). This works for one paper or as a job over every non-arXiv paper with a PDF. The CLI only fetches arXiv TeX source by itself.
Server-side logic layered on CLI results¶
- Author merge candidates:
name_candidatesis computed on the server (exact full name, case-folded, minus ORCID matches and self). The CLI lacks this. - Author list filter: the "hide single-paper authors" filter runs server-side, because the CLI has no flag for it.
- ORCID checks: format,
orcid.orgURL prefix stripped and check digit. The CLI stores any string. - Annotation anchors: validated with strict pydantic and re-serialized to
{v,version,page,color,quote,rects}. The CLI stores any string. - Library search: local match plus
paper searchfor queries of 3+ characters, merged. If the deep search fails, you get the plain hits plus anX-Deep-Search-Errorheader. - Project export: one
GET /projects/{id}/export?format=…that streams the file back and uses the linXiv desktop app's slugified filename. - Project import: a stateless preview step, then a commit that re-uploads the file.
- Upload endpoints: bibtex, zotero and PDF import take uploads instead of host paths.
Web UI features with no CLI or server counterpart¶
- Search history in localStorage, honoring the shared
search_history_enabledand_maxsettings, plus a "Clear search history" button the linXiv desktop app lacks. - Batch metadata edit, which reuses
GET …/lookupandPUT …/metadataper paper, one at a time. - Crossref search tab (the CLI supports it, the linXiv desktop app doesn't) and a Query Builder for arXiv.
- Zoom and density settings per browser.
- Upload and Trash sidebar toggles that exist only in the web app.
- Settings groups with
#iddeep links.
Blocked on the CLI¶
These exist in linXiv, but only in the linxiv-headless HTTP API (linXiv docs/api.md), not in the CLI or linxiv-mcp (checked against v0.7.0). linXiv-web would need either new upstream CLI commands or linxiv-headless as its backend. The headless server cannot share the library with the CLI, because linXiv allows one process per library.
| Feature | linxiv-headless route | linXiv-web today |
|---|---|---|
| Per-paper reading status | GET /api/reading-status, PUT /api/reading-status/{sid} |
Not available |
| Link or unlink one paper and one author | POST / DELETE /api/authors/{id}/papers/{pid} |
Merge whole authors only |
| Change a highlight's anchor or color in place | PATCH /api/annotations/{id} |
A color change deletes the highlight and creates a new one |
| Clear a project's color | PATCH /api/projects/{id} with color_hex: null |
Color can be set but not cleared |
| Saved search state and history shared with the app | GET / POST /api/search/state, GET /api/search/history |
History is kept per browser |
| TeX diff between two versions of a paper | GET /api/papers/{id}/full-text-diff |
Not available |
| Backups taken before schema upgrades | GET /api/storage/pre-migration-backups |
Not listed |