AI-assisted discovery for scientific papers.
π Live Demo
Searching arXiv means knowing the right keywords. Ask it a real question β "how do transformers actually handle long context?" β and keyword matching gives you nothing useful. Researchers think in concepts; the search box wants terms.
PaperMind puts a language model between your question and the search index. You ask in plain English, an LLM distils it into the terminology the archive expects, and you get papers back β no query-crafting required.
Type a question, not keywords. A Groq-hosted model condenses it into a precise search phrase before the query reaches arXiv.
"What are the latest breakthroughs in quantum computing?" β
quantum computing breakthroughs
If the model is unavailable, the search falls back to your raw query rather than failing.
- Classic β a paginated grid of paper cards with expandable abstracts.
- Swipe β one card at a time, drag to move through the deck. Reaching the end loads more.
Every card links to the PDF and the arXiv abstract page.
Every result opens onto /article/<arXiv id> β the full abstract, authors, categories, DOI, author comments, and links to the PDF and the arXiv record. Old-style identifiers with a slash (cs/0701001) work as well as modern ones.
Papermind keeps its own copy of every paper it has seen, so these pages keep resolving when arXiv is rate limiting or down β which, in practice, is often.
Any paper can be shared as a card image with a QR code that points back at its Papermind page. It is the same image social platforms show when the link is posted, so the preview and the downloaded PNG never drift apart.
Shared folders of papers. Create one, add papers from anywhere in the app, and invite people with a link that expires after a week. Members add and remove their own papers; the owner can remove any of them, rename the group, hand it over, or delete it while they are still its only member.
Sign up to bookmark papers to your profile. Auth is a hand-rolled JWT setup in HttpOnly cookies with bcrypt hashing, silent token refresh, distributed rate limiting, account lockout after repeated failures, and Postmark-delivered password resets. Accounts can be deleted outright: owned groups pass to their longest-standing member, and contributions stay behind without a name.
| Component | Technology | Why |
|---|---|---|
| Framework | Next.js 16 (App Router) | Route handlers + React 19, deployed serverless |
| Database | MongoDB Atlas | Document store for users and saved papers |
| LLM | Groq (openai/gpt-oss-120b) |
Sub-second keyword extraction |
| LLM plumbing | Vercel AI SDK | Thin, provider-agnostic wrapper |
| Papers | arXiv API | Live access to pre-prints |
| Auth | jsonwebtoken + bcryptjs |
Cookie-based sessions, no third-party dependency |
| Postmark | Password-reset delivery | |
| Styling | Tailwind CSS v4 + Motion | Utility-first CSS, spring animations |
This project uses Bun.
git clone https://github.com/alangnt/papermind.git
cd papermind
bun installCreate .env.local:
# Required
MONGODB_URI= # MongoDB Atlas connection string
MONGODB_NAME= # database name, e.g. Astra
SECRET_KEY= # signing key for access tokens
# Recommended
GROQ_API_KEY= # without it, search uses your raw query verbatim
POSTMARK_SERVER_TOKEN= # without it, password reset returns 500
WEBSITE_URL= # absolute URL used in reset emails (default: http://localhost:3000)
REFRESH_SECRET_KEY= # separate key for refresh tokens (default: SECRET_KEY)
# Optional β sensible defaults exist
ALGORITHM=HS256
REFRESH_ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30
REFRESH_TOKEN_EXPIRE_MINUTES=43200Note:
MONGODB_NAMEhas no default. A fallback would let a misconfigured deployment silently read and write the wrong database, so the app throws instead.
Unique indexes on users.username and users.email are what actually prevent duplicate accounts β without them, concurrent sign-ups race. Check first, then apply:
bun run db:indexes:check # dry run, writes nothing
bun run db:indexes # creates them; refuses if duplicates already existbun run devOpen http://localhost:3000.
| Script | Purpose |
|---|---|
bun run dev |
Dev server with Turbopack |
bun run build |
Production build |
bun run lint |
ESLint β fails on any warning |
bun run lint:fix |
ESLint with autofix |
bun run format |
Prettier across the repo |
bun run knip |
Report unused files, exports and dependencies |
bun run db:indexes |
Create the required MongoDB indexes (idempotent) |
bun run test |
Vitest β the whole suite, needs MONGODB_URI |
bun run test:unit |
Everything that does not touch the database |
bun run test:watch |
Vitest in watch mode |
A husky pre-commit hook runs lint and test:unit, and blocks the commit on any finding. The database-backed suites run against a scratch database on the same cluster, wiped before and after; they are skipped when no connection string is available, so a commit never depends on the network.
Semantic vector search is the headline goal and is not implemented yet. Finishing it needs an embedding model wired in β either @xenova/transformers in-process or a hosted embeddings API β and then the aggregation below over a documents collection carrying an embedding field.
[
{
$vectorSearch: {
index: 'search_similar',
path: 'embedding',
queryVector: [], // the embedded query goes here
numCandidates: 200,
limit: 10,
},
},
{
$project: {
_id: 0,
id: 1,
pdfLink: 1,
title: 1,
summary: 1,
authors: 1,
published: 1,
score: { $meta: 'vectorSearchScore' },
},
},
];- π§ Vector search β embed abstracts, retrieve by concept similarity
- π¬ RAG answers β synthesise a cited answer from retrieved abstracts
- βοΈ Email verification β accounts are currently auto-verified on sign-up
- π Group discovery β public groups, browsable, alongside today's invite-only ones
- π Notifications β tell members when a paper lands in a group they are in
- β‘ Query caching β arXiv responses are cached for a day
- π Distributed rate limiting β limits live in MongoDB, shared across instances
- π§ͺ Test suite β Vitest, with the database-backed rules covered against a real server
- Data source: arXiv API
- Inference: Groq
- LLM SDK: Vercel AI SDK
Thank you to arXiv for use of its open access interoperability.