diff --git a/CHANGELOG.md b/CHANGELOG.md
index 11609b2f9..de882cd57 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- CLI npm package name is `okcodes`. Install with `npm install -g okcodes`; the `okcode` binary name is unchanged.
+## [0.0.13] - 2026-04-01
+
+See [docs/releases/v0.0.13.md](docs/releases/v0.0.13.md) for full notes.
+
+### Added
+
+- Push notifications for approval requests, user-input requests, turn completions, and session errors on mobile.
+- QR code pairing flow: desktop shows scannable QR, mobile supports clipboard paste and auto-pair.
+- Token rotation and revocation model with short-lived pairing tokens.
+- Connection state banner for mobile companion (connecting, reconnecting, disconnected).
+- Android `POST_NOTIFICATIONS` and `SCHEDULE_EXACT_ALARM` permissions.
+- iOS `UIBackgroundModes` for background processing.
+- Capacitor `LocalNotifications` plugin configuration.
+- `GET /api/pairing` HTTP endpoint for short-lived pairing link generation.
+- WebSocket methods: `server.generatePairingLink`, `server.rotateToken`, `server.revokeToken`, `server.listTokens`.
+
## [0.0.12] - 2026-04-01
See [docs/releases/v0.0.12.md](docs/releases/v0.0.12.md) for full notes and [docs/releases/v0.0.12/assets.md](docs/releases/v0.0.12/assets.md) for release asset inventory.
diff --git a/apps/mobile/android/app/src/main/AndroidManifest.xml b/apps/mobile/android/app/src/main/AndroidManifest.xml
index 8685e51da..91dd4ef74 100644
--- a/apps/mobile/android/app/src/main/AndroidManifest.xml
+++ b/apps/mobile/android/app/src/main/AndroidManifest.xml
@@ -45,4 +45,8 @@
+
+
+
+
diff --git a/apps/mobile/capacitor.config.ts b/apps/mobile/capacitor.config.ts
index 8585caffb..a2bca8946 100644
--- a/apps/mobile/capacitor.config.ts
+++ b/apps/mobile/capacitor.config.ts
@@ -7,6 +7,13 @@ const config: CapacitorConfig = {
server: {
androidScheme: "https",
},
+ plugins: {
+ LocalNotifications: {
+ smallIcon: "ic_launcher",
+ iconColor: "#10B981",
+ sound: "default",
+ },
+ },
};
export default config;
diff --git a/apps/mobile/ios/App/App/Info.plist b/apps/mobile/ios/App/App/Info.plist
index 455cef0d9..9bc48ca1c 100644
--- a/apps/mobile/ios/App/App/Info.plist
+++ b/apps/mobile/ios/App/App/Info.plist
@@ -60,5 +60,10 @@
UIViewControllerBasedStatusBarAppearance
+ UIBackgroundModes
+
+ fetch
+ processing
+
diff --git a/apps/web/src/components/mobile/MobilePairingScreen.tsx b/apps/web/src/components/mobile/MobilePairingScreen.tsx
index f604ff606..a9522f9b2 100644
--- a/apps/web/src/components/mobile/MobilePairingScreen.tsx
+++ b/apps/web/src/components/mobile/MobilePairingScreen.tsx
@@ -34,6 +34,40 @@ export function MobilePairingScreen() {
}
};
+ const handlePasteFromClipboard = async () => {
+ try {
+ const text = await navigator.clipboard.readText();
+ if (!text || text.trim().length === 0) {
+ setErrorMessage("Clipboard is empty.");
+ return;
+ }
+ setPairingInput(text.trim());
+ setErrorMessage(null);
+
+ // Auto-submit if it looks like a valid pairing link.
+ if (
+ mobileBridge &&
+ (text.trim().startsWith("okcode://") || text.trim().includes("?token="))
+ ) {
+ setIsSubmitting(true);
+ try {
+ const nextState = await mobileBridge.applyPairingUrl(text.trim());
+ if (!nextState.paired) {
+ setErrorMessage(nextState.lastError ?? "Could not pair this device.");
+ return;
+ }
+ window.location.reload();
+ } catch (error) {
+ setErrorMessage(error instanceof Error ? error.message : "Could not pair this device.");
+ } finally {
+ setIsSubmitting(false);
+ }
+ }
+ } catch {
+ setErrorMessage("Could not read clipboard. Paste the link manually instead.");
+ }
+ };
+
const handleReset = async () => {
if (!mobileBridge) {
return;
@@ -63,8 +97,8 @@ export function MobilePairingScreen() {
Pair this device
- Paste a pairing link like okcode://pair?server=…&token=… or a server URL
- that includes ?token=….
+ Open Settings → Mobile Companion on your desktop to show a QR
+ pairing code, then copy the link and paste it below.
@@ -81,13 +115,25 @@ export function MobilePairingScreen() {
-
+
+
+ You can also open a pairing link directly from another app — it will be handled
+ automatically via deep link.
+