Skip to content

[Feature]: Server-side scheduled tasks — start agent runs automatically (one-shot + recurring) #7966

Description

@ImBIOS

Motivation

T3 Code only starts agent runs when the user sends a message. A lot of real agent work is time-shaped instead:

  • nightly maintenance — "bump dependencies every night", "run the test suite each morning and report failures"
  • delayed follow-ups — "check back on this deploy in 30 minutes"
  • recurring chores per project — "summarize open TODOs every weekday at 9:00"

The closest primitive today is thread snooze: time-based visibility whose wake is client-derived (web sets a local timeout off snoozedUntil). The contracts comment around thread.unsnoozed explicitly anticipates future wake conditions, but nothing currently wires time to starting a turn. If no client is open — or the server restarts — nothing happens. Wake logic needs to become server-authoritative.

Proposed MVP

Stay event-sourced, mirroring the snooze precedent end-to-end:

  1. Contracts: task.schedule / task.cancel commands; task.scheduled / task.fired / task.cancelled events. Schedule spec v1: one-shot at OR interval every anchored at creation (no cron expressions yet).
  2. Decider: validate due times; fire via deterministic commandIds (server:task-fire:<taskId>:<dueAt>) so crash-retry collapses into the existing idempotent command receipts.
  3. Scheduler layer: modeled on ProviderSessionReaper (Effect Schedule.spaced loop, manual-tick seam for tests). Each tick finds due tasks in the projection and dispatches fire through the engine. A reactor consumes task.fired and dispatches a normal thread.turn.start, reusing the existing bootstrap.createThread path when no thread is attached.
  4. Read model: projection_tasks table, tasks.list query, capability gate following threadSnooze.
  5. Web UI: create / cancel / list scheduled tasks per project. Mobile inherits the commands automatically via client-runtime; screens can follow later.

Non-goals for v1

  • cron syntax (presets + fixed intervals cover the common cases)
  • event-based triggers ("when PR merges") — separate follow-up
  • multi-fire catch-up semantics (missed fires during downtime coalesce into one)

Will open a PR referencing this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions