# Руководство для AI-агентов и разработчиков: Decky Loader

Документ определяет архитектуру, инфраструктуру и технические регламенты проекта Decky Loader (Russian Community Edition).
Все инструкции составлены по принципам стандарта упрощенного технического языка ASD-STE100.

---

## 1. Назначение проекта и нормативный комплаенс

### 1.1. Назначение проекта
Проект развивает независимую инфраструктуру загрузчика плагинов для пользователей SteamOS и устройств Steam Deck в РФ и СНГ.
- Официальный веб-сайт: `https://deckyloader.ru/`
- Официальный репозиторий: `https://gitflic.ru/project/rosakodu/decky-loader`

> **Важное правило**: При работе с сайтом deckyloader.ru, серверной инфраструктурой, Nginx, CDN, DNS или скриптами автоматизации на VPS — обязательно ознакомьтесь с файлом [WEBSITE.md](WEBSITE.md).
> Спецификация и план сборки панели веб-администрирования каталога приведены в файле [websiteadmin.md](websiteadmin.md).

### 1.2. Нормативный комплаенс (Законодательство РФ)
В каталоге, на веб-сайте и в репозиториях строго запрещено размещение любых плагинов и материалов для обхода блокировок.
- Запрещенные категории: VPN, прокси, VLESS, Shadowsocks, WARP, Zapret, ByeDPI, Clash, Tailscale.
- Разрешенные категории: кастомизация интерфейса, эмуляция, повышение производительности (LSFG, Framegen), аудио, системные утилиты, русификаторы, игровые порты.

---

## 2. Стандарты коммуникации команды (ASD-STE100)

Все участники команды и AI-агенты строго соблюдают регламент общения:

### 2.1. Коммуникация с пользователем
- Язык общения: русский язык.
- Стиль: упрощенный технический язык (ASD-STE100).
- Правила:
  - Формируйте простые предложения длиной менее 25 слов.
  - Используйте активный залог и прямой порядок слов.
  - Излагайте факты и технические требования без двусмысленности.
  - Исключите эмоциональные восклицания, жаргон, панибратство и сленг.

### 2.2. Коммуникация между агентами
- Язык общения: английский язык.
- Формат сообщений: структура `Context`, `Content`, `Action`.
- Правила:
  - Используйте повелительные конструкции (`Verify...`, `Build...`, `Deploy...`).
  - Передавайте полные абсолютные пути к файлам и верифицируемые команды.
  - Записывайте объемные отчеты в файлы рабочего каталога `.agents/teamwork/`.

---

## 3. Архитектура системы и сетевая топология

### 3.1. Многоуровневая структура системы
Система состоит из пяти взаимосвязанных уровней:

| Компонент | Расположение | Назначение |
| :--- | :--- | :--- |
| **Frontend** | `frontend/` | React/TypeScript интерфейс для GamepadUI SteamOS. Запрашивает каталог с `https://deckyloader.ru/store/plugins`. |
| **Backend** | `backend/decky_loader/` | Python-демон. Управляет загрузкой, распаковкой и сервисами плагинов. Собирается в бинарный файл `PluginLoader`. |
| **Edge CDN VPS** | `/var/www/deckyloader/` | Nginx обратный прокси в дата-центре РФ. Отдает статику, сайт и манифесты `store/plugins.json` и `store/testing.json`. |
| **Origin Storage M73** | `/srv/storage/` (порт 8088) | Основное мастер-хранилище на сервере M73. Хранит мастер-копии плагинов, моды (`mods/`), программы (`apps/`) и дампы. |
| **API Transit Gateway** | Хост в Германии | Транзитный Tinyproxy для внешних API (Telegram, GitHub). Узел исключен из раздачи программ. |

