<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Applescript | Derek Armstrong — Staff Engineer &amp; Solutions Architect</title><link>https://derekarmstrong.dev/tags/applescript/</link><atom:link href="https://derekarmstrong.dev/tags/applescript/index.xml" rel="self" type="application/rss+xml"/><description>Applescript</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Sun, 24 May 2026 00:00:00 +0000</lastBuildDate><image><url>https://derekarmstrong.dev/media/sharing.png</url><title>Applescript</title><link>https://derekarmstrong.dev/tags/applescript/</link></image><item><title>How I Bridged CLI AI Agents to Apple's Walled Garden</title><link>https://derekarmstrong.dev/blog/giving-my-ai-coding-assistant-access-to-apple-reminders/</link><pubDate>Sun, 24 May 2026 00:00:00 +0000</pubDate><guid>https://derekarmstrong.dev/blog/giving-my-ai-coding-assistant-access-to-apple-reminders/</guid><description>&lt;p&gt;Every time I work with a CLI AI tool — opencode, Claude Code, Copilot CLI — the same wall shows up.&lt;/p&gt;
&lt;p&gt;These tools are genuinely useful inside the terminal. They edit files, run commands, search codebases. But outside, they&amp;rsquo;re blind. They can&amp;rsquo;t see your tasks, check your calendar, read your notes, or look at your email. The apps that actually run your day &amp;ndash; that is mostly apps built by Apple &amp;ndash; are in Apple&amp;rsquo;s walled garden with no public APIs.&lt;/p&gt;
&lt;p&gt;I built a bridge into Reminders to prove the concept. The same pattern works for Notes, Calendar, Mail, Contacts, and any other Apple app that exposes local data. CLI AI agents can talk to the apps you already use every day.&lt;/p&gt;
&lt;h2 id="the-apple-walled-garden-problem"&gt;The Apple Walled Garden Problem&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re an Apple user, your data lives in Apple&amp;rsquo;s apps. Reminders for tasks. Calendar for events. Notes for ideas. Mail for communication. Contacts for people.&lt;/p&gt;
&lt;p&gt;These apps are well integrated, highly usable, and completely locked down. Apple doesn&amp;rsquo;t expose public APIs. There&amp;rsquo;s no &lt;code&gt;GET /reminders/today&lt;/code&gt; endpoint. No &lt;code&gt;POST /calendar/event&lt;/code&gt;. The obvious approach &amp;ndash; send your data to an AI platform via their cloud API &amp;ndash; works against what these apps were built for: keeping data local and private.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s the constraint. You have great tools that don&amp;rsquo;t talk to anything outside the ecosystem. Now you also have powerful AI tools that can&amp;rsquo;t see anything inside it. A simple bridge between them changes what those AI agents can actually do for you.&lt;/p&gt;
&lt;h2 id="the-bridge-sqlite--applescript"&gt;The Bridge: SQLite + AppleScript&lt;/h2&gt;
&lt;p&gt;Every one of Apple&amp;rsquo;s built-in apps stores data locally in SQLite databases and responds to AppleScript. That gives us two paths:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SQLite&lt;/strong&gt; &amp;ndash; read fast. Local, instant queries against the same database the app uses. These are read-only because the databases are encrypted and direct writes can corrupt them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AppleScript&lt;/strong&gt; &amp;ndash; write safely. It&amp;rsquo;s the OS&amp;rsquo;s sanctioned way to write data. Slower than a direct database insert, but it respects all the integrity constraints the app depends on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A hybrid approach, not a beautiful one, but it works.&lt;/p&gt;
&lt;h2 id="reminders-the-proof-of-concept"&gt;Reminders: The Proof of Concept&lt;/h2&gt;
&lt;p&gt;Reminders was the first app I bridged because task management is useful in a coding workflow. The SQLite database lives at:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~/Library/Group Containers/group.com.apple.reminders/Container_v1/Stores/Data-*.sqlite
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The schema is clean enough to query directly. A simple SQL join gets today&amp;rsquo;s tasks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ZTITLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ZNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ZDUEDATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ZFLAGGED&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ZREMCDREMINDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ZREMCDBASELIST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ZLIST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Z_PK&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ZMARKEDFORDELETION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ZCOMPLETED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ZDUEDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BETWEEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;today_start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;today_end&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ZPRIORITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ZDUEDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Writes go through AppleScript:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tell application &amp;#34;Reminders&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt; make new reminder in list &amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;list_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#34; with properties &lt;/span&gt;&lt;span class="se"&gt;{{&lt;/span&gt;&lt;span class="s1"&gt;name:&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;}}\n&lt;/span&gt;&lt;span class="s1"&gt;end tell&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;osascript&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;-e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The wrapper is a Python script that exposes structured commands. Each one returns JSON so the CLI agent can parse and present it naturally:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 reminders_helper.py today
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 reminders_helper.py overdue
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 reminders_helper.py lists
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 reminders_helper.py search &lt;span class="s2"&gt;&amp;#34;databases&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 reminders_helper.py create &lt;span class="s2"&gt;&amp;#34;follow up on PR&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Reminders&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 reminders_helper.py &lt;span class="nb"&gt;complete&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Update Runner VM docs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s what that actually looks like in a session:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; &amp;ldquo;What do I have on my task list today?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agent:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Today&amp;#39;s tasks:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; • Update Runner VM documentation
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; • Review blog post for Reminders integration
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; • Fix SHA256 checksum bug in update-runners.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; &amp;ldquo;Create a reminder to follow up on the Forgejo migration article&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agent:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Created: follow up on the Forgejo migration article
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A few seconds. No context switching, no opening apps, no manual typing.&lt;/p&gt;
&lt;h2 id="the-same-pattern-every-apple-app"&gt;The Same Pattern, Every Apple App&lt;/h2&gt;
&lt;p&gt;Reminders was just the first one. The same SQLite read + AppleScript write pattern applies to most of the apps you probably use every day.&lt;/p&gt;
&lt;h3 id="calendar"&gt;Calendar&lt;/h3&gt;
&lt;p&gt;Your schedule lives in &lt;code&gt;~/Library/Calendar/Calendar.sqlitedb&lt;/code&gt;. Read today&amp;rsquo;s events with a single query. Create, update, and delete events through AppleScript. The agent suddenly knows your meeting schedule when it&amp;rsquo;s helping you plan work.&lt;/p&gt;
&lt;h3 id="notes"&gt;Notes&lt;/h3&gt;
&lt;p&gt;Notes stores content in &lt;code&gt;~/Library/Group Containers/group.com.apple.notes/Documents/&lt;/code&gt;. You can search across all notes, read specific note content, or append new notes. When you&amp;rsquo;re in the middle of planning something, the agent can pull context from your existing notes instead of making you switch windows.&lt;/p&gt;
&lt;h3 id="mail"&gt;Mail&lt;/h3&gt;
&lt;p&gt;Mail&amp;rsquo;s database is at &lt;code&gt;~/Library/Mail/&lt;/code&gt; &amp;ndash; complex schema, but the recent inbox, unread counts, and message searches are straightforward. AppleScript handles sending replies or flagging messages. The agent can summarize your inbox or find that email from last week without you touching Mail.app.&lt;/p&gt;
&lt;h3 id="contacts"&gt;Contacts&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;~/Library/Application Support/AddressBook/&lt;/code&gt; has the complete address book. Queries give you contact details, groups, notes. No API &amp;ndash; just read the local database. When the agent is helping draft outreach or organizing projects, having contact data available matters.&lt;/p&gt;
&lt;h3 id="shortcuts--reminders"&gt;Shortcuts / Reminders&lt;/h3&gt;
&lt;p&gt;The Reminders skill already covers this, but the same AppleScript bridge extends to Shortcuts automations. A skill can trigger existing shortcuts, creating deeper automation between your CLI tools and the Apple ecosystem.&lt;/p&gt;
&lt;h2 id="the-skill-architecture"&gt;The Skill Architecture&lt;/h2&gt;
&lt;p&gt;Each app gets its own skill &amp;ndash; a Python helper script and a Markdown instructions file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;skills/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; reminders/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; SKILL.md # Instructions for the agent
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; scripts/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; reminders_helper.py # Main entry point
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; calendar/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; SKILL.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; scripts/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; calendar_helper.py
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; notes/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; SKILL.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; scripts/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; notes_helper.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;SKILL.md&lt;/code&gt; tells the agent what commands exist and when to call them. The Python script runs queries or AppleScript, returns structured JSON. That&amp;rsquo;s it &amp;ndash; the whole bridge.&lt;/p&gt;
&lt;h2 id="how-it-works-with-any-cli-ai-tool"&gt;How It Works With Any CLI AI Tool&lt;/h2&gt;
&lt;p&gt;None of this is specific to one AI tool.&lt;/p&gt;
&lt;p&gt;opencode uses skills &amp;ndash; Markdown files that describe available actions alongside scripts. Claude Code has the same skill system. Copilot CLI uses extensions. Any CLI agent that can run commands and read structured output can use this pattern.&lt;/p&gt;
&lt;p&gt;The mechanism is universal: a local script exposes data and actions through the command line, the agent&amp;rsquo;s instructions tell it when and how to call the script, the output is structured enough for the agent to reason about.&lt;/p&gt;
&lt;h2 id="why-this-matters"&gt;Why This Matters&lt;/h2&gt;
&lt;p&gt;Most CLI AI tutorials focus on making the agent faster at coding. But the more interesting use case is giving the agent context about your actual life. Your tasks. Your schedule. Your notes. Your email. Your contacts.&lt;/p&gt;
&lt;p&gt;The data already exists. It just lives inside apps that don&amp;rsquo;t talk to anything else. Once you bridge that gap &amp;ndash; locally, privately, with scripts anyone can write &amp;ndash; the agent suddenly understands what you&amp;rsquo;re working on and what you need to do next.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s more useful than any code completion feature. Because the agent knows more about your context, not just how to type faster.&lt;/p&gt;
&lt;h2 id="the-takeaway"&gt;The Takeaway&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re using a CLI AI tool and you want it to understand your world, the pattern is simple. Apple&amp;rsquo;s apps are locked down, but their local databases and AppleScript bridges give you a way in. Write a script that exposes the data as structured JSON. Give the agent instructions for when to call it. The data never leaves your machine.&lt;/p&gt;
&lt;p&gt;Reminders proved this works. Calendar, Notes, Mail, Contacts &amp;ndash; same pattern, same privacy guarantees. The walled garden has doors, you just need to know where they are.&lt;/p&gt;
&lt;h2 id="next"&gt;Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&amp;ndash; how to combine multiple tools without creating more noise than signal&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>