# iNotes (`INoteSync`) ## Purpose Sync Notes.app notes with the server, and apply web-initiated note edits back via AppleScript. ## Direction Bidirectional via AppleScript — accepted fragility per `~/.claude/plans/magical-tumbling-peach.md:108-117`. ## OS surface Notes.app via AppleScript (`NSAppleScript`). No linker entry needed; the target has no `linkerSettings` (`Package.swift:90-94`). Requires Automation > Notes. ## Files - `Reader.swift` — `public final class NotesReader` (line 49): `requestAuthorization()` (line 59), `fetchAllNotes()` (line 70). The fetch script reads `id, name, body, folder, modification date` from every note in every account (`@packages/inotes/Sources/INoteSync/Reader.swift:78-95`). - `APIClient.swift`: - `syncNotes(_:)` -> `POST /client/inotes/sync` (`@packages/inotes/Sources/INoteSync/APIClient.swift:79`) - `getStats()` -> `GET /client/inotes/stats` (line 94) - `getPendingSends()` -> `GET /client/inotes/send-queue/pending` (line 109) - `reportSendResult(...)` -> `POST /client/inotes/send-queue/:id/result` (line 132) - `Sender.swift`: - `NoteApplying` protocol (line 65) + production `AppleScriptNoteApplier` (line 110) and a `NoteSender` facade wrapper (line 76). - Scripts assembled by `scriptForCreate`, `scriptForUpdate`, `scriptForDelete` (lines 149, 163, 181) using `AppleScriptEscape.quote` for all interpolation. - `NoteSendTransport` adapts the typed APIClient calls into `SendQueueTransport` (line 231). - `SyncManager.swift` — slow interval (600s) because AppleScript is expensive; `lazy var sendQueueClient: SendQueueClient` drains every 60s (`SyncManager.swift:54-72`). Batch size 100 (line 51). ## Timing - Read interval: **600s** (`@packages/inotes/Sources/INoteSync/SyncManager.swift:79`). - Outbound poll interval: **60s** (`@packages/inotes/Sources/INoteSync/SyncManager.swift:60`). - Note batch size: 100. ## Server surface - Entity tables: `icloud.notes`, `icloud.note_send_queue` (`src/server/src/app/server.ts:47-48`). - Allowed actions: `create_note`, `update_note`, `delete_note` (`src/server/src/entities/noteSendItem/types.ts:12`). - Client routes (`src/server/src/surfaces/client/inotes.ts`): - `POST /client/inotes/sync` (line 29) - `GET /client/inotes/stats` (line 35) - `GET /client/inotes/send-queue/pending` (line 39) - `POST /client/inotes/send-queue/:id/result` (line 57) - Web routes (`src/server/src/surfaces/my/notes.ts`): - `GET /my/notes/stats` (line 41) - `GET /my/notes/` (line 49) - `POST /my/notes/` (line 66) - `PUT /my/notes/:id` (line 76) - `DELETE /my/notes/:id` (line 88) - Admin enqueue: `POST /admin/note-send-queue/enqueue` (`src/server/src/surfaces/admin/note-send-queue.ts:13`). ## Web surface - Tab: `/notes` (`web/src/App.tsx:62`). - API helpers: `web/src/api/notes.ts`. ## AppleScript snippets Create (`@packages/inotes/Sources/INoteSync/Sender.swift:149-160`): ```applescript tell application "Notes" set targetFolder to first folder whose name is "" set newNote to make new note at targetFolder with properties ¬ {name:"", body:""} return id of newNote end tell ``` Delete (`Sender.swift:181-189`): ```applescript tell application "Notes" delete (every note whose id is "") end tell ``` All interpolated values pass through `AppleScriptEscape.quote(_)` (`@packages/shared/Sources/MacSyncShared/Util/AppleScriptEscape.swift:13`). ## Known limitations - Attachments and Apple Pencil drawings don't round-trip — title, body, folder, and modification date only. See [known-limitations](../known-limitations.md#applescript-fragility). - Formatting fidelity is partial; basic HTML survives, advanced styles can flatten. - Pinned / locked notes: the AppleScript surface does not expose locking state; locked notes may be unreadable to the reader. ## Tests (`@packages/inotes/Tests/INoteSyncTests/`) - `AppleScriptTests.swift` — exercises `Reader.parse(_:)` against canned AppleScript output (`@packages/inotes/Sources/INoteSync/Reader.swift:104`), and validates the script strings emitted by `scriptForCreate` / `scriptForUpdate` / `scriptForDelete`. - `SenderDispatchTests.swift` — `NoteSender` action routing against a fake `NoteApplying` (hermetic). Not covered: real AppleScript execution, Notes.app side effects, Automation prompts.