{"id":"loopify","name":"loopify","summary":"Claude Codeで自動動作するエージェントループ、Cronのスケジュールタスク、または定期的なワークフローを設定したい場合。","body":"# /loopify — Set up an agent loop\n\nWizard for going from *\"this task should run periodically\"* to a working loop with the right pacing, idempotency, and bail-out. Reference: `ScheduleWakeup` (dynamic pacing), `CronCreate` (fixed schedule), and the built-in `/loop` (dynamic self-paced re-entry).\n\n## Step 0 — Confirm what you're looping\n\nAsk if not obvious from context: *\"What task should this loop do each iteration?\"*\n\nThen get the essentials:\n\n| Question | Why it matters |\n|---|---|\n| **How often?** | Determines cron vs dynamic vs one-shot |\n| **When to stop?** | Bail-out condition — loops must have one |\n| **What's the loop body doing?** | Determines idempotency requirements |\n| **Where does output go?** | File / notification / commit / nothing |\n| **What's the failure mode if it runs twice?** | Idempotency validation |\n\n## Step 1 — Pick the pattern\n\nThree primary patterns. Route by the answer to \"how often\":\n\n### Pattern A — Cron (fixed schedule)\n\n**Use when**: task runs at predictable intervals — daily at 8am, weekly on Fridays, hourly on the hour.\n\nTool: `CronCreate` — schedules a recurring task with a cron expression.\n\n```\nCronCreate({\n  schedule: \"0 8 * * *\",           // daily at 8am local\n  prompt: \"<loop body prompt>\",\n  timezone: \"America/Los_Angeles\"\n})\n```\n\nCommon cron patterns:\n- `0 8 * * *` — daily at 8am\n- `0 9 * * 1` — Mondays at 9am\n- `0 9 * * 5` — Fridays at 9am\n- `0 */2 * * *` — every 2 hours\n- `*/15 * * * *` — every 15 minutes\n\n**Trade-offs:**\n- ✅ Predictable, human-readable, easy to reason about\n- ✅ Best for time-of-day-dependent tasks (morning brief, EOD summary)\n- ❌ Runs at the scheduled time even if the last run isn't done — need idempotent body\n- ❌ No self-pacing — over-schedules if the task duration varies wildly\n\n### Pattern B — Dynamic pacing (self-scheduled)\n\n**Use when**: task should react to state, not the clock. Monitor-until-condition-met patterns. Waiting on an external event.\n\nTool: `ScheduleWakeup` — the current run schedules its own next wake-up.\n\n```\nScheduleWakeup({\n  delaySeconds: 270,               // stay in cache window (< 5min)\n  reason: \"checking build status; sleeping under 5min to stay cache-warm\",\n  prompt: \"<same task, re-entered>\"\n})\n```\n\n**Critical delay rules** (from `ScheduleWakeup` docs — internalized in the wizard):\n\n| Delay range | Use for | Cache impact |\n|---|---|---|\n| **60s–270s** | Active work — polling build, waiting for state that's about to change | Stays in 5-min prompt cache — fast + cheap |\n| **300s** ❌ | **DON'T USE THIS** | Worst of both worlds — pay cache miss without amortizing |\n| **300s–3600s** | Waiting on something that takes minutes to change | Pay cache miss but justified |\n| **1200s–1800s** (20–30 min) | Idle ticks with no specific signal | Default for autonomous loops |\n\nNever pick 300s literally — either drop to 270 (cache stays warm) or commit to 1200+ (cache miss buys longer wait).\n\n**Trade-offs:**\n- ✅ Adaptive — sleeps longer when idle, shorter when active\n- ✅ Cache-optimal when tuned right\n- ❌ Requires the loop body to know when to schedule next (extra logic)\n- ❌ Harder to reason about when it'll run\n\n### Pattern C — One-shot loop (until-condition)\n\n**Use when**: task runs until a condition is met, then stops. No recurrence after that.\n\nTool: `/loop` (built-in) with an exit condition in the prompt itself.\n\n```\n/loop\nCheck if the deploy is healthy. If yes → stop. If no → wait 5 min and check again.\nMax 10 iterations. If still failing after 10, alert and stop.\n```\n\n**Trade-offs:**\n- ✅ Simplest for check-until-condition\n- ✅ Bounded — always eventually terminates\n- ❌ Not for indefinite recurrence — that's Pattern A or B\n\n## Step 2 — Design the loop body for idempotency\n\nIdempotent = running the loop twice produces the same result as running it once. **Non-negotiable for cron and dynamic patterns** because they'll fire while the previous iteration is still running or partially complete.\n\nIdempotency patterns:\n\n- **Use \"already done\" markers**: e.g., commit a state file `<vault>/.loopify/<name>-last-run.txt` with the timestamp of last successful run. Loop body checks the timestamp before doing work.\n- **Use dedupe keys**: if the loop writes to a DB or file, key by content-hash or timestamp so re-runs are no-ops.\n- **Use transactions**: DB writes in the loop body should be atomic — either all commit or all roll back.\n- **Query before mutate**: check current state before applying the change. If already applied, skip.\n\nShow the user the loop body draft, highlighting the idempotency check. If none exists, add one.\n\n## Step 3 — Bail-out condition\n\nEvery loop needs one. Options:\n\n| Bail-out | When to use |\n|---|---|\n| **Max iterations** (e.g., stop after 100 runs) | Cron loops — prevents runaway |\n| **State-based** (e.g., stop when metric X drops below Y) | Monitoring loops |\n| **Time-based** (e.g., stop after 24 hours) | Bounded monitoring |\n| **Error-based** (e.g., stop on 3 consecutive failures) | All loops — catches degradation |\n\nIf the loop is truly indefinite (e.g., a weekly cron with no end), still add a manual bail-out via `CronDelete`. Document it in the SKILL/loop notes so the user knows how to stop it.\n\n## Step 4 — Set the schedule\n\nBased on the pattern from Step 1:\n\n**Cron (Pattern A):**\n```\nCronCreate({\n  schedule: \"<expression>\",\n  timezone: \"<tz>\",\n  prompt: \"<loop body>\",\n})\n```\nReport the `cron_id` returned so the user can `CronDelete` later.\n\n**Dynamic (Pattern B):**\nWrap the loop body prompt so it ends with a `ScheduleWakeup` call:\n```\n<do the work>\nThen: ScheduleWakeup({delaySeconds: <tuned per Step 1>, prompt: \"<same body>\", reason: \"<why this cadence>\"})\n```\n\n**One-shot (Pattern C):**\nJust run `/loop <prompt with exit condition>`.\n\n## Step 5 — Verify the first run\n\nWait for the first iteration (or trigger it manually via `/loop` with the same prompt for a dry-run). Confirm:\n\n- Output landed where expected\n- Idempotency check works (run twice — second should be a no-op)\n- Bail-out condition would fire correctly if triggered\n- Log/notification appears if configured\n\n## Step 6 — Report + follow-ups\n\nReport:\n- Pattern picked (A/B/C) + why\n- Cron ID or wakeup pattern registered\n- Bail-out condition set\n- Idempotency mechanism in place\n- How to stop the loop (`CronDelete <cron_id>` or \"just don't call the wakeup\" for dynamic)\n\nOffer:\n- *\"Save this loop configuration as a skill via `skillify from-chat`?\"*\n- *\"Want to also register a `weekly-review` or `daily-startup` loop while we're here?\"*\n- *\"Should the loop write to `second-brain` outputs when it runs?\"*\n\n## Common loop recipes\n\nTemplates for frequent loop types (fill in as they're used):\n\n- `references/daily-brief.md` — morning routine loop (calendar + priorities + overnight)\n- `references/weekly-review.md` — Friday portfolio pulse\n- `references/upstream-check.md` — periodic check for changes to an adapted skill's upstream\n- `references/vault-compile.md` — periodic raw/ → wiki/ compilation\n- `references/metric-monitor.md` — poll a metric until it crosses a threshold, then alert\n\n## Composes with\n\n- **`skillify`** — sibling in `-ify` trifecta. Use `skillify` to author a new SKILL.md — use `loopify` when the goal is a scheduled task, not a skill.\n- **`toolify`** — sibling. Use `toolify` for adding an integration — use `loopify` when the goal is running something on top of an already-integrated tool on a schedule.\n- **`second-brain`** — many loops write to the vault (raw/ or outputs/). The vault auto-commit pattern applies.\n- **`pm`** — daily-brief and weekly-review loops often read from pm before generating output.\n\n## Notes on quality\n\n- **Never pick 300s for `delaySeconds`.** Worst of both worlds. Drop to 270 or commit to 1200+.\n- **Every loop needs a bail-out.** Even indefinite ones need a documented manual stop.\n- **Idempotency is non-negotiable for cron + dynamic.** Assume the loop will fire twice while a previous iteration is running.\n- **Prefer dynamic pacing over over-frequent cron.** Cron every 15 min wastes tokens if the work isn't ready; dynamic pacing scales down when idle.\n- **Document the cron_id.** Otherwise the loop is orphaned and hard to stop.\n- **Log every iteration briefly** — even a single line (\"2026-06-30 08:00 daily-brief: ran, 3 items\") makes debugging drift trivial.\n- **Loops that touch external APIs need rate-limit respect.** If the vendor has a 100/day limit, don't schedule 500/day.\n- **Bounded > unbounded when uncertain.** If unsure whether to run for a week or a month, start with a week — extend after seeing it work.","author":"@coreyhaines31","ownerProfile":null,"authorContacts":null,"sourceUrl":"https://github.com/coreyhaines31/makerskills/tree/main/skills/loopify","license":"MIT","category":"document","lang":"en","tokens":2208,"stars":0,"calls30d":2,"claimed":false,"visibility":"public","origin":"crawler","version":"0.1.0","createdAt":"2026-08-22","updatedAt":"2026-08-22","files":[],"requires":{"mcp":[],"tools":[]},"safety":{"flags":[],"scannedAt":"2026-08-22","hasScripts":false,"networkEndpoints":[]}}