agent-swarm
Install, self-host, deploy, operate, or use agent-swarm. Covers Docker Compose, Kubernetes,…
Guardrails for polling, scheduled jobs, and long-running external operations. Use whenever a task waits on CI, builds, deploys, browser jobs, or another asynchronous API so work survives heartbeat checks without duplicate delivery.
$ npx -y skills add desplega-ai/agent-swarm --skill scheduled-task-resilience --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/scheduled-task-resilienceContext preview
The summary Claude sees to decide when to auto-load this skill.
Guardrails for polling, scheduled jobs, and long-running external operations. Use whenever a task waits on CI, builds, deploys, browser jobs, or another asynchronous API so work survives heartbeat checks without duplicate delivery.
name: scheduled-task-resilience description: Guardrails for polling, scheduled jobs, and long-running external operations. Use whenever a task waits on CI, builds, deploys, browser jobs, or another asynchronous API so work survives heartbeat checks without duplicate delivery.
Use these rules whenever a scheduled or regular task polls or waits on a long-running operation. They prevent heartbeat collisions, lost work, duplicate delivery, and sessions that fail after holding an external job open too long.
The runtime heartbeat staleness threshold may sit near the same window as the model prompt-cache TTL. Sleeping for five minutes or longer can therefore look like a dead worker and cause the heartbeat sweep to fail the task mid-poll.
Instead:
Aggregate **every** check run before you decide the poll is over. Reading a single row such as `.[0].state` reports one check and can look terminal while another required check is still pending or failing.
# ONE cycle per agent turn. Resolve PR_NUMBER from the current task or repository context.
sleep 240
if out=$(gh pr checks "$PR_NUMBER" --json name,state,bucket \
--jq 'if any(.[]; .bucket == "pending") then "PENDING"
elif any(.[]; .bucket == "fail" or .bucket == "cancel") then "FAILING"
else "PASSED" end' 2>&1); then
echo "$out"
else
case "$out" in
*"no checks reported"*) echo "PENDING" ;; # no check contexts yet — not a failure
*) echo "$out" >&2; exit 1 ;; # real gh error: auth, network, bad PR
esac
fi⚠️ Do not substitute the exit code for the aggregate here. Plain `gh pr checks <pr>` exits `8` while any check is pending and `1` on failure, but **`--json` suppresses that — it exits `0` even mid-run** (verified on gh 2.97.0). A cycle that adds `--json` and then reads `$?` reports success on a still-pending PR, which is the exact bug the aggregate exists to prevent.
⚠️ Treat `no checks reported` as `PENDING`, not as a failure. Right after a PR is opened or a new commit is pushed, GitHub can briefly report zero check contexts. In that window `gh pr checks` exits `1` and prints `no checks reported on the '<branch>' branch` **before** the `--json` exporter runs, so the aggregate never executes at all (verified on gh 2.97.0). A cycle that treats any non-zero exit as failure will stop polling — or report CI as broken — before the workflows have even appeared. That is why the sample branches on the error text instead of on the exit status alone.
Handle each aggregate distinctly: `PASSED` means polling is done. For `PENDING`, call `store-progress`, then run one more cycle in the next turn; cap the number of cycles and hand off to a follow-up task once the total wait approaches the heartbeat staleness threshold. For `FAILING`, stop polling immediately, inspect the failed checks with `gh pr checks <pr> --json name,state,bucket` and the run logs, then report or fix the failure — never sleep again on a failing aggregate.
Any task automatically retried after a session loss must include `reboot-retry` in its tags. If you recreate a lost task manually, add the same tag so the deployment's boot-sweep logic can identify it correctly.
Resolve the original task from the current task's parent or retry metadata. Do not copy a task ID from another incident or deployment.
Workers that poll silently can look stale to the heartbeat sweep.
After every poll cycle — that is, after each shell call that sleeps and checks once — call `store-progress` with a concrete progress message such as `polling CI status (attempt 3/10)`. Even when the remote state has not changed, the progress update records that the worker is still active. This is only possible because each cycle returns control to the agent turn, which is why Rule 1 forbids batching sleeps.
Resolve the active task ID from the current task context. Never embed an agent ID, task ID, organization ID, or other deployment-specific identifier in a reusable polling script.
Two immediate failures with the same heartbeat-staleness reason usually indicate an infrastructure or lifecycle problem, not a transient job failure. Do not create a third identical attempt.
Concurrent sessions can pick up equivalent scheduled work. Before sending scheduled output to Slack, email, a blog, or another external destination:
1. Query recent tasks using the current schedule ID or schedule tag. 2. Search the destination history for an equivalent delivery in the relevant time window. 3. If a recent completion already delivered the result, stop and record the duplicate detection with `store-progr
Repo: desplega-ai/agent-swarm
Install, self-host, deploy, operate, or use agent-swarm. Covers Docker Compose, Kubernetes,…
Rebuild the feel of a reference motion-design clip (camera, depth of field, easing, captions,…
Reverse-engineer a short motion-design / product-update video (animation technique, timing…
Make a design-led motion-graphics video (showreel, eval comparison, feature or bug-hunt…
How to generate repo-committed video content (README hero videos, case-study clips, landing…
Read the task-digest extension's output. Use when someone asks how many tasks completed or…