Skip to content

Scheduled tasks

A scheduled task is a prompt and a cadence: “every weekday at 02:30, triage today’s new issues”. spwn runs it without you, headlessly and read-only, in a session of its own, and flags that session when it’s done so the result is waiting for you.

Open a project’s ◷ Scheduled Tasks row in the sidebar and click + New Task:

  • Name and Prompt: what the agent should do. It can read the project; it can’t edit files.
  • Time: local time of day.
  • Days: pick weekdays, or none for every day.
  • Use project context: prepend the project’s Merge tray (on by default).

Each task has Run now, Disable / Enable, Edit and Delete, and shows when it last ran.

A task can live in the repository instead, as .spwn/schedules/<name>.toml:

.spwn/schedules/nightly-triage.toml
name = "Nightly triage" # optional; the file stem otherwise
time = "02:30" # local time, 24h HH:MM
weekdays = [1, 2, 3, 4, 5] # 0 = Sun … 6 = Sat; omit for every day
enabled = true # optional, default true
use_context = true # optional, default true
prompt = """
Triage today's new issues and comment on anything that looks like a duplicate.
"""

prompt and time are required. Unknown keys are an error, so a typo like uses_context is reported rather than silently ignored. A file that doesn’t parse still appears in the panel, disabled, with its error.

spwn watches .spwn/schedules, so adding, editing or pulling a file takes effect straight away. Commit it to share the task with your team, or leave it untracked to keep it to this machine. spwn never writes into the file; when it last ran is kept in spwn’s own store. The panel shows file tasks read-only, with Run now, and you change them in the file.

When a task fires, spwn:

  1. adds a session to the project titled ◷ <task name>,
  2. gives it its own worktree and branch off the project’s current branch (through the session-created hooks, with any hook prompt declined), or runs in the project folder if it isn’t a git repo,
  3. starts the default agent headlessly with a first turn made of the Merge tray’s blocks (if use_context is on and the tray isn’t empty) followed by the prompt,
  4. flags the session for your attention when the run ends, successfully or not.

For Claude the headless command is claude -p … --permission-mode plan, which is what keeps the run read-only. The run is an ordinary rmux pane, so you can open the session and watch it work, and it survives a restart of spwn. The finished session stays until you delete it.

A task never runs twice at once.

Tasks fire only while spwn is running; it checks every 30 seconds. If spwn was down when a task was due, it runs once when spwn comes back, however many occurrences it missed. It catches up the most recent occurrence within the last week.

A file task spwn has never seen is the exception. Pulling a branch with five schedule files shouldn’t fire five runs for times before the files existed, so a new file task waits for its next occurrence. Use Run now if you don’t want to wait.

The Merge tray is the project’s reusable context space: notes, files and turns you’ve collected from sessions. With use_context on, each run starts with those blocks, assembled into Markdown, then ---, then your prompt. That’s how a nightly task knows the conventions you’ve written down without repeating them in every prompt. Turn it off for a task that should see only its prompt.