Agent-almanac choose-loop-wakeup-interval
git clone https://github.com/pjt222/agent-almanac
T=$(mktemp -d) && git clone --depth=1 https://github.com/pjt222/agent-almanac "$T" && mkdir -p ~/.claude/skills && cp -r "$T/i18n/caveman-ultra/skills/choose-loop-wakeup-interval" ~/.claude/skills/pjt222-agent-almanac-choose-loop-wakeup-interval-9742a7 && rm -rf "$T"
i18n/caveman-ultra/skills/choose-loop-wakeup-interval/SKILL.mdChoose Loop Wakeup Interval
Pick
delaySeconds for ScheduleWakeup → respects prompt cache 5-min TTL + scheduler whole-min granularity + [60, 3600] clamp. Non-trivial: "wait ~5 min" → worst-of-both zone → pay cache miss without amortizing wait.
Reasoning travels w/
ScheduleWakeup tool desc at call time → but loop already scheduled. This skill hoists reasoning → planning time.
Use When
- Designing autonomous
or/loop
continuation → pick per-tick delayScheduleWakeup - Heartbeat cadence for long-running agent
- Tuning polling vs. cost/cache-warmth
- Post-hoc: loop cost review → mis-sized interval
- Guide/runbook w/
exampledelaySeconds
In
- Required: What loop waits for (event, state transition, idle tick, periodic check)
- Required: Next tick needs fresh ctx (cache-warm) or cold re-read OK (cache-miss OK)
- Optional: Known lower bound on event occurrence ("build ≥4 min")
- Optional: Cost ceiling (ticks × per-tick cost)
Do
Step 1: Classify the Wait
Tier decision:
- Active watch (cache-warm): Change expected <5 min → build near done, state transition, just-kicked proc
- Cache-miss wait: Nothing worth checking <5 min → cache cold OK
- Idle: No specific signal → checking in case
→ Classification: active-watch, cache-miss, or idle.
If err: Can't classify → no honest answer to "what waiting for?" → loop shouldn't exist → skip to Step 5.
Step 2: Apply Three-Tier Decision
Pick
delaySeconds:
| Tier | Range | Cache | Use when |
|---|---|---|---|
| Cache-warm | 60 – 270 s | Warm (<5-min TTL) | Active watch — fast cheap re-entry |
| Cache-miss | 1200 – 3600 s | Cold; miss buys long wait | Idle, or event can't happen sooner |
| Idle default | 1200 – 1800 s (20–30 min) | Cold | No specific signal; periodic |
Do not pick 300 s. Worst-of-both: cache misses, wait too short to amortize. Reaching for "~5 min" → drop to 270 s (warm) or 1200 s+ (amortize).
→ Specific
delaySeconds from one of three tiers, not round-minute habit.
If err: Keep landing on 300 s → real question is "should loop exist at this cadence?" → re-examine Step 1.
Step 3: Size for Minute Boundary
Scheduler fires on whole-min boundaries.
delaySeconds = N → actual N to N + 60 s, depending on call second.
Example:
atScheduleWakeup({delaySeconds: 90})→ targetHH:MM:40→ actual 140 s, not 90 s.HH:(MM+2):00
Sub-minute intent meaningless. Value = floor, not precise. Min of skew matters → cadence too tight for this mech.
→ Accepted actual wait up to 60 s longer than requested. Cache-warm: 270 s → ~330 s → tips into cache-miss.
If err: Near-ceiling values common (265 s for cache-warm) → pad down → 240 s preserves warmth under worst-case skew.
Step 4: Respect the Clamp
Runtime clamps
delaySeconds → [60, 3600]. Out-of-range → silently adjusted. Telemetry: chosen_delay_seconds vs. clamped_delay_seconds + was_clamped: true.
Plan vs. clamped, not requested:
- Req <60 → actual 60 s + skew (up to 120 s)
- Req >3600 → actual 3600 s (1 h)
- No ceiling extension → multi-hour = multi tick
→ Value in
[60, 3600] or clamp accepted.
If err: Genuinely multi-hour ("wake in 4 h") → chain wakeups (3600 s tick reschedules) or cron loop (
CronCreate w/ kind: "loop").
Step 5: Write Specific reason
reasonreason = telemetry + user status + cache-warmth reasoning. 200-char limit. Specific.
- Good:
,checking long bun build
,polling for EC2 instance running-stateidle heartbeat — watching the feed - Bad:
,waiting
,loop
,next tickcontinuing
Reader = user glancing at status → write for them.
→ Concrete one-phrase reason sensible to glancing user.
If err: No specific reason → revisit loop existence (Step 1, Step 6).
Step 6: Recognize Don't-Loop Case
Not every "come back later" = scheduled wakeup. Do NOT schedule when:
- User actively watching → their input is trigger, not timer
- No convergence criterion → no "done" def
- Interactive task (asks user between ticks)
- Cadence <clamp floor (60 s) → tight polling = event-driven, not loop
→ Conscious choice: schedule wakeup vs. no loop. "Because I could" ≠ reason.
If err: User keeps interrupting wakeups → pattern wrong, not interval.
Check
- Wait classified: active-watch, cache-miss, or idle
-
in one of three tier ranges (60–270, 1200–3600, 1200–1800 idle)delaySeconds - Value ≠ 300 (worst-of-both)
- Value in
or clamp explicitly accepted[60, 3600] - Minute-boundary skew accounted (value = floor)
-
concrete + <200 charsreason - Don't-loop check done → wakeup warranted
Traps
- Round-minute default (300 s): #1 mistake. "About 5 min" feels natural, is wrong. → 270 s or 1200 s+.
- Ignoring minute-boundary skew: 60 s req near min end → ~120 s actual. Cache-warm: past 5-min TTL.
- Sub-min precision: Min granularity. 85 vs. 90 vs. 95 s = noise. Pick + move.
- Opaque
:reason
= nothing. Write for user status line."waiting" - Justifying unnecessary loop: Vague "watching for?" → no interval helps → loop shouldn't exist.
- Hand-clamping in prompt: Don't clamp in reasoning ("cap at 3600"). Runtime clamps.
- Forgetting 7-day age-out: Dynamic loop reaped after 7 days default (up to 30). Long loops end before ceiling.
Examples
Example 1 — Cache-warm active watch
bun build kicked off → agent checks quick → cache warm at results.
- Classify: active watch (Step 1)
- Tier: cache-warm (Step 2) → 240 s
- Min boundary (Step 3): worst-case ~300 s → under 5-min TTL w/ 60 s buffer
- Reason (Step 5):
checking long bun build
Example 2 — Idle heartbeat
Autonomous agent watches low-volume feed 1×/h.
- Classify: idle (Step 1)
- Tier: idle default (Step 2) → 1800 s (30 min)
- Min boundary (Step 3): irrelevant → 60 s skew negligible
- Reason (Step 5):
idle heartbeat — watching the feed
Example 3 — Anti-pattern
Agent wants "wait 5 min" → remote API retries → 300 s req.
- Problem: cache cold at 5 min → 300 s pays miss but too short to amortize
- Fix: → 270 s (warm) or 1500 s (amortize). Not 300.
→
— cost ceilings; cache-aware sizing is one levermanage-token-budget
— observe/act pattern; this skill sizes observe-clock when cron-lessdu-dum
— cross-session handoff; this = within-session wakeupsread-continue-here
— complement ofwrite-continue-hereread-continue-here