Paperless-NGX Cortex is a separate intelligence layer for Paperless-ngx. It keeps Paperless as the source of truth, processes documents locally (sync, OCR layers, embeddings, suggestions), and supports explicit manual writeback only.
I built this because Paperless-ngx is excellent at storage and search, but I wanted a focused intelligence layer that can be audited, resumed, and controlled without ever auto-writing back. The goal is to make document understanding and metadata suggestions fast, local, and reviewable.
This started as personal project and is heavy biased towards my personal home setup. I thought, maybe the code, prompts, techniques or else could be useful for someone out there, looking to achieve similar.
- Keeps Paperless-ngx as the source of truth and never auto-writes.
- Adds local OCR quality checks and optional vision OCR without overwriting the baseline.
- Produces embeddings, semantic search, suggestions, and summaries you can review before applying.
- Handles large documents with resumable, observable pipeline steps.
- Adds per-document chat with follow-up question suggestions.
- Surfaces similar documents and potential duplicates from embeddings.
flowchart TD
A[Paperless-ngx] --> B[Sync metadata + baseline text]
B --> C{Need extra OCR?}
C -- No --> E[Embeddings]
C -- Yes --> D[Vision OCR optional]
D --> E
E --> F[Suggestions]
F --> G{Large doc?}
G -- Yes --> H[Page notes + hierarchical summary]
G -- No --> I[Review]
H --> I
I --> J[Manual writeback]
MVP(core intelligence layer): Done- Sync from Paperless, local storage, embeddings, semantic search, suggestions, queue/worker, manual writeback.
Phase 1(robustness + UX streamlining): Done- Pipeline hardening + triage/log observability baseline delivered.
Phase 2(advanced evidence locator / on-the-fly bbox resolution): Planned / partial design only- Spec exists, full implementation not complete yet.
- You can use the app end-to-end today.
- Current engineering focus is quality and reliability, not greenfield features.
- No automatic writeback to Paperless.
- All AI outputs are reviewed locally first.
- Writeback is explicit and manual.
- Local processing should be resumable, observable, and robust for large docs.
- Sync metadata + text baseline from Paperless.
- Optionally run vision OCR as additional layer (never overwrite baseline).
- Generate embeddings (paperless and/or vision source strategy).
- Generate suggestions (paperless/vision + best pick).
- For large docs: page notes + hierarchical summary.
- Review locally, then explicitly write back selected fields.
Per-document operations also allow targeted manual re-runs for individual steps (for example similarity_index) without forcing a full reset/reprocess.
- Python
>=3.13for the backend. - Node.js
>=18for the frontend. - Paperless-ngx instance reachable by URL and API token.
- Postgres, Redis, and a supported vector store (
QdrantorWeaviate) (local installs or Docker). - An OpenAI-compatible LLM endpoint (local or remote).
For user-facing operations and UI guidance, see
docs/manual/README.md.
cd backend
uv sync
uv run alembic upgrade head
uv run uvicorn app.main:app --reload --port 8000A pinned requirements.txt is generated at backend/requirements.txt.
cd backend
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
alembic upgrade head
uvicorn app.main:app --reload --port 8000To refresh requirements.txt from pyproject.toml:
cd backend
uv export --format requirements.txt --no-dev --output-file requirements.txtcd backend
uv run python -m app.workercd frontend
npm install
npm run dev- Copy
.env.exampleto.envand fill values. Do not commit.envto GitHub. - Ensure Postgres, Redis, and your active vector store are running.
- Create the database specified by
DATABASE_URL. - Run migrations with Alembic.
Example Postgres setup:
createdb paperless_intelligence
createuser paperlessExample migrations:
cd backend
uv run alembic upgrade headdocker compose -f docker-compose.app.yml up --builddocker compose -f docker-compose.full.yml up --buildImportant: LLM_BASE_URL must be set in your .env. It is not set in docker-compose.full.yml.
Docker uses :8000 for the API and serves the frontend from the backend container unless you run the frontend dev server separately.
docker compose -f docker-compose.worker.yml up --buildSet values in .env.
PAPERLESS_BASE_URLPAPERLESS_API_TOKENDATABASE_URLVECTOR_STORE_PROVIDER- vector-store-specific settings for Qdrant or Weaviate
LLM_BASE_URLTEXT_MODELEMBEDDING_MODEL
.env.examplefor concrete environment variables and example valuesdocs/config-reference.mdfor grouped runtime configuration guidancedocs/architecture-overview.mdfor the technical component overview
MANUAL.md: documentation entry pointdocs/manual/README.md: end-user manualdocs/manual/14-tages-checkliste.md: daily checklistdocs/manual/12-similar-workflow.md: similar-doc review workflowdocs/manual/13-team-policy.md: concise working rules
docs/manual/15-admin-und-betrieb.md: admin and UI operations guidedocs/manual/16-settings-und-live-model-provider.md: live model-provider settings and API-key behaviordocs/architecture-overview.md: architecture overviewdocs/config-reference.md: grouped configuration reference
CHANGELOG.md: granular change historyagents.md: compact project state and next actionsCONTRIBUTING.md: contribution notesdocs/execution-blueprint-large-doc-worker.md: large-document worker strategy
cd frontend
ORVAL_API_URL=http://localhost:8000/api/openapi.json npm run api:generateThe root VERSION file is the source of truth.
python scripts/sync_version.pyThis synchronizes:
backend/pyproject.tomlfrontend/package.jsonfrontend/src/generated/version.ts
GET /api/status exposes app_version, api_version, and frontend_version; the frontend footer renders them.
MIT License. See LICENSE.
Provided “as is”, without warranty of any kind.