Skip to main content
How-To Guides Last updated: 20 April 2026

Schedule tasks

There are several ways to run tasks on a schedule: the /at command for quick one-shot delays, Telegram's built-in message scheduling, and Untether's trigger ...

There are several ways to run tasks on a schedule: the /at command for quick one-shot delays, Telegram’s built-in message scheduling, and Untether’s trigger system (webhooks and cron).

One-shot delays with /at

The /at command schedules a prompt to run after a delay — useful for reminders, follow-ups, or “run this in 30 minutes”:

/at 30m Check the build
/at 2h Review the PR feedback
/at 60s Say hello

Duration format: Ns (seconds), Nm (minutes), or Nh (hours). Minimum 60 seconds, maximum 24 hours.

After scheduling, you’ll see a confirmation:

Untether ⏳ Scheduled: will run in 30m Cancel with /cancel.

When the delay expires, the prompt runs as a normal agent session. Use /cancel to cancel all pending delays in the current chat.

Not persistent Pending /at delays are held in memory. They are lost if Untether restarts. For persistent scheduled tasks, use cron triggers instead.

Engine and project frozen at schedule time When you run /at, Untether snapshots the chat’s current project mapping and engine at that moment. That snapshot is what fires when the delay expires — changing /agent, /ctx, or /planmode afterwards does not affect already-scheduled delays. Cancel with /cancel and re-schedule if you change your mind. (#362)

Telegram scheduling

Telegram’s native message scheduling works with Untether out of the box.

In Telegram, long-press the send button and choose Schedule Message to run tasks at a specific time. You can also set up recurring schedules (daily/weekly) for automated workflows.

This is the simplest approach — no server or config changes needed.

How to schedule In Telegram, long-press the send button (iOS) or tap the clock icon (Android/Desktop) and choose Schedule Message. Pick a date and time, then tap Send. Untether receives the message at the scheduled time and starts the run automatically.

Cron triggers

For more control, use Untether’s built-in cron system. Cron triggers fire on a schedule and start agent runs automatically.

=== “toml”

```toml
[triggers]
enabled = true

[[triggers.crons]]
id = "daily-review"
schedule = "0 9 * * 1-5"
project = "myapp"
engine = "claude"
prompt = "Review open PRs and summarise their status."
```

This runs every weekday at 9:00 AM (server time) in the myapp project using Claude Code. Add timezone = "Australia/Melbourne" to evaluate in a specific timezone, or set default_timezone in [triggers] for all crons. See Webhooks and cron for details.

Common schedules:

ExpressionMeaning
0 9 * * *Daily at 9:00 AM
0 9 * * 1-5Weekdays at 9:00 AM
*/30 * * * *Every 30 minutes
0 */4 * * *Every 4 hours

Add run_once = true to fire a cron exactly once, then auto-disable. Fired state persists to run_once_fired.json (sibling of your untether.toml), so a reload or restart will not re-fire it. Remove the cron from your TOML to clean up.

Autonomous crons in plan-mode chats (Claude) {#autonomous-crons}

By default a cron inherits the chat’s permission mode, so if you’ve set /planmode plan on a Claude chat the scheduled run will pause for your approval too. That’s rarely what you want for an 8 AM summariser that runs while you’re asleep.

Set permission_mode = "auto" on the cron to make that run autonomous without flipping the whole chat:

[[triggers.crons]]
id = "overnight-review"
schedule = "0 6 * * *"
chat_id = -1001234567890
engine = "claude"
prompt = "Review overnight PRs and reply with a summary."
permission_mode = "auto"

Precedence (Claude): cron permission_mode > per-chat /planmode > engine config default. Every autonomous run logs trigger.cron.permission_mode_override. Valid values: default, plan, auto, acceptEdits, bypassPermissions. Claude-only for now; other engines silently ignore the field (#332 tracks full coverage).

Webhook triggers

Webhooks let external services (GitHub, Slack, PagerDuty) trigger agent runs via HTTP POST.

=== “toml”

```toml
[triggers]
enabled = true

[[triggers.webhooks]]
id = "github-push"
path = "/hooks/github"
auth = "hmac-sha256"
secret = "whsec_abc..."
event_filter = "push"
project = "myapp"
prompt_template = "Review push to {{ref}} by {{pusher.name}}"
```

See Webhooks and cron for the full setup guide, including authentication, prompt templating, and testing.

Was this helpful?

Related Articles