AI-powered academic article screening and analysis tool
Project description
Lutz
Languages: English | Português | Español
AI-powered tool for organizing, screening, and analyzing academic PDF articles — with a full browser interface and command-line access.
Tags: systematic review, academic screening, scientific articles, generative AI, LLM, RAG, embeddings, PDF, LanceDB, Python, open science, academic research.
Lutz helps researchers, students, and literature review teams work with large sets of PDF articles. It creates a reproducible project structure, processes and embeds PDFs into a local vector database, and uses language models to screen, analyze, and chat about your articles — all through a browser interface or the command line.
The package is named after Bertha Maria Julia Lutz, an important Brazilian scientist, biologist, and researcher who contributed to biology and to the recognition of science in Brazil.
What's new in v0.3.0
- React web interface — full browser UI replacing the previous Streamlit prototype. Faster, more responsive, works on any device on the local network.
- Background jobs — vectorize, analyze, and extract citations while freely navigating the interface. A notification bell tracks every job.
- Chat with sessions — conversation history persisted on disk, automatic memory extraction, and support for context files alongside articles.
- Reading roadmap — LLM-generated staged reading plan that groups and orders relevant articles by dependency.
- Inline PDF viewer — open any article directly in the browser without leaving the interface.
- Smart rename — suggest a clean filename from the article's own content with one click, no vectorization required.
- Multi-provider LLM/embedding — OpenAI, Anthropic, Docker Model Runner, Ollama, llama.cpp — configurable from the Settings page.
- Windows installer — one-click setup wizard with license, shortcuts, and uninstaller; no Python or Node required.
Table of contents
- Installation
- Quick start
- Web interface
- Model configuration
- CLI reference
- Complete systematic review workflow
- How to write prompts
- Security model
- Architecture
- Contributing
- How to cite
- License
Installation
Windows — installer (recommended for non-technical users)
Download lutz-setup-windows-x64.exe from the latest release and run it. The wizard will:
- Show the MIT license agreement
- Let you choose the install directory
- Create a Start Menu entry and optional Desktop shortcut
- Register an uninstaller in Windows Settings → Apps
After installation, open Lutz Research from the Start Menu. The browser interface opens automatically.
No Python or Node.js required. Everything is bundled in the installer.
pip (Python users)
pip install lutz-research
lutz web
Requires Python 3.10+. A virtual environment is recommended:
python -m venv .venv
source .venv/bin/activate # Linux / macOS
.\.venv\Scripts\Activate.ps1 # Windows PowerShell
pip install lutz-research
lutz web
uv (fast, isolated — recommended for Linux / macOS)
uv installs and runs the tool in a fully isolated environment with a single command:
uv tool install lutz-research
lutz web
To update later:
uv tool upgrade lutz-research
Docker
Ideal for servers, shared environments, or Linux users who prefer containers:
# Start the server, mounting your project directory
docker run -v $(pwd):/project -p 8765:8765 ghcr.io/jooguilhermesc/lutz
# Then open http://localhost:8765 in your browser
The container bundles the full stack (Python, dependencies, React UI). Your article files and reports live in the mounted /project directory and are never copied into the image.
From source
git clone https://github.com/jooguilhermesc/lutz.git
cd lutz
pip install -e ".[dev]"
Build the React frontend to use the web interface from source:
cd web && npm ci && npm run build
cd ..
lutz web
Quick start
# 1. Create a new project
mkdir my-review && cd my-review
lutz init
# 2. Copy your PDFs into articles/ (or upload via the web interface)
lutz load --f ~/Downloads/pdfs --so linux
# 3. Open the web interface
lutz web
The browser opens at http://localhost:8765. From there you can vectorize articles, run analyses, chat with your corpus, and generate reports — no more command line needed.
Web interface
lutz web starts a local FastAPI server and opens the browser automatically.
lutz web # default: localhost:8765
lutz web --port 8080 # custom port
lutz web --host 0.0.0.0 # expose on local network
lutz web --no-browser # server only, no auto-open
lutz web --project /path/to/project # explicit project directory
Pages
Home
Project dashboard showing article count, vectorized chunks, analyses run, and quick-action buttons. Entry point for first-time setup.
Library (Vetorização)
Upload PDFs via drag-and-drop or file picker. View all articles with size, vectorization status, and a one-click rename suggestion. Start vectorization as a background job and navigate freely while it runs.
Vector Store
Inspect the LanceDB index: total chunks, unique documents, embedding model, last update. Query the index directly with DuckDB SQL. Reset the store when you need to rebuild from scratch.
Analysis
Write or upload a Markdown prompt, choose RAG or per-article mode, set workers and chunk limits, and dispatch the analysis as a background job. A live log panel appears on the page if you return while the job is still running.
Citations
Select a per-article analysis report and extract the 3–5 passages that best justify each article's classification. Runs as a background job with real-time progress.
Roadmap
Generate a staged reading plan from your relevant articles. The LLM groups articles by conceptual dependency and suggests an order for reading.
Reports
Table of all past analyses. Click any row to expand the full results, including per-article verdicts, analysis text, token usage, and model metadata. Download JSON reports.
Chat
Conversational interface over your corpus. Each conversation is a persistent session saved to disk. The assistant can search the article vector store, attached context files, or use only its own knowledge — configurable per message. Memories pinned manually or extracted automatically from conversations are shown in a sidebar panel.
Settings
Configure LLM and embedding providers, API keys (write-only — never displayed after saving), base URLs, response language, and model parameters. Changes are saved to .env immediately.
Background jobs and notifications
Long-running operations (vectorize, analysis, citations, roadmap) run as server-side background tasks. A bell icon in the top bar shows a badge when jobs are running or completed. Clicking it opens a panel with status, elapsed time, and the option to cancel in-progress jobs. If you navigate away from a page while a job is running, an Active Job panel appears when you return, allowing you to reconnect to the live log stream.
Model configuration
Configuration lives in .env at the project root, created from .env.example by lutz init. It can also be edited from the Settings page in the web interface.
Docker Model Runner (local, no API key)
EMBEDDING_PROVIDER=docker_model_runner
EMBEDDING_MODEL=nomic-embed-text
LLM_PROVIDER=docker_model_runner
LLM_MODEL=ai/llama3.2
DOCKER_MODEL_HOST=http://localhost:12434/engines/v1
Pull models first:
docker model pull nomic-embed-text
docker model pull ai/llama3.2
Ollama (local, no API key)
EMBEDDING_PROVIDER=sentence_transformers
EMBEDDING_MODEL=all-MiniLM-L6-v2
LLM_PROVIDER=openai
OPENAI_BASE_URL=http://localhost:11434/v1
OPENAI_API_KEY=ollama
LLM_MODEL=llama3.2
OpenAI
EMBEDDING_PROVIDER=openai
EMBEDDING_MODEL=text-embedding-3-small
LLM_PROVIDER=openai
OPENAI_API_KEY=your-key-here
LLM_MODEL=gpt-4o-mini
OpenRouter (free models available)
EMBEDDING_PROVIDER=sentence_transformers
EMBEDDING_MODEL=all-MiniLM-L6-v2
LLM_PROVIDER=openai
OPENAI_BASE_URL=https://openrouter.ai/api/v1
OPENAI_API_KEY=your-key-here
LLM_MODEL=google/gemma-3-12b-it:free
Anthropic
EMBEDDING_PROVIDER=sentence_transformers
EMBEDDING_MODEL=all-MiniLM-L6-v2
LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=your-key-here
LLM_MODEL=claude-haiku-4-5-20251001
Configuration reference
| Variable | Purpose | Default |
|---|---|---|
LLM_PROVIDER |
openai, anthropic, or docker_model_runner |
— |
LLM_MODEL |
Model name for analysis and chat | — |
LLM_MAX_TOKENS |
Maximum response size | 4096 |
LLM_TEMPERATURE |
Response variation | 0.2 |
EMBEDDING_PROVIDER |
openai, sentence_transformers, or docker_model_runner |
— |
EMBEDDING_MODEL |
Embedding model name | — |
OPENAI_API_KEY |
Key for OpenAI or compatible services | — |
OPENAI_BASE_URL |
Alternative base URL for OpenAI-compatible APIs | — |
ANTHROPIC_API_KEY |
Anthropic API key | — |
DOCKER_MODEL_HOST |
Docker Model Runner address | — |
REPORT_LANGUAGE |
Language for generated reports | português |
CLI reference
The full workflow is also available from the command line. The CLI and the web interface share the same project structure and .env.
lutz init [PROJECT_NAME]
Creates a new project with articles/, prompts/, analysis/execution_reports/, .env.example, .gitignore, and a local Git repository.
lutz init
lutz init my-review
lutz load --f FOLDER [--so OS] [--overwrite]
Copies PDFs from a source folder into articles/.
lutz load --f ~/Downloads/articles --so linux
lutz load --f "C:\Users\Ana\Downloads\articles" --so windows
lutz vectorize [options]
Processes PDFs and creates the vector index in .lutz/vector_store/.
| Option | Description | Default |
|---|---|---|
--chunk-size |
Chunk size in words | 512 |
--chunk-overlap |
Overlap between chunks | 64 |
--extraction |
Extraction backend: pymupdf, marker, or auto (see below) |
pymupdf |
--section-parse |
Split articles into labeled sections before chunking | disabled |
--skip-security |
Skip PDF security checks | disabled |
--quarantine |
Process files in articles/_quarantine/ |
disabled |
lutz vectorize
lutz vectorize --section-parse # section-aware chunking
lutz vectorize --chunk-size 256 --chunk-overlap 32
lutz vectorize --extraction marker # OCR + multi-column layout
lutz vectorize --extraction marker --section-parse
lutz vectorize --extraction auto # auto-detect scanned PDFs
Extraction backends
| Document type | Recommended backend | Reason |
|---|---|---|
| Digital article, single column | pymupdf (default) |
Fast, no extra deps |
| Digital article, 2+ columns (IEEE, Elsevier, ACM) | marker |
Layout detection |
| Scanned book or old article | marker |
OCR via surya |
| Mixed corpus | auto |
Detects and adapts per file |
# Install the marker backend (model weights ~500 MB, downloaded once)
pip install "lutz-research[marker]"
lutz vectorize --extraction marker
The marker backend handles multi-column layouts and scanned PDFs without requiring Poppler or Tesseract. When --section-parse is combined with --extraction marker, sections are parsed directly from the Markdown headings that marker produces — no layoutparser needed.
lutz analysis --p PROMPT [options]
Analyzes vectorized articles using a Markdown prompt.
| Option | Description | Default |
|---|---|---|
--p |
Path to the .md prompt |
required |
--per-article |
One model call per article | disabled (RAG mode) |
--workers |
Parallel calls in per-article mode | 1 |
--top-k |
Chunks to retrieve in RAG mode | 10 |
--max-chunks-per-article |
Chunk limit per article | no limit |
--filter-sections |
Restrict to specific sections | no filter |
--multiple |
Path to a YAML multi-experiment file | — |
lutz analysis --p prompts/screening.md --per-article --workers 4
lutz analysis --p prompts/methodology.md --filter-sections methodology,results
lutz citations --analysis FILE [options]
Extracts the key passages that justify each article's classification.
lutz citations --analysis analysis/execution_reports/screening_<ts>.json \
--workers 4 --only-relevant
lutz vector-store [options]
Inspects the vector index.
lutz vector-store --summarize
lutz vector-store --sections # section breakdown per article
lutz vector-store --export # JSON export
lutz unvectorize
Deletes the vector index. PDFs are not affected.
Complete systematic review workflow
# 1. Create project
lutz init my-review && cd my-review
# 2. Configure AI model (.env or Settings page in the web UI)
cp .env.example .env
# 3. Add PDFs
lutz load --f ~/Downloads/articles --so linux
# 4. Vectorize with section-aware parsing
lutz vectorize --section-parse
# 5. Screen articles by abstract (fast and cheap)
lutz analysis --p prompts/screening.md --per-article --workers 4 \
--filter-sections abstract
# 6. Deep analysis on methodology and results
lutz analysis --p prompts/methodology_analysis.md \
--filter-sections methodology,results
# 7. Extract citations from relevant articles
lutz citations \
--analysis analysis/execution_reports/screening_<timestamp>.json \
--workers 4 --only-relevant
# 8. Inspect the index
lutz vector-store --summarize --sections
Or open lutz web and do all of the above from the browser.
How to write prompts
Prompts are Markdown files inside prompts/. They tell the model what to analyze.
# Screening prompt
## Objective
Determine whether each article describes a study that applies machine learning
to predict clinical outcomes in ICU patients.
## Inclusion criterion
Include articles that: use supervised or unsupervised ML; analyze ICU patient data;
report a clinical outcome (mortality, length of stay, readmission).
## Exclusion criterion
Exclude: review articles without original data; studies outside the ICU context;
studies using only statistical methods without ML.
## Response format
1. Summary of the article's approach (2–3 sentences).
2. Evidence for or against inclusion.
3. Verdict: INCLUDE, EXCLUDE, or UNCERTAIN.
lutz init creates ready-to-edit templates: systematic_review.md, methodology_analysis.md, evidence_quality.md, thematic_synthesis.md.
Security model
Before vectorizing, Lutz checks PDFs to reduce common risks.
| Check | What it detects |
|---|---|
| Structural analysis | Embedded JavaScript, automatic actions, XFA forms |
| Prompt injection | Phrases attempting to override model instructions |
| Academic structure | Basic signs of academic articles (abstract, methodology, references) |
| Corpus anomaly | Statistical outliers when 5 or more documents are present |
Suspicious files are moved to articles/_quarantine/. To process them after manual review:
lutz vectorize --quarantine
Architecture
lutz/
├── cli.py # Click CLI entry point
├── commands/
│ ├── init.py # lutz init
│ ├── load.py # lutz load
│ ├── vectorize.py # lutz vectorize / unvectorize
│ ├── analysis.py # lutz analysis
│ ├── experiments.py # --multiple YAML runner
│ ├── citations.py # lutz citations
│ ├── vector_store.py # lutz vector-store
│ └── web.py # lutz web (FastAPI launcher)
├── core/
│ ├── security_checker.py # PDF security checks
│ ├── extraction.py # pluggable extraction strategies (PyMuPDF, marker)
│ ├── pdf_processor.py # text extraction and chunking
│ ├── section_parser.py # section detection
│ ├── vector_store.py # LanceDB wrapper
│ ├── context_store.py # chat context file store
│ ├── embedding_client.py # embedding providers
│ └── llm_client.py # LLM providers
├── server/
│ └── app.py # FastAPI server (REST + SSE + WebSocket)
├── web/ # pre-built React SPA (bundled in wheel)
└── utils/
├── html_report.py # HTML report generation
├── document_reader.py # multi-format extraction (PDF, DOCX, XLSX…)
├── project.py # project detection and .env loading
└── templates.py # files created by lutz init
web/src/ # React 18 + Vite + Tailwind (source)
├── pages/ # one component per page
├── components/ # shared UI components
│ ├── ActiveJobPanel.tsx # reconnects to running job log on page return
│ ├── NotificationsPanel.tsx # bell icon + job status dropdown
│ └── ConfirmDialog.tsx # delete confirmation dialogs
└── contexts/
├── NotificationsContext.tsx # WebSocket job state (global)
└── LanguageContext.tsx # i18n (pt / en / es)
The vector index lives in .lutz/vector_store/ inside the project (LanceDB format). Chat sessions and memory are stored in .lutz/chat/. Neither should be committed to Git.
Contributing
Contributions are welcome. To set up a development environment:
git clone https://github.com/jooguilhermesc/lutz.git
cd lutz
pip install -e ".[dev]"
# Build the React frontend
cd web && npm ci && npm run build && cd ..
lutz web
Before proposing large changes, open an issue to discuss the idea.
How to cite
If you use Lutz in your research, please cite it using the information below or refer to the CITATION.cff file.
APA
Cabral, J. G. S., & Azevedo Farias, A. K. (2026). Lutz: AI-powered academic article screening and analysis tool (Version 0.3.0) [Software]. Zenodo. https://doi.org/10.5281/zenodo.19982571
BibTeX
@software{cabral2026lutz,
author = {Cabral, João Guilherme Silva and Azevedo Farias, Anna Karoline},
title = {{Lutz: AI-powered academic article screening and analysis tool}},
year = {2026},
version = {0.3.0},
doi = {10.5281/zenodo.19982571},
url = {https://github.com/jooguilhermesc/lutz},
license = {MIT}
}
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lutz_research-0.3.1.tar.gz.
File metadata
- Download URL: lutz_research-0.3.1.tar.gz
- Upload date:
- Size: 11.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
06becea537d9292c1e893b7f6b451966d38cf9d14491fecec31d9cbb9cc2a1dd
|
|
| MD5 |
4ff5a8dfb7d54037f6243e2b6effa4c0
|
|
| BLAKE2b-256 |
4ab2acc1392263b2b91f47083e710eb3774a2dcb07e56b769a051ef35d7464a9
|
File details
Details for the file lutz_research-0.3.1-py3-none-any.whl.
File metadata
- Download URL: lutz_research-0.3.1-py3-none-any.whl
- Upload date:
- Size: 2.9 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c1b9101c396aea47d523ce39ca4def29c8519a00ea7e93a7d078ce87a7603fcc
|
|
| MD5 |
3e37efafedb3d13c266fbc1a24e45a3b
|
|
| BLAKE2b-256 |
3a771e1b7eee2d85e38ad5691fffaf1daa2a8be84124e9fe3ec4626c23da54fc
|