Erin Skidds757 downloadsOrganize and manage attachments, rename pasted files, and extract text via OCR — all within your Obsidian vault.
Note: This plugin is being vibe coded. So, if you are not wanting AI code in your vault, please do not use this plugin. Though I am a full time Full Stack Developer so I can validate none of the code is leaking secrets or collecting personal data if that helps you.
A comprehensive Obsidian plugin that organizes and manages attachments, renames pasted files automatically, and extracts text from images and PDFs using OCR — all within your vault.
{{year}}, {{month}}, {{day}}, {{type}}, {{filename}}{{year}}, {{month}}, {{day}}, {{time}}, {{type}}, {{filename}} (active note name), {{original}} (pasted file's original name)_files → _ocr) while preserving nested pathsDudeThatsErin/vaultkeeper_files beside each linking note (for example 02 - Journals/August/_files)attachments)Ctrl/Cmd+P)2026-05-04.png){{year}}, {{month}}, {{day}}, {{time}}, {{type}}, {{filename}} (note name), {{original}} (pasted file's original name)_files folder), Obsidian's attachment folder, or Vaultkeeper's organize destination_files → _ocr), a specific folder, the source file's folder, Obsidian's attachment folder, or Vaultkeeper's organize destinationPull a multimodal model — a text-only model will fail with "model does not support multimodal requests":
ollama pull qwen2.5vl:7b
Then set Custom server base URL to http://localhost:11434/v1 and Custom model to qwen2.5vl:7b. Nothing leaves your machine. Raise Custom request timeout if the model runs on CPU.
PDFs are only supported by Gemini and Anthropic. OpenAI and self-hosted vision models take images only — convert pages to images first.
| Command | Description |
|---|---|
OCR: Process all files (new + existing) |
OCR every compatible file in the watch scope, overwriting existing OCR notes |
OCR: Process new files only |
OCR only files that do not already have an OCR note |
OCR: Re-process existing files |
Re-OCR only files that already have an OCR note |
OCR: Process current file |
OCR the file currently open in the editor |
OCR: Pick attachment to process |
Choose any file in the vault to OCR |
OCR: Stop processing |
Halt batch processing after the current file finishes |
Each OCR result is saved as a .md note (e.g. screenshot.png → screenshot (OCR).md) using a customizable template. Default structure:
---
ocr-processed: true
---
# OCR Result for screenshot.png
## Extracted Text
[extracted text here]
Turn on Note properties to add your own YAML frontmatter. For example:
source: "[[{{path}}]]"
processed: {{date}}
status: {{status}}
produces:
---
source: "[[assets/screenshot.png]]"
processed: 2026-08-11
status: completed
ocr-processed: true
---
The OCR processed field is always appended (and not duplicated if you list it yourself).
Images: PNG, JPG, JPEG, WEBP, BMP, GIF, HEIC, HEIF — Documents: PDF
| Setting | Description |
|---|---|
| Attachment extensions | Comma-separated list of extensions treated as attachments |
| Ignore folders | Comma-separated folder paths to skip during organizing or purging |
| Setting | Description |
|---|---|
| Destination | Obsidian settings, Same location as file, or Separate folder |
| Obsidian attachment folder | Read-only preview of what Obsidian's own setting resolves to |
| Default folder name | Folder name used in separate folder mode |
| Sort into subfolders by | None, Date (year/month), File type, or Custom pattern. Not applicable in Same location as file mode. |
| Custom subfolder pattern | Tokens: {{year}}, {{month}}, {{day}}, {{type}}, {{filename}} |
| Organize on startup | Auto-organize every time Obsidian starts |
| Auto-organize interval | Re-organize on a timer (minutes, 0 = disabled) |
| Setting | Description |
|---|---|
| Rename mode | None, Date-based, Custom pattern, Ask each time, or Date + ask |
| Date format pattern | Pattern used for date-based and date+ask modes |
| Custom rename pattern | Pattern used for custom mode |
Available tokens for paste rename patterns:
| Token | Value |
|---|---|
{{year}} |
4-digit year |
{{month}} |
2-digit month |
{{day}} |
2-digit day |
{{time}} |
HHmmss timestamp |
{{type}} |
File extension (e.g. png) |
{{filename}} |
Name of the active note |
{{original}} |
Original pasted filename (without extension) |
| Setting | Description |
|---|---|
| Confirm before purging | Show confirmation prompt before deleting unlinked attachments |
| Setting | Description |
|---|---|
| Enable OCR | Toggle OCR processing on/off |
| OCR provider | Custom / self-hosted, OpenAI, Anthropic, or Google Gemini |
| Custom server base URL | OpenAI-compatible endpoint root, e.g. http://localhost:11434/v1 |
| Custom model | Vision-capable model name as your server reports it |
| Custom API key | Optional — leave unset for servers that need no auth |
| Custom request timeout | Seconds to wait before giving up (30–1800) |
| Test connection | Prominent first OCR action for checking the custom server and selected model |
| OpenAI / Anthropic / Gemini API key | Stored via Obsidian's secret storage, never in plain settings |
| OpenAI / Anthropic / Gemini model | Model used by the selected provider |
| OCR watch folder | A specific folder, any folder with a specific name, Obsidian's attachment folder, or Vaultkeeper's organize destination |
| Watch folder path | The folder to monitor, when A specific folder is selected. Empty = whole vault. |
| Watch folder name | Exact folder name to monitor everywhere in the vault, e.g. _files |
| OCR output folder | Sibling folder next to the watched folder, a specific folder, the source file's folder, Obsidian's attachment folder, or Vaultkeeper's organize destination |
| Sibling OCR folder name | Folder name used by sibling output mode; defaults to _ocr and preserves nested paths below _files |
| Output folder path | The folder to write notes to, when A specific folder is selected |
| Output subfolder | Subfolder appended to the resolved output location. Empty = write directly there. |
| Setting | Description |
|---|---|
| Batch size | Files processed per batch (1 recommended for free tier) |
| Max file size (MB) | Files larger than this are skipped |
| Force reprocess | Re-OCR files even if a note already exists |
| Auto-process new files | OCR files automatically when added to watch folder |
| Auto-process modified files | Re-OCR when a source file is updated |
| OCR processed field | Frontmatter field name used to mark processed files |
| Setting | Description |
|---|---|
| Note properties | Add YAML frontmatter properties to each OCR note |
| Properties | One key: value per line, token-substituted |
| OCR prompt | Prompt sent to the model for each file |
| OCR output template | Body of the generated note |
Available variables in both the properties and the output template:
| Token | Value |
|---|---|
{{content}} |
The extracted text (output template only) |
{{filename}} |
Source filename with extension |
{{basename}} |
Source filename without extension |
{{path}} |
Full vault path to the source file |
{{link}} |
Wikilink to the source file |
{{date}} |
YYYY-MM-DD |
{{time}} |
HH:mm |
{{datetime}} |
YYYY-MM-DD HH:mm |
{{status}} |
Processing status, e.g. completed |
{{provider}} |
Provider that ran the OCR |
{{model}} |
Model that ran the OCR |