research-agent
Your long-term research memory — papers indexed, gaps found, reports generated
What is this?
research-agent is a research server for AI agents: it indexes papers (arXiv, Semantic Scholar, local PDFs) into a local SQLite library, and your agent drives it over MCP — ingesting, searching, tracking reading progress, analyzing coverage gaps with its own model, and filing survey reports. No API key required.
The same binary also works as a standalone CLI for terminals and scripts.
Web UI
Showcase
The Ontology Lineage — 2,300 years of ontology research distilled into one static page (Korean · English): a lineage timeline, an integrated architecture, a five-stage learning route, and a browser for all 425 papers — collected, gap-analyzed, and organized with research-agent. The Uncanny Valley of AI Writing — why readers turn away from AI-generated text, fact-checked (Korean · English): 5 cited sources independently verified, 86 papers from arXiv/OpenAlex mapped across 7 themes, counter-evidence, and a 4-gap ledger — collected, gap-analyzed, and organized with research-agent.
Features
Quick Start
Install it as a plugin in your AI agent — no Rust toolchain needed:
Claude Code
claude plugin marketplace add epicsagas/research-agent
claude plugin install research-agent@research-agent
Codex
codex plugin marketplace add epicsagas/research-agent
codex plugin add research-agent@research-agent
Antigravity (agy)
agy plugin install https://github.com/epicsagas/research-agent
agy plugin enable research-agent
Grok Build
grok plugin marketplace add epicsagas/research-agent
grok plugin install research-agent@research-agent --trust
Hermes Agent
hermes plugins install https://github.com/epicsagas/research-agent
hermes plugins enable research-agent
Hermes loads the root plugin.yaml and register(ctx) in __init__.py.
It has no MCP support, so the agent drives research through the bundled
skill's CLI commands — install the binary first (brew install epicsagas/tap/research-agent or the curl installer); the SessionStart
auto-install hook does not apply to hermes. If skills_guard blocks the
install scan, set plugins.scan_on_install: false in the hermes config.
The plugin auto-installs the research binary on session start and exposes
18 MCP tools, so the agent can ingest, search, analyze with its own model, and file reports on its own.
Once installed, ask your agent things like:
- "Ingest recent papers on graph neural network training from arXiv"
- "What gaps are left in my coverage?"
- "Generate a survey report for "
What those requests look like on the tool level:
Everything runs against one local SQLite library (default
~/.research/research.db). For a project-private library, point the server at
a different file once in the host's MCP config ("args": ["mcp", "--db", "./project.research.db"], --db is a global flag), or have the agent pass
--db on skill/CLI invocations.
How your agent uses it
The plugin auto-installs the research binary on session start and starts the
stdio MCP server (research mcp) — the agent discovers and calls the tools
directly; no human typing CLI commands.
Tools (18): init · ingest · index_rebuild · import_papers ·
paper_body · paper_references · query_papers · topic_brief ·
gaps_record · list_gaps · report_material · report_save ·
topics_list · topic_add · state · update_read ·
papers_missing_keywords · enrich_paper.
Analysis is agent-native: topic_brief and report_material hand over the
structured library state (papers, reading progress, recorded gaps, coverage),
the agent reasons over it with its own model, and gaps_record / report_save
persist the findings. When inspecting text, paper_body accepts an optional query
to return anchored evidence snippets (with section and page) instead of the whole body,
saving context. No [llm] config or API key is required anywhere in the
MCP flow.
Smoke test the server over raw JSON-RPC:
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"t","version":"0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
| research mcp 2>/dev/null
The mcp cargo feature is on by default; build CLI-only with
cargo build --no-default-features.
Standalone CLI (secondary)
Prefer driving it by hand? The same binary works as a plain CLI.
# macOS / Linux — pre-built binary, no Rust required
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/epicsagas/research-agent/releases/latest/download/install.sh | sh
# Windows — pre-built binary, no Rust required
irm https://github.com/epicsagas/research-agent/releases/latest/download/install.ps1 | iex
# Homebrew (macOS / Linux)
brew install epicsagas/tap/research-agent
Using the dashboard
Same database, visual side. Launch it from a terminal, browse it in a browser:
research dashboard # then open http://127.0.0.1:7777 (loopback only)
Typical loop: check Overview for topic coverage, open Results for the recorded gaps, go back to the terminal and aim the next ingest at those gaps, then track reading progress under Papers.
First-run onboarding
Run research init in a terminal and it walks you through the settings that
matter: database location, the LLM provider used for gap analysis and reports
(the key itself is read from the env var you name, never stored in the file).
Local servers (Ollama, LM Studio) are probed for their
loaded models so you pick from what actually exists. Re-running it is safe:
existing values become the defaults and nothing is reset.
Everything that is configurable shows up in ~/.research/config.toml:
options you have not set appear as commented-out lines with their defaults,
so the file documents itself. research init --no-onboard skips the prompts
(also automatic when stdin is not a terminal, so scripts are never blocked).
Updating
Verify the installed version:
research --version
Commands
Verifying the Zotero push needs a running Zotero (10+ for writes): run
cargo test zotero_write -- --ignored for the live read, then do one
research export --to zotero --apply against a test item and confirm the tag
appears in Zotero. Writes pop a per-item confirmation dialog unless you pick
"Always Allow" (confirmations are capped at five per minute).
Every subcommand also accepts a global --db <path> flag to use a specific
database instead of ~/.research/research.db — useful for isolated or test
workspaces.
Example workflows
Research loop: survey, find gaps, fill them
research init # first run only: sets up DB + LLM settings
research topics add "Graph DB internals" # prints the topic ID
research ingest "latch-free graph database" --topic <TOPIC_ID> --limit 20
research gaps --topic <TOPIC_ID> # what the survey missed
# aim the next ingest at what the gap analysis flagged:
research ingest "MVCC snapshot isolation graph store" --topic <TOPIC_ID>
research status # papers, coverage, gaps per topic
research gaps and research report use the [llm] provider from
onboarding; without one they return placeholders instead of failing.
Find something already ingested
research query "latch-free transaction" --evidence # matches body text, shows section and page
research read <PAPER_ID> --body # dump the stored full text
research read <PAPER_ID> --status completed --rating 5
One library per project
research --db ./project.research.db init
research --db ./project.research.db ingest "your topic" --topic <TOPIC_ID>
research dashboard --db ./project.research.db
Requirements
- Rust 1.92+ (only if building from source; pre-built binaries need nothing)
- Data lives at
~/.research/(research.dbindex,config.toml) - Linux binaries target glibc ≥ 2.38 (Ubuntu 24.04+)
- Optional: an LLM for
research gaps/research reportfrom the CLI only — set[llm]in~/.research/config.toml(provider,model,api_key_env, andbase_urlfor OpenAI-compatible endpoints); the key is read from that env var at call time. The MCP flow never needs it - Config reference:
[dashboard] port(default 7777), plushostandtokenwhen you bind beyond loopback — a token is generated intoconfig.tomland required for every request - Optional:
research enrichadds search keywords so queries worded differently from the abstract still find the paper. It uses[llm]when set; without one it prints the papers needing keywords, for an agent (or you) to fill in viaresearch enrich <ID> --keywords "...". See ROADMAP.md for what is deliberately not built yet
Contributing
See CONTRIBUTING.md and the ROADMAP. PRs welcome.