Status: ✅ Phase 1 Complete (Reviewed & Fixed)
The plugin has been reviewed, fixed, and rebuilt. All critical and major issues from the code review have been resolved.
🔧 Fixes Applied (Post-Review)
Critical Bugs (all fixed)
| # |
Issue |
File |
Fix |
| 1 |
SyncTracker corrupted plugin settings |
src/sync/tracker.ts |
Now merges with existing data before saving |
| 2 |
runCommand() hung on spawn errors |
src/utils/process.ts |
Added error event handler + dedup resolution |
| 3 |
Invalid "dir" in manifest |
manifest.json |
Removed property |
| 4 |
Wrong vault path handling |
src/sync/downloader.ts |
Uses vault.adapter paths directly |
Major Issues (all fixed)
| # |
Issue |
File |
Fix |
| 5 |
ls flag order (Go parser) |
src/rmapi/bridge.ts |
--json before positional path |
| 6 |
No incremental sync |
src/sync/downloader.ts |
Checks modifiedClient vs lastSynced |
| 7 |
Unsanitized filenames |
src/sync/downloader.ts |
sanitizeFileName() replaces illegal chars |
| 8 |
Broken authenticate() |
src/rmapi/bridge.ts |
Replaced with isAuthenticated() + user message |
| 9 |
Only root-level sync |
src/sync/downloader.ts |
listAllDocuments() recursively traverses folders |
| 10 |
Noisy load/unload notices |
src/main.ts |
Removed; status bar shows state instead |
| 11 |
Dev watch script broken |
esbuild.config.mjs |
Uses esbuild.context().watch() |
| 12 |
Dead killProcess() code |
src/utils/process.ts |
Removed |
| 13 |
mkdir silent failures |
src/sync/downloader.ts |
Wrapped in try/catch with warning log |
Minor Issues (all fixed)
| # |
Issue |
File |
Fix |
| 14 |
pageRenderer as any cast |
src/settings.ts |
Proper union type cast |
| 15 |
syncInterval text input |
src/settings.ts |
type="number" with min="0" + validation |
| 16 |
Static status bar |
src/main.ts |
Dynamic: "Idle" / "Syncing..." / "Last sync: HH:MM:SS" |
📁 Project Structure
🚀 Usage
- Install plugin: Copy folder to Obsidian plugins directory
- Install rmapi: Download from https://github.com/ddvk/rmapi/releases
- Configure: Open Settings → reMarkable Sync
- Authenticate: Run
rmapi in a terminal once to pair with your tablet
- Sync: Click ribbon pencil icon or run command "Sync from reMarkable"
🔄 Sync Flow
⚙️ Configuration
| Setting |
Default |
Description |
remarkableHost |
https://10.11.99.1 |
reMarkable tablet URL |
rmapiBinaryPath |
rmapi |
Path to rmapi binary |
downloadPath |
remarkable/ |
Vault folder for downloads |
convertToPdf |
true |
Auto-download annotated PDFs |
enableHandwritingMd |
true |
Enable OCR pipeline (Phase 2) |
glmocrServerUrl |
http://100.103.83.12:5002 |
GLM-OCR SDK Server |
glmocrApiKey |
any-string |
Dummy key for self-hosted |
ollamaHost |
http://100.103.83.12:11435 |
Ollama server |
styleModel |
qwen3:32b |
Model for markdown cleanup |
pageRenderer |
drawj2d |
.rm → PNG tool |
javaPath |
java |
Java runtime for drawj2d |
syncInterval |
0 |
Minutes between auto-sync (0 = off) |
📦 External Dependencies
Required (user-provided)
Optional (for Phase 2 OCR)
- GLM-OCR Server: Run
python -m glmocr.server on configured host
- Ollama: With
qwen3:32b (or chosen model) pulled
- Java: For
drawj2d page rendering
🔮 Phase 2: Handwriting OCR Pipeline (Planned)
- Extract HWR text from
.rm file's built-in handwriting recognition layer
- Render pages to PNG via
drawj2d or rM2svg
- POST to GLM-OCR Server (
glm-5.1:cloud equivalent) for structured markdown
- Style refinement via Ollama (
qwen3:32b) — light cleanup (Option A):
- Fix heading hierarchy
- Consolidate fragments
- Detect lists, emphasis
- Preserve all content
📝 Notes
- Auth token storage:
RMAPI_CONFIG points to .obsidian/rmapi inside vault (portable)
- Sync state: Stored via Obsidian's
saveData() API, merged with settings
- Auto-sync: Registered via
registerInterval() — Obsidian cleans up on unload
- Filename safety:
sanitizeFileName() replaces [\\/:*?"<>|] with _
- Incremental logic: Compares ISO timestamps (
lastSynced >= modifiedClient)
🎯 Build & Install
Status: ✅ Ready for testing. All reviewed issues fixed.