针对 AI agent 开发的轻量工具,在代理运行时自动防止 Mac 睡眠,提升工程体验但用户较小众。
服用注意 ・ 为那些在你睡着后还在值班的机器。
凌晨 3 点。你睡着了。Agent 还醒着——它仍在思考一个你几小时前启动的会话,而你像闭不上的眼皮一样把盖子盖上了。caffeinate 和 Amphetamine 是兴奋剂:无论是否有人在,它们都让机器永远保持活力。Adrafinil 是促醒剂。它静静等待,直到一个 agent 获取它,只在那个工作进行期间通过闭上的盖子保持 Mac 唤醒,当最后一个会话释放时立即清除。它只为工作而唤醒——然后你们都睡了。♡
仅在 AI agents 工作时保持 Mac 唤醒。
Adrafinil 是一个 macOS 菜单栏应用,能防止系统睡眠——包括合盖(盖子闭合)睡眠——仅限于 AI 编码 agent 有活跃会话的时候。当没有 agent 工作时,睡眠行为不受影响:合上盖子,Mac 正常睡眠。
它与 caffeinate 或 Amphetamine 这样的始终唤醒工具相反。Adrafinil 仅在 agent(Claude Code、Codex、Cursor 等)正在进行任务时干预,而在工作完成时立即退出。
三种保持唤醒的方式:
自动 — Agent hooks 告诉 Adrafinil 一个 turn 何时开始和结束,因此它仅在 agent 实际工作时保持睡眠。(可选的进程嗅探也能发现没有安装 hooks 的正在运行的 agent。)
Agent 驱动 — 一个 agent 可以通过捆绑的 MCP 工具或 adrafinil hold CLI 故意让 Mac 在其回复之后保持唤醒,用于长构建或部署。
手动 — 菜单栏的 Keep awake 按钮可以为自己设置一个有时间限制的保持,即使没有 agent 运行;Let it sleep 可以清除所有内容。
覆盖合盖睡眠需要 root。Adrafinil 将其隔离在一个小的、经过审计的帮助程序中,该程序仅暴露 setSleepBlocked(Bool)——所有策略都在一个无特权的守护程序中。它为空闲睡眠保有一个标准的 IOPMAssertion,并为合盖(盖子闭合)睡眠使用 pmset disablesleep,在验证更清洁的私有 IOPMrootDomain 路径在无显示合盖 Mac 上不会保持唤醒后。见 Docs/ARCHITECTURE.md §2。
睡眠仅在 ≥1 个 agent 会话持有断言时被阻止。零个会话 → 正常睡眠,包括合盖。
一键安装程序将 Adrafinil 接入 Claude Code、Codex、Cursor、Gemini CLI、Aider、Hermes、OpenCode、Cline 和 Pi 的 hook 系统。
adrafinil acquire / release 从 agent hooks 调用,与守护程序往返耗时不到 50ms,因此不会拖延 agent 的工作流。
重叠的会话堆叠得很干净;只有当最后一个释放时睡眠才解除。
如果盖子闭合时皮肤/CPU 温度超过阈值,所有断言会被强制释放,防止装在包里的 Mac 自行过热。
所有者进程已死亡或 CPU 空闲 N 分钟的断言会自动丢弃。
即使没有安装 hooks,守护程序在看到已知 agent 二进制文件运行时也能自动获取。
菜单栏的 Keep awake 按钮可按需启动有时间限制的保持——用于长下载、本地作业、任何 off-agent 任务——然后 Let it sleep 释放它。
当你合上盖子时一声蜂鸣确认断言被保持(屏幕关闭,没有通知);重新打开会显示你不在时运行的内容、峰值温度以及热截断是否激发。
删除它在所有 agent 配置中添加的每个 hook 条目。
macOS Tahoe 26.4。这是我构建和测试的版本;它可能在早期的 26.x 版本上运行,但我没有在那里测试过。在 macOS 15 Sequoia 上?valentine 维护了一个回溯分支。
Xcode 26+ 来构建,启用 Swift 6 严格并发。
管理员权限用于标准安装(特权帮助程序通过 SMAppService 安装)。非管理员安装路径会将 CLI 放在 ~/.local/bin 中,而不是 /usr/local/bin 中。
下载 Adrafinil——一个签名的、公证过的磁盘映像。打开它,将 Adrafinil 拖到应用程序,然后启动。第一次启动会要求一次管理员权限来注册特权帮助程序。需要 macOS 26.4 或更高版本。
或通过 Homebrew:brew install --cask kageroumado/tap/adrafinil — 同样的 DMG,通过我的 tap。完全限定的名称在 Homebrew 6 的 tap-trust 系统下自动信任 cask。
喜欢自己构建?
git clone https://github.com/kageroumado/adrafinil.git
cd adrafinil
open Adrafinil.xcodeproj
在 Xcode 中,选择 Adrafinil scheme 并运行。你需要为代码签名设置开发团队——守护程序(LaunchAgent)和帮助程序(LaunchDaemon)被嵌入到应用包中,并在应用启动时注册到系统。(没有 Team ID 被硬编码到源代码中;XPC 调用者检查在运行时读取你自己的签名团队,所以在任何 Developer ID 下重新构建都授权其自己的组件,无需代码更改。)
对于无头编译检查,不需要本地签名身份:
xcodebuild -project Adrafinil.xcodeproj -scheme Adrafinil -configuration Debug \
-destination 'generic/platform=macOS' \
CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY='' build
共享逻辑作为 Swift 包独立构建和测试:
cd AdrafinilShared
swift test
Agent 不直接与 Adrafinil 通信。每个 agent 的 hook 系统调用捆绑的 CLI:
adrafinil acquire <session-key> --tool claude-code --reason "long build" # when a turn starts
adrafinil release <session-key> # when the agent goes idle
保持是活动作用域的,而不是会话作用域的:Claude Code 在 UserPromptSubmit 时获取,在 Stop 时释放,因此 Mac 仅在 agent 实际工作时保持唤醒——一个在提示处开放但空闲的会话让它正常睡眠。
守护程序按会话密钥进行引用计数,并在计数非零时要求帮助程序阻止睡眠。
一个 agent 也可以通过有时间限制的保持让 Mac 对于超越其回复的后台任务保持唤醒(长构建或部署)——通过直接调用 adrafinil hold 或,对于支持 MCP 的 agent,通过捆绑的 MCP 工具,adrafinil mcp 服务:
adrafinil hold --for 30m --reason "deploy" # keep awake up to 30 min, then auto-release
adrafinil mcp # speak the Model Context Protocol on stdio (for agents)
你根本不需要 agent:菜单栏的 Keep awake 按钮可以手动放置相同类型的有时间限制的保持——用于长下载或任何 off-agent 任务——Let it sleep 释放所有内容。所以 Adrafinil 覆盖所有三种:它通过 hooks 自动检测 agent 活动,让 agent 通过 MCP/CLI 显式驱动它,并可以在需要时手动翻转。
其他子命令:status、install-hooks、uninstall-hooks、daemon-status、version。
Adrafinil 为常见的 agent 提供集成,但 CLI 适用于任何工具——守护程序接受来自任何同一用户调用者的任意 --tool 标签,因此无需更改任何内容来接入一个 Adrafinil 从未听说过的工具。Settings → Agents → Add your own agent 从你输入的名称生成精确的代码片段;选择与你的 agent 匹配的形式:
它有 hooks / 事件 — 在开始和停止时添加 acquire 和 release,以你的 agent 的会话 id 为键,所以每个 turn 都能干净地括起来:
adrafinil acquire "$SESSION_ID" --tool my-agent # on start / prompt submit
adrafinil release "$SESSION_ID" --tool my-agent # on stop / finish
它没有 hooks — 包装命令,使保持跨越整个运行(以 shell 的 $$ 为键),或为后台作业放置一个单一的定时保持:
adrafinil acquire $$ --tool my-agent && my-agent "$@"; adrafinil release $$ --tool my-agent
adrafinil hold --for 2h --pid $$ --reason "my-agent session"
自定义 agent 不是自动检测或进程监视的,所以将每个 acquire 与可靠的 release 配对——空闲释放超时和每个保持的时间限制是如果有一个被遗漏时的安全网。
四个产品跨越三个特权层(完整细节,包括 Xcode 项目布局,在 Docs/ARCHITECTURE.md):
┌──────────────────────────────────────────────────────────────┐
│ Adrafinil.app (menu bar app, user-facing) │
│ • Status item, settings, installer GUI, lid-open summary │
└─────────────────────────────┬────────────────────────────────┘
│ XPC
▼
┌──────────────────────────────────────────────────────────────┐
│ AdrafinilDaemon (LaunchAgent, runs as user, always-on) │
│ • Reference-counted assertion registry │
│ • Process watchers (kqueue NOTE_EXIT + periodic sweep) │
│ • Thermal monitor (SMC) • Lid-state monitor (IORegistry) │
│ • Lid-close chime • CLI socket at …/Adrafinil/cli.sock │
└─────────────────────────────┬────────────────────────────────┘
│ XPC (privileged Mach service)
▼
┌──────────────────────────────────────────────────────────────┐
│ AdrafinilHelper (SMAppService LaunchDaemon, root) │
│ • The ONLY component that touches sleep-blocking APIs │
│ • setSleepBlocked(Bool) + read-only state/version │
│ • Verifies caller's code-signing requirement │
└──────────────────────────────────────────────────────────────┘
adrafinil (CLI, ships inside the .app, symlinked onto PATH)
• acquire / release / hold / mcp / status / install-hooks / uninstall-hooks
• Connects to the daemon socket; <50ms round-trip
AdrafinilShared — 一个在每个目标之间共享的 Swift 包:数据模型(AgentKind、Assertion)、IPC 有线格式、AssertionRegistry、CallerVerifier、hook-install 规格和 CLI 参数解析器。单元测试就在这里。
Helper 保持平凡以供审计。 它不持有策略——引用计数、热、空闲和 lid 逻辑都在守护程序中。特权表面是一个单一的变异端点加上只读内省。
守护程序是真实来源。 应用是一个纯视图层;它可以自由地退出和重启而不影响保持的断言。
公共 IOPM 断言不打败合盖睡眠。 带有公共类型的 IOPMAssertionCreateWithName(因此 caffeinate)不会让合盖 Mac 保持唤醒。Adrafinil 的 v1 使用 pmset disablesleep 1,这很钝(它也禁用空闲睡眠)且必须在关闭时清除,否则会泄漏——帮助程序在响应之前重置为 disablesleep 0,然后重新应用状态。
守护程序处理程序在任意队列上运行。 XPC 和 socket 回调可以在任何 dispatch 队列上到达,所以断言注册表和共享状态相应地同步。修改守护程序时小心处理并发。
CLI 在延迟预算上。 acquire/release 在每个 agent 会话的热路径中,因此是静态查找(例如 AgentKind.allBinaryNames)和一个瘦 socket 协议而不是完整的 XPC 用于 CLI ↔ 守护程序跳转。
MIT。随意做任何事,无保证。
由 @kageroumado 构建,在 kagerou.glass 提供。这个名字是对 adrafinil 的致敬——一个促醒原药——因为这个应用仅在你的机器实际有工作时让它保持唤醒。