Scheduled jobs
at and cron persist on the control plane. They keep running after this chat ends. They are not a loop inside a live MCP session.
Who can schedule: repository owner or write (including agents). Read members cannot. Run capabilities and check can_schedule instead of guessing.
Scheduling does not need Slack HITL. Jobs run as the identity that created them (created_by). They do not become the repository owner. File modes, agent jail, and remaining owner-only ops (sudo, chgrp, custom-hostname publish, …) still apply at fire time.
Done looks like
crontab -l (or atq for a one-shot) shows a job id. When the time hits, runs list --kind scheduled_job has a row. runs show JOB_ID is not stuck in needs_attention. The script’s side effect exists (mail sent, file written, goal finished).
Worked example: weekday morning script
You have write access (can_schedule: true). Put a script in the repo, then cron it.
mkdir -p scripts
scripts/morning-status.sh:
#!/usr/bin/env bash
set -euo pipefail
goal --background --path sites/sails --time-budget 30m "Write today's status note under pages/blog/. Then mail site-bot that it shipped."
Five-field cron (UTC): 0 14 * * 1-5 is 14:00 UTC, Monday–Friday (8:00am America/Denver during MDT).
echo 'bash scripts/morning-status.sh' | cron '0 14 * * 1-5'
# or: cron '0 14 * * 1-5' bash scripts/morning-status.sh
crontab -l
Expected shape (ids differ):
<job-id> 0 14 * * 1-5 bash scripts/morning-status.sh
Edit the script in place; keep one schedule line.
One-shot: at
Live CLI takes a sleep-style duration (+5m, +2h, +1d), not wall-clock “now + …”:
echo 'bash scripts/morning-status.sh' | at +5m
atq
atrm JOB_ID
Use at to prove the script before you cron it, or for a single reminder.
Who sees which jobs
| Role | Create | List / cancel |
|---|---|---|
| Write (human or agent) | Own jobs | Own jobs |
| Owner | Any | Every job; crontab -r with no id cancels all cron jobs |
| Read | No | No |
Write members cancel with crontab -r JOB_ID or atrm JOB_ID on jobs they created. Owners (or HITL-elevated goals) can cancel anyone’s.
Commands
cron 'M H D M W' bash scripts/job.sh
echo 'bash scripts/job.sh' | cron 'M H D M W'
crontab -l
crontab -r [JOB_ID]
at +5m bash scripts/job.sh
echo 'bash scripts/job.sh' | at +5m
atq
atrm JOB_ID
runs list --kind scheduled_job
runs show JOB_ID
runs log JOB_ID
capabilities
| Command / flag | What it does |
|---|---|
cron 'EXPR' … | Recurring job. Standard 5-field expression (UTC). |
crontab -l | List cron jobs you can manage. |
crontab -r JOB_ID | Cancel one cron job. No id: your cron jobs, or all if you are owner. |
at +DURATION | One-shot. Suffixes: 30, 30s, 5m, 2h, 1d. |
atq / atrm | List / cancel waiting one-shots. |
runs list --kind scheduled_job | Fire history. |
runs show / runs log | Status / attempts / transcript. |
capabilities | JSON; look at can_schedule. |
There is no --path on cron / at. Cwd is the repository workspace. Scope the work inside the script (goal --path …, or cd to a folder you can write).
Failure modes
| What you see | What it means | What to do |
|---|---|---|
Hint that write access is required / can_schedule: false | You are a read member | Ask a write member or owner to schedule it |
Job missing from crontab -l | Pipe failed, or someone ran crontab -r | Recreate; do not invent a second name |
Empty runs list --kind scheduled_job after fire time | Expression is UTC, or script path is wrong | Recheck 5 fields; use repo-relative bash scripts/… |
needs_attention | attempt_count >= max_attempts | runs show / runs log; fix the script; schedule stays |
Script cannot sudo / custom-hostname publish | Job runs as creator, not as owner | Owner runs that part, or elevate a Slack goal for owner-only ops — not for cron itself |
| Agent jail blocks the folder the script edits | Jail still applies at fire time | agent jail the path, or start goal --path on a writable folder |
You used at now + 5m | Live CLI expects +DURATION | at +5m |
goal: unknown flag --token-budget / --budget | Those flags do not exist on goal | Use --time-budget 30m |
How to: Run something every morning. Starting work from HTTP instead of a clock: Start a goal from a webhook.