Hark
Let your scripts, services, and AI agents reach your iPhone through a server you host—whether to send a quick status update, track a long job on the Lock Screen, or pause and ask for a decision.
iOS ·
When a script needs to ask you a question
A nightly backup can let you know it finished. A deploy script can stream its progress to your Lock Screen—or pause mid-run and ask if you want to push to production. Hark gives your scripts, cron jobs, and AI agents a clean way to reach your iPhone via standard notifications, interactive questions, or iOS Live Activities. Webhooks come with sensible defaults for titles and priority, so a basic monitoring script just has to send the message text.
On the backend, it’s a single Go binary backed by Postgres. That one binary runs the API, serves the web dashboard, logs history, and dispatches pushes through Apple Push Notification service (APNs). Once you sign in on the iOS app, your phone registers its device token and capabilities. Any unanswered questions also sit in the app’s inbox, so you won’t lose track of a prompt if you accidentally swipe away the notification.
Prompts can ask for an Approve/Deny decision, a Yes/No, or a free-text reply. Binary choices can show up as interactive buttons right inside a Live Activity on your Lock Screen, while text replies use standard notification actions or the app. If none of your devices support interactive Live Activities, Hark automatically drops back to a question notification. Ordinary Live Activities keep a job’s status and progress visible as it runs.
Scripts can ask, but only you can answer
Hark isn’t a public service, and there’s no public sign-up; each self-hosted instance has one admin who creates accounts for themselves or their team. Every account gets its own isolated devices, webhook services, API tokens, and message history. You log in with a password, and the iOS app stashes its session token in the system Keychain.
Your scripts talk to Hark through a service webhook or a scoped API token, and MCP agents get the same permissions with a token supplied directly or obtained through Hark’s OAuth sign-in. Crucially, permissions are strictly one-way: a token can be allowed to send notifications, post questions, and update Live Activities, but it’s never allowed to answer a question. Managing credentials and registering devices require a signed-in owner session, and creating accounts requires the admin.
Because notification actions and Lock Screen buttons have to work without the main app’s session, each question push carries a response token tied to that question. When you tap “Approve,” Hark verifies that your phone is still an active device on the account and that the question hasn’t changed since the version shown on your phone. Stale prompts can’t answer an updated question, and a conflicting second answer is rejected.
Hosting and webhook callbacks
Running Hark just takes Postgres, a root secret, a public URL, and your Apple push credentials. All messages, prompts, replies, and delivery logs live in your database.
Hark stores only hashes of API and webhook tokens and strips webhook paths out of HTTP access logs. A notification can also carry a link, an avatar, or a Wallet pass URL (from Pocketful, say); the iPhone’s notification extension downloads avatars and passes directly from public HTTPS URLs.
If your script doesn’t want to poll for an answer, it can pass a public HTTPS callback URL and a bearer token when it posts a question through a webhook. Hark encrypts that callback token at rest, validates the destination host before connecting, and refuses to follow HTTP redirects—so your callback credential is never forwarded to another host.
Delivery logs, timeouts, and retries
Hark logs the exact outcome for every device on your account, and it still records why a send failed if you have no active phones yet or forgot to configure APNs. If Apple reports a device token as permanently dead, Hark deactivates it until that phone registers again. Push notifications themselves aren’t retried on failure, with one exception: if Apple rejects an expired provider token and Hark can refresh it, Hark tries once more.
Scripts can either poll the API or hold open a short wait request until you answer, as long as the question hasn’t expired. Retrying with the same idempotency key returns the existing record instead of spamming your phone, while reusing that key with a different payload counts as a conflict. Once you answer a prompt, Hark tries to end its Live Activity—though if that final push fails or the update token is missing, the answered card might linger on your Lock Screen.
Webhook callbacks have their own retry queue, which persists in Postgres across server restarts and backs off between attempts. If your receiving server processes the answer but Hark can’t record the success, it might see a duplicate delivery on retry. Once all retries run out, Hark marks the callback failed, though your script can still fetch the answer by polling the API. Expired and canceled questions don’t generate callbacks.