Tasks from your phone
In the reference install, the owner adds a label to a task in Todoist on the phone. The box picks it up, does the work, and leaves the result as a comment on the same task.
- Green Oak Kitchen, boxed lunches, about $14 a head
- Luna Taqueria, taco bar, about $12 a head
- Hillside Deli, sandwich platters, about $11 a head
Example screen with made-up data.
Where you see it
The owner sees Todoist, the to-do app on the phone. To hand a task to the system, the owner adds the label claude to it. That is all.
Later, a comment appears on that task with the result, and the card moves to an Updates column. The vault also keeps a text copy of each top-level Todoist card, so tasks can be read and filtered there too.
What happens, step by step
Say the owner is in line at the store and adds a task: "Find three caterers near the office that do lunch for 20." They add the claude label.
- Every 15 minutes, a timer on the box starts a small program,
todoist-claude-pickup.py(the pickup). - The pickup gets the latest copy of the vault.
- It runs
todoist_sync.py(the sync). This is plain code, no AI. It copies changes between Todoist and the vault's task files: new cards, edits, moves, and archives. - It saves only the task folders it changed, by name, and sends them to git. It never saves "everything," because other sessions may be working in the vault at the same time.
- The sync reports any task that is ready: it has the
claudelabel, and its due date is today, in the past, or empty. - If none are ready, it stops. On a normal day, that is what happens. No AI runs at all.
- If one is ready, the pickup starts one Claude run on a cheaper model, Sonnet. The run follows a skill that says: no sends, no passwords, nothing that cannot be undone.
- Claude does the caterer search and writes the answer as a comment on the task.
On a claude task, the due date means "start on this day," not "finish by this day." A task due next Tuesday is skipped until next Tuesday. This is on purpose: it lets the owner line up work for later without a separate timer. But it is backwards from every other to-do app, and it fails silently. The log just says "no changes." If a labeled task is not getting picked up, check its due date first. That is nearly always the answer.
What powers it
| Part | What it does |
|---|---|
todoist-claude-pickup.timer | The systemd timer (the box's job scheduler) that fires every 15 minutes. |
todoist-claude-pickup.py | The wrapper. Gets the vault, runs the sync, saves, and starts Claude only if needed. |
todoist_sync.py | The plain-code sync between Todoist and the vault. Decides what is ready. |
pickup-claude-labeled-tasks | The skill Claude follows to do the work, with its guardrails. |
| A file lock | Stops two runs from stacking if one runs long. |
Why it works this way
This used to start a full AI session every 15 minutes, for both the sync and the pickup. Most of the time there was nothing to do. On one day, 37 sessions in a row ran and found nothing. Each took one to two and a half minutes. It was the biggest single user of the owner's Claude usage.
The fix was to split the work in two. Copying fields between Todoist and the vault is mechanical, so plain code does it for free. Doing the task needs judgment, so Claude does it, but only when a task is truly ready.
The same idea shows up all over Company OS: cheap, certain work in code; judgment work in AI, only when needed.
A small note on sub-tasks: they work. A labeled sub-task's result lands as a comment on the parent card, since the vault only keeps copies of top-level cards.
Connected to
- How a project runs: for bigger work that needs a plan, steps, and an agent that holds it.
- Morning prep: another routine that runs on its own, with the same "code first, AI only when needed" idea.
- Agents vs routines: why this is a routine, not an agent.
- Working for you: where scheduled jobs like this one show on screen.
- Proof it ran: how the system knows a routine really ran.