agentsclimarketplace

Automating messages

Skill SpillwaveSolutions/automating-mac-apps-plugin/plugins/automating-mac-apps-plugin/skills/automating-messages

Agents, Skills and Commands for automating Keynote, Notes, Reminders, Numbers and more using AppleScript and PyXA (JXA too).

Install
npx -y skills add SpillwaveSolutions/automating-mac-apps-plugin --skill automating-messages

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

Automates macOS Messages (iMessage/SMS) via JXA with reliable service→buddy resolution. Use when asked to "automate iMessage", "send Messages via script", "JXA Messages automation", or "read Messages history". Covers send-bug workarounds, UI scripting for attachments, chat.db forensics, and launchd polling bots.

SKILL.md

5.3 KB, as published. Nobody here has run it

Automating Messages (JXA-first with UI/DB fallbacks)

Contents

Permissions and scope

  • Grants needed: Automation + Accessibility; Full Disk Access for any chat.db reads.
  • Keep automation scoped and auditable; avoid unsolicited sends and DB writes.
  • Pairs with automating-mac-apps for common setup (permissions, osascript invocation, UI scripting basics).

Default workflow (happy path)

  1. Resolve transport: pick serviceType (iMessage or SMS) before targeting a buddy.
  2. Identify recipient: filter buddies by handle (phone/email). Avoid ambiguous names.
  3. Send via app-level send: pass Buddy object to Messages.send().
  4. Verify window context: activate Messages when mixing with UI steps.
  5. Fallbacks: if send/attachments fail, use UI scripting; for history, use SQL.

Quick recipe (defensive send)

const Messages = Application('Messages');
Messages.includeStandardAdditions = true;

function safeSend(text, handle, svcType = 'iMessage') {
  const svc = Messages.services.whose({ serviceType: svcType })[0];
  if (!svc) throw new Error(`Service ${svcType} missing`);
  const buddy = svc.buddies.whose({ handle })[0];
  if (!buddy) throw new Error(`Buddy ${handle} missing on ${svcType}`);
  Messages.send(text, { to: buddy });
}
  • Wrap with try/catch and log; add small delays when activating UI.
  • For groups, target an existing chat by GUID or fall back to UI scripting; array sends are unreliable.

Attachments and UI fallback

  • Messages lacks a stable JXA attachment API; use clipboard + System Events paste/send.
  • Ensure Accessibility permission, bring app forward, paste file, press Enter.
  • See references/ui-scripting-attachments.md for the full flow and ObjC pasteboard snippet.

Data access and forensics

Reading messages limitation: The AppleScript/JXA API for Messages is effectively write-only. While send() works reliably, reading messages via chat.messages() or similar methods is broken/unsupported in modern macOS. The only reliable way to read message history is via direct SQLite access to ~/Library/Messages/chat.db.

Security consideration: Reading chat.db requires Full Disk Access permission, which grants broad filesystem access beyond just Messages. This is a significant security trade-off - granting Full Disk Access to scripts or applications exposes all user data. Consider whether reading message history is truly necessary before enabling this permission.

  • Use SQL against chat.db for history; JXA chat.messages() is unreliable/non-functional.
  • Requires: System Settings > Privacy & Security > Full Disk Access for your terminal/script.
  • Remember Cocoa epoch conversion (nanoseconds since 2001-01-01); use sqlite3 -json for structured results.
  • See references/database-forensics.md for schema notes, typedstream handling, and export tooling.

Example read query (requires Full Disk Access):

sqlite3 ~/Library/Messages/chat.db "SELECT
  CASE WHEN m.is_from_me = 1 THEN 'Me' ELSE 'Them' END as sender,
  m.text,
  datetime(m.date/1000000000 + 978307200, 'unixepoch', 'localtime') as date
FROM message m
JOIN handle h ON m.handle_id = h.rowid
WHERE h.id LIKE '%PHONE_NUMBER%'
ORDER BY m.date DESC LIMIT 10;"

Bots and monitoring

  • Implement polling daemons with launchd now that on-receive handlers are gone.
  • Track rowid, query diffs, dispatch actions, and persist state.
  • See references/monitoring-daemons.md for the polling pattern and plist notes.

Validation Checklist

  • Automation + Accessibility permissions granted
  • Service resolves: Messages.services.whose({ serviceType: 'iMessage' })[0] returns object
  • Buddy lookup works: svc.buddies.whose({ handle })[0] returns target
  • Test send completes without errors
  • Full Disk Access granted if using chat.db reads

When Not to Use

  • For reading message history without Full Disk Access (AppleScript/JXA cannot read messages)
  • For cross-platform messaging (use platform APIs or third-party services)
  • For business SMS automation (use Twilio or similar APIs)
  • When iMessage/SMS features are not available on the target system
  • For bulk messaging (rate limits and security restrictions apply)
  • When security policy prohibits Full Disk Access grants (required for any read operations)

What to load

  • Control plane and send reliability: references/control-plane.md
  • UI scripting + attachments fallback: references/ui-scripting-attachments.md
  • SQL/history access: references/database-forensics.md
  • Polling bots/launchd: references/monitoring-daemons.md

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.