
I make it no secret that I have kids. It comes with lots of joys and occasional sorrows—and sometimes things that can be boring and feel repetitive.
One such thing is getting those emails from schools (and when you have kids in 4 different schools, you get at least 4) saying when the school holidays and school-specific days off occur.
Such emails may contain tables as the following for nation-wide holidayor this for school-specific days off.
Importing each of this in a calendar (times 4) is a chore, so last year I thought that I could automate most of it by using AppleScript.
Using AppleScript meant I could write the following code in Script Editor and get all my events added.
tell application "Calendar"
tell calendar "Home" -- Change "Home" to the name of your calendar
set newEvent to make new event at end of events with properties {summary:"Summer Holiday", start date:date "Saturday, 4 July 2026 at 00:00:00", end date:date "Sunday, 16 August 2026 at 00:00:00"}
-- add other events
end tell
end tell
This still meant I had to write something by hand and—although better than creating each event individually—was still painful.
This year, however, LLMs have gotten much more powerful so I decided to feed them the screenshots of the relevant tables and prompted them like so
Given the table attached as an image, output the following sentence for each row of the table set newEvent to make new event at end of events with properties {summary:"<Text in the first column>", start date:date "<start date as found in the row in format as 02-12-2025>", end date:date "<end date as found in the row in format 03-12-2025>" } I only need this sentence, one line per row, no code. Before the very first line, output tell application "Calendar" tell calendar "Home". After the very last line output end tell end tell
This is the result having fed the first image
tell application "Calendar"
tell calendar "Home"
set newEvent to make new event at end of events with properties {summary:"Herfstvakantie", start date:date "18-10-2025", end date:date "26-10-2025"}
set newEvent to make new event at end of events with properties {summary:"Kerstvakantie", start date:date "20-12-2025", end date:date "04-01-2026"}
set newEvent to make new event at end of events with properties {summary:"Voorjaarsvakantie", start date:date "21-02-2026", end date:date "01-03-2026"}
set newEvent to make new event at end of events with properties {summary:"Tweede Paasdag", start date:date "06-04-2026", end date:date "06-04-2026"}
set newEvent to make new event at end of events with properties {summary:"Meivakantie", start date:date "22-04-2026", end date:date "05-05-2026"}
set newEvent to make new event at end of events with properties {summary:"Hemelvaartsdag", start date:date "14-05-2026", end date:date "15-05-2026"}
set newEvent to make new event at end of events with properties {summary:"Tweede Pinksterdag", start date:date "25-05-2026", end date:date "25-05-2026"}
set newEvent to make new event at end of events with properties {summary:"Zomervakantie", start date:date "04-07-2026", end date:date "16-08-2026"} end tell
end tell
Pretty good! I’ve copy-pasted into Script Editor, and I got myself covered for the year to come!

macOS Script editor showing the script ready to be executed
Nerdy details
What’s my workflow under the hood? I’ve used the following tools/LLM
- On the command line, I’ve installed llm by Simon Willison using
uv
(uv’s website) withuv tool install llm
- Then, I’ve created a gemini API key. Gemini-2.5 seems to be the king of the hill for tabular OCR, and this job only costs fractions of cents. To use Gemini-2.5 with the
llm
tool, runllm install llm-gemini
andllm keys set gemini
- Once you have the screenshot (⇧⌘4 on the Mac. It will save a file on your Desktop), do
llm -a path/to/my/screenshot -m gemini-2.5-pro 'prompt'
whereprompt
is what I’ve written above! - If you’re feeling adventurous and believe the LLM of your choice will only output valid AppleScript, you can write
llm -a path/to/my/screenshot -m gemini-2.5-pro 'prompt' | osascript -
without copy-pasting between the terminal and Script Editor. - Want even less copy-pasting? Copy the prompt from above and in the terminal, run
pbpaste | llm -a path/to/my/screenshot -m gemini-2.5-pro | osascript -
Have fun!