paperless-ngx with ai document tagging
Paperless-NGX scans, OCRs, and archives documents. adding an AI sidecar means every document that comes in gets automatically titled, tagged, and assigned a correspondent — without any manual sorting.
the problem with documents
PDFs accumulate fast. bank statements, insurance forms, receipts, medical records. manually tagging each one takes time and consistently doesn't happen. the result is a pile of documents named scan_2024_03_14.pdf that can't be found when you need them.
paperless-ngx
Paperless-NGX is a document management system. it watches a consume folder, OCRs anything that lands there, and stores it in a searchable archive. you can tag documents, assign correspondents (who sent it), set document types, and search full text.
it can also pull from email. a Gmail IMAP rule watches for PDF attachments and automatically imports them into the consume pipeline.
the ai sidecar
Paperless-AI runs alongside Paperless-NGX as a separate container. it watches for newly consumed documents, sends the text to an LLM, and applies the returned tags and title back via the Paperless API.
the model here is deepseek/deepseek-chat via OpenRouter — an OpenAI-compatible API endpoint that routes to various models. the AI reads the document content and returns structured metadata: a clean title, relevant tags, and a correspondent name.
the gmail rule
Paperless can poll a Gmail account via IMAP and import attachments automatically. a few settings matter:
- folder:
[Gmail]/All Mail— not INBOX. archived emails won't be in INBOX. - action: Flag (not Mark as read). "Mark as read" only works on unread emails. "Flag" is the only action that lets you process already-read and archived mail.
- scope: Only attachments,
*.pdffilter — otherwise Paperless tries to consume the raw email body as a document.
gotchas
don't hardcode the API token in the compose file. if you ever delete the stack with volumes, Postgres gets wiped, the admin user is regenerated, and the API token changes. entering it through the Paperless-AI UI wizard means you just update it in one place. hardcoding means broken deploys.
the API URL must use the Docker service name. Paperless-AI needs to reach Paperless-NGX over the Docker network. http://webserver:8000 works. http://10.0.3.21:8010 (the host IP) fails because the request goes out to the host and back in — Docker routing doesn't handle this the way you'd expect.
Paperless-AI settings don't survive a redeploy. the sidecar stores its config (API keys, model settings) in /app/data/.env inside the container. no volume is mounted there by default, so a container recreation wipes the config. the fix is a bind mount to persist the settings file — worth adding to the compose before you need it.
eli5
imagine a mail room (Paperless-NGX) that receives every document you own, scans it, and files it in a cabinet. previously someone had to read each document and write the label on the folder. now there's an assistant (the AI sidecar) who reads each document as it comes in, figures out what it is, and writes the label automatically. if it's a bank statement from Chase, it gets tagged "bank statement," assigned to "Chase," and titled "Chase Statement March 2024." the Gmail rule is like a dedicated inbox that automatically forwards any PDF attachments from your email to the mail room as soon as they arrive.