Capture and tools
The on-device capture grammar that turns a sentence into a task, and the single tool catalogue that Siri, the assistant, MCP clients and agents all share.
Capture in two seconds
TaskNLParser turns a plain sentence into a task. It is pure Foundation code: no network, no key and no model.
let r = TaskNLParser().parse("call mom tomorrow 5pm #family !high ~15m")
// r.draft → title "Call mom", due tomorrow 17:00, priority High,
// estimate 15 min, context "family", kind Call
// r.understood → ["High", "≈15 min", "#family", "<tomorrow>, 5:00 PM", "Call"]
let task = try store.createTask(r.draft)
Alongside the draft it returns an understood list, which the app shows as confirmation chips so you can see what it picked up before saving. Words it does not recognise stay in the title: it never invents a wrong date or drops what you typed.
You can try a JavaScript port of the same rules on the Tasker showcase.
The grammar
| Aspect | Examples | Result |
|---|---|---|
| Relative days | today, tonight, tomorrow, tmrw, day after tomorrow | Due date |
| Offsets | in 3 days, in 2 weeks, in 2 hours, in 30 min | Due date and time |
| Weekdays | friday, next monday, this wed | The next matching day |
| Calendar dates | jun 12, 12 june, june 12 2027 | Due date; rolls to next year if the date has passed |
| Times | at 5pm, 5:30pm, 17:00, noon, midnight, at 5 | Time of day; a bare at 5 means 5 PM |
| Day parts | morning, afternoon, evening | 9:00, 14:00 and 19:00 |
| Priority | urgent, asap, important, !high, critical, high priority, someday | Low, high or critical |
| Estimate | ~15m, 30 min, for 2 hours, 90min | Estimated minutes |
| Energy | deep work, ~focused, #quick | Quick, focused or deep work |
| Tags | #errands, @phone | Contexts |
| Recurrence | every day, every weekday, weekly, every monday | Repeats, with a first due date |
| Defer | defer to friday, starting next week | Hidden until that day |
| Kind | call …, buy …, meet …, pay …, waiting on … | Call, errand, meeting, admin or waiting |
| Prefixes | remind me to …, todo: …, idea: … | Stripped; idea: also sets the kind |
Defaults keep results predictable: a day with no time is due at 9:00, a time with no day means today (or tomorrow if that time has passed), and a recurring task with neither starts today at 9:00. in 2 hours is a due time, not an estimate.
An optional model, after the rules
For messy dictation, the app can refine the result with a language model you configure. The rules always run first and the model only fills gaps; it never overrides a confident rule match. It is the only capture path that can send text off the device, it runs only when you have added a key, and any network or parsing error falls back to the rules result.
ByokKeyStore.set(userEnteredKey) // device Keychain, never synced
let backend = LLMTaskBackend(config: .openAI()) { ByokKeyStore.get() }
let r = await TaskNLParser().parse(messyDictation, backend: backend)
One tool catalogue
Every AI surface acts through TaskToolkit, so Siri, the in-app assistant, MCP clients and assistants behave the same way. Each tool carries a JSON Schema and runs by name with JSON arguments:
let toolkit = TaskToolkit(store: store)
let result = try await toolkit.call("capture_task", ["text": .string("pay rent by jun 1 urgent")])
// → { "ok": true, "task": { id, title, due, priority, … }, "understood": [ … ] }
| Tool | Reads only | Purpose |
|---|---|---|
capture_task | Create a task from a natural-language phrase | |
create_task | Create a task from explicit fields | |
list_tasks | Yes | Open, today, overdue, available, waiting or all, with list, project and context filters |
complete_task | Mark a task done by id or title | |
reschedule_task | Change a due date | |
defer_task | Hide a task until a date | |
plan_day | Yes | An ordered plan within a minute budget |
create_project | Create a project that groups tasks | |
list_projects | Yes | Projects with progress |
create_space | Create a page space, optionally bound to a project | |
create_page | Create a page with an optional Markdown body | |
append_to_page | Append Markdown to a page | |
read_page | Yes | Read a page’s metadata and body |
list_pages | Yes | List pages by space, label or title |
link_page | Link a page to a task or project | |
search_pages | Yes | Full-text search across pages |
Conventions an agent can rely on:
- A malformed call (unknown tool, missing required argument) throws.
- “No matching task” is a normal result,
{ "ok": false, "error": … }, so an agent can recover. - Dates accept ISO 8601 or natural language, such as
"tomorrow 5pm".
Siri, Shortcuts and Spotlight
TaskIntents builds on the same toolkit, so spoken results match the app: add a task in plain language, plan my day, complete a task, create a task and add to a page. An AppShortcutsProvider registers the phrases, so they appear in Siri, the Shortcuts app and Spotlight with no setup.