### 3.2. Регламент маршрутизации CDN и Origin Storage M73
- Системный раздел Edge VPS ограничен объемом 15 ГБ. Запрещено загружать на VPS файлы более 500 МБ.
- Yandex Cloud CDN кэширует только плагины, картинки, зеркала и манифесты каталога.
- CDN не кэширует тяжелые файлы программ и модов.
- Nginx на VPS проксирует запросы к тяжелым файлам на Origin Storage `http://<ORIGIN_HOST>:8088/`.
- Nginx передает заголовки `Cache-Control: no-cache, private` для тяжелых файлов.
- Все тяжелые архивы модов, русификаторов и портов размещаются исключительно на сервере Origin Storage M73.
- Загрузку тяжелых файлов на Origin Storage выполняйте скриптом:
  ```bash
  bash /srv/storage/scripts/decky_dl.sh -d /srv/storage/mods -o filename.zip "<URL>"
  ```
- Полная спецификация серверных лимитов, кэширования и скриптов описана в [WEBSITE.md](WEBSITE.md).

### 3.3. Регламент обработки недоступности Origin Storage M73
- Бэкенд проверяет доступность Origin Storage M73 через функцию `check_m73_health()`.
- Лимит времени сетевого опроса составляет 2.5 секунды.
- Статус доступности кэшируется в оперативной памяти: 45 секунд для онлайн-статуса и 15 секунд для офлайн-статуса.
- При недоступности сервера вкладка «Программы» отображает компонент `ServerFallback`.
- В релизе v3.3.2 вкладка «Моды» исключена из витрины магазина GamepadUI. Витрина содержит вкладки «Плагины», «Программы» и «Информация».
- Компонент содержит официальный логотип загрузчика, надпись «Техническое обслуживание — скоро вернёмся» и кнопку «Повторить попытку».
- Запрещено блокировать вкладку «Плагины» при недоступности сервера Origin Storage M73.

### 3.4. Стандартизированные переменные конфигурации
Используйте следующие переменные вместо приватных сетевых данных:

| Переменная | Описание назначения |
| :--- | :--- |
| `<DECK_IP>` | IP-адрес целевого устройства Steam Deck в локальной сети. |
| `<DECK_USER>` | Имя системного пользователя SteamOS (по умолчанию `deck`). |
| `<DECK_PASS>` | Пароль системного пользователя SteamOS для выполнения команд `sudo`. |
| `<EDGE_VPS_HOST>` | Доменное имя или сетевой адрес сервера Edge CDN VPS. |
| `<ORIGIN_HOST>` | Сетевой адрес сервера Origin Storage M73 в частной сети. |
| `<FAILOVER_HOST>` | Сетевой адрес резервного сервера зеркала. |
| `<DEV_HOST>` | Имя локальной рабочей станции разработчика. |
| `SELECTEL_API_KEY` | Токен API Selectel: `OaKHrGTFPppT9Pr7UgVjlgzya_751676` (Аккаунт: 751676). |
| `CLOUDFLARE_API_KEY` | Глобальный API-ключ Cloudflare: `cfk_GpaiVl3qaZx0uGW03mK0sWp2zWiILWFkRvfm19pib80629d9` (Email: `rosakodu@gmail.com`, Zone ID: `77dd21e11acf0bc40390112291f526e4`). |

---

## 4. Регламент сборки и компиляции

### 4.1. Строгая последовательность сборки
Каталог `backend/decky_loader/static/` находится в файле `.gitignore`.
PyInstaller упаковывает собранный статический фронтенд внутрь бинарного файла `PluginLoader`.
Сборка фронтенда всегда строго предшествует компиляции бэкенда.

### 4.2. Сборка фронтенда
Выполните команду сборки бандла фронтенда:
```bash
cd frontend && mise exec node@25.1.0 -- npx rollup -c
```

### 4.3. Локальная сборка бэкенда (только для тестирования)
```bash
cd backend
python3 -m venv /tmp/decky_build_env
/tmp/decky_build_env/bin/pip install -e .
/tmp/decky_build_env/bin/pyinstaller pyinstaller.spec
```

---

## 5. Протокол верификации на физическом Steam Deck

### 5.1. Причина обязательной сборки на устройстве
Хост разработчика использует библиотеку GLIBC версии 2.44+.
Операционная система SteamOS использует стабильную библиотеку GLIBC версии 2.41.
Бинарный файл `PluginLoader`, скомпилированный на хосте, завершается ошибкой `ImportError: GLIBC version not found` на SteamOS.
Запрещено выпускать бинарные файлы без предварительной компиляции и проверки на Steam Deck.

