# Scheduled AI agent tasks, governed in advance

> Scheduled AI agent tasks run with nobody present to approve, so the controls that count are set first: role restrictions, frozen arguments, a narrowed grant.

**TL;DR** A scheduled task calls your SaaS tools when nobody is there to approve anything, so the only controls that matter are the ones configured before it runs. Through Elaichi, a scheduled run acts as the member whose OAuth grant the client holds, under that member's role restrictions, and the audit trail names both the member and the client. The three things to set first are restrictions on the role, frozen parameters on a toolbox entry, and a grant scoped to chosen toolboxes.

## Why scheduled AI agent tasks need controls set before the run

A scheduled task fires at 6am with nobody at the keyboard. That single fact decides the rest. Scheduled AI agent tasks are made safe by what you configure in advance. The approval prompt that would normally catch a bad call has no one there to answer it.

Most teams reach for approval first. Right instinct, wrong layer. Over Elaichi's MCP endpoint, the OAuth grant is the approval. MCP is the protocol an AI client uses to find and call tools. OAuth is the sign-in that issues a client a token on a person's behalf. The person ticked scopes on Elaichi's consent screen for that named client, and that was the human decision. There is no per-call prompt on the endpoint, and any approval card an MCP client renders from Elaichi's results is display only. This applies specifically to the OAuth-gated pattern described here. Some MCP servers authenticate with static API keys or mTLS instead. That removes the consent-screen step entirely and pushes all authorization decisions onto whatever issued the key. If your stack uses that pattern, the "grant as approval" argument below doesn't transfer; you need an equivalent decision made at key-issuance time. [The layers of approval](/blog/human-approval-for-ai-agent-actions/) sets out who decides what, and where.

One limit belongs in the open. The endpoint does not inspect prompts and cannot, because an MCP server never sees the user's prompt. It only sees the tool call and arguments the client's model chose to send. The prompt-injection write gate in the Elaichi Agent window does not apply to `POST /mcp`. What does hold on the endpoint: permissions per operation, the forbidden classification, output redaction, OAuth scope limits and full audit logging. None of these five inspect the natural-language prompt that produced the call; all five constrain or record the call itself.

## What do scheduled tasks in Claude and ChatGPT do today?

Three surfaces, three different answers, each read on the vendor's own page.

