About Daily
Daily is a personal schedule and life planner that your AI agents can run. You tell an assistant (Claude, or any app that speaks MCP) what your life looks like and what you want from it; it builds and keeps your schedule here, and you see and adjust everything in the app, on your laptop or phone.
- App: https://carpeday.app
- For agents: MCP at
https://carpeday.app/api/mcp, this document as Markdown at https://carpeday.app/about.md, a short guide at https://carpeday.app/llms.txt, and the HTTP API spec at https://carpeday.app/api/v1/openapi.json.
Contents
- What you can do
- Connect your agent
- How Daily thinks about your time
- Working with agents: conventions
- Accounts, sharing and privacy
- Running your own Daily
- Questions
- Tool reference
What you can do
Daily is split into sections. Each one is a page in the app, and everything on it can also be done by an agent.
| Section | What's there |
|---|---|
| 📅 Calendar | Your days and weeks: drag to move, drag the bottom edge to resize, tap to edit. Travel time shows as striped blocks before events. |
| ✅ Activities | Your to-dos at the top, then everything you do grouped by kind (work, fitness, people, reading, meals, errands, getting around), with how it repeats and when it's next. |
| 🏋️ Fitness | This week's workouts with exercises, weights and reps; how each day's meals add up against your calorie and protein targets; your goals. |
| 🍽️ Food | The week's meal plan and a shopping list for the meals you cook, grouped by store section with rough prices. |
| 💵 Money | A weekly budget from your plan (groceries, eating out, gas, rideshares, your bills' share) and the same plan per month; your bills. |
| 🎧 Content | Your lists: books, audiobooks, podcasts, movies. Each event that plays from a list knows what's up next. |
| 👥 People | Contacts, who to call on drives (in turn), accounts and calendars you share, RSVP links. |
| ⚙️ Settings | Sign-in and keys, syncing with Google or Apple Calendar, connecting agents, Strava and Apple Health, the raw JSON. |
Connect your agent
Claude (claude.ai, desktop, mobile). Settings → Connectors → Add custom connector. Name it Daily and paste https://carpeday.app/api/mcp. Claude sends you to Daily to sign in with your passkey, shows what it will be able to do, and you tap Allow. The connection then appears under Settings → Access, where you can revoke it.
Claude Code. Run claude mcp add --transport http daily https://carpeday.app/api/mcp, then /mcp to sign in.
Any other MCP client. Point it at https://carpeday.app/api/mcp. It discovers the sign-in on its own (OAuth 2.1 with dynamic client registration and PKCE; discovery at https://carpeday.app/.well-known/oauth-protected-resource).
Scripts and servers. Create an API key under Settings → Access with only the access it needs, and send it as Authorization: Bearer dly_…. The same tools are plain HTTP: POST https://carpeday.app/api/v1/<tool> with a JSON body (read-only tools also accept GET with query parameters). Responses are {"result": …} or {"error": "…"}.
Then just ask: "Set up my routine in Daily", "Plan my week around three workouts and dinner with Sam on Thursday", "Add renew passport by Friday to my to-dos and find time for it", "What's on tomorrow and when do I need to leave?"
How Daily thinks about your time
Each idea below is what the app shows and what the tools read and write. Field names are in code.
Events. Anything with a time: a meeting, a gym session, dinner. An event has a title, a start and end, a category (work, meeting, commute, workout, meal, date, movie, social, reading, personal, errand, sleep, other) and a calendar (personal, work, relationship, health… you can add more). Optional: a place (locationId), travel, people (attendees, and optionalAttendees for maybes), a workout, meals, media, notes and costs.
Times are local. Every time is written YYYY-MM-DDTHH:mm in your own time zone (set in settings), with no offset: 2026-11-02T07:00 means 7am wherever you live.
Repeating events. recurrence turns an event into a routine: { "freq": "weekly", "byDay": ["MO", "WE", "FR"] }, with interval (every 2 weeks), until or count. Change a single day without touching the rest; each day of a routine is addressed as eventId::YYYY-MM-DD.
Seasons. Named stretches of the year (ski season, summer). A routine can run only during some seasons (onlyIn) or pause for them (notIn), so a winter Saturday can be a ski day and a summer one disc golf.
Places and travel. Places (locations) have an address and coordinates. Set your home in settings and Daily estimates travel between places by your usual way of getting around, or uses the minutes you give (travel: { "minutes": 20, "mode": "drive" }). If you can't make it in time, it warns you.
Workouts and meals. A workout lists exercises with sets, reps, weight and equipment. Meals list what you eat with calories and protein; Daily adds them up per day against your targets. A meal can be someone else's (for), so it goes on the grocery list without counting toward your totals. Meals eaten out carry a cost for the budget.
Lists. Ordered lists of books, podcasts, movies (queues). A list either gives a new item each time (movies), stays on one until you finish it (books), or takes turns (podcasts). An event that plays from a list shows what's next.
People. Contacts you invite to events and call. A call list rotates: each drive calls the next people in line.
To-dos. One-off things to get done, with an optional due date and list. Ones due on a day show up when an agent reads that day.
Money. Bills (rent, insurance) count toward each week by their share. Gas is figured from miles with your car's mpg and the gas price. Rideshares, eating out and groceries come from the plan.
Your profile. Goals, nutrition targets, age, height and weight, and your car. Agents read these to tune plans.
History. Every change records who made it: you in the app (ui), an agent (agent:<name>), a guest RSVP or an import. recent_changes shows the latest.
Working with agents: conventions
These are for agents, and for anyone curious how they should behave.
- Start with
get_started. It says what's set up, what's missing (home location, goals, people) and how to build. - Read before writing. Look at the week with
get_agendaand the to-dos withlist_tasks. - Make changes in one plan.
apply_plantakes many operations and applies all of them or none. Run it with"dryRun": truefirst; it returns what each operation would make andcheck_schedule's findings. Fix those, then run it for real. - Name what you create. Give new things your own short ids (
"gym-mon","home") so later operations in the same plan can point at them. - Change one day, not the routine, with
update_eventand"scope": "occurrence"plus the date. - Check your work with
check_schedule: overlaps, not enough travel time, references to people, places or lists that don't exist, and days whose meals are far off target.find_free_timefinds open slots. - Ask before deleting things the person made, and explain what you changed in plain words.
A plan looks like this:
{
"dryRun": true,
"operations": [
{ "op": "upsert_item", "collection": "locations", "item": { "id": "gym", "name": "Gym", "address": "123 Main St" } },
{ "op": "create_event", "event": { "id": "lift", "title": "Lift", "category": "workout", "calendar": "health",
"start": "2026-11-02T07:00", "durationMin": 60, "locationId": "gym",
"recurrence": { "freq": "weekly", "byDay": ["MO", "WE", "FR"] } } },
{ "op": "add_task", "title": "Buy lifting shoes", "due": "2026-11-03" },
{ "op": "update_profile", "patch": { "goals": ["Lift 3x a week"] } }
]
}
The collections upsert_item and remove_item work on: locations, people, callLists, media, queues, groceries, workoutTemplates, calendars, subscriptions, seasons, bills, tasks.
Accounts, sharing and privacy
- Signing in. You sign in with a passkey (Face ID, Touch ID, your phone or a security key): no passwords. Each person has their own account and their own schedule; nobody else can see it unless you share.
- Joining. People join with an invite link from the owner (People → Accounts), or by signing up if the owner has turned that on.
- Agents get only what you allow. Each agent or app has its own key with a set of permissions: read (
schedule:read), change (schedule:write), make share links (share), import workouts (import), calendar feed only (feed), or everything (admin, never given to connected apps). Revoke any of them under Settings → Access. - Sharing a calendar with someone who has an account lets them see it, or also edit it. Your meals never count toward their totals.
- RSVP links let anyone see one event or one day and reply, without an account. They never show phone numbers or call lists.
- Calendar feeds for Google or Apple Calendar carry a read-only token: they can show your calendar but never change it.
Running your own Daily
Daily is open to run yourself: a Next.js app with a SQLite database (a local file, or Turso when hosted). On your computer: npm install, npm run dev, and open http://localhost:3000; with no secrets set, it's open to you alone on your machine. To put it online (Vercel + Turso), set DAILY_DB_URL, DAILY_DB_AUTH_TOKEN, DAILY_SECRET, DAILY_API_TOKEN and DAILY_PUBLIC_URL, deploy, and set up your passkey with the admin token. DAILY_OPEN_SIGNUP=true lets anyone create an account.
Questions
Does Daily replace Google or Apple Calendar? It can sit beside them: export your Daily calendars as feeds they subscribe to, and show their calendars inside Daily (read-only).
What happens if an agent makes a mess? Every change is logged with who made it (recent_changes), apply_plan is all-or-nothing, and you can revoke an agent's key at any time.
Can my partner and I share? Yes: each of you has an account, and you share a calendar (say, "relationship") with each other to view or edit.
Is it on my phone? Open the site and use Share → Add to Home Screen (iPhone) or Install app (Android).
Tool reference
Every tool is available over MCP and as POST https://carpeday.app/api/v1/<tool>. Access names the permission a key needs.
Start and read
Begin with get_started; read a week with get_agenda.
get_started
START HERE. Who this schedule belongs to, what's already set up (calendars, places, people, routines, lists, to-dos, goals) and what's missing, plus how to build a schedule with these tools. Call it first in a new conversation.
- Access:
schedule:read(read-only) - Inputs: No inputs.
get_agenda
Concrete schedule between two dates (inclusive), with recurring events expanded, travel/leave-by times, who to call on commutes, workouts, meals and media. Each line has a key (eventId::date) used by move_event/log_occurrence/share. format=text (default, for reading) or json.
- Access:
schedule:read(read-only) - Inputs:
from(string): YYYY-MM-DD, default today;to(string): YYYY-MM-DD, default from+6;format(text | json)
check_schedule
Find problems between two dates (default: the next two weeks): overlapping events, not enough time to travel between places, events pointing at people/places/lists that don't exist, and days whose meals are far from the calorie target.
- Access:
schedule:read(read-only) - Inputs:
from(string);to(string)
find_free_time
Open slots between two dates: gaps of at least minMinutes (default 30) between dayStart and dayEnd (default 08:00–21:00), optionally only on some weekdays (days: [MO, TU…]). Travel time to events counts as busy.
- Access:
schedule:read(read-only) - Inputs:
from(string);to(string);minMinutes(integer);dayStart(string);dayEnd(string);days(list of MO | TU | WE | TH | FR | SA | SU)
get_schedule
Raw schedule JSON (the source of truth). Optionally only some top-level sections, e.g. ['events','people'].
- Access:
schedule:read(read-only) - Inputs:
sections(list of string)
recent_changes
Most recent writes, newest first: when, which actor (ui, mcp:
- Access:
schedule:read(read-only) - Inputs:
limit(integer)
Build and change
apply_plan does many changes at once; the single-purpose tools are there for small edits.
apply_plan
Make many changes in one go, all or nothing: operations [{op: create_event, event} | {op: update_event, id, patch, scope?, date?} | {op: move_event, key, start, end?} | {op: delete_event, key, scope?} | {op: upsert_item, collection, item} | {op: remove_item, collection, id} | {op: add_task, title, due?, list?} | {op: complete_task, id} | {op: update_profile, patch} | {op: update_settings, patch}]. dryRun: true tries it without saving. Either way it returns what each operation made and check_schedule's findings for checkFrom..checkTo (default: the next two weeks).
- Access:
schedule:write - Inputs:
operations(list of items, required);dryRun(boolean);checkFrom(string);checkTo(string)
create_event
Create an event. Times are local 'YYYY-MM-DDTHH:mm'. Give end or durationMin. Optional: category (work|meeting|commute|workout|meal|date|movie|personal|errand|sleep|other), calendar (personal|work|relationship|…), locationId, travel {minutes, mode}, recurrence {freq: daily|weekly|monthly, interval, byDay:[MO..SU], until, count}, callListId, workout {kind, exercises:[{name, equipment, sets, reps, weight, unit}]}, meals [{slot, items:[{name, calories, protein, buy:[{grocery, qty}]}], source: home|out, servings, cost, for: personId when it's someone else's portion (shopping only, not your totals)}], media [{mediaId, note}], costs [{label, amount, kind: food|drinks|gas|rideshare|activity|gear|other, miles (gas only: priced with profile.car)}], notes.
- Access:
schedule:write - Inputs:
event(object, required)
update_event
Patch an event's fields. For a recurring event, scope='occurrence' + date changes just that day (stored as an override); default scope is the whole series.
- Access:
schedule:write - Inputs:
id(string, required);patch(object, required);scope(occurrence | series);date(string)
move_event
Reschedule (like drag-and-drop) by occurrence key from get_agenda. scope 'occurrence' (default) moves one day; 'series' shifts every occurrence.
- Access:
schedule:write - Inputs:
key(string, required);start(string, required);end(string);scope(occurrence | series)
delete_event
Delete an event (scope 'series', default) or cancel one occurrence of a recurring event (scope 'occurrence' with a key).
- Access:
schedule:write - Inputs:
key(string, required): event id or occurrence key;scope(occurrence | series)
log_occurrence
Log what actually happened for an occurrence: status (done|skipped), notes, people actually called, actual workout sets/weights, meals eaten, media consumed. Marking a queue-driven event (e.g. movie night) done ticks off its up-next item so the next occurrence moves on.
- Access:
schedule:write - Inputs:
status(planned | done | skipped);log(string);called(list of string);workout(object);meals(list of object);media(list of object);key(string, required)
upsert_item
Create or update a library item. collection: locations {id,name,address,lat,lng} | people {id,name,phone,email} | callLists {id,name,people:[personId],perSession} | media {id,kind: audiobook|podcast|youtube|playlist|music|movie|series,title,creator,url,progress,done} | queues {id,name,mode: each (one item per session, e.g. movies) | untilDone (stay on the current item until marked done, e.g. books) | rotate (cycle, e.g. podcasts),items:[mediaId]} (set an event's queueId to play from it) | workoutTemplates {id,name,kind,exercises} | calendars {key,name,color} | subscriptions {id,name,url (secret ICS URL),calendar} | groceries {id,name,section,unit,pack:{size,label,price},pricePerUnit,staple} | seasons {id,name,ranges:[{from,to}]} (recurring events can set recurrence.onlyIn / notIn to season ids) | bills {id,name,amount,every: month|year,day,kind: rent|insurance|utilities|subscription|other,notes} (counted in weekly_budget).
- Access:
schedule:write - Inputs:
collection(locations | people | callLists | media | queues | groceries | workoutTemplates | calendars | subscriptions | seasons | bills | tasks, required);item(object, required)
remove_item
Remove a library item by id (calendars by key).
- Access:
schedule:write - Inputs:
collection(locations | people | callLists | media | queues | groceries | workoutTemplates | calendars | subscriptions | seasons | bills | tasks, required);id(string, required)
update_profile
Patch the profile: ageYears, heightIn, weightLb, goals [string], nutrition {calories, proteinG, carbsG, fatG, notes}, car {name, mpg, gasPrice (USD/gal), owned}. Daily meal totals in get_agenda are compared against nutrition targets; gas costs given in miles are priced with the car.
- Access:
schedule:write - Inputs:
patch(object, required)
update_settings
Change settings: timezone (IANA, e.g. America/New_York), homeLocationId (a location id; travel is estimated from it), weekStartsOn (0 Sun – 6 Sat), dayStartHour / dayEndHour (the calendar's visible hours), defaultTravelMode (drive, transit, walk, bike, rideshare).
- Access:
schedule:write - Inputs:
patch(object, required)
replace_schedule
Replace the ENTIRE schedule JSON (validated). Prefer the targeted methods; use this for bulk restructuring. Read with get_schedule first.
- Access:
admin - Inputs:
schedule(object, required)
To-dos
list_tasks
To-dos: open ones (overdue and undated first, with due dates and lists) and ones checked off in the last week. Use add_task / complete_task to change them.
- Access:
schedule:read(read-only) - Inputs: No inputs.
add_task
Add a one-off to-do. Optional: due (YYYY-MM-DD), list (e.g. Home, Paigy, Errands), notes.
- Access:
schedule:write - Inputs:
title(string, required);due(string);list(string);notes(string)
complete_task
Check a to-do off by id (done: false puts it back).
- Access:
schedule:write - Inputs:
id(string, required);done(boolean)
Food and money
shopping_list
Groceries for the home meals in a week, grouped by store section with quantities, whole packs and an estimated cost; pantry staples listed separately. Default: 7 days from the next grocery run. format=text (default) or json.
- Access:
schedule:read(read-only) - Inputs:
from(string): YYYY-MM-DD;days(integer);format(text | json)
weekly_budget
Planned spending for a week: groceries (from the shopping list), eating out (meals with source 'out': office café, restaurants, bars, with what to order and cost), gas (event.costs kind gas, in dollars or miles priced with profile.car), rideshares, other event costs (tickets, gear…) and each bill's share of the week (rent, insurance), plus the same plan per month. Default: 7 days from the next grocery run.
- Access:
schedule:read(read-only) - Inputs:
from(string): YYYY-MM-DD;days(integer)
Sharing and calendars
share
Create a public link someone can open and RSVP to. scope: 'event' (whole series), 'occurrence' (eventId + date), or 'day' (date).
- Access:
share - Inputs:
scope(event | occurrence | day, required);eventId(string);date(string);invitee(string)
list_shares
All share links with their RSVPs.
- Access:
schedule:read(read-only) - Inputs: No inputs.
calendar_feed_urls
Subscription URLs for Google Calendar / Apple Calendar (all events, or one calendar such as 'work').
- Access:
schedule:read(read-only) - Inputs: No inputs.
Imports
import_activities
Import completed activities (e.g. from Strava or Apple Health) as done workout events; dedupes by externalId per source.
- Access:
import - Inputs:
source(string, required);activities(list of object, required)
Keys
Only with the admin scope.
list_api_keys
API keys for agents and integrations: name, scopes, when created and last used, and whether revoked. Secrets are never shown again.
- Access:
admin(read-only) - Inputs: No inputs.
create_api_key
Create a key for one agent or integration. scopes: schedule:read, schedule:write, share, import, feed, admin. Returns the token once (dly_…); the agent sends it as Authorization: Bearer <token> and its writes are logged as agent:
- Access:
admin - Inputs:
name(string, required);scopes(list of schedule:read | schedule:write | share | import | feed | admin, required)
revoke_api_key
Revoke an API key by id; it stops working at once.
- Access:
admin - Inputs:
id(string, required)