Claude skill wake sleep
Add a wake-on-visit / auto-stop-when-idle (hibernation) mechanism to an AWS deployment to cut cost. Generates drop-in Terraform + Python Lambda wake/ autosleep functions + a manual CLI, assembled from composable adapters for the target's compute target, idle signal, and in-flight-work probe. Use when the user wants to: stop an idle EC2 / ECS / Auto Scaling Group / RDS and auto-start it on traffic or on a schedule; add a "serverless-ish" sleep mode to an always-on single box; save cloud spend by shutting down non-prod compute off-hours; hibernate / auto-start-stop / schedule a server.From its SKILL.md
npx -y skills add colinzyang/claude-skill-wake-sleepAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 18 days oldThe repository was created 18 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 0 stars0 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
7.3 KB, ~1.8k tokens by cl100k_base, as published. Nobody here has run it
wake-sleep
Turn an always-on AWS resource into a pay-only-when-used one: it starts on traffic (or on a schedule), serves, and stops itself after a proven-idle window. Zero new always-on spend by design — it reuses infra the project already has (an ALB, or a cheap cron), and the two Lambdas sit in the free tier at low traffic.
This is a kit of parts, not one hardcoded stack. Read the target project, pick adapters, assemble.
The contract (what's generic vs. pluggable)
The orchestration is fixed and correct-by-construction; only the cloud-specific bits swap:
| Seam | Options (pick one per axis) |
|---|---|
| compute driver | ec2_instance · ec2_asg · ecs_fargate · ecs_ec2 · rds · composite |
| wake trigger | alb (reuse existing ALB) · apigw (no ALB) · schedule (office hours) · manual (CLI only) |
| idle signal | cw_requestcount (ALB reqs) · cw_metric (any CloudWatch metric) · http (a probe URL) · none (schedule-only sleep) |
| busy probe | ssm (shell cmd on the box) · http (200 = busy) · none |
Everything else is universal and ships unchanged every time (see design-decisions.md for the why):
- Ground-truth health check — never trust load-balancer target health (it
lags
unhealthy_threshold × intervalafter a stop); the wake Lambda hits a configurableHEALTH_URLthat is routed directly to the target, bypassing the wake path, to avoid recursion. - Recursion-safe routing — when the trigger is an ALB, listener rules are
ordered so
/→ wake Lambda → health check → EC2 can't loop. - Reload cap — a forgotten tab during a slow boot can't pin the box awake.
- Fail-safe-busy — any error in the busy probe is treated as "busy"; we never stop on uncertain signal.
- Min-uptime guard + idempotent start/stop + DRY_RUN default true.
Workflow
1. Interview the target (infer from repo, confirm with user)
Use AskUserQuestion to lock these. Many have a sensible default you can
propose first:
- Compute target — what gets slept? (single EC2 / ASG / ECS service / RDS / a group). Find how it's currently defined (Terraform? Console? ECS cluster name?).
- Existing public ingress? — is there an ALB the trigger can reuse (cheapest, zero new always-on spend)? If not, offer API Gateway or schedule-only.
- Idle signal — default
cw_requestcountif there's an ALB; elsecw_metric(e.g. CPU) orhttp. - In-flight work — does the target run async jobs? If yes, pick a busy probe and pick the exact command from job-probe-recipes.md (Celery / RQ / BullMQ / Sidekiq / k8s Job / DB-row / none).
- Schedule window? — office-hours wake (don't start at 3am even if poked) and/or schedule-only mode. Optional.
- Notify? — SNS/Slack on wake/sleep. Optional.
2. Generate the lambda bundle (always)
Copy all of assets/lambda/ (wake.py, autosleep.py, compute_drivers.py,
signals.py, state.py) into the project verbatim — they are generic and
env-driven. Only the env vars differ per deployment (set in Terraform).
3. Generate Terraform (compose fragments)
Always: assets/terraform/variables.tf + wake-sleep-core.tf (IAM roles
scoped to the chosen driver, both Lambdas sharing one zip, autosleep
EventBridge rate(5 minutes)).
Then add one wake trigger:
- ALB present →
wake-alb.tf(listener rules with the recursion-safe priority ordering +/_healthbypass). This is the zero-new-spend path. - No ALB, want on-demand wake →
wake-apigw.tf - Schedule only →
wake-schedule.tf
Optional: notify-sns.tf.
Fill the resource references for the project's integration mode:
- Same Terraform state (ALB/instance managed here): replace
var.*IDs with direct resource refs (aws_instance.app.id,aws_lb.public.arn, etc.). - External (managed elsewhere): pass IDs via variables or
datasources. Both are shown as comments inwake-sleep-core.tf.
4. Adapt the busy probe
Drop the project-specific busy-probe command into BUSY_PROBE_CMD (Terraform
env var). See references/job-probe-recipes.md. If none, autosleep skips the
probe.
5. Wire ground-truth health
Ensure HEALTH_URL resolves to a 200 from the target, served through the wake
trigger but routed directly to the target (not back into the wake Lambda).
- ALB trigger: add a high-priority listener rule forwarding
HEALTH_PATH(default/_health) straight to the target group. The fragment does this. - Else: point
HEALTH_URLat the target's own health endpoint.
6. Ship DRY_RUN, validate, flip
Generate autosleep with AUTOSLEEP_DRY_RUN = true. Tell the user:
terraform apply- Watch CloudWatch Logs for
autosleep— confirm it logs "keep alive" / "would stop" with the right reasoning for a few cycles. - Flip
AUTOSLEEP_DRY_RUN = false,applyagain.
7. Hand off
- Wake URL to bookmark (ALB:
http://<alb>/<wake_path>; APIGW: the endpoint; schedule: "starts at HH:MM"). - sleepctl — copy
assets/sleepctl.sh, setDRIVER+ resource IDs + region,chmod +x.status | up | down [--force]. - Cost note: compute bills per-second while running, ~$0 while stopped; only storage + ingress baseline keep accruing.
Minimum-viable fast path
The 80% case — single EC2 behind an existing ALB, with an async worker — is
just the MAAP reference shape: driver ec2_instance, trigger alb, idle
cw_requestcount, busy ssm. Reach for that first; only deviate when the
interview says so.
Reference index
- porting-guide.md — decision tree: which driver/signal/trigger per stack, with copy-paste configs.
- job-probe-recipes.md — busy-probe one-liners per task system.
- design-decisions.md — the why behind every default (read before deviating).
- generated-layout.md — what the generated layout looks like and how to wire it.
Iron rules (don't regress)
- Never weaken fail-safety: probe errors ⇒ busy; never stop on uncertain signal.
- Never ship autosleep without DRY_RUN first.
- Never trust LB target health as the wake-ready signal.
- Keep data traffic off the wake Lambda — only the wake path goes through it; app traffic flows target-direct. (ALB trigger: the default listener action and all non-wake rules forward to the target, not the Lambda.)
- IAM least-privilege per driver — don't grant
ec2:*when the driver only needs ECS, etc.
What ships with it: 21 files
79.6 KB alongside SKILL.md, 7 of them executable
assets/
- lambda/autosleep.pyruns2.2 KB
- lambda/compute_drivers.pyruns6.4 KB
- lambda/signals.pyruns3.7 KB
- lambda/state.pyruns1.8 KB
- lambda/wake.pyruns5.2 KB
- sleepctl.shruns6.5 KB
- terraform/notify-sns.tf745 B
- terraform/variables.tf6.5 KB
- terraform/wake-alb.tf3.8 KB
- terraform/wake-apigw.tf2.1 KB
- terraform/wake-schedule.tf2.6 KB
- terraform/wake-sleep-core.tf8.8 KB
references/
- design-decisions.md4.6 KB
- generated-layout.md3.6 KB
- job-probe-recipes.md2.8 KB
- porting-guide.md4.4 KB
scripts/
- validate.shruns2.2 KB
- CLAUDE.md5.5 KB
- .gitignore135 B
- LICENSE1.0 KB
- README.md5.1 KB
Gives 0 of the 12 instructions most containers cloud skills give in ~1.8k tokens
Counted across 607 of the 657 authors here whose files we hold, read 2026-08-07
- Run containers as a non-root userin 66 of 607, across 46 files
- Use multi-stage buildsin 53 of 607, across 44 files
- Use Promise.all for independent operationsin 47 of 607, across 13 files
- Import directly instead of barrel filesin 46 of 607, across 12 files
- Use ternary instead of AND for conditionalsin 45 of 607, across 12 files
- Use Set or Map for O(1) lookupsin 42 of 607, across 10 files
- Create a .dockerignore filein 41 of 607, across 31 files
- Read individual rule files for detailsin 39 of 607, across 9 files
- Copy dependency files before source codein 36 of 607, across 23 files
- Authenticate server actions like API routesin 35 of 607, across 7 files
- Use next/dynamic for heavy componentsin 34 of 607, across 9 files
- Use React.cache for per-request deduplicationin 34 of 607, across 10 files
Said here and by no other author read
- pick one adapter per axis
- interview the target to lock variables
- copy the lambda bundle verbatim
- generate terraform using composable fragments
- fill resource references for integration mode
- adapt the project busy probe command
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.