Wakehook
/install wakehook
wakehook → OpenClaw
wakehook is a tiny self-hosted service that watches the user's sleep data
(Google Health / Fitbit), detects the moment they woke up, and POSTs OpenClaw
a neutral user.awake event so the morning routine runs itself — at most once
per morning. OpenClaw maps that event into a wake action (its native pattern), so
wakehook stays vendor-neutral.
Work through the steps in order. Ask the user at the decision points instead of assuming. Do not improvise from the README — these steps are verified.
Prerequisites (check, don't assume)
- Bun ≥ 1.3 —
bun --version; install withcurl -fsSL https://bun.sh/install | bash. wakehook is Bun-only (bun:sqlite); never run it with Node. - Google OAuth credentials — a Google Cloud project with the Health API
enabled and the
googlehealth.sleep.readonlyscope, plus an OAuth 2.0 client (client id + secret). An API key will NOT work; sleep data needs user-consented OAuth. Ask the user for the id + secret (reuse their existing Google project if they have one).
Step 1 — add an OpenClaw mapped hook
wakehook POSTs the raw user.awake event to an OpenClaw mapped hook; OpenClaw
turns it into a wake of the main session via hooks.mappings. In the OpenClaw
gateway config:
{
hooks: {
enabled: true,
path: "/hooks", // must not be "/"
token: "\x3CHOOKS_TOKEN>", // any strong random string
mappings: [
{
match: { path: "wakehook" }, // matches POST /hooks/wakehook
action: "wake",
wakeMode: "now",
name: "wakehook",
// reads fields straight from wakehook's user.awake event:
messageTemplate: "You woke at {{wokeAt}} (slept {{session.durationMin}} min).",
},
],
},
}
Note the gateway address (host + port — OpenClaw's docs examples use
127.0.0.1:18789; confirm the user's actual port). The delivery URL is then
http://\x3Cgateway-host>:\x3Cport>/hooks/wakehook, and \x3CHOOKS_TOKEN> is the token
wakehook must present. (Verified: /hooks/* is gated by the token in a header —
Authorization: Bearer \x3Ctoken> or x-openclaw-token: \x3Ctoken>; query-string
tokens are rejected. The mapping then renders messageTemplate and wakes the
session.)
Step 2 — choose how wakehook gets the sleep data (ask the user)
Two modes — confirm which they want; don't assume:
- poll (recommended default) — wakehook pulls from Google on a timer.
No public URL / tunnel / open port (all outbound). By default it only polls
around the morning window and stops once it has fired today (
pollWindowOnly), so a shortpollIntervalMs(5 min default) is cheap — wake is detected within one interval. This path is verified end-to-end. - webhook — Google pushes the instant data lands → fires immediately, but requires a public HTTPS endpoint for wakehook plus registering a Google Health sleep subscription. ⚠️ This path is not yet verified — only choose it if the user explicitly wants instant fires and can expose an endpoint.
If the user has no preference, use poll.
Step 3 — configure wakehook
Create config.json in the working directory. Set timezone to the user's
IANA zone, the subscriber url to the mapped hook from Step 1, and pass the
\x3CHOOKS_TOKEN> as the Authorization header:
{
"dbPath": "./wake.sqlite",
"source": "google-health",
"inference": {
"timezone": "Europe/Brussels",
"windowStart": "04:00",
"windowEnd": "11:00",
"minDurationMin": 180,
"supersedeGapMin": 45
},
"google": { "mode": "poll", "pollIntervalMs": 300000, "pollLookbackMin": 720, "pollWindowOnly": true, "pollWindowMarginMin": 30 },
"subscribers": [
{
"id": "openclaw",
"url": "http://\x3Cgateway-host>:\x3Cport>/hooks/wakehook",
"headers": { "Authorization": "Bearer \x3CHOOKS_TOKEN>" }
}
]
}
No
presetneeded —generic(the raw signed event) is the default and is what the OpenClaw mapping expects.\x3CHOOKS_TOKEN>must equal the gateway'shooks.tokenfrom Step 1.If the user chose webhook mode instead: set
"google"to{ "mode": "webhook", "webhookAuthToken": "\x3Crandom>" }, also putGOOGLE_WEBHOOK_AUTH_TOKENin.env, expose wakehook's/webhookover public HTTPS, and register a Google Health sleep subscription pointing at it. (Unverified.)
Create .env (keep secrets out of config.json):
GOOGLE_CLIENT_ID=\x3Cclient-id>
GOOGLE_CLIENT_SECRET=\x3Cclient-secret>
GOOGLE_REDIRECT_URI=http://localhost:8080/oauth/callback
Ensure http://localhost:8080/oauth/callback is an authorized redirect URI on the OAuth client.
Step 4 — authorize once
bunx wakehook-auth
Prints a Google consent URL — give it to the user to open and approve. It stores
a refresh token in ./wake.sqlite and auto-refreshes forever (one-time step).
If Google returns HTTP 400, the OAuth client is missing the
localhost:8080/oauth/callback redirect URI — add it and retry.
Step 5 — run it
bunx wakehook
(Docker alt: docker run -v wakehook-data:/data --env-file .env ghcr.io/robbeverhelst/wakehook.)
Keep it running (long-lived process / service). In poll mode it polls Google
every pollIntervalMs around the morning window only (set pollWindowOnly: false to poll all day) and, on the morning wake, POSTs OpenClaw once.
Step 6 — decide what happens on wake (optional)
By default the Step-1 mapping just nudges the main session. To make waking up do something, shape the behavior in the mapping (this is OpenClaw-side config, not wakehook). wakehook only supplies the trigger; the actual abilities (calendar, weather, messages, …) come from OpenClaw's own skills/tools — install/enable those separately.
A — simple nudge, routine in the prompt (action: "wake"): make
messageTemplate the instruction the main session executes.
{
match: { path: "wakehook" },
action: "wake",
wakeMode: "now",
messageTemplate: "Good morning — the user just woke ({{wokeAt}}). Run the morning routine: review today's calendar, summarize overnight messages, and give the weather.",
}
B — full routine run on a dedicated agent (action: "agent"): route to an
agent that has the relevant skills, and deliver the result to a chat surface.
{
match: { path: "wakehook" },
action: "agent",
agentId: "morning", // an agent you've set up with calendar/weather/etc. skills
wakeMode: "now",
messageTemplate: "User woke at {{wokeAt}} (slept {{session.durationMin}} min). Produce the morning briefing.",
deliver: true, // send the result back to a chat surface…
channel: "last", // …e.g. Telegram/Discord (defaults to last used)
}
Note: you generally don't trigger a cron from this — wakehook is the real wake signal, so it replaces guessing a fixed time. Just run the task on the event. The capabilities themselves are separate OpenClaw skills; this step only wires when and what to ask for.
What OpenClaw receives
wakehook POSTs the raw, neutral event (the OpenClaw mapping templates it):
POST http://\x3Cgateway-host>:\x3Cport>/hooks/wakehook
Authorization: Bearer \x3CHOOKS_TOKEN>
Content-Type: application/json
{ "event": "user.awake", "wokeAt": "2026-06-13T08:04:00Z", "user": "self",
"source": "google-health",
"session": { "start": "...", "end": "2026-06-13T08:04:00Z", "durationMin": 464 } }
The Step-1 mapping turns this into a now wake of the main session with the
templated text — handle that as the trigger to run the morning routine. wakehook
also sends X-Wake-Event-Id (and X-Wake-Signature if a secret is set) for
optional extra verification. Fires at most once per morning.
Verify without waiting for morning
curl -X POST http://localhost:8080/test/replay \
-H 'Content-Type: application/json' -d '{}'
Injects a synthetic wake "now" and delivers it exactly like a real one — confirm OpenClaw maps it and runs the routine.
Gotchas
- Bun-only — never run with Node.
- The
Authorizationbearer MUST equal OpenClaw's gatewayhooks.token, or/hooks/wakehookrejects it (401). Hooks must be enabled and the mapping (match.path: "wakehook") must exist, or the path won't route. - poll needs the OAuth creds but no inbound URL; webhook is instant but unverified — prefer poll unless the user asks otherwise.
- A Google API key is not enough — it needs the OAuth client +
wakehook-auth. - If the hook returns 200 but nothing happens, check the OpenClaw version (a known
issue affected some 2026.3.x builds) and that the mapping
action: "wake"is set.
Source + full docs: https://github.com/robbeverhelst/wakehook
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install wakehook - 安装完成后,直接呼叫该 Skill 的名称或使用
/wakehook触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
Wakehook 是什么?
Install, configure, authorize and run wakehook so OpenClaw runs the user's morning routine when they wake up. wakehook turns Google Health / Fitbit sleep dat... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 37 次。
如何安装 Wakehook?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install wakehook」即可一键安装,无需额外配置。
Wakehook 是免费的吗?
是的,Wakehook 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。
Wakehook 支持哪些平台?
Wakehook 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。
谁开发了 Wakehook?
由 Robbe Verhelst(@robbeverhelst)开发并维护,当前版本 v1.0.0。