git:20260720.b43e22a to git:20260804.50a9e49

5 added, 5 removed. Audit A to A.

---
name: scheduling-tasks
description: Schedules reminders and recurring tasks via the letta cron CLI. Use when the user asks to be reminded of something, wants periodic messages, or needs to manage scheduled tasks.
---
# Scheduling Tasks
This skill lets you create, list, and manage scheduled tasks using the `letta cron` CLI. Scheduled tasks send a prompt to the agent on a timer — useful for reminders, periodic check-ins, and deferred follow-ups.
## When to Use This Skill
- User asks to be reminded of something ("remind me to X at Y")
- User wants a recurring check-in ("every morning ask me about X")
- User wants a one-shot delayed message ("in 30 minutes, check on X")
- User wants to see or cancel existing scheduled tasks
## Where Schedules Run (`--runner`)
There are two schedule runners, selected with the optional `--runner local|cloud` flag:
- - **`cloud`** (default for cloud agents): a durable Cloud schedule stored by the Letta API. It fires from the cloud and executes in the agent's cloud sandbox, so it survives local shutdown — the computer, sandbox, or session that created it can disappear and the schedule still fires.
+ - **`cloud`** (default for cloud agents): a durable Cloud schedule stored by the Letta API. With no runner or computer flag, it keeps executing where it was created: a registered external listener becomes the schedule's target, and a managed cloud sandbox gets an untargeted schedule that fires in the agent's cloud sandbox. Either way the schedule survives process restarts.
- **`local`**: a task local to the current computer (`~/.letta/crons.json`), executed by the Letta session running there. It only fires while a session is running on that computer, and it dies with that computer's local state.
- You normally don't need the flag — the default does the right thing. Local-backend agents (`agent-local-*`) and self-hosted servers always use the local runner.
+ You normally don't need the flag. Use explicit `--runner cloud` to run in the agent's Cloud sandbox instead of the current listener. Local-backend agents (`agent-local-*`) and self-hosted servers use the local runner.
If the scheduled work must run on a **specific computer** (it needs that computer's filesystem, local services, or credentials — e.g. a bring-your-own machine like a Railway/VPS box or a home workstation), prefer a Cloud schedule that executes on that computer:
```bash
letta cron add ... --computer <deviceId>
```
- The deviceId comes from `letta environments list`. The computer must be connected to your Letta account (run `letta server` on it, or enable remote access in the desktop app). The schedule stays durable in the cloud; if the computer is offline when it fires, execution falls back to the agent's cloud sandbox. Use `--runner local` (run on the target computer itself) only when that sandbox fallback is unacceptable — a local task never runs anywhere but its own computer.
+ The deviceId comes from `letta environments list`. The computer must be a registered external environment, such as a manual `letta server`, VPS, or Railway listener. Managed sandboxes and Desktop-local proxy connections are not currently valid targets. The schedule stays durable in the cloud; if the computer is offline when it fires, execution falls back to the agent's Cloud sandbox. Use `--runner local` on the target computer only when that fallback is unacceptable.
Notes for the cloud runner:
- - Untargeted schedules execute in the agent's cloud sandbox, not on the computer where you created them; `--computer` executes on the named computer with sandbox fallback.
+ - The implicit default infers the current runtime: a registered external listener is targeted, a managed sandbox falls through to an untargeted schedule. `--computer` overrides it. Explicit `--runner cloud` always creates an untargeted Cloud-sandbox schedule.
- Recurring `--cron` expressions are currently interpreted in UTC (the CLI output includes a note about this). `--at` and `--every` are unaffected.
- If creating a Cloud schedule fails, no schedule is created — there is no silent fallback to local storage. Retry, or pass `--runner local` deliberately.
## CLI Usage
All commands go through `letta cron` via the Bash tool. Output is JSON.
### Creating a Task
```bash
letta cron add --name <short-name> --description <text> --prompt <text> <schedule>
```
**Required flags:**
| Flag | Description |
|------|-------------|
| `--name <text>` | Short identifier for the task (e.g. "dog-walk-reminder") |
| `--description <text>` | Human-readable description of what the task does |
| `--prompt <text>` | The message that will be sent to the agent when the task fires |
**Schedule (pick one):**
| Flag | Type | Example |
|------|------|---------|
| `--every <interval>` | Recurring | `5m`, `2h`, `1d` |
| `--at <time>` | One-shot | `"3:00pm"`, `"in 45m"` |
| `--cron <expr>` | Raw cron (recurring) | `"0 9 * * 1-5"` |
**Optional flags:**
| Flag | Description |
|------|-------------|
| `--agent <id>` | Agent ID (defaults to `LETTA_AGENT_ID` from the current shell/session) |
| `--conversation <id>` | Conversation ID (defaults to `LETTA_CONVERSATION_ID` from the current shell/session, otherwise `"default"`) |
| `--runner <runner>` | `cloud` or `local` — see "Where Schedules Run" above (defaults to `cloud` for cloud agents) |
- | `--computer <id>` | (cloud runner only) Execute on a connected computer instead of the agent's sandbox; falls back to the sandbox if the computer is offline |
+ | `--computer <id>` | (cloud runner only) Override execution with a registered external environment; falls back to the Cloud sandbox if it is offline |
### Listing Tasks
```bash
letta cron list
```
Optional filters: `--agent <id>`, `--conversation <id>`
### Getting a Single Task
```bash
letta cron get <task-id>
```
### Binding a Task to the Right Conversation
If exact routing matters, pass both `--agent` and `--conversation` explicitly.
`letta cron add` will otherwise fall back to `LETTA_AGENT_ID` and `LETTA_CONVERSATION_ID` from the current shell/session. Those values may be correct for the current chat, but they can also be inherited from surrounding tooling, another conversation, or an older shell.
Safest pattern:
```bash
letta cron add \
--name "email-check" \
--description "Daily email summary in this conversation" \
--prompt "Check the user's email and post a summary here." \
--cron "0 10 * * *" \
--agent "$AGENT_ID" \
--conversation "$CONVERSATION_ID"
```
Then verify the binding explicitly:
```bash
letta cron list --agent "$AGENT_ID" --conversation "$CONVERSATION_ID"
```
### Deleting Tasks
```bash
# Delete a specific task
letta cron delete <task-id>
# Delete all tasks for the current agent
letta cron delete --all
```
## Examples
### "Remind me every morning at 9am to walk the dog"
```bash
letta cron add \
--name "dog-walk-reminder" \
--description "Daily morning reminder to walk the dog" \
--prompt "Hey! It's 9am — time to walk the dog." \
--every 1d
```
Note: `--every 1d` fires once daily at midnight. For a specific time like 9am, use a raw cron expression:
```bash
letta cron add \
--name "dog-walk-reminder" \
--description "Daily 9am reminder to walk the dog" \
--prompt "Hey! It's 9am — time to walk the dog." \
--cron "0 9 * * *"
```
### "Check on the deploy in 30 minutes"
```bash
letta cron add \
--name "deploy-check" \
--description "One-time check on deployment status" \
--prompt "The user asked you to check on the deploy — ask them how it went." \
--at "in 30m"
```
### "Every weekday at 5pm, remind me to submit my timesheet"
```bash
letta cron add \
--name "timesheet-reminder" \
--description "Weekday 5pm timesheet reminder" \
--prompt "Friendly reminder: don't forget to submit your timesheet before EOD!" \
--cron "0 17 * * 1-5"
```
### "What reminders do I have?"
```bash
letta cron list
```
If you need to confirm the exact conversation a task is bound to, list with explicit filters instead:
```bash
letta cron list --agent "$AGENT_ID" --conversation "$CONVERSATION_ID"
```
### "Cancel the dog walk reminder"
First list to find the task ID, then delete:
```bash
letta cron list
# Find the task ID from the output, then:
letta cron delete <task-id>
```
## Writing Good Prompts
The `--prompt` value is what gets sent to you (the agent) when the task fires. Write it as a message that will make sense when you receive it later, with enough context to act on:
- **Good**: "The user asked to be reminded to review the PR for the auth refactor. Check if it's still open and nudge them."
- **Bad**: "reminder"
Include context about what the user originally asked for, so you can give a helpful response when the prompt arrives.
## Important Notes
- **Minimum granularity**: 1 minute. Intervals under 60 seconds are rounded up.
- **Recurring tasks**: No longer auto-expire. They remain active until explicitly cancelled.
- **One-shot cleanup (local runner)**: One-shot local tasks are garbage-collected 24 hours after firing.
- **Timezone**: Local-runner tasks use the user's local timezone. Cloud-runner recurring `--cron` expressions are currently interpreted in UTC.
- **Default binding precedence**: `letta cron add` uses `--agent` / `--conversation` first, then falls back to `LETTA_AGENT_ID` / `LETTA_CONVERSATION_ID`, then finally uses `"default"` for the conversation if no env var is present.
- **Local scheduler requirement**: Local-runner tasks only fire while a Letta session is running on that computer (a WS listener must be active). If no session is running, tasks will be marked as missed. Cloud-runner schedules fire from the cloud regardless.
- **`--at` for specific times**: `--at "3:00pm"` schedules a one-shot. If the time has already passed today, it schedules for tomorrow.
- **`--every` for daily**: `--every 1d` fires daily at midnight. For a specific time of day, use `--cron` instead (e.g. `--cron "0 9 * * *"` for 9am daily).
## Cron Expression Reference
For `--cron`, use standard 5-field cron syntax:
```
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sun=0)
│ │ │ │ │
* * * * *
```
Common patterns:
- `*/5 * * * *` — every 5 minutes
- `0 */2 * * *` — every 2 hours
- `0 9 * * *` — daily at 9am
- `0 9 * * 1-5` — weekdays at 9am
- `30 8 1 * *` — 8:30am on the 1st of each month