Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

agent-awake

agent-awake

Agents keep your Mac awake while they work.

This repo is the agent side of AllNighter/KeepAwake: hooks and instructions so coding agents hold an agent keep-awake switch for the duration of a task, then release it when they hand control back. No app code lives here.

Requires AllNighter / KeepAwake ≥ v1.1.0 with the local agent API on http://127.0.0.1:17893. With ≥ v1.2.0 holds are leased and expire on their own if a session dies without releasing (see below).

Override matrix

There are two user switches (display keep-awake, closed-lid keep-alive) and one agent switch. Combined effect:

effectiveDisplay = userDisplay OR agent
effectiveLid     = userLid     OR agent

Agent-off never overrides user-on (agent contributes only when on).

User display User lid Agent Effective display Effective lid Notes
OFF OFF OFF off off Idle defaults
ON OFF OFF on off User display only
OFF ON OFF off on User lid only: display may sleep; system stays awake with lid closed
ON ON OFF on on Both user switches on
OFF OFF ON on on Agent force-enables both
ON OFF ON on on Agent fills in lid
OFF ON ON on on Agent fills in display
ON ON ON on on Fully on
  • Agent ON force-enables display keep-awake and closed-lid keep-alive (OR with both user switches).
  • Agent OFF leaves effective state exactly as the user switches; it never turns off something the user has on.
  • Leased (app ≥ v1.2.0): a hold not refreshed for 30 minutes expires on its own; the PostToolUse keepalive hook refreshes it as long as the session is actually working. On older apps holds are sticky (no TTL). App restart drops agent state; user switches remain as the app defines.
  • Escape hatches: menu Clear agent keep-awake, or POST /agent/clear.

Requirements

Quick start

./install.sh

Flags:

./install.sh --dry-run              # plan only; no writes
./install.sh --hooks-only           # Claude Code hooks only
./install.sh --instructions-only    # instruction file only

The installer:

  1. Probes port 17893 and points you at the AllNighter releases page if the app is absent.
  2. Optionally installs hook scripts under ~/.claude/hooks/ and deep-merges the hooks block into ~/.claude/settings.json (backup first; append only; dedupe by (type, command); atomic write; JSON verified).
  3. Optionally copies instructions/AGENT-AWAKE.md to ~/.claude/AGENT-AWAKE.md.
  4. Prints a verification line against /status.

Manual hook setup (Claude Code)

  1. Copy scripts:

    mkdir -p ~/.claude/hooks
    cp hooks/agent-awake-on.sh hooks/agent-awake-off.sh ~/.claude/hooks/
    chmod +x ~/.claude/hooks/agent-awake-*.sh
  2. Merge hooks/settings-snippet.json into ~/.claude/settings.json under the top-level "hooks" key. Expand ~ to your home path in the command fields (or use absolute paths). Prefer ./install.sh --hooks-only so merge/dedupe/backup are handled for you.

Events:

Event Script Role
UserPromptSubmit agent-awake-on.sh acquire hold
PostToolUse agent-awake-on.sh lease keepalive (refresh)
Stop agent-awake-off.sh release
StopFailure agent-awake-off.sh release
SessionEnd agent-awake-off.sh release

StopFailure matters: a turn that ends on an API error never fires Stop, so off must still run. Double-off is safe (unknown id → no-op 200).

PostToolUse matters: it re-POSTs /agent/on on every tool call, which on app ≥ v1.2.0 refreshes the hold's lease. A session that dies without any off-hook (crash, kill, closed terminal, interrupt) stops refreshing, and the app drops its hold ~30 minutes later instead of keeping the Mac awake forever.

A user interrupt also skips Stop → the hold stays until SessionEnd, a manual Clear, or lease expiry (app ≥ v1.2.0).

Manual instruction setup (any agent)

Paste or attach instructions/AGENT-AWAKE.md as persistent memory / CLAUDE.md / system-prompt “soul” text. That file is self-contained: when to call on/off, session id rules, and the exception that explicit user keep-awake requests use the user routes (/on, /off, /lid/*), not /agent/*.

How it works

API contract

Base: http://127.0.0.1:17893

Action Request
Agent on POST /agent/on?id=<session>
Agent off POST /agent/off?id=<session>
Agent status GET /agent/status
Clear all agent POST /agent/clear

Fire-and-forget example:

curl -m 2 -s -o /dev/null -X POST "http://127.0.0.1:17893/agent/on?id=default"
curl -m 2 -s -o /dev/null -X POST "http://127.0.0.1:17893/agent/off?id=default"
  • id: platform session id (Claude Code: session_id from hook stdin JSON). Fallback: default. Server-side this is a set of ids: duplicate /agent/on calls with the same id collapse to one membership; a single /agent/off?id= releases that id; agent mode ends when the set is empty.
  • Leased (app ≥ v1.2.0): every /agent/on also refreshes that id's lease; a hold not refreshed within leaseSeconds (default 1800) is dropped by the app. GET /agent/status reports ageSeconds per id and the active leaseSeconds. Still always send off when done — expiry is the safety net, not the mechanism. On app ≤ v1.1.x holds are sticky (no TTL).
  • App restart drops agent state (clears the set).
  • Hooks never print to stdout (Claude Code treats stdout as context). They always exit 0; missing app must not delay the agent. Session ids in query strings are URL-encoded.

Stuck on

On app ≥ v1.2.0 an orphaned hold self-heals: with no keepalive arriving, it expires ~30 minutes after the session's last activity. To clear it immediately (or on older apps):

  1. Menu bar: Clear agent keep-awake

  2. Or:

    curl -m 2 -s -o /dev/null -X POST "http://127.0.0.1:17893/agent/clear"

The pulse

When agent keep-awake is active (non-empty agent id set), the menu bar shows a gold pulsing ring.

Agent keep-awake pulse

The cycle is 1 s: the glow builds for 0.8 s, fades sharply over 0.2 s, and a thin black contrast ring shows at the trough. The GIF above is rendered from the app's own --preview output, so it matches shipped pixels.

Safety

  • Lid closed: closed-lid keep-alive while working can mean heat and battery drain. Do not leave a closed, plugged-in Mac in a bag. User lid-only (display off, lid on, agent off) keeps the system awake with the lid closed while still allowing the display to sleep.
  • Orphaned holds: if the agent dies without /agent/off, the hold expires on its own after ~30 minutes (app ≥ v1.2.0). Clear manually (menu or /agent/clear) if you don't want to wait, or on older apps.
  • App restart: agent state is dropped; do not assume agent on survived a relaunch.

License

MIT — see LICENSE.

About

Agents keep your Mac awake while they work — persistent instruction set + Claude Code hooks for AllNighter's agent keep-awake switch

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages