agentsclimarketplace

Loop test

Skill restarter/lets-workflow/.claude/skills/loop-test

Local sandbox for experimenting with Claude Code's /loop command (interval + dynamic/self-paced scheduling) applied to LETS workflows. Use when the user says "loop test", "loop-test", "test the loop skill", "цикл LETS", "ScheduleWakeup experiment", or wants to design a periodic /loop that polls state or babysits a long-running job. Local-only — not part of the lets plugin payload. For convergent autonomous work toward an end state, use sibling skill `goal-test` (which covers /goal).From its SKILL.md

Install
npx -y skills add restarter/lets-workflow --skill loop-test

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 17 stars17 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

8.9 KB, as published. Nobody here has run it

loop-test (local experiment)

/loop schedules periodic re-invocations of the same prompt. Two modes:

ModeSyntaxMechanic
Interval/loop 5m /foo · /loop /standup 1h · /loop check the deploy every 20mCron entry in .claude/scheduled_tasks.json. Default 10m when only [interval] shorthand. Survives session restart (durable).
Dynamic / self-paced/loop check the deploy (no interval anywhere)Model calls ScheduleWakeup(delaySeconds, prompt, reason) at the end of each turn. Skip → loop ends silently.

/loop is the wrong tool for sequential workflow phases. It repeats the same prompt each tick — to chain plan → review → check, the prompt itself has to be phase-aware (read state, advance, write back). For state-convergent autonomy, use /goal instead (see goal-test skill).

Right tool for /loop:

  • Polling external state (CI runs, deploys, PR comments)
  • Periodic checks (every 20m: any new bd-ready tasks?)
  • Babysitting a long-running job (check progress, surface failures)
  • Continuous monitoring during a long focused session

How /loop actually works

Reverse-engineered from claude binary v2.1.150.

Dynamic-mode contract

This is the mode you care about most — interval is just cron.

  1. User runs /loop <prompt> (no interval).
  2. Model does the work.
  3. Before yielding, model calls ScheduleWakeup(delaySeconds, prompt, reason):
    • delaySeconds clamped to [60, 3600]
    • prompt must be exactly the same string as the original /loop input
    • reason is one sentence shown to user + sent to telemetry — be specific ("polling CI run" beats "waiting")
  4. Harness re-invokes the model at the scheduled time. Loop continues.
  5. Skip ScheduleWakeup → loop ends silently. No error.

Cache TTL gotcha

Anthropic prompt cache TTL is 5 minutes. Picking delaySeconds:

  • < 270s → cache stays warm, cheap re-invocation
  • >= 1200s → commit to the miss, one cache-miss amortizes over a long wait
  • 300s is worst-of-both — you pay the miss without amortizing. Avoid exactly 300.

For idle ticks with no specific signal to watch, default 1200-1800s (20-30 min). User can always interrupt if they need you sooner.

Minute-boundary rounding gotcha (empirical, Experiment 1)

delaySeconds is NOT honored exactly. The actual wakeup time is rounded UP to the next clean minute boundary. Binary cron expression is MM HH * * * (minute-only granularity).

Examples from Experiment 1:

  • Requested 30s, clamped to 60s, actual scheduled 65s (we were at HH:MM:55)
  • Same request next tick, actual scheduled 101s (we were at HH:MM:19)

Implication: for any tick under ~1min you get 60-119s of real delay. Designing precise polling cadences <2min is futile — pick 60s (floor) and accept jitter, or accept >120s with predictable bucketing. Also note dispatch latency adds ~10-25s on top.

Cancellation / collisions

  • Re-issuing /loop with the same prompt cancels the previous pending wakeup for that prompt (ZP5(_) in binary). One prompt = one live loop.
  • User interrupt cancels all pending loop wakeups (b76() returns count cancelled).
  • Recurring max age: 7 days (recurringMaxAgeMs = 604800000). After that the loop auto-ages-out.

Sentinels (fully autonomous)

For unattended runs where there's no user prompt sitting in the channel:

  • <<autonomous-loop>> — cron-mode autonomous (CronCreate-backed)
  • <<autonomous-loop-dynamic>> — ScheduleWakeup-mode autonomous

Useful for /lets:schedule-style routines but probably YAGNI for LETS right now.

Telemetry

  • tengu_kairos_loop_dynamic — feature flag for dynamic mode
  • tengu_loop_dynamic_wakeup_scheduled — fired per ScheduleWakeup
  • tengu_loop_dynamic_wakeup_aged_out — fired when 7-day cap hits

