Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Run Apple Notes automation in CI on macOS runners. Trigger: "apple notes CI".
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 8% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 85% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 30% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 8% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 25% | 0% |
Apple Notes automation is macOS-only because it depends on the Apple Events subsystem and Notes.app. CI pipelines must use GitHub Actions macOS runners (macos-latest or macos-14). However, macOS CI runners have restricted TCC (Transparency, Consent, and Control) permissions, which means direct Notes.app automation via osascript will fail in CI. The standard pattern is to run unit tests against a mock JXA client in CI, and reserve real Notes.app integration tests for local macOS machines or self-hosted runners with pre-granted automation permissions.
yaml# .github/workflows/notes-ci.yml name: Notes Automation CI on: push: branches: [main] pull_request: branches: [main] jobs: unit-tests: runs-on: macos-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: "20", cache: "npm" } - run: npm ci - name: Verify macOS version run: sw_vers - name: Lint JXA scripts run: | # Validate JavaScript syntax in all .jxa files for f in scripts/*.jxa; do node --check "$f" 2>/dev/null || echo "WARN: $f is osascript-only" done - name: Unit tests (mocked Notes client) run: npm test - name: Validate JXA templates run: | # Ensure osascript can parse (but not execute) JXA scripts for f in scripts/*.jxa; do osascript -l JavaScript -e "$(cat "$f")" 2>&1 | grep -v "Not authorized" || true done
typescript// tests/mocks/notes-client.mock.ts export class MockAppleNotesClient { private notes: Array<{ id: string; title: string; body: string; folder: string }> = []; createNote(title: string, body: string, folder = "Notes"): string { const id = `mock-note-${Date.now()}-${Math.random().toString(36).slice(2)}`; this.notes.push({ id, title, body, folder }); return id; } listNotes() { return [...this.notes]; } getNote(id: string) { return this.notes.find(n => n.id === id) || null; } searchNotes(q: string) { return this.notes.filter(n => n.title.includes(q) || n.body.includes(q)); } deleteNote(id: string) { this.notes = this.notes.filter(n => n.id !== id); } getFolders() { return [...new Set(this.notes.map(n => n.folder))]; } }
bash# On a self-hosted macOS runner, pre-grant automation permissions: # 1. Open System Settings > Privacy & Security > Automation # 2. Grant your CI user's terminal access to Notes.app # 3. Verify with: osascript -l JavaScript -e 'Application("Notes").defaultAccount.notes.length' # For headless runners, use tccutil (requires SIP adjustment or MDM profile): # sudo tccutil --insert com.apple.Notes --service AppleEvents --app /usr/bin/osascript
| Issue | Cause | Solution | |-------|-------|----------| | "Not authorized to send Apple events" in CI | TCC blocks automation on CI runners | Use mock client; real tests on self-hosted runner | | osascript syntax errors not caught | JXA has no standalone linter | Use node --check for JS syntax; parse-only validation | | Flaky tests on macos-latest | Runner image updates change Notes state | Pin to macos-14; always use mocked client | | Tests pass locally, fail in CI | Different macOS version or missing app | Check sw_vers output; ensure Notes.app exists on runner | | Timeout waiting for Notes.app | App launch delay on cold runner | Add open -a Notes && sleep 3 before osascript calls |
For diagnosing CI failures, see apple-notes-common-errors. For production deployment of automation scripts, see apple-notes-deploy-integration.
Other measured skills in the registry, with their headline benchmark lift.