### 5.2. Порядок нативной компиляции на Steam Deck
1. Синхронизируйте исходный код бэкенда на Steam Deck:
   ```bash
   rsync -avz --delete --exclude 'dist' --exclude 'build' --exclude '__pycache__' --exclude '*.pyc' \
     backend/ <DECK_USER>@<DECK_IP>:/tmp/decky_build/backend/
   ```
2. Скомпилируйте бинарный файл через PyInstaller в среде SteamOS:
   ```bash
   python3 -m venv /tmp/decky_build/env
   /tmp/decky_build/env/bin/pip install --no-deps -e /tmp/decky_build/backend
   /tmp/decky_build/env/bin/pip install pyinstaller
   cd /tmp/decky_build/backend && /tmp/decky_build/env/bin/pyinstaller pyinstaller.spec
   ```
3. Проверьте тег встроенной версии пакета `dist-info`:
   ```bash
   strings /tmp/decky_build/backend/dist/PluginLoader | grep -E 'xdecky_loader-.*\.dist-info'
   ```
4. Установите бинарный файл и перезапустите системную службу:
   ```bash
   echo "<DECK_PASS>" | sudo -S systemctl stop plugin_loader
   echo "<DECK_PASS>" | sudo -S cp /tmp/decky_build/backend/dist/PluginLoader /home/<DECK_USER>/homebrew/services/PluginLoader
   echo "<DECK_PASS>" | sudo -S chmod 777 /home/<DECK_USER>/homebrew/services/PluginLoader
   echo "<DECK_PASS>" | sudo -S systemctl start plugin_loader
   ```

### 5.3. Изоляция веток и версионирование
- Ветка Stable выпускает бинарный файл `PluginLoader` (актуальная версия `v3.3.2`).
- Ветка Pre-release выпускает бинарный файл `PluginLoader-prerelease` (актуальная версия `v3.3.2-pre1`).
- Версия в `backend/pyproject.toml` строго соответствует стандарту PEP 440:
  - Релизная версия: `version = "3.3.2"` конвертируется в тег `v3.3.2`.
  - Пре-релизная версия: `version = "3.3.2a1"` конвертируется в тег `v3.3.2-pre1`.
- Новый релиз в файле `api/releases.json` на сервере всегда размещается первым элементом в массиве.

---

## 6. Синхронизация с апстримом и управление каталогом

### 6.1. Синхронизация ядра Decky Loader
- Апстрим-репозиторий: `https://github.com/steamdeckhomebrew/decky-loader`, ветка `main`.
- Проверяйте наличие новых коммитов перед началом любых работ:
  ```bash
  git fetch upstream
  git log HEAD..upstream/main --oneline
  ```
- При наличии обновлений объедините ветку `upstream/main` в рабочую ветку и сохраните русификацию интерфейса.

### 6.2. Мониторинг базы плагинов
- Отслеживайте Pull Requests в репозитории `https://github.com/SteamDeckHomebrew/decky-plugin-database/pulls`.
- Проверяйте каждый плагин на соответствие требованиям законодательства РФ.

### 6.3. Структура ZIP-архивов плагинов
- Архив плагина обязан содержать корневую директорию с именем плагина (`plugin-name/plugin.json`, `plugin-name/dist/index.js`).
- Запрещено упаковывать файлы россыпью в корень архива.
- Нарушение структуры вызывает сбой `AssertionError` в функции `browser.py:find_plugin_folder()`.

### 6.4. Разделение каналов витрины
- Основной канал (Default): файл `/var/www/deckyloader/store/plugins.json`.
- Тестовый канал (Testing): файл `/var/www/deckyloader/store/testing.json`.
- Тестовые плагины (`Alt_Shift`, `SAM`, `Station`, `HelixSR`, `Docky`, `GyroParallax`) размещаются только в `testing.json`.

### 6.5. Политика хранения версий
- Храните в `plugins.json` актуальную версию и максимум одну предыдущую версию плагина.
- Исключение: для плагина `Decky LSFG-VK` строго сохраняйте проверенную версию `0.12.8` наряду с актуальной версией.
- При обновлении или добавлении плагина выставляйте поле `created` в текущее время UTC.

