Three things my agent does for me every day

In the first article of this series I wrote that the best way to start using an agent is with a task that is small, real and reversible. Since then a few people have asked what I actually delegate myself. The honest answer is that the most useful jobs I have running are boring. None of them "writes code" or "manages my inbox". Each saves me about ten minutes a day, and none of them ever forgets.
I run an agent on a Mac mini at home, on Hermes Agent by Nous Research. It talks to me over Telegram and has a built-in scheduler that checks every minute whether a job is due. That scheduler does almost everything described below.
The rule: the agent doesn't do the work
Before the examples, the design, because it is what keeps this from wrecking my bill.
Every task is a cron job with a Python script in front of it. The script does the real work: calls the API, reads my calendar, filters, compares against state kept in a JSON file. Whatever the script prints goes into the model's prompt already digested. The model only does what it is good at: writing me a message, asking what I want, recording my answer, and telling me everything went fine. When there is nothing to say, it answers [SILENT] and I get nothing.
The first version of the gym job was not built this way. The model had the tools and did everything itself: called the API, read the calendar, decided what to show. It cost around 700K tokens every morning to produce a list of twelve classes. One day Grok cut me off for hitting the spending limit, which was the push I needed. Now the script does the work and the model receives a JSON and returns a list. That is 6K tokens per morning, on a cheaper model. A hundred times less, with a better result, because a script doesn't get distracted.
1. The gym
I train at a gym almost every day, and group classes are booked through the club's app, in a window that opens 24 hours before the class. The good classes sell out. Either I'm watching the clock at the right minute, or I'm out.
At 08:00 a script logs into the gym app's API and asks for tomorrow's schedule. Then it strips what I don't care about: the modalities I've marked as "dislike", anything that collides with an event in my calendar, and classes I'm already booked into. For every class left it computes the exact moment booking opens, which is the start time minus 24 hours.
The model gets that list and sends me a numbered message on Telegram, with time and instructor, asking which ones I want. I reply "1 and 4". The agent stores the choice and creates, for each class, a one-shot job scheduled for the minute booking opens. That job runs a single terminal command with the class id already filled in. If the class is full, the same script puts me on the waiting list. If I get in, it creates a calendar event with the class name. If I'm waitlisted, it creates nothing, because I don't want classes I might not attend in my calendar.
Yesterday it went like this: list at 08:00, my reply at 08:02, booking made at 19:30 for today's 19:30 yoga. I never opened the app.
2. The restaurant menu
There's a restaurant in Coimbra (Portugal) where I have lunch often, Legumes e Outros Vícios. The menu changes daily and is posted in the morning on their website, as an image. I don't like every dish, and I got tired of opening the site every day to find out whether it was worth going.
At 10:00 a script fetches the page and finds the menu image. Here the model has to do more than format, because the menu is a poster. It reads the image, transcribes the dishes and matches them against a file holding my ratings, 0 to 5. Right now it has 57 dishes rated. The rule is simple: show me only dishes rated 3 or above, with the score next to them. Anything below 3 never appears. For a dish it doesn't know yet, it asks for a rating in a numbered list, I reply with numbers, and it saves them.
After two weeks the 10:00 message became just "On the menu today: Chicken breast with mustard, lemon and honey (4), Green chickpea curry (3)". If nothing is above 3, it stays quiet.
The annoying part was timing. At 10:00 the poster is often still yesterday's. So there is a second job, every 15 minutes until 11:45, that only wakes the model if the image address has changed. A monitor script keeps a hash of the last address and compares. And the model is told to read the date printed on the poster and keep quiet if it isn't today's. Without that I was getting yesterday's menu as if it were new, and for the first couple of weeks I did.
3. My club's fixtures
I support Académica. The league schedules matches round by round, sometimes two or three at once, and almost always with "time to be confirmed" for weeks. Keeping that in a calendar by hand is the kind of task you abandon after a month.
This job is the simplest of the three and doesn't use the model at all. At noon a script asks the Liga Portugal API for the team's whole season in one request and compares it with what it has stored. Each match has a stable code, and the script keeps the mapping between that code and the calendar event. New match, create the event. Known match with a different date or time, edit the existing event, looking it up by the old date so it never ends up duplicated. When the match is over, the title changes from "Académica-CD Feirense" to "Académica 1-0 CD Feirense", with the score.
The other day six matches got their dates on the same day and the calendar was correct by noon without me touching it. When nothing changed, the script prints nothing and the scheduler sends me nothing. Zero tokens, zero notifications.
What is still wrong
I don't want to paint this better than it is.
The gym waiting list is only half solved. The script puts me on it, tells me I'm waitlisted, and stops there. When a spot frees up the gym app notifies me, and then it's a race: whoever taps first gets in. I still have an entry, a Pilates class, that says "waitlist" in the state file. It was over long ago. The next iteration is a job that watches the class and grabs the spot the moment it opens, before I've even seen the notification.
The menu depends on the model reading a poster correctly. It almost always does. When a dish is written slightly differently from what's in the file, it asks me to rate something I've already rated. I put up with it, because the alternative is doing the matching by hand.
And the cost, while low, isn't zero. The menu burns about 40K tokens a day, because reading an image is expensive. That's the price of the restaurant posting a poster instead of text.
Where to start yours
The three cases have the same shape. There's a data source that changes every day, a rule of yours about what matters, and a place where the result has to end up. A script does the fetching and the filtering, a file stores what you decided, and the model handles the conversation.
Look through your week for something you check repeatedly at the same time. A class schedule, a price, an agenda, a menu, the status of an order. If you can state the rule in one sentence ("only if it's rated above 3", "only classes that don't clash with my calendar"), it's a candidate.
Then start with the version where the model does everything, because it's the fastest to get working. Only once it works is it worth taking the work away from it and moving it into a script. That's what I did, and it was the Grok bill that reminded me to.