respawn
Skill2 starsChanged 10 days agoMITView on GitHub
Sets up automatic revival of this session after Claude's 5-hour usage limit is hit. It waits until the window reopens, notifies the user, and resumes automatically unless the user cancels within a configurable grace window (default 5 min). It can also pause itself at a usage threshold (soft stop) and uses live usage readings for timing when the Claude desktop app provides them. Use when the user says "respawn", "set up respawn", "auto-resume", "revive this session", or wants to avoid having to remember to come back after a rate-limit cutoff. MUST be invoked proactively, BEFORE the account is actually blocked; does not work reactively after a cutoff. v0.4.1; the v0.2 core is field-tested through multiple overnight multi-window multi-session runs, the v0.3 and v0.4 additions less so; not an officially supported Anthropic feature.
3 other projects use a version of this.
Adopted by
Most recently taken up by
- vicnaum/vics-agent-skillstheir own version, first seen Oct 25, 2026
- yuzhi9257/respawn-skilltheir own version, first seen Oct 11, 2026
- mdorf/agent-skillstheir own version, first seen Aug 13, 2026
Other versions3 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 3
- vicnaum/vics-agent-skills★ 53same name
- mdorf/agent-skills★ 1same name
- yuzhi9257/respawn-skill★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
Show its rules and text
We split this skill into the rules it gives an agent
17 rules. About 0 are common, 9 are distinctive, and 8 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈9
Distinctive · estimate
This author's own choices. Worth a look.
8
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 31
Call mcp__ccd_session_mgmt__get_usage (no arguments).
- Very specific: line 39
Use resetsAt, not resetsIn.
- Distinctive: line 45
Every one-shot in this skill (reset-time jobs, soft-stop resumes, 15-minute rechecks, the cancel-window follow-up) is scheduled so that it …
- Distinctive: line 49
If the computed time is already in the past or less than 2 minutes away, use now + 3 minutes, again avoiding minute 0 and 30.
- Distinctive: line 54
Read usage (fresh reading).
- Very specific: line 57
If the target is missing or already in the past, use now + 5 hours.
- Distinctive: line 58
Add the margin from "Safe timing".
- Very specific: line 93
Shorthand arguments: if invoked with arguments (e.g.
- Distinctive: line 106
If no valid arguments were given, briefly confirm with the user what's about to happen (see Activation message below), and remind them of …
- Very specific: line 119
If usage=off, the hook layer is present and stop is a number, write the armed marker with the Write tool (see "Hook messages and the armed …
- Distinctive: line 138
P from N - 15 up to (not including) N, warning tier: do not start new large fan-outs.
- Very specific: line 142
Write a short state note in the conversation, starting with respawn soft stop:, giving what is done, what is next, and resume_after=<raw …
- Very specific: line 145
Pause one-shot: Create the new timed one-shot (kind=timed, same state line, backstop=<the ID chosen in step 1>) at the target plus margin, …
- Distinctive: line 146
Clean up: Delete any other pending one-shot of this run (timed or recheck) and, if step 1 created a day-restricted backstop, the old …
- Distinctive: line 192
If the conversation already shows this cutoff was resumed, cancelled, or already re-armed or cleaned up (step 3 below ran for it), do …
- Very specific: line 196
If windows is 0 (indefinite) or >1, re-arm for the next possible cutoff: decrement windows by 1 (leave 0 as 0), then
- Distinctive: line 200
Do this quietly, with no need to re-confirm with the user unless something about the setup changed (say so if the target switched to a …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
respawn
Gaming metaphor: the session "dies" (gets blocked by the 5-hour usage limit), waits, and respawns automatically once the window reopens.
Critical precondition: this must be set up BEFORE the account gets blocked. After a cutoff, no new message can be sent in any session until the window reopens, so there is no reactive way in. The user must invoke /respawn proactively (at the start of a heavy/long session, or when they notice they're approaching the limit).
Confirmed by repeated real-world use (multiple overnight runs, multiple sessions running /respawn in parallel, multiple consecutive windows in a single run): a recurring CronCreate job does survive repeated rate-limit rejections and fires correctly once the window reopens, the detect → notify → cancel-window → resume flow works end to end (tested with the then-fixed 5-minute cancel window), and this holds across several concurrent sessions without interference. Still not an officially supported Anthropic feature: auto-resume after a rate limit was requested in GitHub issues anthropics/claude-code #26775 and #36320, and Claude Code v2.1.234 and later has a built-in autoContinueAtUsageLimit setting that may already suit the user (this skill is an independent alternative with a cancel window, multi-window coverage and a soft stop). The v0.3 additions (live usage readings, backstop, soft stop) are newer and have seen less field testing than that core.
Two modes, one skill. Usage mode uses the live usage readings from mcp__ccd_session_mgmt__get_usage (see "Reading usage"). Classic mode has no usage readings of its own and times its checks from a user-given reset time or a blind 30-minute poll, like v0.2.0 (only the optional usage hook layer can give it readings, and only for the soft stop; see "Hook messages and the armed marker"). Classic mode is always the fallback. It keeps the v0.2.0 flow, with four improvements that apply to both modes: the off-minute margin in "Safe timing", silent-cutoff detection, re-arming before resuming, and re-invocation replacing an old run.
Limitations (tell the user a short version when the skill is activated, and the full list if they ask).
Confirmed by the CronCreate tool documentation:
- Jobs are session-only. They live in memory and disappear without a trace if the session ends or the app is closed, so this app/session must stay open for the entire waiting period.
- Recurring jobs auto-expire after 7 days. Treat
/respawnas covering at most a 7-day wait. For a weekly-limit wait that long, the backstop (see below) may expire before the reset and only the one-shot is left. - Jobs fire only while the session is idle. If a check or the cancel-window deadline lands while the user is actively interacting (or another turn is in flight), that firing is delayed or effectively skipped. This especially undermines the "resuming in N min" promise in the push notification.
- A recurring job can fire late, by up to half its period (at most 30 minutes). A one-shot scheduled on minute :00 or :30 can fire up to 90 seconds early, which is why timed jobs use an off-minute margin.
Still unverified:
- The token cost of rejected attempts while the window is closed.
- Whether a one-shot that fires while the account is still blocked survives (this is why, in usage mode, a recurring backstop runs alongside the timed one-shot once usage nears the limit; see "Backstop and idle expiry"). If usage jumps to the limit with no checkpoint reading in between, there is no backstop and only that one-shot is left.
- How precisely
resetsAtmatches the moment the window actually reopens.
Reading usage
Call mcp__ccd_session_mgmt__get_usage (no arguments). It exists only in the Claude desktop app; if the tool is not available in this environment, there is no usage mode and everything below that needs it is classic.
Observed result shape:
plan.status:"ok","unavailable", or"not_applicable".plan.windows[]: entries withlabel("5-hour limit","Weekly · all models","Weekly · <model>"),percentUsed(integer),resetsAt(ISO-8601 UTC),resetsIn(display text, e.g."4h 49m").
Rules:
- Identify windows by
label: the 5-hour window is the one whose label contains "5-hour"; weekly windows are the ones whose label starts with "Weekly". There can be several weekly windows, and any window can be missing. Never rely on order or on the exact weekly labels. - Use
resetsAt, notresetsIn. It is UTC: convert it to local time before building a cron expression, becauseCronCreatecron expressions are local time. It lands on a whole hour and exists even at low usage. - A usable reading means: the call succeeded,
plan.statusis"ok", and a 5-hour window is present. Anything else (tool absent, error,"unavailable","not_applicable", no 5-hour window) is not usable, and the step in question is classic. A 5-hourresetsAtthat is missing or already in the past does not make the reading unusable; "Choosing the target time" handles it. percentUsedis account-wide: other sessions and scheduled tasks share it.
Safe timing
Every one-shot in this skill (reset-time jobs, soft-stop resumes, 15-minute rechecks, the cancel-window follow-up) is scheduled so that it does not land on minute :00 or :30:
- A reset-time job is scheduled at the reset time (
resetsAt, or the user-given time) plus a margin of 3 to 5 minutes. Use +4 and move to +3 or +5 if the resulting local minute is 0 or 30. - Any other one-shot (a
recheck15 minutes out, the cancel-window follow-upcancel_windowminutes out): compute the time, and if it lands on minute 0 or 30, add 1 minute. For example a recheck that would land on 22:30 is scheduled for 22:31. - Express a one-shot as a cron expression with fixed minute, hour, day-of-month and month (local time, which can fall on the next calendar day), and
recurring: false. - If the computed time is already in the past or less than 2 minutes away, use now + 3 minutes, again avoiding minute 0 and 30.
Choosing the target time
Used whenever a reset-time job is created (invocation, soft stop, re-arm). In usage mode:
- Read usage (fresh reading).
- Weekly cap: if any weekly window has
percentUsedof 98 or more, or the cutoff message mentions a weekly limit, the target is that weekly window'sresetsAt(if several qualify, the latest one). If the message mentions a weekly limit but no weekly window can be read, use the reset time named in the message if it gives one, otherwise the 5-hour reset. Tell the user it is the weekly reset: the wait may be days, and the 7-day expiry of recurring jobs means the backstop may disappear before then. - Otherwise the target is the 5-hour window's
resetsAt. - If the target is missing or already in the past, use now + 5 hours. This is the raw reset time (no margin yet); a soft-stop note records it as
resume_after. - Add the margin from "Safe timing". The result is the time the one-shot is scheduled for.
In classic mode the target is the user-given time, or (when re-arming) now + 5 hours, plus the margin. For a soft-stop pause in a classic run with the hook layer, the raw target is the reset time named in the latest hook note instead (the weekly reset when the note says so), or now + 5 hours if it names none.
Job prompts
All state lives inside the CronCreate prompt text. Nothing is written to files, except the optional armed marker in classic runs with the usage hook layer (see "Hook messages and the armed marker"). Every job this skill creates uses the template below, copied verbatim. Substitute only the values in the respawn-state: line, and add the context: line only for a soft-stop resume. Do not shorten, paraphrase or extend the rest: later jobs are created from earlier ones, and a paraphrase of a paraphrase drifts.
respawn-state: usage=<on|off> windows=<N> cancel_window=<M> stop=<S|off> kind=<kind> backstop=<id|self|none>
context: <soft-stop resume only: resume from the `respawn soft stop:` note written at <local date and time>>
This is a respawn job (respawn skill). First get the current local date, time and UTC offset from the shell (e.g. `date '+%F %H:%M %z'`, or in PowerShell `Get-Date -Format 'yyyy-MM-dd HH:mm zzz'`). If kind=followup, go straight to step 4. A firing that resumes nothing makes its tool calls first and ends its turn with exactly one `respawn log: <local date and time> | ...` line as its only text (step 1 or 3), no chat sentence.
1. If kind=backstop or kind=poll and a `respawn soft stop:` note is waiting (its resume_after not reached yet, and no `soft stop superseded` log line after it): end the turn with `respawn log: <local date and time> | <kind> | paused`.
2. Look for an unhandled cutoff since respawn was armed. Signals: (a) a usage-limit error message; (b) a turn that stopped mid-work: the last message that is not respawn's own is a tool result with no assistant follow-up, and either 30+ minutes have passed since it or (usage=on) a 5-hour reset time recorded in the conversation before it has passed since; (c) a `respawn soft stop:` note whose resume_after is reached and that is not followed by a `soft stop superseded` log line. Respawn's own messages (everything in a turn started by a respawn job prompt, unless that turn resumed the work, plus `respawn log:` lines) never count as the last message, and an app message asking for visible output is looked past, never counted. A cutoff is handled once a respawn "Window is open again" or "Reset reached" notification, or a kind=followup job, appears after it, or once the work was resumed or cancelled.
3. Nothing unhandled (this includes a handled cutoff whose follow-up is pending). If a handled cutoff's notification is older than cancel_window + 10 minutes and nothing has resumed or cancelled since, the follow-up was lost: go to step 4 as kind=followup. Otherwise: (a) Idle expiry: if no cutoff notification waits for its follow-up, no `respawn soft stop:` note is waiting, and the earliest `respawn log:` line after the last message that is not respawn's own is 4.5 hours old or more (24 hours if windows=0), delete every job whose prompt starts with respawn-state: (find them with CronList; without it, use the job IDs listed in the conversation), send a PushNotification "Respawn disarmed: no cutoff and no activity for hours. Arm it again if you still need it.", and end the turn with `respawn log: <local date and time> | <kind> | disarmed, idle`. (b) If kind=timed and usage=on and no follow-up is pending: roll over, unless CronList lists another kind=timed job of respawn that fires later than now (then the run is already covered; skip to the log line). Read each listed timed job's fixed minute, hour, day and month as the occurrence nearest to now (around New Year that can be the next or the previous year). Count it only if that occurrence is later than now; one that is now or in the past is this firing itself or stale: ignore it. When unsure, roll over: a duplicate check costs less than a run with no jobs. Call mcp__ccd_session_mgmt__get_usage. Target: the 5-hour resetsAt, or the resetsAt of a weekly window at 98 % or more; now + 5 hours if it is missing or past. resetsAt is UTC: convert it to local time with the shell for the cron expression (e.g. GNU `date -d '<resetsAt>' '+%F %H:%M'`, or in PowerShell `([datetime]'<resetsAt>').ToLocalTime()`, or any equivalent that applies the local time zone at that date, which also handles a daylight-saving change before the reset), add 3 to 5 minutes so the minute is not :00 or :30, and if the result is past or under 2 minutes away use now + 3 minutes. Backstop level B = stop - 15, or 70 if stop=off. If percentUsed is at or above B or a weekly window is at 98 % or more, first make sure a backstop exists (check with CronList, or without it trust the backstop ID in the state line; create one, kind=backstop backstop=self, if there is none) and use its ID; otherwise delete any backstop of this run and use backstop=none. Then create the new kind=timed one-shot with that backstop value, same state line otherwise. (c) If kind=timed and usage=off, schedule kind=recheck 15 minutes out; if kind=recheck, create the recurring 30-minute poll (kind=poll, minutes 13,43). Then end the turn with one line `respawn log: <local date and time> | <kind> | <detail>`, where detail is `5-hour <percentUsed>% resets <resetsAt>` with resetsAt copied verbatim as returned (UTC; compare it with local times only after converting) if usage=on (from the reading in (b), or a fresh mcp__ccd_session_mgmt__get_usage call), else `no cutoff`.
4. Unhandled cutoff found, or kind=followup: load the respawn skill (Skill tool) for reference only, do not run its "On invocation", and follow its "On each check firing" step 4 (cutoff found) or "On the cancel-window follow-up" (kind=followup) with the state line above. If the skill cannot be loaded: for kind=followup, if the user replied CANCEL, stop or no since the notification, delete every job whose prompt starts with respawn-state: and confirm; otherwise delete those jobs, send a PushNotification that the window is open again and respawn is now disarmed, and resume the interrupted work. For a found cutoff with cancel_window > 0, send a PushNotification "Window is open again. Resuming in <cancel_window> min. Reply CANCEL to stop.", create a kind=followup one-shot from this template cancel_window minutes out, and end the turn; with cancel_window = 0, act as for kind=followup without a cancel reply.
New jobs copy this template verbatim. Schedule one-shots in local time, off minute :00 and :30 (reset time + 3 to 5 minutes).State-line fields:
usage:onif the invocation-time reading was usable (usage mode for the whole run), otherwiseoff(classic for the whole run).windows: remaining windows to cover (0= indefinite).cancel_window: minutes.stop: soft-stop percentage, oroff(alwaysoffin a classic run without the usage hook layer).kind:timed(one-shot at a reset time),backstop(recurring usage-mode poll),poll(classic recurring poll),recheck(classic 15-minute recheck),followup(cancel-window follow-up).backstop: the job ID of this run's backstop (selfin the backstop's own prompt, since it cannot know its own ID in advance;nonein classic runs, and in usage-mode runs while usage is below the backstop level, see "Backstop and idle expiry"). To make this possible, always create the backstop first and the timed one-shot second, and pass the backstop's ID into the one-shot's and the follow-up's prompts.
Keep track of the job IDs you create (the setup-complete message lists them) so they can be passed to CronDelete. Find the rest with CronList when available, recognizing this skill's jobs by the respawn-state: prefix. A CronCreate prompt cannot be edited: to change a job's state, delete it and create a new one. If IDs are lost (for example after context compaction) and CronList is unavailable, delete what the conversation still lists, and accept that a stray one-shot may fire once later; it will find nothing unhandled, and a stray timed job only rolls over when no other timed job of respawn is pending, so it cannot start a second run. At most one backstop and at most one pending timed one-shot may exist per respawn run, except for the moment inside a re-arm or soft stop between creating the new jobs and deleting the old ones.
Respawn's own messages are everything in a turn started by a respawn job prompt (unless that turn resumed the work), plus respawn log: lines. An app message asking for visible output is looked past as well. They are ignored only when deciding what the last real message is (signal b) and for idle expiry. They still count as evidence that a cutoff was handled. To keep this clean, a firing that resumes nothing writes nothing except its log line.
On invocation
/respawn here refers to whatever phrase triggers this skill (see the trigger phrases in the frontmatter description above). It is not necessarily a registered slash command; treat it as shorthand for "when this skill fires." If this skill was loaded from inside a respawn job (step 4 of the template), skip this section.
Re-invocation: if a respawn run is already armed in this session (job IDs listed earlier in the conversation, or jobs with the respawn-state: prefix in CronList), delete all of its jobs first (an armed marker is overwritten in step 5 of the new run, or set to stop=off if the new run needs none, see "Hook messages and the armed marker") and tell the user the new settings replace the old run. If a respawn soft stop: note of the old run is still waiting, write respawn log: <local date and time> | soft stop superseded so the new run does not treat it as its own. Never keep two runs side by side.
Shorthand arguments: if invoked with arguments (e.g. /respawn 3, /respawn 22:15, /respawn 3 22:15 cancel=10, /respawn nocancel, /respawn stop=70), parse instead of asking conversationally:
- A bare integer token →
windows(0= indefinite). - A token matching
H:MM/HH:MM(24h) → known reset time (see step 3 for how it combines with a usage reading). until-cancelledorinf→windows: 0.cancel=N→ cancel-window length in minutes (see below).nocancel→ shorthand forcancel=0.stop=N→ soft-stop percentage (integer 1 to 100, default85); see "Soft stop".nostop→ disables the soft stop (stop=off).- Any combination of the above, in any order. Anything that doesn't parse cleanly, or no arguments at all → fall back to asking conversationally (step 2 below).
Steps:
- Read usage (see "Reading usage"). A usable reading →
usage=on. Otherwiseusage=offand the whole run is classic. Withusage=on, skip the hook-layer check: usage mode needs no marker and writes no files. Withusage=off, check whether the usage hook layer is present (see "Hook messages and the armed marker"); that matters only for classic runs, where it switches the soft stop on, and it yields a value for P when its cache file is fresh. Then, with the soft stop on (usage mode, or a classic run with the hook layer; call the 5-hour percent P, from the reading or from the hook layer's cache file, and the soft-stop level N), and also when shorthand arguments skipped the conversation: if P is known and at or above N - 15 and the user did not givestopexplicitly, do not arm silently. The default would pause the session at the first checkpoint (or block new fan-outs), which is the opposite of what someone nearing the limit usually wants. Say that usage is already P %, and ask whether to keepstopat N, raise it (for example to the lower of 100 and P + 10), or turn it off (nostop). If they have no preference, usenostopfor this run and say so. If the user did givestopexplicitly, respect it and just mention the current P. - If no valid arguments were given, briefly confirm with the user what's about to happen (see Activation message below), and remind them of the limitations above if this is the first time they've used the skill in this session. Ask:
- How many consecutive 5-hour cutoffs to auto-resume through (
windows): default1(resume once, then stop) if they don't say.0or "until cancelled" means keep re-arming indefinitely. A soft-stop pause also uses up one window. - Only if
usage=off: whether they already know the reset time for this cutoff (the app UI often shows it). Optional, and most people won't know it yet if they're setting this up pre-emptively. In usage mode do not ask: the reset time comes from the reading. - How long the cancel window should be once a cutoff is detected (
cancel_window, minutes): default5if they don't say.0means resume immediately with no cancel window at all, only a heads-up notification after the fact. - The soft stop (
stop) is not asked about: use the default85unless the user brings it up (see "Soft stop"). In a classic run it applies only if the hook layer is present; otherwise usestop=off.
- How many consecutive 5-hour cutoffs to auto-resume through (
- Pick the target time and create the jobs with
CronCreate, each prompt built from the template in "Job prompts":usage=on(timed path, backstop near the limit):- Target time: "Choosing the target time" from the reading just taken (this includes the weekly-cap rule). If the user gave an
HH:MM(next occurrence in the future), use it instead, unless it differs from the reading's raw target by more than 30 minutes: then use the earlier of the two and tell the user about the mismatch, since a time of day that has already passed today means tomorrow and would otherwise delay the first check by most of a day. - If P is at or above the backstop level (see "Backstop and idle expiry"), or the target is a weekly reset, create the backstop first:
recurring: true,cronevery 30 minutes on off-minutes, e.g."13,43 * * * *", withkind=backstop backstop=self. Otherwise create no backstop now; a checkpoint reading creates it later if usage climbs. - Then create the timed one-shot (
recurring: false) at the target, withkind=timedandbackstop=<the backstop's job ID>, orbackstop=noneif step 2 created none.
- Target time: "Choosing the target time" from the reading just taken (this includes the weekly-cap rule). If the user gave an
usage=offand a reset time is known (given by the user, or auto-computed as now + 5 hours for a later window; see the re-arm step of the follow-up), classic timed path: first job is ONE-TIME (recurring: false), scheduled at the reset time plus the margin from "Safe timing", withkind=timed backstop=none. The known reset time replaces the blind 30-minute cadence for the first check, since the harness can't read a live reset time from inside a blocked job itself. Safety net if the estimate was off: if this job fires and finds no unhandled cutoff, it schedules one more ONE-TIME recheck 15 minutes later (kind=recheck); if that also finds nothing, it falls through to the blind 30-minute recurring poll.usage=offand no reset time known (classic blind path):recurring: true,cron: every 30 minutes, offset from the hour/half-hour, e.g."13,43 * * * *",kind=poll backstop=none.
- Note the job ID(s) from the response (needed for
CronDeletelater). - If
usage=off, the hook layer is present andstopis a number, write the armed marker with the Write tool (see "Hook messages and the armed marker"). This happens once, here, with the user present; no unattended step ever writes or deletes files. - Briefly confirm it's set up (see Setup-complete message below).
Activation message: cover these points, adapted to the user's language and phrasing, not a literal script:
Setting up respawn: I'll watch for the usage-limit cutoff and auto-resume once the window reopens ([windows] window(s), [cancel_window]-min cancel grace / no cancel grace). [Usage mode: current usage is [P]% of the 5-hour limit (resets around HH:MM local) and [W]% of the weekly limit(s) where readable; soft stop at [N]% (account-wide percent) unless disabled. | Classic mode: usage readings are not available here, so I'll fall back to the reset time you give me or a 30-minute poll, and the soft stop is off unless the usage hook layer is present (then it is on at [N]%, driven by hook notes).] [First time only: one-line limitations summary: requires this session to stay open, unofficial workaround, see full list if asked.]
Setup-complete message: cover these points. It always carries the reset time, the current usage and the soft-stop level, so shorthand invocations (which skip the activation message) still show them, and because signal (b) of the template relies on a reset time recorded in the conversation:
Respawn is armed: [usage mode: first check at HH:MM (5-hour reset at YYYY-MM-DD HH:MM plus a few minutes of margin; weekly reset instead if a weekly limit is nearly used, and then still name the 5-hour reset), with a 30-min backstop poll [running now | that starts once usage reaches [B]%] | classic: checking once around HH:MM (+ 15-min safety recheck) | classic: polling every 30 min] until the window reopens[, repeating for up to N windows]. [Usage mode: current usage [P]% of the 5-hour limit and [W]% weekly where readable; soft stop at [N]%, or off. | Classic mode: soft stop at [N]% driven by hook notes if the hook layer is present, otherwise off; an explicit
stopis ignored then (no usage readings here).] [If cancel_window > 0: you'll get [cancel_window] min to cancel once it fires. | If cancel_window = 0: it'll resume immediately on detection, no cancel window, and you'll just get a heads-up after the fact.] It disarms itself, with a push notification, after roughly 5 to 10 hours with no cutoff and no activity in this session (about 24 hours withwindows=0; until then a classicwindows=0run polls every 30 minutes, each poll a full turn). Jobs: [IDs].
Soft stop
Active when stop is not off and either the run is in usage mode (usage=on) or it is a classic run with the usage hook layer present (its notes are the readings, see "Hook messages and the armed marker"). Without either, the stop argument is ignored; say so in the setup-complete message instead of silently dropping it.
The point: instead of running into the hard cutoff mid-step, pause deliberately at a threshold, at a clean place in the work. Important caveats to tell the user if they ask: the percent is account-wide (other sessions and scheduled tasks share it), a single big step can overshoot the threshold, so stop=N with N close to 100 behaves almost like classic respawn (run until the wall, then resume), which remains the fallback, and a pause uses up one of the covered windows.
Checkpoints. While respawn is armed, read usage at natural checkpoints: between steps of the work, and before starting a large fan-out (a Workflow, or several subagents at once). Not after every tool call. A message from the optional usage hook counts as a checkpoint reading too. Take the 5-hour percentUsed (call it P); also apply the weekly cap check from "Choosing the target time" (a weekly window at 98 or more counts as the stop tier regardless of N, with the weekly reset as the target). In usage mode, take checkpoint readings even with stop=off, for the backstop alone: any checkpoint reading at or above the backstop level, or with a weekly window at 98 % or more, in a run without a backstop creates one (see "Backstop and idle expiry"). With stop=off, a weekly window at 98 % or more also moves the pending timed one-shot to that weekly reset (create the new one first, then delete the old).
Tiers, with N = stop:
- P below N - 15: carry on normally.
- P from N - 15 up to (not including) N, warning tier: do not start new large fan-outs; prefer finishing the current unit of work. Mention this once in the conversation, then continue.
- P at or above N, stop tier:
- Finish the current step. Do not abandon a half-made edit.
- Take a fresh reading and run "Choosing the target time".
- Write a short state note in the conversation, starting with
respawn soft stop:, giving what is done, what is next, andresume_after=<raw reset time as local date and time, e.g. 2026-11-03 03:00>(the target before the safe-timing margin). - Set up the jobs in this order, creating before deleting so a failed
CronCreatenever leaves the pause without a resume job:- Backstop (usage mode). The pause keeps a backstop as the safety net in case the account gets blocked anyway (for example by another session) and the one-shot fires while blocked; its firings only write a
pausedlog line (template step 1), but each is still a full-context turn. If the target is 12 hours away or less, keep the run's backstop, or create a normal one (13,43 * * * *) if it has none. If the target is more than 12 hours away (a weekly reset), create a day-restricted backstop instead that fires from the resume hour H to the end of the day, on the resume day D and the day after:13,43 H-23 D,D+1 M *, for example13,43 9-23 6,7 11 *for a resume after 09:00 on 6 November. At a month end, list both months, for example13,43 9-23 1,30 11,12 *for a resume on 30 November (the 1 November that already passed and 30 December lie outside the job's 7-day life); the old backstop, if any, is deleted in step 3. - Pause one-shot. Create the new timed one-shot (
kind=timed, same state line,backstop=<the ID chosen in step 1>) at the target plus margin, from the template with acontext:line pointing to the state note. - Clean up. Delete any other pending one-shot of this run (timed or recheck) and, if step 1 created a day-restricted backstop, the old backstop. In a classic run, keep the classic poll as it is: it is the run's only safety net.
- Backstop (usage mode). The pause keeps a backstop as the safety net in case the account gets blocked anyway (for example by another session) and the one-shot fires while blocked; its firings only write a
- Send a
PushNotification: "Paused at [P]% usage. Resuming around [HH:MM]." - End the turn. Start no further work.
- If the user explicitly tells you to keep going past the stop level, or continues the work themselves during the pause, replace the pause one-shot with a plain timed one-shot (no
context:line) at the same target plus margin, so the run keeps its check at the reset (create first, then delete); if the pause had a day-restricted backstop, replace it with a normal13,43 * * * *backstop and carry that ID in the new one-shot, writerespawn log: <local date and time> | soft stop superseded, and do not stop again until the next window. A note followed by that log line is no longer waiting and is not a cutoff.
A soft-stop pause counts as one covered window: it is resumed through the same flow as a hard cutoff, including the cancel window and the windows decrement. Once the last covered window has been resumed and the run's jobs are deleted, respawn is no longer armed and there are no more soft-stop checkpoints.
Backstop and idle expiry
Every firing is a full model turn that re-reads the whole conversation, so a run that waits for a cutoff that never comes must not keep firing. windows only counts down when a cutoff (or soft-stop pause) is resumed, so without these rules an unneeded run would poll every 30 minutes until the 7-day expiry.
- Backstop level B:
stop - 15when the soft stop is on,70whenstop=off. In a classic run there is no backstop (the poll plays that role) and B does not apply. - Lazy backstop (usage mode). The backstop is only needed when a cutoff is plausible. It is created at invocation if P is at or above B or the target is a weekly reset, otherwise at the first checkpoint reading (a
get_usagereading or a hook note) that reaches B or shows a weekly window at 98 % or more. To create it later: create the backstop (kind=backstop backstop=self), then create a copy of the pending timed one-shot whose state line carries the new ID, then delete the old one-shot. A soft-stop pause creates one if it is still missing. The re-arm after a resumed cutoff follows the same rule, so in a fresh window (P low) it creates only the timed one-shot. - The trade-off, stated plainly: checkpoints depend on the work reaching them. If usage jumps from below B to the limit with no reading in between (another session spending the shared quota while this one runs one long step, or a single large fan-out), the run has no backstop, and only the timed one-shot is left. If the reset time was off and that one-shot fires while the account is still blocked, whether it survives is unverified. Arm with a lower
stop(which lowers B) if that risk matters more than the extra firings. - Roll-over (usage mode). A timed firing that finds nothing unhandled does not end the run: it schedules the next timed one-shot at the fresh reading's reset, and deletes the backstop if P is below B (template step 3b). It does this only when no follow-up is pending and no other timed job of respawn is pending, so stray or duplicate jobs cannot multiply. An active session stays covered window after window without spending
windows. - Idle expiry (all runs). Each firing that finds nothing unhandled ends with one
respawn log:line carrying its local date and time. If the earliest such line after the last message that is not respawn's own is 4.5 hours old or more (24 hours for a run armed withwindows=0, "until cancelled"), the firing deletes every job of the run, sends a push notification, and logsdisarmed, idle(template step 3a). The clock starts at the first check after the last activity, so this takes roughly 5 to 10 hours from the last activity: in usage mode without a backstop it is the second or third timed firing, with the classic poll about ten polls. Never while a cutoff notification waits for its follow-up or a soft-stop note is waiting, and a cutoff is always detected first (template step 2), so a session that was cut off mid-work is resumed, not disarmed. Awindows=0run gets the longer threshold because the user asked for open-ended cover; until it expires it costs one firing per reset in usage mode while usage is low, and the 30-minute poll in classic mode. - Turns the app starts for other reasons (a message from another session, a task notification) are not respawn's own, so they count as activity. An app message asking for visible output does not. A lead session that ends its turn and waits for other sessions for many hours (for example through a block) can idle-expire; the push notification says so, and
windows=0stretches the threshold to 24 hours.
Hook messages and the armed marker
Optional, and for classic runs only (usage=off). Usage mode has its own readings from get_usage, writes no marker and never needs the hook; a hook note in a usage-mode run, if one ever appears, is just an extra reading. A usage hook layer (a hook plus a statusline tap, installed as described in the README) can watch a statusline usage reading for you in the terminal CLI. Everything in this skill works without it, and without it nothing is ever written to files.
- Your session ID:
${CLAUDE_SESSION_ID}. If that shows a literal dollar sign and braces instead of an ID, treat the hook layer as absent. - Is the hook layer present? Only at invocation, and only when
usage=off: get the user's absolute home folder from the shell, then Read<home>/.claude/respawn-usage/<session ID>.json. Present means the file exists and parses as JSON (the statusline tap wrote it for this session). If itsts(epoch seconds) is under 10 minutes old, itsfive_hour.used_percentageis P for the near-limit check in "On invocation" step 1. If the file is missing, say in the setup-complete message that no usage hook layer was found for this session, and that if the hook layer is installed, the statusline has probably not written its first reading yet (that happens after the session's first reply), so invoking respawn again after a reply switches the soft stop on. - Arm (once, at invocation): with the layer present and
stopa number, use the Write tool (plain text, UTF-8) to create<home>/.claude/respawn-armed/<session ID>holding one line:stop=<S>. Write it after the jobs exist, while the user is present. The cancel-window follow-up, re-arming, the end of a run and the job template never touch files. If writing fails, carry on without it. - Disarm (interactive paths only): when the user themself, in a normal turn (not one started by a respawn job), cancels, tells you to stop, asks to disarm, or re-invokes respawn: overwrite the marker with the single line
stop=offusing the Write tool. The hook treats that as inert and removes the marker itself. If a run ends unattended (the last window resumed, or a cancel handled inside a job turn), nothing is written: the marker stays, the hook may still send a note, and a note that arrives when norespawn-state:job exists in this session is ignored. - A hook message counts as a checkpoint reading. A message starting
Usage note from the respawn hookgives the 5-hour percent P and its reset time (or names the weekly reset). Apply the tiers in "Soft stop" to it. In a classic run it is the only reading there is: wherever the soft stop says to take a fresh reading, use the latest hook note, and use its reset time as the raw target (now + 5 hours if it names none). The hook speaks once per crossing, so a quiet hook means nothing; keep taking checkpoint readings yourself wheremcp__ccd_session_mgmt__get_usageexists.
On each check firing
This covers every firing of kind timed, backstop, poll or recheck. Steps 1 to 3 are the template's quick check (see "Job prompts"); a firing only loads this skill for step 4.
Confirmed by repeated use: if the account is still blocked by the usage limit when the job fires, the turn never runs at all (rejected before any model turn starts), so the fact that this prompt actually runs is evidence the window is open. Behave accordingly. (The exception is a soft-stop pause: the account is not blocked there, which is why the note has its own resume_after.)
- Soft-stop pause. A backstop or poll firing while a
respawn soft stop:note waits for itsresume_afterwrites only apausedlog line: no usage reading, no idle check. - Detect an unhandled cutoff since
/respawnwas activated, using signals (a) to (c) and the "handled" rule from the template. Signal (b) explained: field-observed, the app can cut a turn off at the limit without showing any error in the conversation, so a trailing tool result with no assistant follow-up counts. An explicit user interruption does not count. To avoid mistaking an unrelated stalled turn for a cutoff, roughly 30+ minutes must have passed since the tool result (as in v0.2.0), or, in usage mode, a 5-hour reset time recorded in the conversation before it (in the setup-complete message, a checkpoint reading or arespawn log:line) has passed since. The second condition catches a silent cutoff shortly before a reset; the first still works if the recorded reset was lost to context compaction. - No unhandled cutoff (including a handled cutoff whose follow-up is pending). Firings are idempotent: do nothing about a handled cutoff. Every such firing applies "Backstop and idle expiry" (idle expiry first, then, for a
timedfiring in usage mode, the roll-over to the next reset), makes its tool calls, and ends its turn with one datedrespawn log:line (in usage mode with a fresh reading, which also calibrates the reset time). Atimedfiring in classic mode schedules the 15-minuterecheck; arecheckcreates the 30-minutepoll. Backstop and poll firings do nothing beyond the log line and the idle check. Exception: the lost follow-up rule in template step 3. - An unhandled cutoff found. In usage mode, take a fresh reading and write
respawn log: <local date and time> | <kind> | cutoff found | 5-hour <percentUsed>% resets <resetsAt>first, with resetsAt verbatim as returned (UTC). Delete this run's other pending one-shots (timed, recheck) withCronDelete, found viaCronListor the conversation, so the cutoff is not handled twice. Keep the backstop (usage mode) or the polling job (classic) for now: it is the safety net if the follow-up job is lost (lost-follow-up rule), and the re-arm step of the follow-up replaces or deletes it before the interrupted work resumes. Then branch oncancel_window(carried in this job's prompt; default5if absent, i.e. jobs created before this option existed):cancel_window > 0: send aPushNotification: "Window is open again. Resuming [brief description of the interrupted work] in [cancel_window] min. Reply CANCEL to stop." (For a soft-stop pause use "Reset reached. Resuming ..." instead, since the account was never blocked.) Create a new ONE-TIMECronCreatejob (recurring: false,kind=followup)cancel_windowminutes out (see "Safe timing"), from the template, carrying the state line forward. If the session ends before the deletes complete, extra jobs may end up live; a second firing finds the cutoff handled and does nothing, so this is not handled specially.cancel_window == 0: no waiting, no cancel opportunity. Send aPushNotification: "Window is open again. Resumed [brief description of the interrupted work] automatically (no cancel window configured)." (For a soft-stop pause: "Reset reached. Resumed ...".) Then go straight into "On the cancel-window follow-up" step 3 (re-arm, which comes first) and step 4 (resume) in this same firing; there's no separate follow-up job to create.
On the cancel-window follow-up
(Reached from a kind=followup job, or from the lost-follow-up rule.)
- If the conversation already shows this cutoff was resumed, cancelled, or already re-armed or cleaned up (step 3 below ran for it), do nothing. Otherwise check whether the user has replied CANCEL (or similar: "stop", "cancel", "no") in the conversation since the notification was sent.
- Cancelled: briefly confirm it was stopped. Delete every job of this run that is still live (backstop, pending one-shots), so no jobs are left running.
Not cancelled: re-arm or clean up FIRST, before resuming the work. The resumed work can be long and can itself hit the next wall or a soft stop; the run's jobs must already reflect the new state by then, otherwise a stale backstop (still carrying the old
windowsvalue) would cover more windows than requested and a soft stop would build its one-shot from stale state. Create the new jobs first and delete the old ones after, so a failedCronCreatenever leaves the run unarmed (report any create failure to the user):- If
windows(carried in this job's prompt) is1, this was the last covered cutoff: create no new jobs, delete every other job of this run (the backstop or poll and any pending one-shot, viaCronListor the conversation), and note that respawn is now disarmed (no more soft-stop checkpoints). - If
windowsis0(indefinite) or>1, re-arm for the next possible cutoff: decrementwindowsby 1 (leave0as0), then- usage mode: take a fresh reading, run "Choosing the target time" (this applies the weekly cap and falls back to now + 5 hours), and redo "On invocation" step 3 for usage mode: a new backstop only if the fresh P is at or above the backstop level or the target is a weekly reset, then a new timed one-shot with
backstop=<new ID>orbackstop=none, carrying the newwindowsand the samecancel_windowandstop. Then delete every other job of this run (the old backstop by the ID in the state line or viaCronList, and any other pending one-shot). Write the new reset time into the conversation (it is the recorded reset time signal (b) relies on). - classic mode: the next reset time is now (resume time) + 5 hours; redo "On invocation" step 3 using the classic timed path with that computed time, carrying the same
cancel_windowandstopvalues forward, then delete every other job of this run (the old poll and any other pending one-shot). This is the same 5-hour rolling window, so the estimate is as good as one the user would have given, with no need to ask them again.
- usage mode: take a fresh reading, run "Choosing the target time" (this applies the weekly cap and falls back to now + 5 hours), and redo "On invocation" step 3 for usage mode: a new backstop only if the fresh P is at or above the backstop level or the target is a weekly reset, then a new timed one-shot with
Do this quietly, with no need to re-confirm with the user unless something about the setup changed (say so if the target switched to a weekly reset).
- If
- Resume: continue the original, interrupted work directly in this session, right where it left off, as if the cutoff never happened. For a soft-stop pause, continue from the state note. If the session's context was compacted or otherwise lost during the wait, say so and ask the user how to proceed rather than guessing at the interrupted task.
About the tools this skill uses
CronCreate, CronDelete, and PushNotification are harness-provided tools (part of the Claude Code / Claude app scheduling system this skill runs in), not something this skill implements. If your environment doesn't expose them, this skill can't function as written. CronList is used when available, to find this run's jobs. mcp__ccd_session_mgmt__get_usage is optional: it exists only in the Claude desktop app, and without it (or when it reports unavailable / not_applicable) the skill runs in classic mode.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

