diff --git a/docs/SPEC.md b/docs/SPEC.md
index 90e1081..b1763e5 100644
--- a/docs/SPEC.md
+++ b/docs/SPEC.md
@@ -915,8 +915,21 @@ class AudioPlaybackService : Service() {
-
-
+
+
+```
+
+**Shizuku Provider (v12+ обязательно, см. ниже §5.3.1):**
+
+```xml
+
```
**PhoneApp (`app-phone-vm/AndroidManifest.xml`):**
@@ -934,9 +947,57 @@ class AudioPlaybackService : Service() {
-
+
```
+### 5.3.1. Интеграция с Shizuku
+
+**Цель.** GlassesApp использует Shizuku (см. память #4779) как обёртку над `IDisplayManager.createVirtualDisplay` без флага `OWN_CONTENT_ONLY` — единственный способ создать VirtualDisplay, на который можно стартовать чужие Activity (`ActivityOptions.setLaunchDisplayId`).
+
+**Зависимости (`gradle/libs.versions.toml`):**
+
+```toml
+shizukuApi = "13.1.5"
+shizukuProvider = "13.1.5"
+shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizukuApi" }
+shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizukuProvider" }
+```
+
+В `app-glasses-vm/build.gradle.kts` — `implementation(libs.shizuku.api)` + `implementation(libs.shizuku.provider)`.
+
+**Манифест — обязательная структура (см. https://github.com/RikkaApps/Shizuku-API):**
+
+1. `` (v12+). Старое `moe.shizuku.permission.SHIZUKU` (v11) НЕ работает — BinderSender на стороне сервера проверяет, что в `requestedPermissions` есть именно `API_V23`.
+2. `` — этот ContentProvider из либы `rikka.shizuku:provider` через свой `onCreate` сам вытаскивает binder у Shizuku-сервера через ContentProvider IPC. **Без него binder к нам никогда не придёт.** Кастомные ContentProvider'ы (например, наш `ShizukuInitProvider`) этого **не заменяют** — у `rikka.shizuku.ShizukuProvider` специальные системные AIDL-хуки.
+3. `` — для Android 11+ package visibility (`bindService` к сервису внутри пакета Shizuku-менеджера иначе возвращает false).
+
+**Activity-side (MainActivity.onCreate, строго после `super.onCreate`):**
+
+```kotlin
+Shizuku.addBinderReceivedListenerSticky(object : Shizuku.OnBinderReceivedListener {
+ override fun onBinderReceived() { refresh() }
+})
+Shizuku.addRequestPermissionResultListener { _, grant -> refresh() }
+if (Shizuku.pingBinder()) refresh() else state.value = AllowState.Waiting
+// где refresh():
+// running = Shizuku.pingBinder(); perm = Shizuku.checkSelfPermission()
+// если perm == GRANTED -> Granted, иначе NeedsPermission + requestPermission(code)
+```
+
+И override `onRequestPermissionsResult(...)` в Activity (нужен для прокидывания результата диалога).
+
+**Запрос разрешения и диалог.** Когда пользователь первый раз запускает GlassesApp:
+1. `Shizuku.checkSelfPermission()` возвращает `PERMISSION_DENIED`.
+2. `Shizuku.requestPermission(code)` → Shizuku-сервер стартует `RequestPermissionActivity` от `moe.shizuku.privileged.api`.
+3. Activity показывает диалог «Allow rayneo-vm to use Shizuku?». После Allow — `onRequestPermissionResult` выстреливает, `refresh()` ставит state=Granted.
+
+**Race condition на RayNeo X3 Pro (см. память #4778).** Системный лаунчер `com.ffalconxr.mercury.launcher` (PID 24482, UID 1000) **иногда** принудительно убивает (`forceStopPackage`) только что запущенную `RequestPermissionActivity` в течение ~14мс. То есть диалог либо показывается, либо нет — гонка. Workaround: при `state==NeedsPermission` после рестарта активности пользователь тапнет ещё раз. В коде: в `refresh()` если `requestPermission()` бросил — повторить на следующем `onResume()`.
+
+**Что НЕ работает:**
+- Кастомный ContentProvider вместо `rikka.shizuku.ShizukuProvider` — binder не придёт.
+- `addBinderReceivedListener` без `Sticky` — пропустим событие, если binder пришёл до того, как мы зарегистрировались.
+- `requestPermission()` без Activity-контекста — сервер стартует Activity, но если она умерла до того, как пользователь нажал Allow, результат не вернётся.
+
### 5.4. Дефолты (фиксировано для ночной сессии)
**Версии — latest stable на сентябрь 2026 (по правилу «брать последнее по возможности»):**