Download The Apps
Install Quave Pager on Android and/or macOS, then create or verify your account and keep your API key in an approved secret store. Release assets are hosted in the public agent repository.
| Latest Android APK | QuavePager.apk |
|---|---|
| macOS automatic install | curl -fsSL https://pager.quave.ai/install-macos.sh | bash |
| macOS manual DMG | QuavePager-macOS.dmg |
| macOS terminal zip | QuavePager-macOS.zip |
| Latest release | quavedev/pager-agent/releases/latest |
| Android package | ai.quave.alarm |
| macOS bundle ID | ai.quave.alarm.mac |
The download links always point to the latest public release assets. Android may ask you to allow installs from your browser or file manager. macOS users have two polished paths: run the terminal installer for an automatic install into ~/Applications, or open the DMG and drag the Quave Pager icon into Applications. The public macOS DMG and zip are Developer ID signed, notarized, and stapled for direct download outside the Mac App Store.
- Android: download and install
QuavePager.apk, then grant notifications, full-screen alerts, exact alarms, Do Not Disturb bypass, and unrestricted battery/background usage when prompted. - macOS automatic: run
curl -fsSL https://pager.quave.ai/install-macos.sh | bash, paste an API key, and enable launch-at-login in Preferences. - macOS manual: download
QuavePager-macOS.dmg, open it, drag Quave Pager into Applications, then open the app. - Copy the generated API key only into
QUAVE_PAGER_API_KEYfor your agent environment or approved secret store. - Run the agent dry-run before the first real page.
macOS Desktop Receiver
The macOS receiver is a native Swift/AppKit client that aims for Android-power parity: Keychain API-key storage, long-poll delivery, cached future alarms, local timers, listener sleep prevention while running, launch-at-login, configurable ringtone/snooze durations, and a full-screen always-on-top alarm with looping sound until dismissed or snoozed.
| Automatic install | curl -fsSL https://pager.quave.ai/install-macos.sh | bash |
|---|---|
| Manual DMG | QuavePager-macOS.dmg |
| Terminal zip | QuavePager-macOS.zip |
| Source | macos/ in the Quave Pager repo |
| Local build | cd macos && swift build |
| Local app bundle | cd macos && ./scripts/build-app.sh |
| Distribution | Direct download after Developer ID signing and Apple notarization; no Mac App Store release is required. |
Device priority metadata is platform-aware: macOS defaults to 10, future iOS to 20, and Android to 30. Android and macOS both expose delivery controls: ring all enabled devices at once, or use ordered escalation every 30 seconds so lower-priority numbers ring first and later devices join until someone dismisses or snoozes.
For AI Agents: Install The Skill First
If you are an AI agent reading this page, install the public skill package and follow its SKILL.md. The package CLI is the preferred interface for creating, listing, editing, snoozing, canceling, dismissing, and removing alarms.
Use --link for the result/action URL from the conversation. Use the AI conversation resume flags when the alarm should bring the user back to Codex, Claude Code, Cursor, or another agent. Native clients render that as a separate Resume AI conversation action.
| Skill repo | quavedev/pager-agent |
|---|---|
| Install command | npx skills add quavedev/pager-agent --skill quave-pager -g -a '*' |
| API key env var | QUAVE_PAGER_API_KEY |
| Machine metadata | /.well-known/quave-pager.json |
Do not paste API keys in chat, URLs, docs, logs, command arguments, or committed files. Keep them in an environment variable, secret manager, or the current process environment.
npx -y github:quavedev/pager-agent trigger --message "Look at Codex: I need your decision." --codex-thread-id "<thread-id>"
npx -y github:quavedev/pager-agent trigger --message "Claude Code is blocked." --claude-session "<session-id>" --ai-cwd "$PWD"
npx -y github:quavedev/pager-agent trigger --message "Review this PR." --link "https://github.com/example/repo/pull/123"
npx -y github:quavedev/pager-agent list
npx -y github:quavedev/pager-agent edit <alarm-id> --scheduled-at "2026-06-13 16:19:00" --time-zone "America/Campo_Grande" --status pending
npx -y github:quavedev/pager-agent remove <alarm-id>
1. Create an API Key
Install the Android app, create or verify your account, then copy the first API key shown by the app. Existing users can create, rotate, and revoke keys through /api/api-keys. The plaintext key is returned only once.
| API key env var | QUAVE_PAGER_API_KEY |
|---|---|
| Agent package | quavedev/pager-agent |
| OpenAPI | /openapi.json |
2. Choose Create Mode
POST /api/alarms supports three scheduling modes. Use exactly one mode per request.
| Mode | How to send it | When it rings |
|---|---|---|
| ASAP | Omit scheduledAt and delaySeconds. | Immediately, then expires after ttlSeconds. |
| Relative | Send delaySeconds, for example 300 for five minutes. | Now plus the delay. |
| Scheduled | Send scheduledAt plus timeZone for local time, or an ISO timestamp with an offset/Z. | At the concrete timestamp. |
Do not combine scheduledAt and delaySeconds; the API returns schedule_conflict.
3. Trigger ASAP
For an immediate alarm, omit scheduledAt and delaySeconds. The server records the alarm immediately and expires it after ttlSeconds, defaulting to 900 seconds.
export QUAVE_PAGER_API_KEY="<user-owned API key>"
curl -fsS -X POST https://pager.quave.ai/api/alarms \
-H "Authorization: Bearer $QUAVE_PAGER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Codex needs you",
"body": "Look at Codex: I need your decision to continue.",
"severity": "critical",
"ttlSeconds": 900,
"aiConversationResume": {
"provider": "codex",
"conversationId": "<thread-id>",
"targets": [
{ "platforms": ["android", "ios", "web"], "kind": "url", "url": "https://chatgpt.com/codex", "label": "Open Codex" },
{ "platforms": ["macos"], "kind": "deeplink", "url": "codex://threads/<thread-id>", "label": "Open Codex app" }
],
"fallbackInstructions": "Open Codex and resume this task."
}
}'
4. Relative Delay
For a relative alarm, send delaySeconds. Five minutes is 300. The API stores the computed scheduledAt timestamp in the response.
curl -fsS -X POST https://pager.quave.ai/api/alarms \
-H "Authorization: Bearer $QUAVE_PAGER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Five-minute follow-up",
"body": "Look at Codex: five-minute follow-up.",
"severity": "critical",
"delaySeconds": 300,
"ttlSeconds": 900,
"aiConversationResume": {
"provider": "codex",
"conversationId": "<thread-id>",
"targets": [
{ "platforms": ["android", "ios", "web"], "kind": "url", "url": "https://chatgpt.com/codex" },
{ "platforms": ["macos"], "kind": "deeplink", "url": "codex://threads/<thread-id>" }
]
}
}'
5. Schedule With Time Zone
For local wall-clock scheduling, send scheduledAt as YYYY-MM-DDTHH:mm:ss plus an IANA timeZone. If timeZone is omitted for a local timestamp, the server defaults to America/Campo_Grande.
Best practice for agents: always include the user's intended IANA time zone when scheduling by local time. Use an explicit offset or Z when scheduling in absolute UTC time.
curl -fsS -X POST https://pager.quave.ai/api/alarms \
-H "Authorization: Bearer $QUAVE_PAGER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Follow-up",
"body": "Look at Codex: scheduled review time.",
"severity": "critical",
"scheduledAt": "YYYY-MM-DDT09:00:00",
"timeZone": "America/Campo_Grande",
"ttlSeconds": 900,
"aiConversationResume": {
"provider": "codex",
"conversationId": "<thread-id>",
"targets": [
{ "platforms": ["android", "ios", "web"], "kind": "url", "url": "https://chatgpt.com/codex" },
{ "platforms": ["macos"], "kind": "deeplink", "url": "codex://threads/<thread-id>" }
]
}
}'
Absolute timestamp alternative
{
"scheduledAt": "YYYY-MM-DDT13:00:00Z",
"ttlSeconds": 900
}
6. Payload Contract
| Field | Required | Notes |
|---|---|---|
title | No | Defaults to Quave Pager. |
body | No | Use one concise sentence with the destination and blocker. |
severity | No | info, warning, or critical. Defaults to critical. |
link | No | Optional http:// or https:// destination/result/action URL. The native app shows an open action. url is accepted as an alias. Do not use this field merely to resume the AI conversation. |
aiConversationResume | No | Optional object that tells compatible native clients how to return to the agent/chat. It renders separately from link as Resume AI conversation. |
scheduledAt | No | ISO timestamp. Local values use timeZone or the default America/Campo_Grande. |
timeZone | No | Valid IANA time zone. Recommended for local scheduling. |
delaySeconds | No | Relative scheduling. Do not combine with scheduledAt. |
ttlSeconds | No | Alarm delivery window after the scheduled time. Clamped from 30 seconds to 24 hours. |
deviceId | No | Omit to page every registered device. |
7. AI Conversation Resume
aiConversationResume is for the action that returns the user to the AI. It is intentionally separate from link, which is the useful result of the conversation. Each resume target declares the devices it supports so Android, iOS, macOS, web, or future clients can choose the safest native action.
| Field | Notes |
|---|---|
provider | codex, claude-code, cursor, or other. |
conversationId | Optional thread/session/chat identifier when the agent knows one. |
targets[].platforms | Required list such as ["android"], ["macos"], or ["android","ios","web"]. |
targets[].kind | url, deeplink, copyCommand, or instructions. |
fallbackInstructions | Short human fallback when no device-specific target is usable. |
Android supports URL and instruction resume targets. macOS supports URL, approved deep links, copyable commands, and instructions. Registered devices also advertise capabilities.aiConversationResume plus capabilities.aiConversationResumeKinds.
{
"aiConversationResume": {
"provider": "claude-code",
"conversationId": "<session-id>",
"targets": [
{
"platforms": ["macos"],
"kind": "copyCommand",
"command": "claude --resume <session-id>",
"cwd": "/path/to/repo",
"label": "Copy Claude resume command"
}
],
"fallbackInstructions": "Open Claude Code in the repository and resume session <session-id>."
}
}
8. Register And Manage Devices
Native clients register themselves with platform metadata. Use GET /api/delivery or GET /api/devices to inspect the account delivery rule, which receivers are active, and which specific device is currently ringing. Use POST /api/delivery to switch between all and ordered, PATCH /api/devices/:deviceId to rename a device, change priority, or disable a receiver, and DELETE /api/devices/:deviceId to logically remove a device without deleting history.
Every device registration and long-poll sync updates lastSeenAt. The long-poll response also includes stoppedAlarmIds so a dismiss, acknowledge, cancel, remove, snooze, or per-device remote dismiss action can stop a locally ringing alarm. Use POST /api/devices/:deviceId/alarms/:alarmId/dismiss to stop one alarm on one remote device without dismissing it from history or stopping other receivers.
| Field | Notes |
|---|---|
platform | android, macos, future ios, or another client type. |
priority | Lower numbers are intended to ring earlier. Defaults: macOS 10, iOS 20, Android 30. |
enabled | Disabled devices stay registered but do not receive event deliveries. |
lastSeenAt | Server timestamp for the receiver's last registration or long-poll sync. Native clients show it as last sync time. |
ringingAlarm | Present when that receiver reported it is ringing. Includes alarmId, title, severity, and timestamps so another device can stop that exact receiver. |
deliveryMode | Account setting. all rings every enabled device at once; ordered rings by priority and adds the next device after escalationIntervalSeconds. |
capabilities | Client-reported support such as longPoll, intrusiveAlarm, fullScreen, localSound, deliveryControls, aiConversationResume, aiConversationResumeKinds, and launchAtLogin. |
curl -fsS https://pager.quave.ai/api/devices \
-H "Authorization: Bearer $QUAVE_PAGER_API_KEY"
curl -fsS -X PATCH https://pager.quave.ai/api/devices/<device-id> \
-H "Authorization: Bearer $QUAVE_PAGER_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "priority": 10, "enabled": true }'
curl -fsS -X DELETE https://pager.quave.ai/api/devices/<device-id> \
-H "Authorization: Bearer $QUAVE_PAGER_API_KEY"
curl -fsS -X POST https://pager.quave.ai/api/devices/<device-id>/alarms/<alarm-id>/dismiss \
-H "Authorization: Bearer $QUAVE_PAGER_API_KEY"
9. List Alarm History
Use GET /api/alarms with the same bearer token to inspect scheduled and past alarms before creating a duplicate. Regular reads hide alarms with removedAt; use ?includeRemoved=true only when auditing logical deletes. Production state is durable in MongoDB.
curl -fsS https://pager.quave.ai/api/alarms \
-H "Authorization: Bearer $QUAVE_PAGER_API_KEY"
The native Android and macOS apps cache this list locally and schedule synced future alarms as a best-effort offline fallback. Online delivery is authoritative for ordered escalation windows.
10. Manage Existing Alarms
The package CLI supports the common management operations directly. Prefer it for agent work; the HTTP endpoints below are the underlying contract. Removed alarms stay in MongoDB with removedAt, but regular list, update, and delivery paths ignore them.
npx -y github:quavedev/pager-agent list
npx -y github:quavedev/pager-agent edit <alarm-id> --scheduled-at "2026-06-13 16:19:00" --time-zone "America/Campo_Grande" --status pending
npx -y github:quavedev/pager-agent remove <alarm-id>
npx -y github:quavedev/pager-agent snooze <alarm-id> --delay-seconds 600
| Action | Endpoint | Notes |
|---|---|---|
| Edit | PATCH /api/alarms/:id or POST /api/alarms/:id | Edit title, body, severity, link, aiConversationResume, deviceId, scheduledAt, timeZone, delaySeconds, ttlSeconds, expiresAt, and status. Use clearAiConversationResume: true to remove resume metadata. Use status: "pending" when rescheduling a past alarm. |
| Snooze | POST /api/alarms/:id/snooze | Send delaySeconds or a concrete scheduledAt plus timeZone. Sets status: "snoozed". |
| Dismiss | POST /api/alarms/:id/dismiss | Keeps the alarm in history and records dismissedAt. |
| Cancel | POST /api/alarms/:id/cancel | Keeps the alarm in history and records canceledAt. |
| Remove | DELETE /api/alarms/:id or POST /api/alarms/:id/remove | Logical delete through removedAt. |
curl -fsS -X PATCH https://pager.quave.ai/api/alarms/<alarm-id> \
-H "Authorization: Bearer $QUAVE_PAGER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"body": "Look at Codex: updated schedule.",
"scheduledAt": "YYYY-MM-DDT09:30:00",
"timeZone": "America/Campo_Grande",
"status": "pending"
}'