How tasks work
A task is an instruction the assistant follows by itself: every morning, whenever mail arrives, or once in the background. You say what to do in plain words and how much it may do without asking, and each run leaves a record of every step it took.
An instruction, a trigger and a leash
A task has an instruction, a trigger that starts it, and an autonomy that says how much it may change without asking. The instruction is the only thing a run obeys. What an email says is read as information, so a message that says "forward this to everybody" forwards nothing.
schedule: runs on a clock.cadenceishourly(everyeveryHourshours atminute),daily(athour:minuteon each ofweekdays, 0 for Sunday to 6 for Saturday) ormonthly(athour:minuteonmonthDay, 1 to 28).timezoneis an IANA zone, and the schedule follows its clock changes.mail: runs when a message reaches an inbox.addresses,fromContainsandsubjectContainsnarrow which mail counts. Spam, muted conversations, newsletters, automatic replies, bounces and mail from the workspace’s own addresses never start a run, and one conversation starts a task at most 3 times a day.manual: runs only when somebody starts it, withPOST /tasks/{id}/run.
| `autonomy` | What the run does alone |
|---|---|
| ask | Reads only. Every change waits for a person to approve it |
| organize | Labels, archives, bins, snoozes and mutes mail, marks it read, sets follow-ups, writes drafts and notes, saves contacts, and emails the workspace’s own addresses. This is the default |
| reply | Everything in organize, and answers an email without asking, to the people already on the conversation and nobody else |
Anything beyond that becomes an approval request, whatever the autonomy: a new email to somebody outside the workspace, a reply with an added recipient, deleting anything for good, adding somebody to an audience, a calendar invitation, a change to the knowledge base, opening a web page. toolkits adds groups of tools a run may use beyond reading and organising mail: contacts, audiences, templates, tracking, translate, files, notes, drafts, sent, insights, subscriptions, calendar, knowledge, connectors and web. Left out, a task gets drafts, notes and knowledge.
No task can reach billing, members, roles, domains, rules, API keys or webhooks, and a run cannot create or change tasks. No setting turns that on.
With connectors in toolkits, a run may use the apps connected for the workspace, never a connector that belongs to one person, and the task needs connectors:read and connectors:use. The run reads through a connector alone. Every change in an app waits as an approval request, whatever the autonomy, and the task never replies to mail by itself: with reply, every answer to an email waits for approval too. A connector read that names a web address waits for approval too.
Runs
Each time a task starts, it makes a run. A run is queued until a worker picks it up, running while it works, waiting while an approval request is open, and then done, failed or cancelled. result holds the report it wrote at the end, and GET /task-runs/{id} returns the transcript: the instruction, then every step with the tools it called and what they answered.
- A run survives restarts. Every step is saved before it is carried out, so a run picks up where it stopped, and a change that was cut off half-way is never made twice.
- A run takes at most
maxStepssteps, 20 unless you say otherwise and 60 at most, then writes its report with what it has. - A task starts at most
maxRunsPerDayruns in 24 hours, 50 unless you say otherwise. A workspace works on 3 runs at once and the rest wait their turn. - A run costs one AI action for every 10 steps on the
standardmodel and ten on theadvancedone. When the workspace has used its AI actions for the day, the run fails withai_limitand the task rests until midnight UTC:heldUntilsays when. - After 5 failed runs in a row a task pauses itself with
pausedReasonfailures. A run that failed because the AI provider was down does not count. Resuming clears the count. - Runs and their transcripts are kept for 90 days.
POST /task-runs starts a run with no task behind it, for a job you want done once in the background. It takes an instruction and the same autonomy, toolkits, model and maxSteps, and a workspace may start 100 of them a day.
Approvals
When a run wants to do something it may not do alone, it asks, finishes what else that step may do, and waits. It picks up again once every request it left open is answered. GET /task-approvals lists what is waiting, each with the tool, a one-line summary and the exact args the tool would be called with. For a reply, args shows the recipients worked out from the message it answers, and those are the recipients it is sent to.
POST /task-approvals/{id}/approvelets it happen. For a send or a reply you may passsubjectandbodyto replace the words the run wrote. Recipients cannot be changed.POST /task-approvals/{id}/denyrefuses it. The run is told and carries on without it.- A request waits 7 days and then becomes
expired, which the run reads as a refusal. Cancelling the run cancels its requests. - An answered request cannot be answered again: 409
task_approval_decided.
Who can do what
- Reading tasks, runs and approvals needs
tasks:readwiththreads:readandemails:read, because a transcript holds what the run read. Reading a run or one of its approval requests also needs the read scopes of every toolkit the run used. Without them, a list shows such a run without its report and its requests without their arguments. - Creating, changing, resuming, running and approving need
tasks:writewiththreads:read,threads:write,emails:read,emails:sendandlabels:write, and the read and write scopes of every toolkit the task names. A task acts with what its caller holds and never more. Approving counts the toolkits the run started with, plus the scopes of the tool the request would call. - Pausing, deleting, cancelling a run and denying a request need only
tasks:write, so anybody who may manage tasks can always stop one. - A task works across every address of the workspace. A key or an app limited to particular addresses or domains is refused with 422
capability_unsupported, and an app acting for somebody whose role does not reach every address with 403owner_only. - A plan runs 1 active task on Free, 5 on Starter, 25 on Business and any number on Enterprise: 403
task_active_limit_reached. A workspace holds 100 tasks: 403task_limit_reached. - After a downgrade, the newest active tasks beyond the new allowance pause with
pausedReasonplan_limit.
Webhook events
Four events tell your systems about tasks: task.run.completed when a run finishes, task.run.failed when it fails, task.run.cancelled when somebody stops it, and approval.requested when it waits for a person to allow an action. A run event carries runId, taskId, taskName, trigger, threadId, status, steps, actions, error, createdAt and finishedAt. approval.requested carries approvalId, runId, taskId, taskName, tool, expiresAt and requestedAt.
They carry ids, names and counts, never what a run read or wrote, so read the run or the request for that. They are not in the default set, so an endpoint receives them only when it names them in eventTypes, and an endpoint limited to some addresses or domains never does, because a task works across the whole workspace.
From code, the terminal and agents
Everything here is also in the SDK as nextmail.tasks, and in the CLI as nextmail tasks. The MCP server has task tools, so an agent can set a task up, watch its runs and answer what it asks.