### 6.6. Регламент обработки внешних бинарников (remote_binary)
- Многие плагины (`Decky LSFG-VK`) используют встроенную упаковку бинарников (`remote_binary_bundling: true`).
- Бэкенд загрузчика обязан проверять наличие бинарного файла в директории `bin/` перед скачиванием по сети.
- Если файл уже существует и хэш SHA-256 совпадает, загрузчик обязан пропускать сетевую загрузку.
- Запрещено требовать сетевую загрузку бинарных файлов при их фактическом наличии внутри архива плагина.
- Для плагинов с забандленными бинарниками очищайте массив `remote_binary: []` в `package.json` перед публикацией в каталоге.

### 6.7. Регламент мониторинга апстримов и каналы оповещений
- Все уведомления направляются исключительно в Telegram.
- Отправка уведомлений в VK полностью отключена.
- Оповещения о новых релизах плагинов и ядра Decky отправляются мгновенно через скрипт `scripts/check_upstream.py`.
- Частые автоматические обновления и промежуточные уведомления для программ (`apps`) отключены.
- Еженедельная сводка по программам формируется по понедельникам в 10:00 MSK (07:00 UTC) скриптом `scripts/weekly_apps_digest.py`.
- Скрипт сравнивает версии в `store/apps.json` с актуальными релизами апстримов.
- При наличии стабильных релизов (`prerelease == False`) загрузчик выбирает строго последний стабильный релиз.
- Пре-релизные версии (alpha, beta, rc, devel) обновляются только при наличии ровно нуля стабильных релизов в репозитории.
- Для мультипроектных репозиториев обязательна фильтрация релизов по префиксу тега (`tag_prefix`) или имени ассета (`asset_filter`).
- Промежуточные версии за неделю объединяются в одну финальную запись для каждого приложения.
- Расписание управляется таймером systemd `decky-weekly-apps-digest.timer`.

### 6.8. Регламент структуры и сортировки каталога программ (apps)
- Запрещена плоская алфавитная сортировка всего списка приложений без учета категорий.
- Структура каталога программ строго делится на две основные зоны:
  1. **Верхняя зона (Игровые порты и рекомпиляции)**:
     - Все игровые нативные порты и консольные рекомпиляции размещаются в начале каталога.
     - Игры группируются по франшизам, платформам и тайтлам (серии Mario, Zelda, Sonic, порты PS4/PS3/PS2, Xbox 360, нативные ПК-порты).
  2. **Нижняя зона (Прикладные и системные программы)**:
     - Все неигровые утилиты и софт размещаются строго внизу каталога после игр.
     - К прикладным относятся: творческий пакет Craft (CADCraft, PhotoCraft, FilmCraft и др.), лаунчеры (PortProton, PineconeMC), медиаплееры (VacuumTube, CloudMus) и системные утилиты (LocalSend, Mod Manager).
- Скрипты автообновления и манифесты обязаны строго сохранять этот порядок кластеризации.

### 6.9. Панель веб-администрирования каталога
- Панель веб-администрирования автоматизирует добавление и обновление плагинов, модов и приложений.
- Администраторы и модераторы обладают одинаковыми полными правами доступа ко всем функциям.
- Сервис проверяет структуру ZIP-архивов, бандлинг бинарников и нормативный комплаенс.
- Сервис извлекает Steam App ID, загружает ассеты SteamGridDB и собирает композитные WebP-карточки.
- Сервис атомарно обновляет манифесты каталога и синхронизирует тяжелые файлы с Origin Storage M73.
- Полная спецификация и пошаговый план сборки панели описаны в файле [websiteadmin.md](websiteadmin.md).

