project · prototype
Calendario
An AI scheduling assistant that reads and books against my Google Calendar, so I can ask the question I was already asking out loud — what do I have tomorrow? — instead of opening an app and scrolling to find out.
- role
- solo — design & build
- timeline
- started 2025 · ongoing
- status
- working prototype
- built with
- Python · Google Calendar API · Cohere
- deployed at
- calendario.db444.xyz private — not open to the public
the problem
A calendar app is built to show you a grid. But nobody thinks in grids — they think in questions. Am I free Thursday afternoon? What's left today? When's the next thing I actually have to be somewhere for?
Answering any of those means opening the app, orienting yourself on the current week, and doing the filtering in your head. It's a small tax, paid many times a day. Calendario started having a second brain figure out what i could prioritize next or what is coming up on my schedule.
what it does
It runs as a REPL. You type in plain language; it works out what you meant, hits your real calendar, and prints the answer. It reads and writes — booking, moving and cancelling events, not just listing them.
Welcome to calenDario. How can I help you today?
You: what do I have today?
Today's Events:
- Morning focus block 9:00 AM - 10:30 AM
- Team standup 11:00 AM - 11:30 AM
You: schedule studio time tomorrow
Schedule 'studio time' on Fri, Aug 7 at 10:00 AM for 60 min?
Reply 'yes' to confirm, or give me a time like 'at 3pm'.
You: at 6pm
Created: studio time
Time: 6:00 PM - 7:00 PM
You: what should I do next
Wrap up anything short before your focus block — it starts in 40
minutes and runs an hour and a half.
Next up: Morning focus block (other)
Starts at 09:00 AM — in 40 minutes
Real output, with my own events swapped out. The green line is the only model-written text — everything around it is printed by the app.
Ten intents cover how I actually use a calendar. The first four read; the next three write; the last three are the ones that make it feel like an assistant rather than a command line.
- show_today
- show_tomorrow
- show_upcoming
- analyze_week
- create_event
- modify_event
- delete_event
- analyze_schedule
- next_action
- free_question
how it works
Every message takes the same path. The model is used once, at the front, and only to decide what you meant — never to do the arithmetic or touch the calendar.
- route the message A single Cohere call turns the message into a JSON object: one of ten intents, plus any entities it can pull out. Temperature 0, because this is classification, not writing.
- resolve the date and time in Python The model returns "tomorrow" and "18:00" as literals and stops there — day-of-week arithmetic is the thing it gets wrong most reliably, so the code does that itself against a fixed timezone.
- act on the calendar Read or write through the Google Calendar API. Anything it creates goes on its own dedicated calendar, so a bad guess is easy to find and undo.
- ask before it books If a create request is missing a title or a time, the app holds the half-finished event and asks for the one piece it needs, rather than inventing it.
the contract
Everything downstream is ordinary Python. The whole interface between the model and the app is this one object:
// "schedule studio time tomorrow at 6pm" becomes:
{
"intent": "create_event",
"entities": {
"title": "studio time",
"date": "tomorrow", // a literal, not a date
"time": "18:00",
"duration_minutes": 60
},
"reply": null // only set for questions it answers directly
}
Keeping the contract this narrow is what makes the rest testable. If the model returns something unparseable, that's one known failure mode with one fallback, instead of a wrong action taken confidently.
what I learned
the hard part isn't the AI
Understanding the question turned out to be the easy half. The genuinely fiddly work was everything underneath: timezones, all-day events that have a date but no time at all, and the difference between listing tomorrow and analysing it — which reads identically to a person and had to be spelled out for the model in as many words.
give the model less to do
The version that worked was the one that asked the model for less. It gets one job — read the message, return the JSON — at temperature 0, and explicitly does not compute dates, because that's the part it fails at quietly. Every step after the router is code I can test.
the empty state is a real answer
"No events scheduled for today" is information. An empty list is a bug you can read. Same for the confirmation step: an assistant that books the wrong thing instantly is worse than one that asks.
where it's going
The idea started in 2025 and sat as a rough script for a while; most of what's described here got built in 2026.
The terminal version is the one that actually works. Getting it out of the terminal is the current project — there's a web front end deployed at calendario.db444.xyz, with Google sign-in wired up, a month calendar and a three-day preview beside the chat. It's private: not open to the public, and it runs on mock events for now. The OAuth handshake is done, but the web app isn't reading a real calendar yet — the page says so on its own badge.
- Connecting the web front end to the same calendar layer the terminal version already uses, so the two stop being different products.
- Teaching it the user's own patterns — there's a profile built from calendar history that the router already gets, and it could be doing much more with it.
- Widening the range of phrasings it understands, so it degrades gracefully instead of falling through to "not sure how to help".