Files
obsidian-remarkable/IMPLEMENTATION.md
T
2026-05-31 14:23:01 +02:00

6.5 KiB

Obsidian reMarkable Sync Plugin - Implementation Summary

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

obidian-remarkable/
├── dist/
│   └── main.js              # Built plugin (minified, ready to install)
├── src/
│   ├── main.ts              # Plugin entry: ribbon, commands, status bar, auto-sync
│   ├── settings.ts          # Settings tab with validation
│   ├── types.ts             # Shared TypeScript types
│   ├── rmapi/
│   │   └── bridge.ts        # rmapi CLI wrapper (env, auth check, JSON parsing)
│   ├── sync/
│   │   ├── downloader.ts    # Recursive doc listing + incremental download
│   │   └── tracker.ts       # Sync state persistence (merges with settings)
│   └── utils/
│       └── process.ts       # Child process runner with error handling
├── main.ts                  # Entry point (re-exports plugin)
├── manifest.json            # Obsidian plugin manifest
├── package.json             # Build scripts
├── esbuild.config.mjs       # esbuild config (build + watch modes)
└── IMPLEMENTATION.md        # This file

🚀 Usage

  1. Install plugin: Copy folder to Obsidian plugins directory
  2. Install rmapi: Download from https://github.com/ddvk/rmapi/releases
  3. Configure: Open Settings → reMarkable Sync
  4. Authenticate: Run rmapi in a terminal once to pair with your tablet
  5. Sync: Click ribbon pencil icon or run command "Sync from reMarkable"

🔄 Sync Flow

User clicks ribbon icon / auto-sync interval
  → isAuthenticated() check (fails with notice if not paired)
  → listAllDocuments("/") recursively
    → ls --json / (root)
    → For each CollectionType: recurse into subfolder
  → For each DocumentType:
    → Skip if lastSynced >= modifiedClient (incremental)
    → sanitizeFileName() for safe filesystem names
    → mkdir downloadPath (vault-relative)
    → rmapi get → download .rm file
    → (if enabled) rmapi geta → download annotated PDF
    → trackDocument() in sync state
  → Status bar updated: "Last sync: HH:MM:SS"

⚙️ 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)

  1. Extract HWR text from .rm file's built-in handwriting recognition layer
  2. Render pages to PNG via drawj2d or rM2svg
  3. POST to GLM-OCR Server (glm-5.1:cloud equivalent) for structured markdown
  4. 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

# Build
npm install
npm run build

# Dev (watch mode)
npm run dev

# Install in Obsidian
Copy the `obidian-remarkable` folder to:
- Linux: ~/.config/obsidian/plugins/
- macOS: ~/Library/Application Support/obsidian/plugins/
- Windows: %APPDATA%\obsidian\plugins\

Status: Ready for testing. All reviewed issues fixed.