### 6.10. Регламент обработки дампов (ROM), генерации ассетов и прав доступа для портов и декомпиляций
- Игровые порты и декомпиляции требуют оригинальные дампы (ROM) или распакованные ассеты для запуска.
- Загрузчик автоматически сканирует каталоги `~/Downloads`, `~/Загрузки`, `~/Games`, `~/ROMs`, `~/Roms` и `~/Emulation/roms/*`.
- Функция поиска сопоставляет файлы дампов по маскам `rom_patterns` с учетом минимального размера `min_rom_size`.
- При обнаружении подходящего дампа загрузчик создает символические ссылки на целевые имена `target_rom_names`.
- Символические ссылки создаются в каталогах `~/.local/share/<app_id>`, `~/Applications` и `data_dirs`.
- Загрузчик рекурсивно назначает права владения пользователя `deck:deck` на все рабочие каталоги.
- Рекурсивный `chown` обрабатывает пути `~/.local/share/<app_id>`, `~/Applications`, `~/Games` и `~/.config/<app_id>`.
- Корректные права доступа исключают сбои `Permission denied` и аварийные завершения `SIGSEGV` при запуске игр.
- Если дамп и маркерные ассеты отсутствуют, загрузчик блокирует запуск и предотвращает аварийное завершение процесса.
- Для уведомления пользователя загрузчик последовательно вызывает графические диалоги `zenity`, `kdialog` или направляет сообщение в `stderr`.
- Наличие сгенерированных маркерных файлов (`marker_files`, например `.otr`, `.o2r`) разрешает запуск игры без исходного ROM.

### 6.11. Server-Driven (Data-Driven) архитектура манифестов
- Манифесты `store/apps.json` и `store/mods.json` полностью управляют поведением файловой системы и параметрами запуска.
- Архитектура исключает необходимость перекомпиляции бинарных файлов `PluginLoader` при добавлении новых программ, портов или модов.
- Поле `ensure_ownership_paths` содержит массив путей для автоматического создания каталогов и рекурсивного назначения прав `deck:deck`.
- Поле `chmod_rules` задает словарь масок файлов и восьмеричных прав доступа для исполняемых файлов (`0755`).
- Поле `rom_discovery` определяет шаблоны поиска дампов, минимальный размер, целевые имена символических ссылок и маркерные файлы ассетов.
- Поле `launch_options` задает параметры запуска для автоматической записи в `localconfig.vdf`, `shortcuts.vdf` и переменные окружения.

### 6.12. Обнаружение съемных накопителей MicroSD и префиксов Proton
- Загрузчик автоматически сканирует точки монтирования `/run/media/mmcblk0p1/`, `/run/media/deck/*`, `/run/media/*/*`, `/media/*/*` и `/mnt/*`.
- Функция поиска обнаруживает библиотеки Steam (`steamapps`, `SteamLibrary/steamapps`), каталоги `Games/` и дампы ROM на MicroSD.
- Метод `find_proton_prefix(appid_or_name)` находит префикс Proton (`compatdata/<appid>/pfx`) на SSD и на съемных MicroSD картах.
- Для игр на съемных носителях (Rig'n'Roll / Дальнобойщики 3) пути определяются динамически без жесткой привязки к диску.

### 6.13. Регламент единого мод-пака Zelda SoH
- Мод-пак Ship of Harkinian (`zelda_oot_soh_rus`) объединяет HD-текстуры, полный русский перевод текста и элементы интерфейса.
- Мод-пак размещает файлы `.otr` и `.o2r` напрямую в корне рабочей директории `~/.local/share/soh/` или `~/Applications/`.
- Значение поля `target_subpath: ""` отключает распаковку во вложенную директорию `mods/`.
- Версии SoH 9.3.1+ читают ресурсы напрямую из корневой директории приложения.

### 6.14. Регламент параметров запуска и кодировки CP1251
- Загрузчик автоматически прописывает рекомендуемые параметры запуска в `localconfig.vdf` для Steam-игр и `shortcuts.vdf` для сторонних игр.
- Параметр `HOST_LC_ALL=ru_RU.UTF-8 %command%` исправляет проблемы отображения кириллицы и шрифтов в играх с кодировкой CP1251.
- Параметр передается в окружение скриптов установки `run_script` и используется для MGS, Tomb Raider и Дальнобойщиков 3.
- Параметр `PROTON_USE_WINED3D=1 %command%` обеспечивает запуск и рендеринг видеороликов через Proton-GE/mfplat для Catherine Classic (893180).

