pi-keepawake
Keep the host from idle sleeping while a pi process is running. Blocks system sleep only — display sleep and the lock screen still work.
Package details
Install pi-keepawake from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-keepawake- Package
pi-keepawake- Version
1.0.2- Published
- Oct 23, 2026
- Downloads
- 704/mo · 704/wk
- Author
- zxh126
- License
- MIT
- Types
- extension
- Size
- 25.3 KB
- Dependencies
- 1 dependency · 0 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-keepawake
English | 简体中文
A pi extension that keeps the host from idle sleeping or hibernating as long as any pi process is running. Display sleep and the lock screen keep working — nothing here interferes with them.
Zero configuration: install it and it works. MIT licensed.
Features
- Process-scoped: held from
session_starttosession_shutdown, i.e. "pi is open, the machine stays awake". Every pi process holds its own OS assertion and the OS aggregates them — open three pi processes, close two, the host still does not sleep. - System sleep only: no
ES_DISPLAY_REQUIRED(Windows), no-d(macOS), noidle/handle-lid-switch(Linux). The screen may turn off, the session may lock. - Zero configuration: no flags, no environment variables, no commands.
- Fail-safe: inside containers, without PowerShell, or on an unsupported platform, pi keeps running and you get one warning in the TUI.
- Cross-platform: every platform uses its own built-in mechanism. No admin rights, no native
addons, no
node-gyp. - Observable: the TUI footer shows
☕ keep-awake, and the underlying helper process (plus its command line) can be inspected directly — see below. - No leftovers: released on normal exit, Ctrl-C and
process.exit(); automatically re-engaged if the OS primitive dies. Asession_startthat follows a reload or session replacement first sweeps helpers left by the previous runtime of the same pi process, so a reload cannot leave a second assertion engaged.
Install
Requires Node.js ≥ 20 (bundled with pi).
1. From npm (recommended)
pi install npm:pi-keepawake
2. From Gitee
pi install git:gitee.com/zxh126/pi-keepaware
Both routes make pi install the dependency (pervigil) for you. Afterwards pi list shows the
package and /reload activates it. To pin a version, spell it out:
pi install npm:pi-keepawake@1.0.0.
3. Manually into the user extensions directory
git clone https://gitee.com/zxh126/pi-keepaware "$HOME/.pi/agent/extensions/keep-awake"
cd "$HOME/.pi/agent/extensions/keep-awake" && npm install
On Windows the path is %USERPROFILE%\.pi\agent\extensions\keep-awake. Pi discovers every
subdirectory of extensions/ that contains an index.ts.
Pi does not install dependencies for local directory packages, so the
npm installstep is mandatory here.
4. Try it once
pi -e npm:pi-keepawake
pi -e git:gitee.com/zxh126/pi-keepaware
pi -e ./pi-keepawake # local path, run npm install first
Uninstall
pi remove npm:pi-keepawake
pi remove git:gitee.com/zxh126/pi-keepaware
Or simply delete ~/.pi/agent/extensions/keep-awake.
What it actually does
The extension only decides when to hold and release; the OS interaction is done by pervigil (zero dependencies, no native addons, MIT).
| Platform | Mechanism | Flags |
|---|---|---|
| Windows | a PowerShell child calls SetThreadExecutionState and blocks to keep that thread alive |
ES_CONTINUOUS | ES_SYSTEM_REQUIRED (no ES_DISPLAY_REQUIRED) |
| macOS | caffeinate(1) |
-i (no -d) |
| Linux | systemd-inhibit(1), falling back to /sys/power/wake_lock |
--what=sleep --mode=block (no idle, no handle-lid-switch) |
Lifecycle:
session_start ──▶ acquire ──▶ [ held for the whole session ] ──▶ session_shutdown ──▶ release
│
└─ helper dies ⇒ primitiveDied ⇒ re-engage (max 5 times)
More notes:
- No power-plan changes (
powercfg), no presentation mode, no input simulation — so neither the lock screen nor the screen saver is suppressed. - A user-initiated sleep/hibernate is not blocked. That is the semantics of an OS assertion, and it is deliberately preserved.
- Inside containers (
/.dockerenv, thecontainerenv var, ...) pervigil becomes a silent no-op instead of throwing.
Verify it is working
The obvious one: the pi footer shows ☕ keep-awake.
From the OS point of view:
Windows (PowerShell, no admin required)
Get-CimInstance Win32_Process -Filter "Name='powershell.exe' OR Name='pwsh.exe'" |
Where-Object { $_.CommandLine -like '*Pervigil*' } |
Select-Object ProcessId, ParentProcessId,
@{ n = 'flags'; e = {
@(
if ($_.CommandLine -match 'ES_SYSTEM_REQUIRED') { 'ES_SYSTEM_REQUIRED' }
if ($_.CommandLine -match 'ES_DISPLAY_REQUIRED') { 'ES_DISPLAY_REQUIRED' }
) -join ','
} }
While pi is running there should be exactly one helper whose flags read ES_SYSTEM_REQUIRED
(not ES_DISPLAY_REQUIRED); it should disappear once pi exits.
powercfg /requestsshows the request as well, but it requires administrator rights and fails in a normal terminal.
macOS
pmset -g assertions | grep -i caffeinate
Linux
systemd-inhibit --list | grep -i pi
Known limitations
- One long-lived PowerShell process on Windows (measured: WorkingSet ≈ 74 MB / Private ≈ 59 MB). That is the direct cost of the "held for the whole session" semantics; it is reclaimed when pi exits.
- On Linux you need a systemd user session (
systemd-inhibit) or a writable/sys/power/wake_lock; otherwise it degrades to a no-op with one warning. - Lid-close suspend is not blocked (the Linux
handle-lid-switchinhibitor is intentionally not requested), and neither is a user-initiated sleep. - Verified on Windows 11 only (helper appears/releases, multiple processes aggregate, re-engage after the helper is killed, no leftovers after a hard kill). The macOS / Linux code paths are reviewed against pervigil's semantics but have no on-device test record.
- If pi is killed in a way no hook can observe (TerminateProcess / OOM), the extension's own cleanup
does not run. On the author's machine the helper dies with its parent anyway; as a safety net every
session_startreaps wake-lock helpers whose parent is this same pi process (a leftover of a reload that skippedsession_shutdown) or whose parent process is gone. Helpers of other live processes are never touched.
Development
pi-keepawake/
├── index.ts # the extension (single source file)
├── package.json # pi manifest: pi.extensions -> ./index.ts, dependency pervigil
├── LICENSE # MIT
├── README.md # this file
└── README.zh-CN.md # Chinese translation
- The extension runs inside the pi process through pi's jiti loader — no build step.
- The only runtime dependency is
pervigil; the@earendil-works/*packages are imported withimport typeonly and stay out ofdependencies. - After editing,
/reloadinside pi is enough. To try a checkout without installing:pi -e <local path>.
Relevant pi events: session_start (create the wake-lock controller and acquire), session_shutdown
(release and clear the footer status). At runtime the pervigil primitiveDied / degraded events
drive re-engagement and the one-time warning.
Release flow (maintainer): bump version in package.json → commit → push to Gitee →
npm publish --registry=https://registry.npmjs.org (the local .npmrc points its default registry
at the npmmirror mirror, which only affects installs — publishing must target the official registry
explicitly).
Dependencies and credits
License
MIT © 2026 zxh126