Triggers: the work keeps going after you close the laptop
Timers, schedules and webhooks that run full agent sessions, with a precheck that spends nothing when nothing changed.
Most agent work has a tail. You push a fix and someone should check CI in twenty minutes. A pull request is open and someone should answer the review comments when they land. Main moves overnight and the docs index needs a rebuild. Without help, that someone is you, polling.
A codecast trigger is a prompt with a clock or an event attached. When it fires, codecast runs a real agent session: either back in the conversation that armed it, with its full history, or in a fresh session. Every trigger gets a short id like tr-42 and a page in the web app. Agents arm their own follow-ups (an agent that pushes a fix sets its own "check CI in 30m"), and most runs finish quietly. The ones that need a person land in your inbox.
/features/triggers: six triggers, 24 firings, 12 of them skipped by a precheck that spent nothing, one run parked at a usage limit and resumed, and exactly one item waiting in the inbox at 09:00.Three clocks
$ cast trigger add "Check if CI is green on main" --in 30m + Trigger tr-41 in 30m: Check if CI is green on main $ cast trigger add "Review open PRs and summarize findings" --every 4h --spawn $ cast trigger add "Respond to new PR review comments" --on pr_comment --pr 482 $ cast trigger add - --every 7d --spawn --title "Weekly blog post" <<'EOF' …a full brief, goal, numbered steps, constraints… EOF
--in 30m: once, after a delay. Follow-through on work that just shipped.--every 4h: a standing duty. Pair it with--into set the first run, which fixes the time of day. Each run re-arms on its slot, counted from when it was due, so a daily check never drifts later by its own runtime, and a run that outlasts its interval skips the missed slots instead of firing them all at once.--on <event>: a webhook event. Pull request events (pr_opened,pr_comment,pr_check_failed,pr_checks_green,pr_conflict,pr_mergedand more), issue events from GitHub or Linear, and events from your running product through a source (error_new,error_spike,metric_alert,deploy,job_failed). Narrow with--repo,--pror--source. Events that arrive while a run is working are kept for the next run, not dropped.
Here, or --spawn
A trigger armed inside a session runs back in that session by default: the run arrives as a new turn with the whole conversation behind it, and its answer lands where the question was asked. That is right for follow-through that needs what this conversation knows, firing once or a few times. It is wrong for anything that repeats, because every inline firing reloads the whole history (the prompt cache has long expired) and buries the thread.
Add --spawn and each run starts a fresh session that carries only its prompt plus the previous run's summary, so the prompt is written as a full brief. Spawned runs nest under the session that armed them, never as separate inbox cards. A once trigger posts its clean result back as a message without waking the thread (--wake wakes it); a repeating one posts nothing on a clean run (--thread posts each result). Either way the arming session is woken if a run fails, dies without reporting, or asks for attention.
--precheck: spend nothing when nothing changed
Most repeating jobs ask a question whose usual answer is no. Has main moved? Is the queue empty? Without a gate, a whole agent session is spent finding out. --precheck <command> asks with a shell command first, in the project directory, before each scheduled or recurring firing. Exit 0 runs the trigger. Any other exit, or 60 seconds without an answer, records a skipped run and re-arms on the normal cadence. A skip is not a failure, so it never burns a retry. Event triggers ignore the gate (the event is already the reason to run), and so does a manual cast trigger run.
$ cast trigger add "Review what landed on main" --every 1h --spawn \ --precheck 'test "$(git rev-parse origin/main)" != "$(cat .last-reviewed)"' $ cast trigger log tr-44 Precheck: test "$(git rev-parse origin/main)" != "$(cat .last-reviewed)" skipped 12m ago, precheck exited 1
/cast-loop skill uses the same gate to drain a task queue overnight: its precheck fails when cast task ready comes back empty, so an idle loop spends nothing.Completion: every run says who acts next
A fired run receives your prompt, its trigger id, and its contract: finish with cast trigger complete <id> --summary "…". The summary is what you read later, so it states the outcome. The flag decides whether you read it at all. Without --needs-attention, nobody needs to act: the run folds into the trigger's history, where every firing links to the conversation it produced, and a quiet trigger reads as quiet, not broken. With it, the run declares itself blocked and stays in your inbox until read; a stashed or killed session is pulled back into the queue, and a --spawn trigger also wakes the session that armed it. A run that ends without reporting is caught too: the arming session is told, with a link to the transcript.
$ cast trigger complete tr-47 --needs-attention --summary \ "New TypeError in checkout since last night's migration. Fix drafted, needs your call on the rollback." ok Trigger completed: tr-47
Built to be left alone
--safe: a spawned run gets its write tools removed and state-changing commands blocked. Right for watchers that should look and report, never touch:cast trigger add "Watch the signup funnel and report anything off" --every 4h --spawn --safe. It is a guard on what the agent may do, not an isolated machine, and a run that injects into an existing session follows that session's rules instead.- Usage limits park, they do not fail. A run that hits a limit parks and resumes its own session when the window resets, keeping its context and spending none of its retries; with account switching on it can move to a saved account with room.
- Failures are visible. A failed run retries after a short backoff, three attempts in all, then the trigger is marked failed, one click from the transcript.
- Each firing runs once. The daemon claims a due firing with a lease, so a second machine or daemon never runs the same firing twice. Every run has a kill cap (
--max-runtime, 10 minutes by default). - Cleanup is symmetric. Killing a session cancels the triggers bound to it; restoring it re-arms them.
- Edits are versioned.
cast trigger update tr-43 --every 8hwrites a new version, andcast trigger history tr-43shows who changed which field, from what, and from where.
Runs execute through the codecast daemon on the machine where the trigger was armed, in that checkout. A laptop that is asleep when a trigger comes due runs it on wake; to keep things running around the clock, arm triggers from a session on a cloud host.




