Pulses
The third primitive: scheduled, stateful HTTP. Tunnels bring traffic to your machine, webhooks catch it when you're gone - pulses act while you sleep. Every run is stored as history (status, headers, body), failures alert you on transitions, and it all runs server-side: no daemon, no deploy, nothing on your machine.
Scheduled runs
A pulse calls a public URL on an interval and keeps the receipts:
# Call your cron endpoint every 10 minutes - responses stored as run history
npx otterkit pulse 10m https://api.your-app.com/cron
# POST with a body and headers, hourly, stop after 3 days
npx otterkit pulse 1h https://api.your-app.com/digest --method POST \
--data '{"kind":"hourly"}' -H 'Authorization: Bearer …' --ttl 3dIntervals are 30s to 1d (30-second floor). Runs land in the same history as webhook captures - browse them with otterkit requests <name>, the console's Pulses page, or the history API. If runs start failing you get one email on the transition (and one when they recover), never a flood.
Dead-man's switch (--expect)
Flip the direction: --expect hands you a URL that something must ping within the window - a backup job, a nightly script, a data pipeline. Silence past the window sends the alert; the next check-in sends the all-clear.
npx otterkit pulse --expect 15m
# → check in with: curl -X POST https://pulse-a1b2c3d4.otterkit.app/checkinCheck-ins are captured like webhook requests - body included - so "did the backup run?" and "what did it report?" are the same question.
Pricing
1 credit per 100 runs (a run is a scheduled tick or a check-in), first credit at creation, and the same cap as everything else: never more than 300 credits ($3) per rolling 30 days. A nightly cron costs a penny a month; an every-10-minutes monitor about 44¢. Pulses default to --ttl never - they're set-and-forget, and the cap bounds the bill.
pulse_create provisions either mode, and webhook_history reads the runs - a durable scheduler your agent can give itself.