Daemon
The WhatCode daemon (@whatcode-ai/sdk) is a lightweight Node.js process that runs on your machine alongside OpenCode. It serves three purposes: exposing OpenCode on your local network so the iOS app can reach it, patching certain OpenCode responses to improve the mobile experience, and delivering push notifications to your iPhone when an agent finishes.
Installation
No installation required. Run it directly with npx:
npx @whatcode-ai/sdk
Or install it globally:
npm install -g @whatcode-ai/sdk
whatcode
Or use it as a library in your own Node.js project:
npm install @whatcode-ai/sdk
import { createWhatcodeServer } from '@whatcode-ai/sdk';
await createWhatcodeServer({
port: 8192,
opencodePort: 4096,
tailscale: true,
password: 'secret',
debug: false,
});
How it works
When you run the daemon:
- It starts OpenCode on localhost (or reuses an existing instance).
- It starts a WhatCode server on port
8192that sits in front of OpenCode, patching responses to improve the mobile experience. - It prints your local network URL and a QR code. Scan it with the app to connect.
- If
--tailscaleis passed, it also prints a secure HTTPS URL on your tailnet.
The WhatCode server layer:
- Patches project sorting - the
/projectendpoint enriches each project with the timestamp of its most recent message, so the app can sort projects by actual activity rather than creation date. - Disables caching - forces
cache-control: no-cacheandx-accel-buffering: noon all proxied responses, which is important for the SSE event stream the app subscribes to. - Exposes
/whatcode/identity- returns the machine ID of the host, used by the app to deduplicate connections across multiple machines. - Handles device token registration - the
/notifications/registerand/notifications/unregisterendpoints let the app register and remove its APNs token.
Push notifications
The daemon subscribes to the OpenCode event stream and watches for three events:
session.idle- the agent finished its turn and is waiting for your input.session.error- the agent hit an unrecoverable error.permission.asked- the agent needs your approval before it can proceed.
When any of these events fire, the daemon sends a push notification to your iPhone via a relay server using APNs. You receive it within seconds, even when the app is in the background. If the event stream drops, the daemon reconnects automatically with exponential backoff.
Password protection
You can protect your daemon with a password. When set, every request must include the password via HTTP Basic Auth.
await createWhatcodeServer({ password: 'your-password' });
In the app, enter the password when adding a connection manually. The QR code does not embed the password.
Debug mode
Enable verbose logging to see what the daemon is doing internally. Useful when something is not working and you need more context.
Via CLI:
npx @whatcode-ai/sdk --debug
Via library:
await createWhatcodeServer({ debug: true });
Debug mode logs events like incoming connections, notification dispatches, APN token registrations, and Tailscale state.
Tailscale
Passing --tailscale exposes the daemon over a secure HTTPS tunnel on your Tailscale network:
npx @whatcode-ai/sdk --tailscale
This runs tailscale serve --bg <port> in the background, which proxies your local port over HTTPS using your Tailscale hostname (e.g. https://my-mac.tail1234.ts.net). The QR code printed in the terminal includes this URL so the app connects over Tailscale automatically. When you stop the daemon (Ctrl+C), it cleans up the Tailscale serve rule automatically.
Requirements
- Tailscale installed and authenticated (
tailscale up) - The same Tailscale account logged in on your iPhone
Resetting the daemon
If notifications stop working or device registrations get into a bad state, you can reset the daemon stored data. This clears all saved APNs tokens, which stops push notification delivery for all linked devices. After resetting, open the app and reconnect to re-register your device.
import { resetWhatcodeServer } from '@whatcode-ai/sdk';
await resetWhatcodeServer();
API reference
createWhatcodeServer(config)
| Option | Type | Default | Description |
|---|---|---|---|
port | number | 8192 | Port the WhatCode server listens on. Change this if 8192 conflicts with another process on your machine. |
opencodePort | number | 4096 | Port the OpenCode server listens on. Must match what OpenCode is actually bound to. |
tailscale | boolean | undefined | When true, exposes the daemon over HTTPS via Tailscale serve. Requires Tailscale installed and authenticated. |
password | string | undefined | Protects all daemon endpoints with HTTP Basic Auth. The app will prompt for this password when connecting manually. |
debug | boolean | false | Enables verbose logging. Useful for diagnosing connection or notification issues. |
resetWhatcodeServer()
Clears all stored APNs device tokens. Use this if notifications stop working or if you need to unlink all devices from this machine.
CLI reference
| Flag | Type | Default | Description |
|---|---|---|---|
--port | number | 8192 | Port for the WhatCode server. |
--opencode-port | number | 4096 | Port for the OpenCode server. |
--tailscale | boolean | - | Expose via Tailscale HTTPS. |
--debug | boolean | - | Enable verbose debug logging. |