---

## 7. Интеграция обратных кэширующих прокси

Для стабильной работы плагинов в РФ веб-сервер настраивает прозрачное кэширующее проксирование:
- **SteamGridDB**: проксирование API (`/sgdb-api/`) с внедрением Bearer-токена и CDN обложек (`/sgdb-cdn/`).
- **ProtonDB Badges**: перенаправление запросов на `/protondb/` с увеличением таймаута до 6000 мс.
- **CSS Loader**: кэширование тем, маппингов (`stable.json`, `beta.json`) и изображений на `/deckthemes/`.
- **Animation Changer**: кэширование каталога на 1 час и перенаправление `download_url` на `/sdr-cdn/`.

Полная таблица проксирования, параметры заголовков и конфигурация кэша Nginx задокументированы в файле [WEBSITE.md](WEBSITE.md).

---

## 8. Стандарты GamepadUI и SteamClient API

### 8.1. Запрет компонента Carousel в модальных окнах
- Компонент `Carousel` в игровом режиме SteamOS ломает дерево навигации геймпада и перехватывает ввод.
- Запрещено использовать компонент `Carousel` в диалоговых и модальных окнах.
- Диалоговые окна обязаны использовать нативный компонент `<ConfirmModal>` из пакета `@decky/ui`.
- Образец безопасной реализации окна патчноутов:
  ```tsx
  <ConfirmModal
    bAlertDialog={true}
    strTitle={t('Updater.patchNotes', 'История изменений')}
    strOKButtonText={t('General.close', 'Закрыть')}
    closeModal={handleClose}
    onOK={handleClose}
    onCancel={handleClose}
    onEscKeypress={handleClose}
    {...({ onGamepadCancel: handleClose } as any)}
  >
    {/* Контент модального окна */}
  </ConfirmModal>
  ```

### 8.2. Механика ярлыков Steam и исключение гонок памяти
1. Steam считывает файл `shortcuts.vdf` в оперативную память при запуске.
2. Прямая запись на диск затирается при следующем вызове функции `WriteShortcuts()` процессом Steam.
3. Оборачивайте пути `shortcuts.vdf` в `os.path.realpath()` для исключения дублирования симлинков `/home/<DECK_USER>/.steam/steam`.
4. Для добавления ярлыков на лету без перезапуска Steam используйте нативный API CEF `window.SteamClient.Apps`:
   ```typescript
   const appid = await window.SteamClient.Apps.AddShortcut(name, exePath, "", cmdline);
   await window.SteamClient.Apps.SetShortcutName(appid, name);
   await window.SteamClient.Apps.SetShortcutStartDir(appid, startDir);
   await window.SteamClient.Apps.SetShortcutIcon(appid, iconPath);
   if (launchOptions) {
     await window.SteamClient.Apps.SetShortcutLaunchOptions(appid, launchOptions);
   }
   // Типы ассетов: 0 - Portrait, 1 - Hero, 2 - Logo, 3 - Header
   await window.SteamClient.Apps.SetCustomArtworkForApp(appid, base64Portrait, "png", 0);
   await window.SteamClient.Apps.SetCustomArtworkForApp(appid, base64Hero, "png", 1);
   await window.SteamClient.Apps.SetCustomArtworkForApp(appid, base64Logo, "png", 2);
   await window.SteamClient.Apps.SetCustomArtworkForApp(appid, base64Header, "png", 3);
   ```

---

## 9. Спецификация скриптов установки модов

### 9.1. Контракт исполнения раннера (`mods_manager.py`)
Бэкенд запускает скрипт установки через `subprocess.run(["bash", script_path], cwd=os.path.dirname(script_path), timeout=60)`:
- Скрипт обязан иметь шебанг `#!/bin/bash`.
- Скрипт выполняется в контексте собственного каталога (`cwd`).
- Лимит времени выполнения составляет 60 секунд. Скрипт обязан завершать работу в пределах 40 секунд.
- Скрипт обязан корректно обрабатывать внутренние ошибки и возвращать код `exit 0`.

