reMarkable Pro → Claude Code OCR → Obsidian Vault
Automatically ingest handwritten notes from a reMarkable tablet, OCR them with Claude Code, and file structured Markdown into your Obsidian vault — complete with frontmatter, wikilinks, and action items.
reMarkable (USB) ←──────────────────────────────┐
↓ │
rm_ingest.py (downloads new notebooks) │
↓ │
Claude Code (OCR + structuring) │
↓ │
Obsidian Vault (markdown with [[wikilinks]]) │
↓ │
Claude Code + MCP (summaries, briefings) │
↓ │
rm_upload.py (sync PDFs back) ─────────────────┘
Two-way sync: Download handwritten notes from reMarkable, process them into Obsidian, then sync generated briefings and summaries back to reMarkable as PDFs.
- Python 3.11+ (for rm_ingest.py only)
- Claude Code (Windsurf IDE with Claude integration)
- reMarkable tablet with USB web interface enabled
- Obsidian with vault at
~/Documents/Obsidian/brain.ai-vault - Obsidian MCP configured in Claude Code
cd /path/to/brain.ai
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtAdd the MCP server config to your Claude Code settings:
{
"mcpServers": {
"obsidian-vault": {
"command": "npx",
"args": ["-y", "mcp-obsidian", "~/Documents/Obsidian/brain.ai-vault"],
"env": {}
}
}
}Or copy from mcp/mcp_config.json.
Edit config.yaml to match your paths and preferences:
vault_path: ~/Documents/Obsidian/brain.ai-vault
inbox_path: ./inbox
remarkable:
host: http://10.11.99.1
# Optional: filter notebooks by name patterns
include_patterns:
- "Meeting*"
- "Work*"
exclude_patterns:
- "*Draft*"Notebook Filtering (optional):
- Leave
include_patternsempty to download all notebooks - Set
include_patternsto only download notebooks matching those patterns - Use
exclude_patternsto skip specific notebooks (even if they match include) - Supports wildcards:
*(any characters),?(single character),[abc](character set) - Case-insensitive matching
Folder-based filtering:
"Sales"→ all notebooks in the Sales folder"Sales/*"→ same as above (explicit wildcard)"Sales/Aruba"→ specific notebook named "Aruba" in Sales folder"Personal"→ all notebooks in Personal folder
Name-based filtering:
"Meeting*"→ notebooks with names starting with "Meeting""*1:1*"→ notebooks with "1:1" anywhere in the name"Work*"→ notebooks starting with "Work"
Combined example:
include_patterns:
- "Sales" # All notebooks in Sales folder
- "Meeting*" # Any notebook starting with "Meeting"
exclude_patterns:
- "*Draft*" # Skip drafts
- "Archive" # Skip Archive folderOn your reMarkable tablet:
- Go to Settings → Storage
- Enable USB web interface
- Connect via USB cable
# Connect reMarkable via USB, then run:
python3 scripts/rm_ingest.pyThis downloads new/changed notebooks as PDFs into inbox/.
In Claude Code, use the workflow:
/process-remarkable-notes
Or simply ask:
"Process the PDFs in my inbox folder and file them into my Obsidian vault"
Claude Code will:
- Read each PDF in
inbox/ - OCR the handwriting using vision
- Generate structured Markdown with frontmatter
- File notes into your vault with proper folder structure
- Create person stubs for
[[wikilinks]] - Move processed PDFs to
inbox/processed/
You can automate the reMarkable download step with launchd:
# Edit the plist to only run rm_ingest.py (remove process_notes.py)
nano launchd/com.brain-ai.ingest.plist
# Create logs directory
mkdir -p logs
# Install the job
cp launchd/com.brain-ai.ingest.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.brain-ai.ingest.plistThen process PDFs with Claude Code whenever convenient.
Note: The provided plist runs both ingestion and processing. Edit it to only run rm_ingest.py if using the Claude Code workflow.
Once notes are in your vault, use Claude Code for:
- "Process the PDFs in my inbox" — triggers the OCR workflow
- "Summarize everything from this week"
- "Find all notes about Project Atlas"
- "Generate a briefing for my meeting with Sarah"
Use the prompt in prompts/weekly_summary.md to generate weekly digests.
Use the prompt in prompts/briefing.md before meetings to get context from past notes.
Generated briefings and summaries can be automatically synced back to your reMarkable as PDFs.
When using the /meeting-briefing or /weekly-summary workflows, PDFs are automatically uploaded to your reMarkable:
# Workflows automatically run:
python3 scripts/rm_upload.py briefings/2026-03-05-Medica-Connect-Briefing.mdThe PDF will appear on your reMarkable with a friendly name like:
- "Briefing - Medica Connect (Mar 5)"
- "Summary - Weekly (Mar 5)"
Features:
- Wikilinks
[[Person Name]]rendered as underlined text - Clean e-ink-friendly formatting
- Proper spacing and readability
- Uploaded to root level (organize manually on device)
Upload any Markdown file to reMarkable:
source .venv/bin/activate
python3 scripts/rm_upload.py path/to/file.mdControl sync behavior in config.yaml:
remarkable:
upload:
enabled: true # Enable/disable upload
auto_sync: true # Auto-upload after generationThe upload script requires system libraries for PDF generation:
# macOS (via Homebrew)
brew install pango
# Already installed if you followed setup
pip install weasyprint markdownNotes are automatically filed into:
brain.ai-vault/
├── Meetings/
│ └── 2026/
│ └── 03/
│ └── 2026-03-05-Sprint-Review.md
├── Notes/
│ └── Projects/
│ └── 2026-03-04-Atlas-Architecture.md
├── People/
│ ├── Sarah Chen.md
│ └── John Davis.md
└── Daily/
Three prompts are included in prompts/:
| Prompt | Purpose |
|---|---|
ocr_and_structure.md |
System prompt for handwriting OCR + markdown generation |
weekly_summary.md |
Generates weekly summaries from vault notes |
briefing.md |
Pre-meeting briefings from past notes |
reMarkable not connecting:
- Ensure USB cable is connected (not just charging)
- Enable USB web interface: Settings → Storage → USB web interface
- Test: open
http://10.11.99.1in a browser
Claude Code can't write to vault:
- Verify Obsidian MCP is configured correctly in Claude Code settings
- Check vault path in
mcp/mcp_config.jsonmatches your actual vault location - Test: ask Claude Code "List files in my Obsidian vault"
OCR quality issues:
- Ensure PDFs are high resolution (reMarkable exports at good quality by default)
- Try processing one page at a time for very dense notes
- Adjust the OCR prompt in
prompts/ocr_and_structure.mdif needed
PDF upload fails:
- Ensure reMarkable is connected via USB
- Check USB web interface is enabled: Settings → Storage → USB web interface
- Test connection:
curl http://10.11.99.1 - Install system dependencies:
brew install pango(macOS) - Check upload is enabled in
config.yaml
brain.ai/
├── config.yaml # Central configuration
├── requirements.txt # Python dependencies (minimal)
├── README.md # This file
├── context/
│ └── project-overview.md # Original project plan
├── scripts/
│ ├── rm_ingest.py # reMarkable → inbox (PDF download)
│ ├── rm_upload.py # Obsidian → reMarkable (PDF upload)
│ └── process_notes.py.standalone-reference # Old standalone script (reference)
├── templates/
│ └── pdf_style.css # PDF styling for reMarkable e-ink display
├── prompts/
│ ├── ocr_and_structure.md # OCR system prompt for Claude Code
│ ├── weekly_summary.md # Weekly summary prompt
│ └── briefing.md # Meeting briefing prompt
├── briefings/ # Generated meeting briefings
├── summaries/ # Generated weekly summaries
├── mcp/
│ └── mcp_config.json # Obsidian MCP config for Claude Code
├── launchd/
│ └── com.brain-ai.ingest.plist # macOS scheduled task (optional)
├── .windsurf/
│ └── workflows/
│ └── process-remarkable-notes.md # Claude Code workflow
├── inbox/ # Raw PDFs land here
│ └── processed/ # PDFs move here after processing
└── logs/ # launchd output logs (if using automation)
If you prefer to use the Anthropic API directly instead of Claude Code:
- Set
processing_mode: standaloneinconfig.yaml - Rename
scripts/process_notes.py.standalone-referenceback toprocess_notes.py - Add
anthropic>=0.40.0,pdf2image>=1.17.0,Pillow>=10.0.0torequirements.txt - Set
ANTHROPIC_API_KEYenvironment variable - Run:
python3 scripts/process_notes.py