claude-nextsession
Schedule a set of instructions to run automatically once your Claude Code usage session resets — no need to babysit the clock or remember to come back.
Install
git clone https://github.com/pcx-wave/claude-nextsession.git && mkdir -p ~/.claude/skills && ln -sf "$(pwd)/claude-nextsession" ~/.claude/skills/claude-nextsession
That's a symlink, not a copy — git pull inside the cloned repo keeps the
skill current, no reinstall. One manual step remains: wiring the rate-limit
cache into your statusLine command, covered in Setup below — it's the
only thing this depends on outside the repo itself.
Usage
This is a Claude Code skill — you talk to it, you don't run Python yourself.
Before you walk away:
postpone this to next session: fix the failing tests in src/
or invoke it explicitly:
/claude-nextsession Fix the failing tests in src/
Claude schedules the run as a tool call and tells you when it'll fire — it
figures out exactly when your current 5-hour usage window resets and
schedules a headless claude -p run for that moment.
When you're back:
what did the scheduled task do?
Claude reads this project's report and continues from whatever's left
outstanding, or hands you the one-line command to reopen that exact
session. See SKILL.md for the precise instructions Claude follows in
both directions.
(The raw python3 postpone.py commands still work directly — see Direct
CLI below — but that path is for cron jobs and scripting, not day-to-day
use.)
Why
Claude Code Pro/Max sessions have a rolling usage window. When you hit it mid-task, you either wait around watching the clock, or you forget and lose the moment your quota comes back. This tool lets you hand off a task and walk away — it fires on its own the instant you're unblocked again.
Walking away is only half of it, though. Coming back to a task that ran
without you is its own problem: the run is over, its reasoning is gone, and
if you postponed work in three repos they all fired at the same reset. So
--resume is scoped to the project you're standing in, leads with what's
still outstanding, and ends with the exact claude --resume <id> for that
run — never a list of sessions to guess between.
How it works
Claude Code already knows exactly when your session resets — it's the same
number behind the session 42% (60m) indicator in your status bar
(rate_limits.five_hour.resets_at, a Unix timestamp, delivered to your
statusLine command on every turn). This tool doesn't call any API; it just
reads that value from a small local cache.
- Your
statusLinecommand writesrate_limitsto~/.claude/cache/rate-limits.jsonon every turn (see Setup below — this one small addition is the only external dependency). postpone.pyreadsrate_limits.five_hour.resets_atfrom that cache.- It schedules
templates/delayed_task.shviasystemd-run --user --on-calendar, which runsclaude -p "$INSTRUCTIONS"at that exact time. - When the run finishes, it writes a report keyed to that project —
including the run's own
session_id— so--resumecan find the right one later and point you back at the exact session.
Because it reads Claude Code's own subscription-session state instead of querying the Anthropic API, there's no API key, no network call, and no confusion with unrelated pay-per-token rate limits.
Setup
1. No Python dependencies — standard library only.
2. Wire the rate-limit cache into your statusLine command. Claude Code
invokes your configured statusLine command (see statusLine in
~/.claude/settings.json) with a JSON payload on stdin that includes
rate_limits. Add this wherever your script parses that payload:
import json, os, time
rl = d.get("rate_limits") or {} # `d` = the parsed stdin JSON
if rl:
cache_path = os.path.expanduser("~/.claude/cache/rate-limits.json")
os.makedirs(os.path.dirname(cache_path), exist_ok=True)
with open(cache_path, "w") as f:
json.dump({"rate_limits": rl, "captured_at": int(time.time())}, f)
If you don't have a custom statusLine command yet, you need one purely to
receive this payload each turn — see Claude Code's statusline
docs for the
minimal setup.
3. Confirm systemd-run is available:
systemctl --user status # should show a running instance
(Any modern Linux desktop/server with systemd has this — nothing to install.)
4. Confirm claude is in $PATH.
That's the whole setup — no .env, no API key, no extra packages.
Direct CLI (cron, scripting, no Claude Code involved)
# Basic — reads the reset time from the local cache
python3 postpone.py --instructions "Your instructions here"
# Run in a specific project directory
python3 postpone.py -i "Check system" -w /path/to/project
# Dry run — see what would be scheduled without actually scheduling it
python3 postpone.py -i "Check system" --dry-run
# Override the detected reset time (for testing)
python3 postpone.py -i "Test" -t "2026-07-26T15:30:00Z"
# Catch up on this project's most recent run
python3 postpone.py --resume
# ...or the most recent run from any project
python3 postpone.py --resume --global
Permissions
The scheduled task runs headless — nobody is there to answer a permission
prompt. Without an explicit flag, claude -p silently declines any Read/Edit
on an existing file and exits 0, so the log looks like a success even though
nothing happened. --permissions controls this:
| Value | Effect |
|---|---|
scoped (default) |
--allowedTools "Read Edit Write Bash Glob Grep" — covers most coding tasks, nothing beyond that |
bypass |
--dangerously-skip-permissions — no restrictions at all |
python3 postpone.py -i "..." --permissions bypass
Pick bypass deliberately for tasks that need it — not as a default, since
nothing reviews what it does before it runs.
Picking up where it left off
Every run writes a report to ~/.claude/cache/claude-nextsession/reports/
(outside this repo — it's public, and reports can contain private task
content). Catch up after starting a new session with:
python3 postpone.py --resume
It only shows reports for the project you're standing in. If you postpone
tasks in several repos, they all fire at the same reset — scoping by working
directory is what keeps them from getting mixed up. Add --global to see the
most recent report from any project instead. (--last-report still works and
behaves identically.)
The report leads with a Next steps section and ends with a one-line resume command:
# claude-nextsession report — SUCCESS
## Next steps
- [x] JWT issue/verify + middleware landed
- [ ] refresh-token rotation - blocked on a TTL decision
- next: wire logout to token revocation
...
## Resume
cd /path/to/your-project && claude --resume 4f2a91c8-77de-4f0b-9c1e-aa0912345678
That resume line reopens the exact headless session that did the work, with its full transcript — no session picker, no guessing which entry belongs to which project.
The "Next steps" section comes from the run itself: every scheduled
instruction gets a short epilogue appended asking Claude to close with a
## NEXT STEPS section (completed / not completed and why / what's next),
which is then lifted to the top of the report. If the run omits it, the
report is simply built without it.
Below that sits the full picture: status (SUCCESS / PARTIAL (N denied) /
FAILED / CRASHED), what was asked, what Claude actually did, any
permission denials, and a git diff --stat of what changed — built from claude -p --output-format json (is_error, permission_denials, cost, turns) plus
a real git diff of the workdir. The full JSON and patch are saved
alongside the summary for anyone who wants the raw detail.
Inspecting a scheduled task
systemctl --user status claudepostpone-<timestamp>-<pid>
journalctl --user -u claudepostpone-<timestamp>-<pid>
# or just tail the log the script itself writes
tail -f /tmp/claudepostpone_*.log
# or the structured report, once it's done
python3 postpone.py --resume
Requirements
- Python 3.10+ (standard library only)
systemd-run+ a working systemd user session (systemctl --user)claudeCLI available in$PATHat execution time- A
statusLinecommand that persistsrate_limitsas described above
Files
postpone.py— main scriptreport.py— builds and reads execution reportstemplates/delayed_task.sh— generated-script template; invokesclaude -p "$INSTRUCTIONS" --output-format jsonin the captured working directory and logs to/tmp/claudepostpone_<timestamp>.logSKILL.md— Claude Code skill definition (frontmatter + full reference)
License
MIT
No comments yet
Be the first to share your take.