claude-powernap 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_powernap-0.3.0/.gitignore +7 -0
- claude_powernap-0.3.0/CHANGELOG.md +96 -0
- claude_powernap-0.3.0/LICENSE +21 -0
- claude_powernap-0.3.0/PKG-INFO +218 -0
- claude_powernap-0.3.0/README.md +197 -0
- claude_powernap-0.3.0/SECURITY.md +35 -0
- claude_powernap-0.3.0/install.ps1 +6 -0
- claude_powernap-0.3.0/install.sh +7 -0
- claude_powernap-0.3.0/pyproject.toml +37 -0
- claude_powernap-0.3.0/src/claude_powernap/__init__.py +2 -0
- claude_powernap-0.3.0/src/claude_powernap/__main__.py +4 -0
- claude_powernap-0.3.0/src/claude_powernap/assets/claude-powernap.service +6 -0
- claude_powernap-0.3.0/src/claude_powernap/assets/claude-powernap.timer +9 -0
- claude_powernap-0.3.0/src/claude_powernap/assets/com.claude-powernap.watcher.plist.template +24 -0
- claude_powernap-0.3.0/src/claude_powernap/assets/config.default.json +19 -0
- claude_powernap-0.3.0/src/claude_powernap/cli.py +273 -0
- claude_powernap-0.3.0/src/claude_powernap/fallback_watch.py +409 -0
- claude_powernap-0.3.0/src/claude_powernap/hooks_config.py +77 -0
- claude_powernap-0.3.0/src/claude_powernap/powernap_common.py +459 -0
- claude_powernap-0.3.0/src/claude_powernap/usage_check.py +250 -0
- claude_powernap-0.3.0/uninstall.ps1 +5 -0
- claude_powernap-0.3.0/uninstall.sh +5 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
|
|
5
|
+
versioning: [SemVer](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [0.3.0] - 2026-07-18
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **PyPI packaging**: installable via `pip install claude-powernap` /
|
|
11
|
+
`uvx claude-powernap setup`; new `setup` / `remove` CLI subcommands replace
|
|
12
|
+
the platform installer scripts (install.sh/.ps1 remain as thin wrappers).
|
|
13
|
+
- **Claude Code plugin**: the repo is its own marketplace —
|
|
14
|
+
`/plugin marketplace add asiagenawi/claude-powernap` then
|
|
15
|
+
`/plugin install powernap@claude-powernap`. Hooks activate with no file
|
|
16
|
+
deployment; `/powernap:watcher` schedules the OS-level fallback watcher;
|
|
17
|
+
`/powernap:status` and `/powernap:toggle` included
|
|
18
|
+
(`watcher-setup`/`watcher-remove` CLI subcommands back them).
|
|
19
|
+
- `claude-powernap version` command.
|
|
20
|
+
- CI: package build + wheel install + entry-point smoke test job; PyPI
|
|
21
|
+
publish workflow on GitHub releases (trusted publishing).
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- Repo restructured to a src-layout Python package (`src/claude_powernap/`);
|
|
25
|
+
install logic consolidated into one cross-platform code path.
|
|
26
|
+
|
|
27
|
+
### Fixed (pre-release audit)
|
|
28
|
+
- Rescue paths now share one ledger — a warned session that then hard-hit
|
|
29
|
+
the limit can no longer be resumed twice (forked).
|
|
30
|
+
- macOS liveness check fails toward "alive" on lsof errors, matching Windows.
|
|
31
|
+
- Warnings are no longer emitted (and marked delivered) on Stop events,
|
|
32
|
+
where injected context reaches no model turn.
|
|
33
|
+
- Local estimation dedupes by request/message id — `claude --resume` copies
|
|
34
|
+
history into a new transcript and previously double-counted it.
|
|
35
|
+
- Keychain: full-keychain enumeration (`dump-keychain`) now runs only on a
|
|
36
|
+
cache miss, never on the steady-state path; check cadence has a 15s floor.
|
|
37
|
+
- Usage requests self-identify as `claude-powernap/<version>` (verified
|
|
38
|
+
accepted) instead of a claude-cli User-Agent.
|
|
39
|
+
- uvx installs embed a stable system interpreter (not uv's collectible
|
|
40
|
+
cache path) into hooks/shims/scheduled jobs; re-running setup repairs a
|
|
41
|
+
stale interpreter in existing hooks.
|
|
42
|
+
- Account switches also reset burn-rate samples; source flips
|
|
43
|
+
(endpoint↔local) reset them too, preventing phantom burn spikes.
|
|
44
|
+
- Warn keys bucket the reset time to the hour, so endpoint drift can't
|
|
45
|
+
re-warn mid-window; an active weekly stop suppresses the contradictory
|
|
46
|
+
5h resume instruction.
|
|
47
|
+
- Watcher dry-run is truly read-only; rescue retries on failed resumes;
|
|
48
|
+
resumed/notified ledgers prune after 24h; cwd is shell-quoted (and falls
|
|
49
|
+
back to home when deleted) in resume commands.
|
|
50
|
+
- `status` reads state under the lock; `--debug` never writes unlocked.
|
|
51
|
+
- Partial `token_weights` config merges over defaults instead of crashing
|
|
52
|
+
the scan; multi-machine calibration guarded by a substantial-usage floor
|
|
53
|
+
and smoothing; missing-budget rescans throttled to hourly.
|
|
54
|
+
- Empty hook session_id falls back to the transcript filename.
|
|
55
|
+
- Removed a stale committed wheel from `dist/` (would have broken future
|
|
56
|
+
publishes); sdist excludes demo/CI files; README/SECURITY corrections
|
|
57
|
+
(Keychain enumeration disclosure, honest UA, cadence and trigger accuracy,
|
|
58
|
+
uninstall matrix per install method, sleep/`caffeinate` caveat, absolute
|
|
59
|
+
image URLs for PyPI).
|
|
60
|
+
|
|
61
|
+
## [0.2.0] - 2026-07-18
|
|
62
|
+
|
|
63
|
+
### Added
|
|
64
|
+
- **Burn-rate prediction**: warnings also fire when the recent burn rate
|
|
65
|
+
projects the limit within `safety_margin_min` minutes — catches fast
|
|
66
|
+
(subagent-heavy) burns the static threshold misses.
|
|
67
|
+
- **Adaptive check cadence**: 30s above 80% usage, every hook event above 90%.
|
|
68
|
+
- **Pause ledger + rescue**: every pause is recorded; the watcher resumes
|
|
69
|
+
napping sessions whose in-session alarm died (sleep/reboot/crash).
|
|
70
|
+
- **Weekly guard** (opt-in, `weekly_guard: true`): warn/pause on the weekly
|
|
71
|
+
window; pauses without scheduling a resume since weekly resets are days out.
|
|
72
|
+
- **Account-switch detection**: per-account cached state clears automatically
|
|
73
|
+
on `/login` to a different account.
|
|
74
|
+
- **Cross-platform state locking**: concurrent sessions can no longer race
|
|
75
|
+
state.json (fcntl/msvcrt; 12-process CI test).
|
|
76
|
+
|
|
77
|
+
## [0.1.0] - 2026-07-18
|
|
78
|
+
|
|
79
|
+
Initial release.
|
|
80
|
+
|
|
81
|
+
### Added
|
|
82
|
+
- Usage monitor hook (`PostToolUse`/`UserPromptSubmit`/`Stop`): warns the live
|
|
83
|
+
session at a configurable threshold (default 90%) of the 5-hour window,
|
|
84
|
+
with the pause-checkpoint-reschedule protocol injected into context.
|
|
85
|
+
- Hybrid usage source: exact numbers from the OAuth usage endpoint with
|
|
86
|
+
automatic fallback to local transcript estimation, continuously calibrated
|
|
87
|
+
against endpoint truth.
|
|
88
|
+
- Fallback watcher: detects sessions that hard-hit the limit, waits for the
|
|
89
|
+
reset, and resumes them visibly (new terminal window) — with a
|
|
90
|
+
never-fork-a-live-session guarantee; notifies instead when in doubt.
|
|
91
|
+
- `claude-powernap on|off|status|log` CLI.
|
|
92
|
+
- Platforms: macOS (Keychain/launchd/osascript), Linux incl. WSL
|
|
93
|
+
(credentials file/systemd user timer/notify-send, terminal auto-detect),
|
|
94
|
+
native Windows experimental (Task Scheduler/toasts/wt).
|
|
95
|
+
- CI: full install→monitor→hook→watcher→uninstall cycle on macOS, Ubuntu,
|
|
96
|
+
and Windows runners.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 asiagenawi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: claude-powernap
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Your Claude Code session sees the 5-hour limit coming, checkpoints its work, and resumes itself when the window resets.
|
|
5
|
+
Project-URL: Homepage, https://github.com/asiagenawi/claude-powernap
|
|
6
|
+
Project-URL: Changelog, https://github.com/asiagenawi/claude-powernap/blob/main/CHANGELOG.md
|
|
7
|
+
Author: asiagenawi
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: anthropic,auto-resume,claude,claude-code,rate-limit,usage-limit
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: MacOS
|
|
15
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# claude-powernap
|
|
23
|
+
|
|
24
|
+
[](https://github.com/asiagenawi/claude-powernap/actions/workflows/ci.yml)
|
|
25
|
+
[](https://github.com/asiagenawi/claude-powernap/releases)
|
|
26
|
+
[](https://github.com/asiagenawi/claude-powernap/blob/main/LICENSE)
|
|
27
|
+

|
|
28
|
+

|
|
29
|
+
|
|
30
|
+
**Your Claude Code session sees the usage limit coming, saves its work, and
|
|
31
|
+
resumes itself when the window resets. You do nothing.**
|
|
32
|
+
|
|
33
|
+
*(Demo below is an illustrative mock-up of a real cycle the tool ran.)*
|
|
34
|
+
|
|
35
|
+

|
|
36
|
+
|
|
37
|
+
## The problem
|
|
38
|
+
|
|
39
|
+
You kick off a long Claude Code automation — a big refactor, a batch
|
|
40
|
+
migration, an overnight research run. You check back three hours later and
|
|
41
|
+
find it died 40 minutes in:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
You've hit your session limit · resets 3:00am
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Everything since the last commit is in limbo. The context that session had
|
|
48
|
+
built up is sitting frozen mid-thought. And the limit reset hours ago — the
|
|
49
|
+
session just had no way to know, no way to save itself, and no way to come
|
|
50
|
+
back. Your subscription's 5-hour window reset while your automation sat
|
|
51
|
+
dead in a terminal.
|
|
52
|
+
|
|
53
|
+
## The idea
|
|
54
|
+
|
|
55
|
+
A session that's *about* to hit the limit still has tokens left. That's
|
|
56
|
+
enough budget to do something smarter than die:
|
|
57
|
+
|
|
58
|
+
1. **A hook watches your usage** (every ~2 min normally, tightening to ~15s
|
|
59
|
+
near the limit; zero workflow changes). It knows your exact window percentage and reset time — the same
|
|
60
|
+
numbers Claude Code's own `/usage` screen shows.
|
|
61
|
+
2. **At 90% — or earlier if your burn rate projects the limit within ~9
|
|
62
|
+
minutes — the session itself gets warned**: the hook injects a message
|
|
63
|
+
into the live conversation: *"you're at 91%, window resets at 3:00am,
|
|
64
|
+
pause now."*
|
|
65
|
+
3. **Claude wraps up gracefully**: finishes the current step, writes a
|
|
66
|
+
checkpoint file (what's done, what's in flight, exact next steps), and —
|
|
67
|
+
when the session has a scheduled-tasks capability — schedules a one-shot
|
|
68
|
+
task for just after the reset. Then it idles.
|
|
69
|
+
4. **At reset, the session wakes itself** — same terminal, same context,
|
|
70
|
+
reads its checkpoint, keeps going. Sessions without a scheduler instead
|
|
71
|
+
checkpoint and tell you when to send any message to resume — and the
|
|
72
|
+
watcher (below) still notifies or reopens as needed.
|
|
73
|
+
|
|
74
|
+
If the estimate is ever wrong and a session hard-hits the wall anyway, a
|
|
75
|
+
background watcher catches that too: after the reset it reopens the session
|
|
76
|
+
in a visible terminal window with the "continue from your checkpoint" prompt
|
|
77
|
+
already submitted. If the original window is still open, you get a
|
|
78
|
+
notification instead — it will never fork a live session.
|
|
79
|
+
|
|
80
|
+
## How it compares
|
|
81
|
+
|
|
82
|
+
| | warns before the limit | session saves its work | resumes automatically | needs tmux |
|
|
83
|
+
|---|---|---|---|---|
|
|
84
|
+
| **claude-powernap** | ✅ | ✅ | ✅ same session | no |
|
|
85
|
+
| usage monitors (ccusage, claude-monitor) | ⚠️ warns *you*, not the session | ❌ | ❌ | — |
|
|
86
|
+
| auto-retriers (unsnooze, claude-auto-retry, …) | ❌ reacts after death | ❌ dies mid-thought | ✅ | mostly yes |
|
|
87
|
+
|
|
88
|
+
Free, privacy-first, local-only, no dependencies (Python 3 stdlib only). macOS, Linux (incl.
|
|
89
|
+
WSL), native Windows (experimental).
|
|
90
|
+
|
|
91
|
+
## Install
|
|
92
|
+
|
|
93
|
+
As a Claude Code plugin (inside any Claude Code session):
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
/plugin marketplace add asiagenawi/claude-powernap
|
|
97
|
+
/plugin install powernap@claude-powernap
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The plugin activates the monitoring hooks immediately. The one thing a
|
|
101
|
+
plugin can't do itself is register the fallback watcher (an OS-level
|
|
102
|
+
background job) — so on first run the hook notices it's missing and has the
|
|
103
|
+
session offer you the one command to set it up (or run `/powernap:watcher`
|
|
104
|
+
yourself anytime). Also ships `/powernap:status` and `/powernap:toggle
|
|
105
|
+
on|off`.
|
|
106
|
+
|
|
107
|
+
From PyPI (all platforms):
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
uvx claude-powernap setup # or: pipx install claude-powernap && claude-powernap setup
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Or from a clone, if you'd rather read what you run first:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
git clone https://github.com/asiagenawi/claude-powernap.git && cd claude-powernap
|
|
117
|
+
./install.sh # macOS / Linux / WSL — same as `claude-powernap setup`
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Native Windows clone (PowerShell 7 recommended): `.\install.ps1`
|
|
121
|
+
|
|
122
|
+
Pick ONE install method — plugin or pip/clone. (Both at once is harmless —
|
|
123
|
+
the shared state throttle makes duplicate checks no-ops — but pointless.)
|
|
124
|
+
|
|
125
|
+
That's the whole setup. Every Claude Code session on the machine is covered —
|
|
126
|
+
no per-project config, no special launcher, no flags to remember. Start your
|
|
127
|
+
long automations exactly the way you already do.
|
|
128
|
+
|
|
129
|
+
Setup is deliberately boring and inspectable: it copies a few Python files
|
|
130
|
+
to `~/.claude/claude-powernap/`, merges three hook entries into
|
|
131
|
+
`~/.claude/settings.json` (backing it up first), and schedules the fallback
|
|
132
|
+
watcher (launchd / systemd user timer / Task Scheduler).
|
|
133
|
+
`claude-powernap remove` (or `./uninstall.sh`) reverses all of it. If you
|
|
134
|
+
set `CLAUDE_CONFIG_DIR`, setup follows it — run setup from a normal shell,
|
|
135
|
+
not from inside a Claude Code session, so the right settings file is edited.
|
|
136
|
+
|
|
137
|
+
On macOS the first usage check may trigger one Keychain prompt — the monitor
|
|
138
|
+
reads Claude Code's own OAuth token to ask Anthropic for your real usage
|
|
139
|
+
numbers (see Caveats). Click "Always Allow".
|
|
140
|
+
|
|
141
|
+
## Toggle
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
claude-powernap on # enable everything
|
|
145
|
+
claude-powernap off # disable everything
|
|
146
|
+
claude-powernap status # current 5h + weekly usage, watcher state
|
|
147
|
+
claude-powernap log # what the watcher and monitor have been doing
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Configure — `~/.claude/claude-powernap/config.json`
|
|
151
|
+
|
|
152
|
+
| key | default | meaning |
|
|
153
|
+
|---|---|---|
|
|
154
|
+
| `enabled` | `true` | master switch (what `on`/`off` flips) |
|
|
155
|
+
| `threshold_pct` | `90` | warn/pause threshold for the 5h window |
|
|
156
|
+
| `check_interval_s` | `120` | base seconds between checks (auto-tightens to 30s above 80%, every event above 90%) |
|
|
157
|
+
| `safety_margin_min` | `9` | also warn when the current burn rate projects the limit within this many minutes |
|
|
158
|
+
| `weekly_guard` | `false` | opt-in: also warn/pause on the **weekly** window (no auto-resume — its reset is days away) |
|
|
159
|
+
| `weekly_threshold_pct` | `90` | weekly-guard warning threshold |
|
|
160
|
+
| `endpoint_enabled` | `true` | `false` = fully local estimation only |
|
|
161
|
+
| `terminal_app` | `Terminal` | macOS: `Terminal`/`iTerm2`; Linux: terminal binary name (auto-detected if unset) |
|
|
162
|
+
| `resume_grace_min` | `3` | schedule resume this long after reset |
|
|
163
|
+
| `headless_resume_extra_args` | `[]` | extra flags for last-resort headless resume |
|
|
164
|
+
| `local_budget_weighted_tokens` | `null` | manual budget for local estimation |
|
|
165
|
+
| `token_weights` | in/out/cache | per-token-type weights for local estimation |
|
|
166
|
+
|
|
167
|
+
## Plays by the rules
|
|
168
|
+
|
|
169
|
+
claude-powernap works *with* the usage limit, not around it:
|
|
170
|
+
|
|
171
|
+
- **Zero extra usage.** The same quota, consumed the same way. It never
|
|
172
|
+
gets you more tokens — it just stops a session from dying mid-thought
|
|
173
|
+
and picks the work back up when your own window resets.
|
|
174
|
+
- **Genuine client, official hooks.** Everything runs inside the real
|
|
175
|
+
Claude Code client through its documented hooks system. It never spoofs
|
|
176
|
+
a client identity and never touches permission systems.
|
|
177
|
+
- **Privacy-first, local-only.** Checkpoints, transcripts, config — all of
|
|
178
|
+
it stays on your machine. The one outbound call is the same usage query
|
|
179
|
+
the built-in `/usage` screen makes, and `endpoint_enabled: false` turns
|
|
180
|
+
even that off.
|
|
181
|
+
|
|
182
|
+
## Caveats
|
|
183
|
+
|
|
184
|
+
- **Undocumented usage endpoint** — exact percentages come from the same
|
|
185
|
+
unpublished API `/usage` uses (read-only, via the OAuth token already on
|
|
186
|
+
your machine; a ToS gray area). Handled: if the endpoint fails or
|
|
187
|
+
you set `endpoint_enabled: false`, the tool switches automatically to
|
|
188
|
+
local transcript estimation, self-calibrated whenever endpoint data was
|
|
189
|
+
available.
|
|
190
|
+
- **The paused session must stay open** — that's the point. If its alarm
|
|
191
|
+
dies anyway (sleep, reboot, crash), the watcher notices the missed wake-up
|
|
192
|
+
and resumes the session itself.
|
|
193
|
+
- **Windows is experimental** — Windows can't reliably tell whether a session
|
|
194
|
+
is still open, so the watcher errs toward caution there: when unsure it
|
|
195
|
+
notifies you instead of auto-resuming (one click, never a forked session).
|
|
196
|
+
CI runs the full cycle on real Windows runners. WSL users: use
|
|
197
|
+
`./install.sh` inside WSL.
|
|
198
|
+
- **Sleep beats timers** — a sleeping laptop fires nothing: the in-session
|
|
199
|
+
alarm and the watcher both wait until the machine wakes, then the watcher
|
|
200
|
+
catches up (rescuing any missed wake-ups). For unattended overnight runs
|
|
201
|
+
keep the machine awake, e.g. `caffeinate -is` on macOS.
|
|
202
|
+
- **Linux notes**: terminal emulator auto-detected; headless servers fall
|
|
203
|
+
through to headless resume; `loginctl enable-linger $USER` keeps the
|
|
204
|
+
watcher running while logged out.
|
|
205
|
+
|
|
206
|
+
## Uninstall
|
|
207
|
+
|
|
208
|
+
By install method:
|
|
209
|
+
|
|
210
|
+
| installed via | uninstall with |
|
|
211
|
+
|---|---|
|
|
212
|
+
| plugin | run `python3 ~/.claude/claude-powernap/cli.py watcher-remove` (if you set up the watcher), then `/plugin uninstall powernap` |
|
|
213
|
+
| PyPI | `claude-powernap remove` (add `--purge` to delete config/state too), **then** `pip uninstall claude-powernap` — in that order |
|
|
214
|
+
| clone | `./uninstall.sh` (or `--purge`); Windows: `.\uninstall.ps1` (or `-Purge`) |
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
MIT
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# claude-powernap
|
|
2
|
+
|
|
3
|
+
[](https://github.com/asiagenawi/claude-powernap/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/asiagenawi/claude-powernap/releases)
|
|
5
|
+
[](https://github.com/asiagenawi/claude-powernap/blob/main/LICENSE)
|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
**Your Claude Code session sees the usage limit coming, saves its work, and
|
|
10
|
+
resumes itself when the window resets. You do nothing.**
|
|
11
|
+
|
|
12
|
+
*(Demo below is an illustrative mock-up of a real cycle the tool ran.)*
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
## The problem
|
|
17
|
+
|
|
18
|
+
You kick off a long Claude Code automation — a big refactor, a batch
|
|
19
|
+
migration, an overnight research run. You check back three hours later and
|
|
20
|
+
find it died 40 minutes in:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
You've hit your session limit · resets 3:00am
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Everything since the last commit is in limbo. The context that session had
|
|
27
|
+
built up is sitting frozen mid-thought. And the limit reset hours ago — the
|
|
28
|
+
session just had no way to know, no way to save itself, and no way to come
|
|
29
|
+
back. Your subscription's 5-hour window reset while your automation sat
|
|
30
|
+
dead in a terminal.
|
|
31
|
+
|
|
32
|
+
## The idea
|
|
33
|
+
|
|
34
|
+
A session that's *about* to hit the limit still has tokens left. That's
|
|
35
|
+
enough budget to do something smarter than die:
|
|
36
|
+
|
|
37
|
+
1. **A hook watches your usage** (every ~2 min normally, tightening to ~15s
|
|
38
|
+
near the limit; zero workflow changes). It knows your exact window percentage and reset time — the same
|
|
39
|
+
numbers Claude Code's own `/usage` screen shows.
|
|
40
|
+
2. **At 90% — or earlier if your burn rate projects the limit within ~9
|
|
41
|
+
minutes — the session itself gets warned**: the hook injects a message
|
|
42
|
+
into the live conversation: *"you're at 91%, window resets at 3:00am,
|
|
43
|
+
pause now."*
|
|
44
|
+
3. **Claude wraps up gracefully**: finishes the current step, writes a
|
|
45
|
+
checkpoint file (what's done, what's in flight, exact next steps), and —
|
|
46
|
+
when the session has a scheduled-tasks capability — schedules a one-shot
|
|
47
|
+
task for just after the reset. Then it idles.
|
|
48
|
+
4. **At reset, the session wakes itself** — same terminal, same context,
|
|
49
|
+
reads its checkpoint, keeps going. Sessions without a scheduler instead
|
|
50
|
+
checkpoint and tell you when to send any message to resume — and the
|
|
51
|
+
watcher (below) still notifies or reopens as needed.
|
|
52
|
+
|
|
53
|
+
If the estimate is ever wrong and a session hard-hits the wall anyway, a
|
|
54
|
+
background watcher catches that too: after the reset it reopens the session
|
|
55
|
+
in a visible terminal window with the "continue from your checkpoint" prompt
|
|
56
|
+
already submitted. If the original window is still open, you get a
|
|
57
|
+
notification instead — it will never fork a live session.
|
|
58
|
+
|
|
59
|
+
## How it compares
|
|
60
|
+
|
|
61
|
+
| | warns before the limit | session saves its work | resumes automatically | needs tmux |
|
|
62
|
+
|---|---|---|---|---|
|
|
63
|
+
| **claude-powernap** | ✅ | ✅ | ✅ same session | no |
|
|
64
|
+
| usage monitors (ccusage, claude-monitor) | ⚠️ warns *you*, not the session | ❌ | ❌ | — |
|
|
65
|
+
| auto-retriers (unsnooze, claude-auto-retry, …) | ❌ reacts after death | ❌ dies mid-thought | ✅ | mostly yes |
|
|
66
|
+
|
|
67
|
+
Free, privacy-first, local-only, no dependencies (Python 3 stdlib only). macOS, Linux (incl.
|
|
68
|
+
WSL), native Windows (experimental).
|
|
69
|
+
|
|
70
|
+
## Install
|
|
71
|
+
|
|
72
|
+
As a Claude Code plugin (inside any Claude Code session):
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
/plugin marketplace add asiagenawi/claude-powernap
|
|
76
|
+
/plugin install powernap@claude-powernap
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The plugin activates the monitoring hooks immediately. The one thing a
|
|
80
|
+
plugin can't do itself is register the fallback watcher (an OS-level
|
|
81
|
+
background job) — so on first run the hook notices it's missing and has the
|
|
82
|
+
session offer you the one command to set it up (or run `/powernap:watcher`
|
|
83
|
+
yourself anytime). Also ships `/powernap:status` and `/powernap:toggle
|
|
84
|
+
on|off`.
|
|
85
|
+
|
|
86
|
+
From PyPI (all platforms):
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
uvx claude-powernap setup # or: pipx install claude-powernap && claude-powernap setup
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Or from a clone, if you'd rather read what you run first:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
git clone https://github.com/asiagenawi/claude-powernap.git && cd claude-powernap
|
|
96
|
+
./install.sh # macOS / Linux / WSL — same as `claude-powernap setup`
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Native Windows clone (PowerShell 7 recommended): `.\install.ps1`
|
|
100
|
+
|
|
101
|
+
Pick ONE install method — plugin or pip/clone. (Both at once is harmless —
|
|
102
|
+
the shared state throttle makes duplicate checks no-ops — but pointless.)
|
|
103
|
+
|
|
104
|
+
That's the whole setup. Every Claude Code session on the machine is covered —
|
|
105
|
+
no per-project config, no special launcher, no flags to remember. Start your
|
|
106
|
+
long automations exactly the way you already do.
|
|
107
|
+
|
|
108
|
+
Setup is deliberately boring and inspectable: it copies a few Python files
|
|
109
|
+
to `~/.claude/claude-powernap/`, merges three hook entries into
|
|
110
|
+
`~/.claude/settings.json` (backing it up first), and schedules the fallback
|
|
111
|
+
watcher (launchd / systemd user timer / Task Scheduler).
|
|
112
|
+
`claude-powernap remove` (or `./uninstall.sh`) reverses all of it. If you
|
|
113
|
+
set `CLAUDE_CONFIG_DIR`, setup follows it — run setup from a normal shell,
|
|
114
|
+
not from inside a Claude Code session, so the right settings file is edited.
|
|
115
|
+
|
|
116
|
+
On macOS the first usage check may trigger one Keychain prompt — the monitor
|
|
117
|
+
reads Claude Code's own OAuth token to ask Anthropic for your real usage
|
|
118
|
+
numbers (see Caveats). Click "Always Allow".
|
|
119
|
+
|
|
120
|
+
## Toggle
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
claude-powernap on # enable everything
|
|
124
|
+
claude-powernap off # disable everything
|
|
125
|
+
claude-powernap status # current 5h + weekly usage, watcher state
|
|
126
|
+
claude-powernap log # what the watcher and monitor have been doing
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Configure — `~/.claude/claude-powernap/config.json`
|
|
130
|
+
|
|
131
|
+
| key | default | meaning |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| `enabled` | `true` | master switch (what `on`/`off` flips) |
|
|
134
|
+
| `threshold_pct` | `90` | warn/pause threshold for the 5h window |
|
|
135
|
+
| `check_interval_s` | `120` | base seconds between checks (auto-tightens to 30s above 80%, every event above 90%) |
|
|
136
|
+
| `safety_margin_min` | `9` | also warn when the current burn rate projects the limit within this many minutes |
|
|
137
|
+
| `weekly_guard` | `false` | opt-in: also warn/pause on the **weekly** window (no auto-resume — its reset is days away) |
|
|
138
|
+
| `weekly_threshold_pct` | `90` | weekly-guard warning threshold |
|
|
139
|
+
| `endpoint_enabled` | `true` | `false` = fully local estimation only |
|
|
140
|
+
| `terminal_app` | `Terminal` | macOS: `Terminal`/`iTerm2`; Linux: terminal binary name (auto-detected if unset) |
|
|
141
|
+
| `resume_grace_min` | `3` | schedule resume this long after reset |
|
|
142
|
+
| `headless_resume_extra_args` | `[]` | extra flags for last-resort headless resume |
|
|
143
|
+
| `local_budget_weighted_tokens` | `null` | manual budget for local estimation |
|
|
144
|
+
| `token_weights` | in/out/cache | per-token-type weights for local estimation |
|
|
145
|
+
|
|
146
|
+
## Plays by the rules
|
|
147
|
+
|
|
148
|
+
claude-powernap works *with* the usage limit, not around it:
|
|
149
|
+
|
|
150
|
+
- **Zero extra usage.** The same quota, consumed the same way. It never
|
|
151
|
+
gets you more tokens — it just stops a session from dying mid-thought
|
|
152
|
+
and picks the work back up when your own window resets.
|
|
153
|
+
- **Genuine client, official hooks.** Everything runs inside the real
|
|
154
|
+
Claude Code client through its documented hooks system. It never spoofs
|
|
155
|
+
a client identity and never touches permission systems.
|
|
156
|
+
- **Privacy-first, local-only.** Checkpoints, transcripts, config — all of
|
|
157
|
+
it stays on your machine. The one outbound call is the same usage query
|
|
158
|
+
the built-in `/usage` screen makes, and `endpoint_enabled: false` turns
|
|
159
|
+
even that off.
|
|
160
|
+
|
|
161
|
+
## Caveats
|
|
162
|
+
|
|
163
|
+
- **Undocumented usage endpoint** — exact percentages come from the same
|
|
164
|
+
unpublished API `/usage` uses (read-only, via the OAuth token already on
|
|
165
|
+
your machine; a ToS gray area). Handled: if the endpoint fails or
|
|
166
|
+
you set `endpoint_enabled: false`, the tool switches automatically to
|
|
167
|
+
local transcript estimation, self-calibrated whenever endpoint data was
|
|
168
|
+
available.
|
|
169
|
+
- **The paused session must stay open** — that's the point. If its alarm
|
|
170
|
+
dies anyway (sleep, reboot, crash), the watcher notices the missed wake-up
|
|
171
|
+
and resumes the session itself.
|
|
172
|
+
- **Windows is experimental** — Windows can't reliably tell whether a session
|
|
173
|
+
is still open, so the watcher errs toward caution there: when unsure it
|
|
174
|
+
notifies you instead of auto-resuming (one click, never a forked session).
|
|
175
|
+
CI runs the full cycle on real Windows runners. WSL users: use
|
|
176
|
+
`./install.sh` inside WSL.
|
|
177
|
+
- **Sleep beats timers** — a sleeping laptop fires nothing: the in-session
|
|
178
|
+
alarm and the watcher both wait until the machine wakes, then the watcher
|
|
179
|
+
catches up (rescuing any missed wake-ups). For unattended overnight runs
|
|
180
|
+
keep the machine awake, e.g. `caffeinate -is` on macOS.
|
|
181
|
+
- **Linux notes**: terminal emulator auto-detected; headless servers fall
|
|
182
|
+
through to headless resume; `loginctl enable-linger $USER` keeps the
|
|
183
|
+
watcher running while logged out.
|
|
184
|
+
|
|
185
|
+
## Uninstall
|
|
186
|
+
|
|
187
|
+
By install method:
|
|
188
|
+
|
|
189
|
+
| installed via | uninstall with |
|
|
190
|
+
|---|---|
|
|
191
|
+
| plugin | run `python3 ~/.claude/claude-powernap/cli.py watcher-remove` (if you set up the watcher), then `/plugin uninstall powernap` |
|
|
192
|
+
| PyPI | `claude-powernap remove` (add `--purge` to delete config/state too), **then** `pip uninstall claude-powernap` — in that order |
|
|
193
|
+
| clone | `./uninstall.sh` (or `--purge`); Windows: `.\uninstall.ps1` (or `-Purge`) |
|
|
194
|
+
|
|
195
|
+
## License
|
|
196
|
+
|
|
197
|
+
MIT
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
## What this tool touches
|
|
4
|
+
|
|
5
|
+
- **Reads** Claude Code's OAuth token. macOS: a `security
|
|
6
|
+
find-generic-password` lookup of the cached Claude Code credentials entry;
|
|
7
|
+
on a cache miss only, it runs `security dump-keychain` once to find the
|
|
8
|
+
right entry name — that command lists metadata (names, not secrets) for
|
|
9
|
+
the whole login keychain. Linux/Windows: reads
|
|
10
|
+
`~/.claude/.credentials.json`. The token is used in memory for one request
|
|
11
|
+
and never written anywhere.
|
|
12
|
+
- **Periodic outbound HTTPS requests** to `api.anthropic.com` (the usage
|
|
13
|
+
endpoint — the same query the built-in `/usage` screen makes), at most one
|
|
14
|
+
per check interval (120s normally, down to 15s near the limit). Requests
|
|
15
|
+
identify themselves honestly as `claude-powernap/<version>`. This is the
|
|
16
|
+
only network traffic the tool ever makes; disable with
|
|
17
|
+
`endpoint_enabled: false` for fully-offline operation.
|
|
18
|
+
- **Edits** `~/.claude/settings.json` to register three hooks (a backup copy
|
|
19
|
+
`settings.json.powernap-backup` is written first; `claude-powernap remove`
|
|
20
|
+
reverses the edit).
|
|
21
|
+
- **Reads** your local Claude Code transcripts (`~/.claude/projects/`) for
|
|
22
|
+
token math and limit detection. Nothing from them leaves your machine.
|
|
23
|
+
- **Schedules** the fallback watcher via launchd / systemd user timer /
|
|
24
|
+
Task Scheduler, running as your user.
|
|
25
|
+
|
|
26
|
+
## Supply chain
|
|
27
|
+
|
|
28
|
+
Python 3 standard library only — no pip packages, no npm, no curl|bash. What
|
|
29
|
+
you clone is what runs: ~1,400 lines of Python you can read first.
|
|
30
|
+
|
|
31
|
+
## Reporting a vulnerability
|
|
32
|
+
|
|
33
|
+
Use GitHub's private vulnerability reporting on this repository
|
|
34
|
+
(Security → Report a vulnerability). Best-effort response from a single
|
|
35
|
+
maintainer.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# claude-powernap installer (native Windows). Idempotent.
|
|
2
|
+
# Thin wrapper: all logic lives in the package CLI (`claude-powernap setup`).
|
|
3
|
+
$ErrorActionPreference = "Stop"
|
|
4
|
+
Set-Location (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
|
5
|
+
$env:PYTHONPATH = "src"
|
|
6
|
+
python -m claude_powernap setup
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# claude-powernap installer (macOS / Linux / WSL). Idempotent.
|
|
3
|
+
# Thin wrapper: all logic lives in the package CLI (`claude-powernap setup`).
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
cd "$(dirname "$0")"
|
|
6
|
+
command -v python3 >/dev/null || { echo "ERROR: python3 required"; exit 1; }
|
|
7
|
+
PYTHONPATH=src exec python3 -m claude_powernap setup
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "claude-powernap"
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "Your Claude Code session sees the 5-hour limit coming, checkpoints its work, and resumes itself when the window resets."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.9"
|
|
13
|
+
authors = [{ name = "asiagenawi" }]
|
|
14
|
+
keywords = ["claude", "claude-code", "anthropic", "usage-limit", "rate-limit", "auto-resume"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Operating System :: MacOS",
|
|
20
|
+
"Operating System :: POSIX :: Linux",
|
|
21
|
+
"Operating System :: Microsoft :: Windows",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Topic :: Software Development :: Build Tools",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/asiagenawi/claude-powernap"
|
|
28
|
+
Changelog = "https://github.com/asiagenawi/claude-powernap/blob/main/CHANGELOG.md"
|
|
29
|
+
|
|
30
|
+
[project.scripts]
|
|
31
|
+
claude-powernap = "claude_powernap.cli:main"
|
|
32
|
+
|
|
33
|
+
[tool.hatch.build.targets.wheel]
|
|
34
|
+
packages = ["src/claude_powernap"]
|
|
35
|
+
|
|
36
|
+
[tool.hatch.build.targets.sdist]
|
|
37
|
+
exclude = ["demo", ".github", "scripts", ".claude-plugin", "hooks", "commands"]
|