Claude Code /loop: Poll a Deploy on a Fixed Interval
Re-fire a prompt on a valid cron interval inside a live Claude Code session.
Run this workflow
CI-verified, 4/4 fixtures passing.
Intended Use
Anyone running Claude Code who wants to poll something (a deploy, a PR, a build) on a fixed interval inside a live session, with a cron expression that is valid before it is scheduled.
Not for
- Schedules that must survive closing the terminal (use the headless or cloud setup instead)
- Sub-minute intervals, cron granularity is one minute
- Extended cron syntax like L, W, ? or MON/JAN aliases, which /loop does not support
The Stack
Tested Against
claude-code@2.1.72node@20.xSide effects & data flow
- Network
- none, local only
- Writes
- ./loopcron.mjs
- Credentials
- none required
Steps
- 1
Schedule the poll
Inside any session, /loop schedules a prompt to re-fire on an interval while the session stays open. Intervals use s, m, h, or d. For a fixed schedule it accepts standard 5-field cron.
- 2
What CI checks: the cron expression is valid 5-field standard
Before /loop schedules anything it needs a valid 5-field cron with no unsupported syntax. This validator accepts the post's examples and rejects extended syntax (L, W, ?) and name aliases (MON, JAN), exactly as the scheduler does. No model, no key.
cat > loopcron.mjs <<'EOF' // Validate a 5-field standard cron the way Claude Code's /loop scheduler does. const ALIASES = ['MON','TUE','WED','THU','FRI','SAT','SUN','JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC']; const OK = new Set('0123456789*/,-'.split('')); function validate(expr) { const f = expr.trim().split(' ').filter(Boolean); if (f.length !== 5) return 'bad field count'; for (const field of f) { const U = field.toUpperCase(); if (U.includes('L') || U.includes('W') || U.includes('?')) return 'unsupported syntax'; if (ALIASES.some(a => U.includes(a))) return 'unsupported alias'; if (![...field].every(c => OK.has(c))) return 'illegal char'; } return 'OK'; } for (const g of ['0 9 * * 1-5', '*/15 * * * *']) { if (validate(g) !== 'OK') { console.log('FAIL valid rejected: ' + g); process.exit(1); } console.log('VALID: ' + g); } for (const b of ['0 9 L * MON']) { const r = validate(b); if (r === 'OK') { console.log('FAIL bad accepted: ' + b); process.exit(1); } console.log('REJECTED: ' + b + ' (' + r + ')'); } console.log('loop cron check OK'); EOF node loopcron.mjs - 3
Run the poll (the model step, not checked by CI)
Once the cron is valid, the loop fires the prompt on each tick. That call invokes the model, so it is non-deterministic and fenced: CI never runs it and the badge never claims it.
Eval, 4 fixtures
Last passed: verified todayvalid-acceptedcontainstimeout 30s · max $0Expected:
VALID: 0 9 * * 1-5bad-rejectedcontainstimeout 30s · max $0Expected:
REJECTED: 0 9 L * MONcheck-okcontainstimeout 30s · max $0Expected:
loop cron check OKclean-exitexit_codetimeout 30s · max $0Expected:
0
Results
The lightest automation tier: zero setup, dies with the session, 7-day auto-expiry.
Did this work for you?
Our CI checks the setup runs. You tell us if the whole thing worked. Tell us straight.
Liked this workflow?
Get new verified workflows in WebAfterAI, three issues a week (Tue, Thu, Sat).