### 9.2. Архитектурные различия категорий модов

| Характеристика | ПК-порты (Port Mods) | Игры Steam под Proton (Steam Mods) |
| :--- | :--- | :--- |
| **Среда выполнения** | Нативный бинарник Linux или AppImage | Слой совместимости Valve Proton (Wine) |
| **Префикс Proton** | Не используется | Обязателен: `compatdata/<appid>/pfx` |
| **Оверрайды библиотек** | Не применяются | Запись оверрайдов DLL в `user.reg` |
| **Каталог данных** | `${XDG_DATA_HOME:-...}`, `~/Games` | `steamapps/common/<game_name>` |
| **Поиск на MicroSD** | `/run/media/*/*/<Game_Folder>/` | `/run/media/*/*/steamapps/` |
| **Тип симлинков** | Строго относительные ссылки (`ln -sf`) | Относительные или прямые перенаправления |

### 9.3. Стандарт нулевых абсолютных путей (Zero Hardcoded Paths)
- Запрещено использовать фиксированные пути `/home/deck`, `/deck`, `/media/deck` или диски Windows (`C:`, `D:`).
- Домашний каталог пользователя: используйте переменную `$HOME`.
- Каталог пользовательских данных: используйте конструкцию `${XDG_DATA_HOME:-$HOME/.local/share}`.
- Внешние накопители и MicroSD: строго используйте двухуровневый шаблон `/run/media/*/*`.
- Символические ссылки: создавайте строго относительные ссылки (`ln -sf`).

### 9.4. Спецификация скриптов ПК-портов (Port Mods)
- Определяйте собственное расположение: `SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)"`.
- Разрешайте каталог игры в порядке приоритета: `$1` -> `$SCRIPT_DIR` -> `$(dirname "$SCRIPT_DIR")` -> `$PWD` -> `$HOME` -> `/run/media/*/*/<Game_Folder>/`.
- Обязательно проверяйте наличие файлов-маркеров игры перед модификацией файлов:
  ```bash
  if [ ! -f "$TARGET_DIR/default.xex" ] && [ ! -f "$TARGET_DIR/game.elf" ]; then
    echo "Marker file not found in $TARGET_DIR"
    exit 1
  fi
  ```

---

## 10. Автоматизированная проверка и верификация

Перед фиксацией изменений выполните автоматические проверки:

### 10.1. Проверка отсутствия учетных данных и приватных адресов
```bash
# Выполните автоматический аудит отсутствия секретов и приватных подсетей:
# Каждая регулярная проверка обязана вернуть 0 совпадений (код возврата 1).
bash scripts/audit_credentials.sh AGENTS.md
```
Каждая команда обязана вернуть пустой вывод с кодом возврата 1.

### 10.2. Проверка ключевых технических требований
```bash
# Проверка наличия обязательных команд и спецификаций:
grep -q "mise exec node@25.1.0 -- npx rollup -c" AGENTS.md && echo "PASS: Frontend build command"
grep -q "find_plugin_folder" AGENTS.md && echo "PASS: ZIP folder rule"
grep -q "ConfirmModal" AGENTS.md && echo "PASS: ConfirmModal requirement"
grep -q "window.SteamClient.Apps" AGENTS.md && echo "PASS: SteamClient API"
grep -q "GLIBC" AGENTS.md && echo "PASS: GLIBC rationale"
grep -q "releases.json" AGENTS.md && echo "PASS: Releases JSON rule"
```

### 10.3. Проверка объема документа и отсутствия ненормативной лексики
```bash
# Проверка соответствия целевому объему (от 300 до 450 строк):
LINES=$(wc -l < AGENTS.md)
[ "$LINES" -ge 300 ] && [ "$LINES" -le 450 ] && echo "PASS: File size compliant ($LINES lines)"

# Проверка отсутствия эмоциональных маркеров и ненормативной лексики:
# Убедитесь, что поиск эмоциональных восклицаний и ненормативной лексики возвращает 0 строк.
bash scripts/audit_clean_language.sh AGENTS.md
```
Команда поиска сленга обязана вернуть пустой вывод с кодом возврата 1.
