Skip to main content
AI/MLjeremylongshore

apple-notes-ci-integration

'Run Apple Notes automation in CI on macOS runners.

Stars
2,267
Source
jeremylongshore/claude-code-plugins-plus-skills
Updated
2026-05-31
Slug
jeremylongshore--claude-code-plugins-plus-skills--apple-notes-ci-integration
View on GitHubRaw SKILL.md

// install — copy + paste into any project

mkdir -p .claude/skills && curl -fsSL https://raw.githubusercontent.com/jeremylongshore/claude-code-plugins-plus-skills/HEAD/plugins/saas-packs/apple-notes-pack/skills/apple-notes-ci-integration/SKILL.md -o .claude/skills/apple-notes-ci-integration.md

Drops the SKILL.md into .claude/skills/apple-notes-ci-integration.md. Works with Claude Code, Cursor, and any agent that loads SKILL.md files from .claude/skills/.

Apple Notes CI Integration

Overview

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.

GitHub Actions Workflow

# .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

Mock Client for CI

// 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))]; }
}

Self-Hosted Runner with TCC Pre-Approval

# 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

Error Handling

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

Resources

Next Steps

For diagnosing CI failures, see apple-notes-common-errors. For production deployment of automation scripts, see apple-notes-deploy-integration.