Designing a useful /loop for LETS

Three rules that fit this project:

  1. Loop only on read-only state polls. Anything that mutates (commit, push, bd close) needs explicit user approval per AUTO MODE rule — auto-loop violates it. /lets:status, /lets:check, bd ready are safe; /lets:commit, /lets:done are not.
  2. One sentence of new information per tick, or nothing. If state hasn't changed, the tick should yield "no change" and reschedule. Don't re-report the same status over and over — the user sees ticks pile up.
  3. Pick the delay for the actual signal, not a round number. Polling a CI run that takes ~8min? delaySeconds=480 is better than delaySeconds=600. Avoid 300 (cache trap).

Concrete /loop templates for LETS

Template A — poll for PR feedback

/loop check `gh pr view <N> --json comments,reviewDecision` for new activity since last check. If nothing new: report "no change" and reschedule (1200s). If new comments or review state changed: report what's new and stop the loop so user can act.

Use case: opened a PR, want to know within 20min when reviewer pings, without keeping the window in focus.

Template B — backlog watcher

/loop run `bd ready --json | jq length`. If count increased since last tick: report which new tasks appeared (bd show each new id, one-line summary). If unchanged: report "no change". Reschedule 1800s.

Use case: long deep-work session on a feature, want to surface if a higher-priority bug landed in the backlog without breaking focus.

Template C — long-running job babysit

/loop check the deploy status at <URL or command>. If still running: report "running, T+Xmin" + estimated remaining. If failed: surface the error and stop. If succeeded: confirm and stop. Reschedule 180s while running.

Use case: triggered a deploy or migration, want hands-off progress reporting.

Combining /loop with /goal (open research)

Interesting question: nest /loop inside /goal?

/goal Repo passes /lets:check three times in a row over the next hour.
/loop 5m /lets:check

The loop schedules the work; the goal defines the termination condition. Untested — see goal-test for the /goal half and try.

Concrete experiment

/loop check git status; if no uncommitted files and `git rev-list main..HEAD --count` is 0, report "clean" and stop. Otherwise report the dirty state and reschedule 90s.

Watch in findings:

  • Does ScheduleWakeup fire after each tick?
  • Is delaySeconds=90 honored, or clamped to 60?
  • How does the UI display loop ticks between user messages?
  • Does the model self-terminate when the stop-condition is met (no ScheduleWakeup call), or does it loop indefinitely?

Open questions

  • How does the cron-mode (/loop 5m ...) persist? Just file on disk, or also stored in session state? Does it survive claude restart?
  • Can a dynamic loop call another dynamic loop? (Probably idempotent on prompt-string — second /loop cancels first.)
  • Does /loop interact with worktrees? Per-worktree state files, or global to the user?
  • What's the practical max number of concurrent loops? (Both cron and dynamic.)
  • How does /loop interact with /goal? Does a Stop hook block a /loop tick from yielding?

Findings (fill in during experiments)

Track in sibling findings.md. One entry per experiment:

### <date> · <prompt>
- Mode:              (interval / dynamic)
- delaySeconds:      requested → actual (clamped?)
- Ticks observed:    N
- Self-terminate?:   yes/no (did it skip ScheduleWakeup when condition met?)
- UI experience:     (intrusive? unobtrusive? useful?)
- Promote to plugin? yes/no + rationale

Promote criteria

Skill graduates to a real /lets:watch (or similar) command in plugins/lets/commands/ only if:

  • At least one template (A/B/C) produces useful repeat-value across 3+ different real situations
  • The "loop only on read-only polls" boundary is enforceable as a command-level guardrail
  • We have a clear answer for: "how does the user stop the loop without losing the context?"

Otherwise: keep notes in findings.md, close lets-53buy with a "investigated, parking the pattern" comment.

See also

  • Sibling skill goal-test — for convergent autonomous work (Stop hook condition). /goal is the right tool for plan → review → check → execute → review → check chaining; /loop is not.
  • LETS Rules AUTO MODE section in .claude/rules/lets-rules.md — gating rules every loop must respect.
  • Binary symbols (claude v2.1.150): tengu_kairos_loop_dynamic, tengu_loop_dynamic_wakeup_scheduled, recurringMaxAgeMs, ScheduleWakeup tool.

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.