| Surface | Default write behavior | Approval model | Execution identity | Source checked |
|---|---|---|---|---|
| ChatGPT scheduled tasks | Can use Gmail, Slack, GitHub and similar apps; writes may pause for approval | Actions that send messages or change data may pause the task for approval; workspace admins control app permissions | Tasks are included in the Compliance API | [OpenAI help center](https://help.openai.com/en/articles/10291617-scheduled-tasks-in-chatgpt), checked October 2026 |
| Claude Code routines (research preview) | Every connected connector is included by default; writes execute without approval | No approval step; the routine calls tools, writes included, unattended | Actions appear as the owning user | [Claude Code docs](https://code.claude.com/docs/en/web-scheduled-tasks), checked October 2026 |
| Claude Cowork scheduled tasks | Uses connectors; runs remotely | Not documented on the cited page | Not documented; the execution identity is unspecified | [Claude support](https://support.claude.com/en/articles/13854387-schedule-recurring-tasks-in-claude-cowork), checked October 2026 |

A pause is the safe outcome and also an unfinished job, the trade-off to weigh before scheduling anything that writes. Claude Code's shape works unattended precisely because it skips that trade-off. That puts the whole weight of the control on what the owning user can reach: if the user's account can delete a repo, the routine can too. Claude Cowork's undocumented identity is not a minor omission. "Whose credential did this action run under" is the first question any access review asks, and a page that doesn't answer it means you're assuming, not verifying. Treat it as an open question to put to Anthropic rather than a gap to fill in with guesswork.

The practical reading: an unattended run may stop and wait, may write without asking, or may act as an identity nobody can name. Pick your controls accordingly, and re-verify this table against the vendor pages periodically. Scheduled-task behavior for all three products is young enough (research preview, in one case) that it is likely to change faster than most API surfaces.

## Whose account does a scheduled run act as through Elaichi?

It acts as the member whose grant the client holds. Nothing else.

Every client points at one organization-wide address, `POST https://api.elaichi.ai/mcp`, and each member signs in there once with their own OAuth grant. A scheduled task calls through whichever grant its client is holding, so the call carries that member's role, that member's restrictions and that member's connections. There is no shared service account in the middle unless somebody deliberately shares a connection. A shared connection runs on its owner's credential, so the app sees the owner's account. The reasoning behind [giving an agent an employee's own permissions](/blog/ai-agents-employee-permissions/) is the same reasoning that makes a scheduled run attributable.

The record says the same thing afterward. Elaichi writes one entry per tool-call attempt, succeeded or failed, and each entry names the member, not a generic "agent" identity. The entry also records the surface, `mcp`, and the OAuth client the call came through. A client's name is marked verified only when its redirect URIs prove it, which covers Claude, ChatGPT and Cursor. A client signing in through a loopback address, such as Claude Code, shows the name it registered with, marked unverified. The approval line on an MCP entry reads "Allowed by the access <client> was granted." That describes the OAuth grant as the authorizing event, not a per-call human decision. [What an AI agent audit log must capture](/blog/what-an-ai-audit-log-must-capture/) covers the rest of the record shape.

## Which controls hold when nobody is present

Three mechanisms, all set before the schedule fires: restrictions on the role, frozen parameters on a toolbox entry, and a grant scoped to chosen toolboxes. These are Elaichi-specific constructs. The general principle (constrain reachable tools, pin dangerous arguments, scope the credential) is portable to any MCP control plane. The specific nouns below are not standard MCP or OAuth terms.

**Restrictions on the role.** A restriction decides which connectors and which individual tools a target may reach. In Elaichi, restriction targets are role or user only; the organization default is the absence of a rule, which means allow everything. Within the winning layer, allow rules union, block rules union, and blocks always beat allows. So a single block on a destructive tool cannot be overridden by any allow rule in the same role, and the two rule types [match a tool by different things](/blog/block-matches-name-allow-matches-operation/). For a scheduled role, blocks on an app's destructive tools are the simplest shape that does not break the rest. An allow rule behaves differently and catches people out. It becomes the role's whole allowlist across every connector, so every other app that role needs takes its own allow rule, naming whole connectors where that is fine. An allow rule naming nothing denies everything. Restrictions are enforced at browse, connect, advertise and execute, plus a final check on the fully substituted outbound URL. So a withheld tool reaches neither `tools/list` nor `search_tools`, and the model behind a scheduled run never learns it exists. This is a stronger guarantee than "the model is instructed not to call it," since the tool is never advertised as an option at all. A restriction change takes effect within about two minutes, which matters when you're trying to close access in a hurry.

**Frozen parameters on a toolbox entry.** A freeze is a per-entry map over a tool's arguments: a destination folder, a payee, a channel. Frozen keys are stripped from the advertised schema, so the model never sees them as fillable fields. Frozen values are merged over caller arguments at execution, so a model that guesses the key name and passes it anyway cannot un-freeze it. The precedence order is: entry defaults, then caller arguments, then frozen values. Frozen values win last. The caveat matters more than the mechanism: a freeze holds only on the path that runs through the entry. If the owner shares the connection itself with the team, the frozen path is bypassed. Anyone holding use on the connection can call the tool unfrozen. The correct setup: the owner keeps the connection unshared with the team. The owner then pins it into a toolbox entry with frozen values, and shares the toolbox at `use`. Do not try to close the other path with a restriction. A block on the tool withholds the frozen entry too, since restrictions apply before entry-level logic runs. [Locking a tool argument the way a wire transfer locks a payee](/blog/frozen-parameters-wire-transfer-receiver/) walks through the setup.

**A grant scoped to chosen toolboxes.** On Elaichi's consent screen, with "Run your connected tools" ticked, a second step asks which toolboxes. The choice is All my tools, or Only the ones I pick, up to 50. For a client that will run unattended, pick. A grant scoped to chosen toolboxes reaches only their tools. If none of them resolves any more there are no connected tools at all, never a silent fallback to everything else the member can reach.

One correction worth carrying into the setup. Leaving "Create and change data" unticked does not make a connected app read-only. For a connected app's tools, "Run your connected tools" covers reads and writes alike. Only a tool whose method is a delete also costs "Delete data and remove access." Read-only access to a connected app is a restriction, not a consent checkbox. [Least privilege without breaking automation](/blog/least-privilege-tool-calls-without-breaking-automation/) covers how far to take that before the task stalls.

## What stops a scheduled task, and how fast?

Some changes stop a scheduled run on its very next call, and some take longer. The difference matters when you are closing access in a hurry. Assuming the wrong latency during an incident is itself a risk.

**Next call (fast path):** removing or suspending the member. In Elaichi, removing or suspending a member revokes every live grant in the same transaction as the membership change. A SCIM deprovision sets the member to suspended rather than removing them, and that is enough to refuse the next call. SCIM is the standard an identity provider uses to push joiners and leavers into an app. Revoking a share or disconnecting an account also takes effect on the caller's next request. A revoked grant returns 401 `invalid_token`; a refresh attempt against a revoked grant returns `invalid_grant`.

**Propagation delay (slow path):** role changes, restriction changes and team membership changes take effect within about two minutes. Never plan a shutdown around a restriction edit for that reason. To stop a task at once, suspend the member or revoke the grant, and leave the role alone.

Then there is the clock the task runs against regardless of what you change. An access token lasts 1 hour. A refresh token lasts 30 days and rotates on every use; reusing an old refresh token or authorization code revokes the whole grant. The grant itself has no expiry. But a client idle past 30 days needs the member to sign in again, in a browser, since sign-in cannot be completed headless. Practical consequence: a schedule that quietly stops running is often a grant that needs reconnecting, not a broken connector. That distinction should be the first thing you check before debugging further.

Last, the person behind the connection. Each toolbox entry records who pinned it, and that identity is re-checked on every call, not just at creation. If that person loses `use`, is removed, or is SCIM-suspended, the entry resolves `unmet` for every grantee until someone present re-pins it. So a scheduled task can stop working weeks after the person who set it up has left. The connection behind a recurring task should belong to someone who will still be there in six months, as a matter of design, not hope. [Offboarding when the agent holds access](/blog/offboarding-when-the-agent-holds-access/) covers the preflight.

## When a scheduled run is the wrong shape

If a person genuinely has to look at every write before it lands, do not schedule it over an MCP endpoint at all. There is no mechanism described above that inserts a human into that loop. The Elaichi Agent fits that requirement: a write or delete there stops at an approval card with Deny, Allow once and Always allow, and a delete asks every time. ChatGPT's scheduled tasks may pause for approval on data-changing actions, so check that behavior against the requirement before relying on it. The MCP endpoint, by design, puts no person in the loop.

If the task only reads, skip the frozen parameters and spend the effort on restrictions. A read-only scheduled summary needs a narrow role and an accurate audit trail. Frozen parameters solve an argument-tampering problem that doesn't exist if no call in the role can write.

And if one team runs one app with one assistant, a scheduled task pointed at that app's own MCP server is often enough. Standing up a separate control plane adds overhead that only pays off once the same role needs to touch more than one system. The case for a control plane starts when the same role touches several apps. That is the argument in [what an MCP control plane is](/blog/what-is-an-mcp-control-plane/). The apps a scheduled role can be pointed at are in the [connector catalog](/connectors/), 600+ connectors in all.

## FAQ

### Does Elaichi ask for approval before a scheduled AI task writes to an app?

No. Over Elaichi's MCP endpoint, the OAuth grant is the approval: the person picked scopes on Elaichi's consent screen for that named client, and the server re-checks those scopes on every call. There is no per-call prompt on the endpoint, and any approval card an MCP client renders from Elaichi's results is display only. Per-call prompting over MCP belongs to the client. Inside the Elaichi Agent, a write or delete does stop at an approval card before it runs.

### Whose permissions does a scheduled AI agent task run with?

Through Elaichi, a scheduled task runs with the permissions of the member whose OAuth grant the client holds. The call carries that member's role, restrictions and connections, and Elaichi's audit entry names that member, the surface (mcp) and the OAuth client it came through. Claude Code routines act as the owning user, per [Anthropic's docs](https://code.claude.com/docs/en/web-scheduled-tasks) (checked October 2026); whose identity a Claude Cowork scheduled task acts as is not documented.

### How long can a scheduled task keep calling without anyone signing in again?

An Elaichi access token lasts 1 hour and a refresh token lasts 30 days, rotating on every use. A client that keeps refreshing can run indefinitely, but one that sits idle past 30 days needs the member to sign in again in a browser, because Elaichi's OAuth sign-in cannot be completed headless. Reusing an old refresh token or authorization code revokes the whole grant.

### What happens to a scheduled task when the employee behind it leaves?

In Elaichi, removing or suspending a member revokes every live grant in the same transaction as the membership change. So the scheduled task's very next call is refused. A SCIM deprovision sets the member to suspended rather than removing them, which has the same effect on live grants. Separately, any toolbox entry that person pinned stops resolving for every grantee until someone present re-pins it.

### Can an argument be locked so a scheduled agent cannot change it?

Yes, with frozen parameters on a toolbox entry in Elaichi. Frozen keys are stripped from the advertised tool schema, so the model never sees them, and frozen values are merged over caller arguments at execution, so passing the key cannot override the freeze. The freeze holds only on the path through that entry, so the connection's owner leaves the connection unshared and shares the toolbox at use instead.

## Read next

- [Human approval for AI agent actions: the layers](/blog/human-approval-for-ai-agent-actions/) — Human approval for AI agent actions comes in layers: a prompt for the person asking, then the role rules, frozen values and requests an admin decides.
- [AI agents with employee permissions, no shared bot](/blog/ai-agents-employee-permissions/) — How to run AI agents with employee permissions instead of one shared service account, and the cases where a named service identity is still correct.
- [Least privilege for AI agents without breakage](/blog/least-privilege-tool-calls-without-breaking-automation/) — Least privilege for AI agents starts from what your pilot actually called: narrow to that recorded set, then confirm the rule landed before you trust it.
