Apple Notes SDK Patterns
Overview
Production patterns for Apple Notes automation: JXA wrapper class, error handling, batch operations, and cross-account support.
Instructions
Step 1: JXA Client Wrapper (Node.js)
// src/notes-client.ts
import { execSync } from "child_process";
class AppleNotesClient {
private runJxa(script: string): string {
const escaped = script.replace(/'/g, "'");
return execSync(`osascript -l JavaScript -e '${escaped}'`, {
encoding: "utf8",
timeout: 30000,
}).trim();
}
listNotes(folder?: string, limit: number = 50): Array<{ id: string; title: string; modified: string }> {
const script = folder
? `const Notes = Application("Notes"); const f = Notes.defaultAccount.folders().find(f => f.name() === "${folder}"); (f ? f.notes() : []).slice(0, ${limit}).map(n => JSON.stringify({id: n.id(), title: n.name(), modified: n.modificationDate().toISOString()})).join("\\n")`
: `const Notes = Application("Notes"); Notes.defaultAccount.notes().slice(0, ${limit}).map(n => JSON.stringify({id: n.id(), title: n.name(), modified: n.modificationDate().toISOString()})).join("\\n")`;
return this.runJxa(script).split("\n").filter(Boolean).map(l => JSON.parse(l));
}
createNote(title: string, body: string, folder?: string): string {
const folderPart = folder
? `let f = account.folders().find(f => f.name() === "${folder}"); if (!f) { f = Notes.Folder({name: "${folder}"}); account.folders.push(f); }`
: "let f = account.folders[0];";
return this.runJxa(`
const Notes = Application("Notes");
const account = Notes.defaultAccount;
${folderPart}
const note = Notes.Note({name: ${JSON.stringify(title)}, body: ${JSON.stringify(body)}});
f.notes.push(note);
note.id();
`);
}
searchNotes(query: string): Array<{ title: string; folder: string }> {
const result = this.runJxa(`
const Notes = Application("Notes");
const q = "${query}".toLowerCase();
Notes.defaultAccount.notes().filter(n =>
n.name().toLowerCase().includes(q) || n.body().toLowerCase().includes(q)
).slice(0, 20).map(n => JSON.stringify({title: n.name(), folder: n.container().name()})).join("\\n");
`);
return result.split("\n").filter(Boolean).map(l => JSON.parse(l));
}
}
export { AppleNotesClient };
Step 2: Batch Operations with Throttling
async function batchCreateNotes(
client: AppleNotesClient,
notes: Array<{ title: string; body: string; folder?: string }>,
delayMs: number = 500,
): Promise<string[]> {
const ids: string[] = [];
for (const note of notes) {
const id = client.createNote(note.title, note.body, note.folder);
ids.push(id);
await new Promise(r => setTimeout(r, delayMs));
}
return ids;
}
Output
- Type-safe JXA client wrapper for Node.js
- List, create, search operations via osascript
- Batch operations with throttling
Resources
1---2name: apple-notes-sdk-patterns3description: |4 Apply production-ready patterns for Apple Notes JXA/AppleScript automation.5 Trigger: "apple notes patterns".6allowed-tools: Read, Write, Edit, Bash(osascript:*), Grep7version: 1.0.08license: MIT9author: Jeremy Longshore <jeremy@intentsolutions.io>10tags: [saas, macos, apple-notes, automation]11compatible-with: claude-code12---1314# Apple Notes SDK Patterns1516## Overview17Production patterns for Apple Notes automation: JXA wrapper class, error handling, batch operations, and cross-account support.1819## Instructions2021### Step 1: JXA Client Wrapper (Node.js)22```typescript23// src/notes-client.ts24import { execSync } from "child_process";2526class AppleNotesClient {27 private runJxa(script: string): string {28 const escaped = script.replace(/'/g, "'");29 return execSync(`osascript -l JavaScript -e '${escaped}'`, {30 encoding: "utf8",31 timeout: 30000,32 }).trim();33 }3435 listNotes(folder?: string, limit: number = 50): Array<{ id: string; title: string; modified: string }> {36 const script = folder37 ? `const Notes = Application("Notes"); const f = Notes.defaultAccount.folders().find(f => f.name() === "${folder}"); (f ? f.notes() : []).slice(0, ${limit}).map(n => JSON.stringify({id: n.id(), title: n.name(), modified: n.modificationDate().toISOString()})).join("\\n")`38 : `const Notes = Application("Notes"); Notes.defaultAccount.notes().slice(0, ${limit}).map(n => JSON.stringify({id: n.id(), title: n.name(), modified: n.modificationDate().toISOString()})).join("\\n")`;39 return this.runJxa(script).split("\n").filter(Boolean).map(l => JSON.parse(l));40 }4142 createNote(title: string, body: string, folder?: string): string {43 const folderPart = folder44 ? `let f = account.folders().find(f => f.name() === "${folder}"); if (!f) { f = Notes.Folder({name: "${folder}"}); account.folders.push(f); }`45 : "let f = account.folders[0];";46 return this.runJxa(`47 const Notes = Application("Notes");48 const account = Notes.defaultAccount;49 ${folderPart}50 const note = Notes.Note({name: ${JSON.stringify(title)}, body: ${JSON.stringify(body)}});51 f.notes.push(note);52 note.id();53 `);54 }5556 searchNotes(query: string): Array<{ title: string; folder: string }> {57 const result = this.runJxa(`58 const Notes = Application("Notes");59 const q = "${query}".toLowerCase();60 Notes.defaultAccount.notes().filter(n =>61 n.name().toLowerCase().includes(q) || n.body().toLowerCase().includes(q)62 ).slice(0, 20).map(n => JSON.stringify({title: n.name(), folder: n.container().name()})).join("\\n");63 `);64 return result.split("\n").filter(Boolean).map(l => JSON.parse(l));65 }66}6768export { AppleNotesClient };69```7071### Step 2: Batch Operations with Throttling72```typescript73async function batchCreateNotes(74 client: AppleNotesClient,75 notes: Array<{ title: string; body: string; folder?: string }>,76 delayMs: number = 500,77): Promise<string[]> {78 const ids: string[] = [];79 for (const note of notes) {80 const id = client.createNote(note.title, note.body, note.folder);81 ids.push(id);82 await new Promise(r => setTimeout(r, delayMs));83 }84 return ids;85}86```8788## Output89- Type-safe JXA client wrapper for Node.js90- List, create, search operations via osascript91- Batch operations with throttling9293## Resources9495- [Mac Automation Scripting Guide](https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/)96- [JXA Examples](https://jxa-examples.akjems.com/)97