O.G.A.S. English

Устройство платформы

Как устроена платформа: ядро и функции, слои, жизненный цикл экземпляра, каналы между частями, хранение и журналы, где что лежит в исходниках.

1 Общие сведения

1.1 Обозначение и наименование

Платформа личных программ O.G.A.S. (ОГАС).

1.2 Программное обеспечение, необходимое для функционирования

Платформа работает в Ubuntu внутри WSL2 на Windows 11; мастерская — программа Windows на системном WebView2 (см. раздел 4). Порядок установки и состав поставки — Сборка, установка и обслуживание.

1.3 Языки программирования

Ядро и функции платформы написаны на Rust, общий код модулей (OGAS SDK) — на Python и Rust, страница мастерской — на HTML, CSS и JavaScript без сборщика.

2 Функциональное назначение

Платформа даёт человеку собирать личные программы из узлов, модулей и пульта без программирования и пользоваться ими. Что она для этого делает, описывают С чего начать и Мастерская.

3 Описание логической структуры

3.1 Слои

3.1.1 Платформа состоит из четырёх слоёв; каждый слой работает в собственных OS-процессах (таблица 1).

Таблица 1 — Слои

Слой Где в репозитории Чем владеет
Ядро core/kernel; общий протокол — core/protocol замок экземпляра, сокет, пересылка сообщений, запуск OS-процессов, запись документов, журналы ядра
Функции платформы functions/<id> каждая — своей задачей; перечень — таблица 2
Модули modules/<id> прикладная работа и её внешние действия
Мастерская functions/ui/window окно в Windows: ввод, отрисовка, раскладка окон
flowchart TD
    user[Человек] --> window[Мастерская в Windows]
    window -->|127.0.0.1, токен| ui[Функция ui]
    ui --> core[Ядро]
    graph[Функция graph] --> core
    canvas[Функция canvas] --> core
    settings[Функция settings] --> core
    modules[Функция modules] --> core
    observe[Функция observe] --> core
    i18n[Функция i18n] --> core
    sources[Функция sources] --> core
    assistant[Функция assistant] --> core
    programs[Программы человека] -->|127.0.0.1, ключ| gate[Функция gate]
    gate --> core
    core --> module[Модуль]

3.1.2 Функции не соединяются друг с другом напрямую: все сообщения проходят через ядро. Структура исходных текстов — приложение А.

3.2 Неизменные правила устройства

Правила устройства обязательны для всех частей платформы и показывают применение правил разработки (Правила разработки) к данной платформе:

1) ядро не содержит предметной логики, узлов графа, интерфейса, кода модулей и сведений о функциях платформы (правило 2.6); 2) функция является самостоятельным OS-процессом; функции не подключают код друг друга и взаимодействуют только через ядро (правило 2.3); 3) модуль не знает устройства платформы и других модулей: всё, что нужно для встраивания, он объявляет в манифесте (правило 2.3); 4) данные передаются через именованные порты и пакеты, а не через скрытое общее состояние (правило 2.7); 5) команда изменяет состояние, запрос только читает, событие сообщает о произошедшем (правило 2.7); 6) ошибка содержит код, категорию, место и признак допустимости повтора (правило 3.2); 7) отказ одного OS-процесса не останавливает остальные, если они могут работать без него (правило 2.3); 8) документы хранятся в файлах и записываются целиком или не записываются совсем; каждую папку данных записывает её хозяин (3.8.1, правила 2.4 и 3.5); 9) мастерская заменяется без изменения ядра (правило 2.3); 10) новая прямая зависимость Rust записывается с причиной в 3.9 (правило 2.8); 11) пределы ядра являются настройками core.*; протокольные величины (версия JSON-RPC, предел строки 4 МиБ) являются константами договора в core/protocol (правило 2.2).

3.3 Ядро

3.3.1 Ядро — один долгоживущий OS-процесс. Ядро:

3.3.2 Ядру известны протокол, идентификаторы, жизненный цикл, пределы, общая обёртка документа и объявленные права функций. Смысл модулей и данных ядру неизвестен. Интерпретатор Python ядро само не запускает и переменных Python не подставляет.

3.3.3 Порядок выбора получателя сообщения:

метод начинается с "core."      → обрабатывает ядро
иначе                           → хозяин метода из handshake (commands, queries)
  хозяина нет                   → method_not_found
  хозяин недоступен             → function_unavailable
  иначе                         → переслать запрос, вернуть ответ отправителю

3.3.4 Функция не может объявить метод с префиксом core.. Любой другой метод принадлежит ровно одной функции.

3.4 Функции платформы

Таблица 2 — Функции платформы

Функция Чем владеет Подробно
graph граф, проверка, включённые программы, события, переменные, выполнение прогонов, контрольные точки, сквозные объекты, прошлые прогоны Программа: граф и запуски
modules манифесты, окружения Python, запуск и выгрузка модулей, распределение видеопамяти, разбор сообщений модулей Модули
canvas документ пульта workspace.json Мастерская, раздел 6
settings схемы, уровни и значения настроек Настройки
i18n словари и язык интерфейса Настройки, раздел 7
observe журнал событий и список проблем 3.8.2
sources источники — витрина O.G.A.S., Hugging Face, Civitai: поиск, файлы, загрузки и папка downloads/ Мастерская, 5.6; Защита, 3.14
profile профиль человека на ogas.space: ключи, посылки и их отправка, свои отправки, письма, что сайт говорит о людях Защита, раздел 8; Методы служб платформы, раздел 7
gate вход для программ человека: ключ, порт на 127.0.0.1, пересылка их запросов Методы служб платформы, раздел 5
assistant помощник: задачи, разговор с сетью, инструменты платформы, права черновика и расширенного доступа, пределы Методы служб платформы, раздел 6
ui связь с мастерской: порт, токен сессии, запуск окна Мастерская, раздел 2

При знакомстве каждая функция объявляет свои команды, запросы, события и папки словарей, а затем регистрирует схему своих настроек у функции настроек — и снова всякий раз, когда та поднимается заново (Настройки, раздел 3). Ядро пересылает сообщения по объявленному списку, не зная их смысла. Добавление или замена функции состоит в том, чтобы положить её папку с описанием и исполняемый файл и изменить запись в реестре; ядро при этом не пересобирается.

3.4.1 Реестр функций и описание функции

Реестр data/functions.json содержит сведения, которые определяет экземпляр: id, путь к исполняемому файлу, enabled, capabilities. Описание functions/<id>/function.json в папке функции содержит сведения о самой функции: requires, optional, platform.min / max, contract, restart, interactive. Форматы обоих — Форматы файлов, раздел 3. Ядро соединяет их по id при запуске экземпляра; функцию, чьё описание не читается, оно не запускает (function_description_invalid), остальные работают.

Повреждённый или отсутствующий реестр не останавливает ядро: ядро работает без функций и отказывает командам, которым нужен реестр.

3.4.2 Знакомство и проверка работоспособности

Первое сообщение функции — function.handshake: id и версия, поддерживаемые версии договора (обязательна contracts.core), команды, запросы, события, права, папки словарей и имена поверхностей — последние нужны только для диагностики (Мастерская, раздел 8). Если первое сообщение другое, соединение закрывается. Одноразовый токен запуска после знакомства удаляется и повторно не принимается. Сообщение целиком — Обмен с ядром, раздел 4.

После знакомства ядро с интервалом core.health_interval_ms запрашивает у функции function.health. При отсутствии ответа в течение core.health_timeout_ms функция становится degraded: ядро её останавливает, и дальше она идёт тем же путём, что упавшая, — расходует одну попытку перезапуска (3.6.4). Обратным запросом core.health функция проверяет работоспособность самого ядра.

3.5 Распределение владения

Документы JSON функции записывают только через файловый сервис ядра и только свои. Папки с файлами (окружение Python, рабочую папку прогона, копии модулей для экспорта, журналы, память узла, файлы результатов) хозяин записывает сам и только в своей папке (3.8.1).

3.6 Жизненный цикл экземпляра

3.6.1 Запуск

  1. Ядро создаёт в папке данных папки run, logs и config. Остальные папки создают их хозяева, когда они понадобятся.
  2. Читает пределы core.* из config/core.json, затем из config/system.json. Если core.json нет, ядро записывает его пустым: умолчания остаются в схеме. Если файл не разбирается, старт отказывается с именем файла и номером строки.
  3. Записывает начало запуска в logs/boot.jsonl.
  4. Берёт замок ogas.lock: записывает в него pid, время старта и случайную метку и держит на файле flock. Замок занят — см. 3.6.3, «Повторный запуск».
  5. Создаёт Unix-сокет с правами 0600. Путь — run/ogas.sock, если папка лежит на файловой системе Linux (не 9p, DrvFs, NFS, CIFS) и путь помещается в 107 байт. Иначе — XDG_RUNTIME_DIR или /tmp с теми же условиями. Ни один вариант не подходит — старт отказывается. Настоящий путь функции получают в OGAS_SOCKET.
  6. Проверяет зависимости функций.
  7. Запускает функции в порядке зависимостей с окружением из 3.7.4.
  8. Ждёт handshake каждой функции с ограничением по времени. Зависимая функция не стартует раньше своих зависимостей.
  9. Сообщает о готовности — полной или неполной, если часть функций недоступна.

Ошибка функции не останавливает ядро. Если функция A зависит от функции B, а B не запустилась, не прошла знакомство или исчерпала перезапуски, A не запускается (или останавливается) и помечается недоступной. Необязательная зависимость (3.4.1) этого не вызывает.

3.6.2 Остановка

Ядро перестаёт принимать новые запуски, публикует system.stopping, ждёт завершения порождённых функциями OS-процессов в пределах core.process_stop_grace_ms и принудительно завершает оставшиеся. Затем ядро закрывает каналы функций: функция дочитывает то, что ей пришло, — system.stopping в том числе — и завершается сама, поэтому то, что она делает на остановку, успевает сделаться: граф останавливает прогоны, функция ui передаёт событие окну, и окно закрывается. Функцию, не завершившуюся до конца core.shutdown_grace_ms, ядро завершает принудительно. Замок снимается при выходе.

При выходе из мастерской функция ui отправляет core.shutdown, и экземпляр останавливается; закрытие окна только прячет его к значку у часов (Мастерская, 2.1). Отказ функции ui или окна экземпляр не останавливает; restart: false только запрещает перезапуск.

3.6.3 Восстановление

Отказавшая функция получает ограниченное число перезапусков подряд — core.function_restart_max — с растущей паузой: первая core.function_restart_base_ms, каждая следующая вдвое длиннее. Успешный handshake обнуляет счётчик. После исчерпания попыток функция отключается до следующего запуска ядра. Незавершённая команда к ней получает function_lost; автоматически повторяются только команды, которые безопасно выполнить повторно.

Замок — это flock(LOCK_EX) на открытом ogas.lock. OS-процесс, завершившийся без снятия замка, освобождает его при закрытии файла системой. JSON внутри файла содержит сведения для диагностики и замком не является. Два одновременных запуска замок не получат.

После завершения функции ядро удаляет запись о её OS-процессе, чтобы завершившаяся функция не отображалась работающей.

Повторный запуск. После отказа мастерской экземпляр продолжает работать без окна, и человек запускает ярлык повторно. Повторный запуск не завершается отказом на замке, а активирует работающий экземпляр:

  1. Глагол start или ui не получил замок. Он берёт pid из ogas.lock, проверяет по /proc/<pid>/exe, что это та же программа, и посылает ей сигнал SIGUSR1. Сам глагол выводит «уже запущено» и завершается с кодом 0.
  2. Ядро рассылает всем функциям событие system.activate и заново запускает каждую функцию с interactive: true, которая не работает. Функции ядро выбирает по признаку interactive из их описаний.
  3. Функция окна, получив system.activate, открывает окно, если его нет: окно не подключено и его OS-процесс не работает. Работающее или запускающееся окно повторно не открывается; событие доходит до страницы окна, и окно, спрятанное у часов, показывается.
  4. Глагол реестра, которому нужна мастерская (5.3), при занятом замке не завершается отказом, как остальные глаголы реестра, а оставляет работающему экземпляру записку — глагол и значения его аргументов (run/launch.json, Форматы файлов, раздел 3) — и посылает тот же сигнал. Разбуженный экземпляр записку забирает и выполняет вызовы глагола сам, если его реестр описывает этот глагол как требующий мастерской и принимает его аргументы. Отказ записывается в журнал ядра, экземпляр продолжает работать. Записка читается один раз; нечитаемая, другого формата или пролежавшая дольше полуминуты просьбой не считается, а экземпляр, который запускается, записку прежнего не берёт.

Функция окна отказавшее окно не перезапускает: окно, отказывающее при старте, перезапускалось бы непрерывно. Окно открывается снова по запросу человека. Глаголы, описанные в реестре, на занятом замке завершаются отказом: они выполнили бы работу, о которой работающий экземпляр не знает.

3.6.4 Состояния функции

stateDiagram-v2
    [*] --> Discovered
    Discovered --> Starting
    Starting --> Handshake
    Starting --> Failed
    Handshake --> Ready
    Handshake --> Failed
    Ready --> Degraded
    Ready --> Restarting
    Ready --> Stopping
    Degraded --> Restarting
    Degraded --> Stopping
    Restarting --> Starting
    Restarting --> Failed
    Failed --> [*]
    Stopping --> [*]

Discovered — найдена в реестре и ждёт своей очереди: функция запускается после тех, без которых не работает; Starting — запускается OS-процесс; Handshake — процесс запущен, ожидается первое сообщение; Ready — работает; Degraded — не ответила на проверку работоспособности, ядро её останавливает; Restarting — вышла сама или остановлена за молчание и ждёт паузу перед перезапуском; Failed — не работает, и ядро её больше не запускает: не запустилась, не познакомилась вовремя, исчерпала перезапуски, осталась без обязательной зависимости или вышла без права на перезапуск; Stopping — экземпляр останавливается. В core.status состояния называются теми же словами строчными буквами (discovered, starting, handshake, ready, degraded, restarting, failed, stopping), их тексты — core.state.<состояние> в словаре ядра.

3.6.5 Состояния модуля

stateDiagram-v2
    [*] --> Missing
    Missing --> Invalid
    Missing --> NeedsEnvironment
    NeedsEnvironment --> Stopped
    Stopped --> Starting
    Starting --> Ready
    Starting --> Crashed
    Ready --> Executing
    Executing --> Ready
    Executing --> Crashed
    Crashed --> Restarting
    Restarting --> Starting
    Ready --> Stopping
    Stopping --> Stopped

Missing — модуля нет, Invalid — манифест с ошибками, NeedsEnvironment — нужно окружение, Stopped — готов к запуску, Starting — запущен и ждёт init, Ready — готов к работе, Executing — выполняет шаг, Crashed — завершился с отказом, Restarting — запускается снова, Stopping — останавливается.

3.7 Каналы

3.7.1 Функция — ядро

Unix-сокет, одно соединение на функцию. Чтение и запись идут в разных потоках, сообщения — JSON-RPC 2.0 по одному на строку, очереди ограничены, права сокета 0600. Что это действительно та функция, которую запустило ядро, подтверждают одноразовый токен запуска и SO_PEERCRED: uid экземпляра и pid порождённого OS-процесса. Правила строки и обёртки сообщения — Обмен с ядром, разделы 2, 3.

Срок ответа ставит только тот, кто спрашивает. Ядро, функция ui и программа окна — посредники: вызов, который они передают хозяину метода, они ждут столько, сколько нужно хозяину, и своего срока не ставят. Иначе посредник прерывал бы работу, которую хозяин выполняет в пределах своего срока, например шаг модуля, которому манифест разрешил десять минут. Вызов без ответа не ожидает бесконечно: при отключении или отказе хозяина метода все его вызовы без ответа сразу получают function_lost; при отключении спросившего ответ ему не передаётся. Сколько вызовов одна функция может держать в ожидании одновременно, ограничивает core.rpc_queue; сверх этого — отказ backpressure.

3.7.2 Канал модуля через ядро

graph   → ядро → modules : module.execute
modules → ядро           : core.process.spawn, core.process.stdin.write
ядро    → stdin модуля   : сообщения JSON-RPC модуля строками
stdout / stderr модуля → ядро → событие process.io.chunk → modules
sequenceDiagram
    participant G as graph
    participant C as ядро
    participant M as modules
    participant P as модуль
    G->>C: module.execute
    C->>M: module.execute
    M->>C: core.process.spawn
    C->>P: OS-процесс
    M->>C: core.process.stdin.write
    C->>P: строка JSON в stdin
    P-->>C: байты stdout
    C-->>M: событие process.io.chunk
    M-->>C: результат
    C-->>G: ответ execute

Ядро проверяет только свою обёртку и не разбирает JSON-RPC внутри stdout модуля: строки собирает и разбирает функция модулей. stdout модуля отдан протоколу, диагностика идёт в stderr. Когда закрыты оба потока, ядро отправляет process.io.closed с кодом завершения. События process.io.* получает только функция, которая запустила этот OS-процесс.

3.7.3 Мастерская — функция ui

TCP на 127.0.0.1, одно окно за раз, тот же JSON-RPC 2.0 по строкам с пределом строки 4 МиБ. Функция ui запускает программу окна и передаёт ей порт и токен сессии. Первое сообщение окна — ui.window.hello с токеном. Запросы окна функция ui передаёт ядру через своё соединение; из методов ядра окну доступны только core.status, core.health, core.event.subscribe и core.shutdown. События ядра приходят окну уведомлением event. Угрозы и защита — Защита, 3.10.

sequenceDiagram
    participant W as Мастерская (Windows)
    participant U as ui (WSL)
    participant C as Ядро
    U->>W: запуск: --port, --token
    W->>U: ui.window.hello {token}
    U-->>W: {status: ready}
    W->>U: process.run.start
    U->>C: process.run.start
    C-->>U: ответ
    U-->>W: ответ
    C->>U: событие run.changed
    U-->>W: событие run.changed

Если окно пропустило события или переподключилось, оно заново запрашивает всё состояние.

3.7.4 Окружение запуска функции

Ядро запускает функцию с пустым окружением и передаёт только:

Таблица 3 — Окружение запуска функции

Переменная Назначение
OGAS_SOCKET полный путь к сокету ядра
OGAS_LAUNCH_TOKEN одноразовый токен для handshake
OGAS_FUNCTION_ID id из реестра
OGAS_INSTALL_DIR папка установки (в ней ogas, bin/, modules/)
OGAS_DATA_DIR папка данных
PATH PATH родителя или /usr/local/bin:/usr/bin:/bin
HOME домашняя папка, если она есть у родителя
LANG, LC_ALL как у родителя; если не заданы — C.UTF-8
http_proxy, https_proxy, no_proxy, all_proxy и они же заглавными как у родителя, если заданы: через них функция ходит в сеть по команде человека, например при установке окружения процесса

Функция ui получает то же окружение; переменные экрана Linux ей не нужны. Поток stdin функции — /dev/null; stdout наследуется от ядра; stderr ядро перехватывает и записывает в свой журнал (3.8.2); протокол передаётся только через сокет.

3.7.5 Окружение запуска модуля

Ядро запускает модуль с пустым окружением и добавляет PATH, LANG / LC_ALL и переменные из поля env запроса core.process.spawn. Функция модулей сама передаёт PYTHONUNBUFFERED=1, PYTHONPATH, HOME, переменные прокси, если они заданы (3.7.4), OGAS_MODULE_ID, OGAS_MODULE_VERSION, OGAS_MODULE_DIR и, кроме службы, OGAS_RUN_DIR; пути к нейросетям, которые выбрали параметры узла, приходят не в окружении, а с шагом (Модули, раздел 11). Папка памяти узла приходит не в окружении, а с каждым шагом: модуль один на все свои узлы, а память у каждого узла своя (Модули, раздел 4). Модуль не получает OGAS_LAUNCH_TOKEN и OGAS_SOCKET и к шине не подключается. Программы, которые части просят запустить, ядро запускает из одного своего потока, живущего столько же, сколько ядро, и каждая получает SIGKILL, когда ядро завершается, в том числе аварийно: модуль посреди долгого шага не держит видеокарту после ядра.

3.8 Хранение и наблюдение

3.8.1 Папка данных

Всё, что относится к рабочему процессу, лежит в одной его папке processes/<id>/: документы, прогоны и их результаты, файлы, данные ему человеком, память его узлов и окружение Python. Удалённая папка уносит процесс целиком, и ничего от него не остаётся в других местах. Прогон называется местными датой и временем начала — 2026-10-08_07-29-12, при совпадении в ту же секунду -2, -3, — и человек находит его результаты в results/ по дате. Папка процесса называется по его идентификатору; переименование процесса папку не меняет: на неё ссылаются вызовы и пути.

Таблица 4 — Папка данных

Путь Что там Хозяин Как пишется
functions.json реестр функций человек, поставка вручную
ogas.lock замок экземпляра ядро само
config/core.json пределы ядра ядро при первом старте, потом функция настроек через файловый сервис
config/system.json, config/user.json настройки уровней system и user; system.json мастерская не пишет функция настроек через файловый сервис
config/layout.json раскладка окон мастерской между запусками функция ui через файловый сервис
config/library.json библиотека мастерской: панели программ и что скрыто от колонки графа функция ui через файловый сервис
library/pieces/<piece_id>.json заготовки интерфейса в библиотеке функция canvas через файловый сервис
processes/<id>/process.json, generation.json документ процесса и его поколение функция графа через файловый сервис
processes/<id>/workspace.json пульт функция canvas через файловый сервис
processes/<id>/settings.json настройки процесса функция настроек через файловый сервис
processes/<id>/state.json значения переменных «помнить» функция графа через файловый сервис
processes/<id>/state/<имя>/, <имя>.saved.json память узла — своя или общая нескольких узлов — и отметка, что она сохранена целиком модуль узла; отметку — функция модулей сам; отметку — через файловый сервис
processes/<id>/modules.lock.json версии и отпечатки модулей функция модулей через файловый сервис
processes/<id>/.venv, requirements.txt, requirements.freeze.txt окружение Python процесса: ссылки на общий кэш пакетов функция модулей сама, программой uv
processes/<id>/inputs/ файлы, которые человек дал процессу человек сам
processes/<id>/runs/<run_id>/checkpoint.json, keep.json контрольная точка и отметка «Хранить» функция графа через файловый сервис
processes/<id>/runs/<run_id>/work/ рабочая папка модуля функция модулей сама
processes/<id>/runs/<run_id>/events.jsonl журнал прогона функция observe сама
processes/<id>/results/<run_id>/ файлы результатов прогона под их именами функция модулей сама
processes/<id>/runs/<run_id>/ и results/<run_id>/ целиком прогон функция графа — только она удаляет прогон через файловый сервис
module-tests/<module_id>/ рабочая папка и результаты тестового вызова модуля вне процесса функция модулей сама
cache/uv/ общий кэш пакетов Python, на который ссылаются окружения процессов функция модулей сама, программой uv
exports/<id>/package.json, documents/ экспорт процесса функция графа через файловый сервис
exports/<id>/modules/ копии модулей для экспорта функция модулей сама
exports/<id>/ целиком экспорт процесса функция графа — только она заменяет экспорт через файловый сервис
problems.json, logs/events-<ГГГГ-ММ>.jsonl проблемы и общий журнал по месяцам функция observe сама
logs/boot.jsonl, logs/core.jsonl журналы ядра ядро само
run/ сокет ядра ядро само

Базы данных нет. Файловый сервис ядра записывает документ целиком: временный файл, fsync, прежний файл переименовывается в .bak, временный встаёт на его место, fsync папки. У набора файлов процесса есть номер поколения; после сбоя принимается только полное поколение. Форматы — Форматы файлов.

3.8.2 Распределение наблюдения

Журналы пишутся в формате JSON Lines:

События, которые ядро разослало до подключения функции наблюдения, — например, что функция не запущена без своей зависимости, — она берёт при запуске из памяти последних событий ядра (core.event.subscribe), начиная после последнего события этого экземпляра в своём журнале: ни один отказ не остаётся без записи и проблемы, и ни одно событие не пишется дважды.

Журналы не укорачиваются: записанное остаётся. Журнал запуска удаляется только вместе с запуском, по правилу graph.runs_keep (Программа: граф и запуски, раздел 12). Старые месяцы общего журнала удаляются только командой человека — observe.logs.remove, «Удалить журнал до месяца» в окне журнала платформы — или настройкой observe.logs_keep_months, по умолчанию — хранить всё (Настройки, раздел 8); нынешний месяц не удаляется никогда. Удаление записывается в журнал событием logs.removed; поиск читает журнал с самого нового месяца назад, пока не наберёт нужное.

Одна запись журнала уходит на диск одним вызовом записи, поэтому записи разных потоков не перемешиваются. Если прошлый запуск оборвали посреди записи и файл не заканчивается переводом строки, следующая запись сначала дописывает перевод строки: оборванная строка остаётся одной испорченной строкой и не портит следующую. Читатели пропускают строку, которую не удалось разобрать.

Запись журнала ядра содержит time, source (core или id функции), event, error_code при ошибке и короткое message. По записи определяются место и причина отказа без чтения исходных текстов.

Перезапуск функции отражается событием function.restarted с номером попытки и паузой; после исчерпания попыток — событием function.failed с кодом function_restart_exhausted.

Функция графа публикует node.changed для модульных узлов: queued, когда шаг ждёт своей очереди к модулю, running, когда модуль его взял, и completed, failed или cancelled (шаг оборван остановкой) после. Узлы платформы (условие, слияние, цикл) таких событий не публикуют, так как не вызывают модуль и срабатывают сразу. Исключение — узлы, на которых ветка стоит: вопрос, ожидание сигнала, пауза. О них функция графа публикует waiting, когда ветка встала, и completed или cancelled, когда она пошла дальше или ожидание снято, — после того как это записано в контрольную точку: иначе никто не узнал бы, что прогон стоит именно здесь.

У событий номер event_id, который только растёт, но не обязательно на единицу: номер получает и событие, посланное одной функции (process.io.*), а в память ядра и к остальным оно не попадает. Подписчик передаёт последний полученный номер, каким бы ни был шаг до него; если такого номера уже нет в памяти ядра (её размер — core.event_ring_size), ответ говорит resync_required, и подписчик заново читает всё состояние. Совместимость формата журналов с OpenTelemetry не обеспечивается.

3.9 Потоки и зависимости

Ядро использует стандартные потоки Rust, без Tokio: поток приёма соединений, поток чтения на каждое соединение, отдельный поток на обработку каждого запроса функции (одновременно не больше core.rpc_queue на соединение, сверх — отказ backpressure), поток наблюдения за каждым порождённым OS-процессом и потоки чтения stdout и stderr модулей. Записи в одно соединение идут под замком. Для экземпляра на одного человека этого достаточно.

Замок удерживается только на время обращения к защищаемым данным. Не допускается брать второй замок, не отпустив первый. Единственное отступление — шлюз видеопамяти функции модулей: под ним освобождается и занимается место на видеокарте с захватом других замков, а сам шлюз никогда не берётся под другим замком, поэтому взаимная блокировка исключена.

Прямые зависимости Rust и их назначение:

Пакеты Cargo в основном наборе: ogas-protocol, ogas-core, ogas-graph, ogas-modules, ogas-settings, ogas-observe, ogas-i18n, ogas-canvas, ogas-sources, ogas-profile, ogas-ui, ogas-gate, ogas-assistant, ogas-module — SDK для модулей на Rust. Отдельный набор — ogas-window в functions/ui/window. Точные версии всех зависимостей фиксирует Cargo.lock.

4 Используемые технические средства

5 Вызов и загрузка

5.1 Одна программа ogas-core содержит ядро и его глаголы командной строки:

ogas-core start   [--data-dir PATH]
ogas-core ui      [--data-dir PATH]
ogas-core doctor  [--data-dir PATH]
ogas-core <глагол из реестра> [--<аргумент> ЗНАЧЕНИЕ …] [--data-dir PATH]

5.2 Глаголы ядра:

5.3 Остальные глаголы описываются в реестре функций (поле cli, Форматы файлов, раздел 3): имя глагола, предварительные вызовы, вызываемый метод, ожидание итога и аргументы с признаками обязательности и умолчаниями. Ядро разбирает аргументы по этому описанию и подставляет их значения в вызов, не зная их смысла. Без обязательного аргумента глагол завершается с кодом 1, не запуская экземпляр. Так же, не запуская экземпляр, отклоняются глагол, которого нет ни у ядра, ни в реестре, флаг, которого нет среди аргументов глагола, флаг без значения, повторённый флаг и второе слово вместо флага; глаголы ядра не принимают флагов, кроме --data-dir (Правила разработки, 3.2.2). При необъявленном методе или ошибке вызова выводится сообщение и возвращается код 1. Флаг --help выводит глаголы ядра и глаголы реестра папки данных с их аргументами. Собственного срока глаголы не устанавливают: они ожидают итога, сколько бы ни длились установка или прогон; ожидание прерывается клавишами Ctrl+C.

Глагол реестра запускает экземпляр без мастерской и после своего вызова останавливает его. Глагол с признаком interactive — «нужна мастерская» — запускает экземпляр вместе с мастерской, как start, и после своих вызовов экземпляр не останавливает; отказ его вызова при запуске завершает запуск с кодом 1. Если экземпляр уже работает, вызовы такого глагола выполняет он (3.6.3). Что именно открывает мастерская по такому глаголу, ядру неизвестно: оно знает только описание вызова.

5.4 Реестр поставки описывает глаголы прогона процесса без мастерской, установки окружения процесса и запуска программы с её лицом (Сборка, установка и обслуживание, 5.2).

5.5 Сведений о функциях ядро не содержит (Правила разработки, 2.6). ./ogas — обёртка над ogas-core (С чего начать, 2.2).

6 Входные и выходные данные

Форматы документов, которые платформа читает и пишет, — Форматы файлов. Сообщения между частями платформы — Обмен с ядром.

Приложение А (справочное). Структура исходных текстов

Приложение указывает, куда помещать новые файлы. Структура исходных текстов подчинена правилам 2.1 и 2.2 (Правила разработки):

А.1 Дерево репозитория

репозиторий
  README.md                лицо репозитория: что это и как запустить
  LICENSE, NOTICE          лицензия платформы; что под какой лицензией, имя и знак
  CONTRIBUTING.md          на каких условиях принимают правку со стороны
  docs/                    документация; частью платформы не является
    README.md              карта документации: какие документы есть и кому они
    guide/                 тому, кто собирает программы: с чего начать, мастерская
    reference/             справочник: виды узлов, форматы, настройки, коды ошибок, термины
    sdk/                   OGAS SDK: руководство автору модулей и сценариев
    platform/              устройство, программа, модули, защита, сборка, правила
    contract/              договоры: обмен с ядром и методы функций
    en/                    английский перевод с той же раскладкой и своей картой
  core/protocol            общий код обмена: JSON-RPC 2.0, JSON Lines, ошибки, идентификаторы
  core/kernel              ядро: цикл, пересылка сообщений, замок экземпляра
  core/data                данные экземпляра разработки: реестр и настройки поставки; процессы и личное человека в git не входят
  functions/<id>           функция платформы — отдельный OS-процесс
  modules/<id>             модуль человека — отдельный OS-процесс; платформа своих модулей сюда не кладёт
  sdk                      OGAS SDK: общий код модулей на Python и Rust, его проверки и тестовые модули
  scripts/                 сборка поставки, перечень чужих лицензий, замеры и проверка правил с её собственными проверками;
  installer/               установщик Windows: сценарий NSIS, `setup.sh` — что он делает внутри Linux, его тексты на двух языках
                           сами проверки правил — в scripts/rules/, файл на группу правил
  assets/                  марка для ярлыка
  work file/               макеты мастерской
  .github/workflows/       CI: запускает `make ci`

Документы лежат только в docs/; их состав — карта документации. В корне лежат рабочие файлы репозитория, а не документы продукта: README.md, лицензия LICENSE и сведения NOTICE о том, что под какой лицензией, условия правки со стороны CONTRIBUTING.md, Makefile, запуск ogas, ogas.cmd и ярлык ogas.desktop, файлы сборки Rust и версия Rust rust-toolchain.toml, рабочая область редактора Concept.code-workspace. Проверки общего кода модулей — в sdk/tests/, тестовые модули, на которых они идут, — рядом, в tests/doubles/: элемент приходит и уходит вместе со своими проверками (правило 2.10). Автор проверяет свой модуль без платформы помощником SDK sdk/python/ogas_check.py и держит такие проверки в папке модуля (test_<id>.py); make ci проверяет платформу, а не модули человека.

А.2 Ядро — core/kernel/

Ядро содержит только то, на чём держится платформа. Новая функция добавляется записью в реестре, а не файлом в ядре.

core/kernel/
  settings.schema.json   схема ключей core.*: умолчания и допустимые значения
  locales/{ru,en}.json   названия и подсказки ключей core.* для человека
  src/
    main.rs              точка входа: разбор командной строки, сигналы, выбор глагола
    codes.rs             коды ошибок ядра
    constants.rs         внутренние величины ядра и сроки, которые не настраиваются

Таблица А.1 — Ядро — core/kernel/

Файл За что отвечает
main.rs точка входа: разбор командной строки, сигналы, выбор глагола
state.rs состояние ядра: подключённые функции, их OS-процессы, счётчики, снимок core.status
connections.rs учёт функций: регистрация после знакомства, права, проверка собеседника, недоступность
routing.rs пересылка вызова хозяину метода и ожидание ответа
methods.rs разбор методов core.*: таблица «метод → файл задачи»
commands.rs память команд: повторная доставка по command_id
events.rs события: номер, рассылка, память последних, досылка подписчику
health.rs проверка здоровья функций: вопрос по сроку, отказ и остановка молчащей
paths.rs пути внутри папки установки и папки данных, граница папки данных
boot.rs замок экземпляра, папки, чтение реестра, журнал запуска
lifecycle.rs порядок запуска функций, перезапуски, пробуждение, каскад недоступности, остановка всего запущенного экземпляром
server.rs приём соединений, handshake и разбор сообщений соединения, работа сервера до остановки
cli.rs глаголы командной строки: разбор, глаголы реестра и их проверка, подстановки в вызовы
doctor.rs глагол doctor: собственные признаки ядра и проверки среды, объявленные функциями
process.rs методы core.process.*: запуск модулей, pidfd, потоки ввода-вывода
document.rs методы core.document.*: чтение, запись, список и удаление файлов в папке данных
settings.rs значения core.*: схема, файлы core.json и system.json, проверка пределов
os.rs обращения к системе: pidfd, flock, путь сокета, замена файла целиком
codes.rs коды ошибок ядра (Коды ошибок)
constants.rs внутренние величины ядра с объяснением, почему выбрано такое значение
tests.rs проверки ядра без запуска OS-процессов

Сквозные проверки — в core/kernel/tests/: hostile.rs (испорченные реестры, замок, отказ handshake), transfer.rs (экспорт и добавление процесса), runs.rs (хранение прогонов), wake.rs (повторный запуск), cli.rs (глаголы командной строки на процессах из fixtures/processes/), latency.rs (замер задержки, запускается вручную), common/ (общий каркас этих проверок), fixtures/ (тестовые функции на Python).

Функции запускает lifecycle.rs, модули — process.rs по просьбе функции с правом process.

Ядро стартует раньше функции настроек, поэтому ключи core.* оно читает само — по своей схеме и своим файлам уровней.

А.3 Функция платформы — functions/<id>/

У всех функций одно устройство:

functions/<id>/
  Cargo.toml
  function.json          что функция такое: зависимости, договор, окно, перезапуск (Форматы файлов, раздел 3)
  settings.schema.json   схема настроек функции, если они есть: ключи, умолчания, допустимые значения
  locales/{ru,en}.json   тексты для человека: названия и подсказки настроек, ошибки, подписи
  src/
    main.rs              точка входа: `start_function` — запуск и знакомство с ядром, таблица «метод → файл задачи»
    state.rs             состояние службы: что функция держит в памяти, пока работает
    codes.rs             коды ошибок функции
    constants.rs         форматы документов и внутренние величины функции
    <задача>.rs          одна задача — один файл
    <задача>/            задача с подзадачами — папка: mod.rs и по файлу на подзадачу

Таблица А.2 — Функция платформы — functions/<id>/

Функция Файлы и их задачи
graph state (состояние службы: включённые программы, идущие прогоны и их итоги, остановленное, замки узлов), check (проверка процесса по запросу, вместе с тем, во что разворачиваются его вызовы), process (создание, открытие, сохранение и список процессов), summary (что библиотека показывает о программах: размер, узлы, модули, очертание графа), run (запуск, остановка, повтор, продолжение, шаг узла), program (включённая программа: включение и выключение, её события и правила их наложения), variables (переменные программы и запомненные значения в state.json), asks (вопросы человеку), signals (сигналы извне, которых ждут ветки), notices (части результата шага и пакеты службы), objects (сквозные объекты программы для пульта), schedule (ближайший срок события по часам), changes (события о записанных документах), worker (исполнитель идущего прогона: вызовы модулей, запись контрольных точек, события), modules (что граф знает о модулях: порты, типы, семантика, выгрузка), nodes (набор видов узлов, их шаблоны и допустимые соединения узла), kinds/ (по папке на вид узла — описание вида, шаг, проверка или разворачивание вызова, слова, знак, проверки; правило 2.10), settings (свои настройки), storage (чтение и запись документов процесса), generation (поколения файлов), insert (вставка графа другого процесса), wrap (обёртка узлов в группу), runs (прошлые прогоны в папках процессов и уборка), transfer (экспорт и добавление процесса), runtime/ (выполнение: types, ports — порты видов из их описаний, validate, queue, field — поле пакета по пути, groups — группы, их дерево и лицо, region — рамки и части, candidates, checkpoint, substitute, read — документ процесса, как его пишет эта версия, rename — переименование переменной вместе со всем, что её называет, run_variables — переменные прогона, steps — шаги модулей, идущие рядом с прогоном, execute — цикл прогона; upgrade — сокращённая запись графов в тестах движка, test_support — общее для тестов движка и видов)
modules state (поднятые модули и чьи они, идущие шаги, сохранившие состояние, шлюз видеопамяти), catalog (установленные модули, проверка манифеста, список), create (новый модуль по шаблону OGAS SDK sdk/templates/python-basic/), manifest (что говорит манифест и верно ли), texts (слова, которые модуль приносит в своих словарях), networks (готовые сети помощника из OGAS SDK, их установка и секреты модуля в .env), states (память узлов процесса, как её видит человек), install (установка окружения процесса по команде), lock (modules.lock.json: версии и отпечатки модулей процесса), run/ (запуск модуля, по файлу на задачу: step — шаг и отмена, process — OS-процесс модуля, unload — выгрузка, gpu — бюджет видеопамяти, service — службы, ping — проверка, отвечают ли долгие модули и службы, stream — stdout и stderr модуля; fake_kernel — ядро в проверках: отвечает на вызовы функции и отдаёт ответы модуля как его stdout), pyenv (интерпретатор, окружение процесса, план запуска), artifacts (рабочая папка и файлы результатов), digest (отпечаток модуля), transfer (копирование модулей и просмотр экспорта), models (папка нейросетей: виды, список, приём скачанной, удаление, каких нейросетей не хватает программе), hardware (что есть у компьютера: видеокарты с их памятью, память, ядра, место на диске нейросетей)
settings state (схемы хозяев, значения сессии, уже названные отказы), levels (уровни значений), schema (сборка схем хозяев, схема core.* от ядра при запуске), values (чтение, запись и сброс значений), validate (проверка значения по схеме)
observe state (журнал, его размер и список проблем), journal (запись и чтение журнала событий), problems (проблемы и problems.json)
canvas state (соединение, через которое функция отвечает), workspace (документ пульта workspace.json: чтение, запись, пустой пульт), document (форма документа: что отклоняется и что дополняется — идентификатор, раздел, размер и место элемента), snapshot (данные для окна: разделы и элементы вместе со сквозными объектами процесса, отметки, числа листа), renames (привязки идут за переименованиями графа), settings (числа листа, вид пульта по умолчанию и предел размера рисунка — настройки функции), images (рисунки пульта в папке процесса: проверка, чтение, запись, перенос с процессом), looks (виды элементов — свои, из папки процесса, и встроенные: проверка документа вида, чтение, запись), elements/ (набор элементов: папка на элемент с описанием, словарями и встроенными видами)
i18n state (где лежат словари), catalog (сборка словарей из папок хозяев)
sources state (идущие и прошлые загрузки сеанса), settings (адреса источников и пределы), net (обращение в сеть через curl системы и контрольная сумма через sha256sum), names (имена и пути файлов, пришедших из сети, и что брать по умолчанию), thing (вещь источника в одном виде для всех источников), query (по чему каждый вид источника отбирает и в каком порядке отдаёт, и проверка запроса поиска), hub (Hugging Face), civitai (Civitai), catalog (витрина ogas.catalog/1), download (загрузка: файлы, пределы, проверка, передача хозяину)
gate door (слушатель, ключ, вошедшие программы и что им можно), settings (открыт ли вход, порт, сколько программ)
profile state (соединение, папка данных, неотправленное, что идёт), keys (код восстановления, ключ компьютера с поручительством, ключ писем), keyfile (файл ключа и пароль на нём), profile (профиль: создать, подключить, карточка, отозвать, удалить, выйти), parcel (поля видов посылок, тело, подпись), work (задачка на счёт), send (неотправленное, отправка, свои отправки), actions (посылки от ключа компьютера и вещи для «Предложить»), offer (файлы вещи: что уходит и что остаётся), check (взгляд на сайт: состояния, письма, доска, отзывы, профили), site (файлы сайта с проверкой подписи), letters (письма профилю), store (документы профиля через ядро), settings (свои настройки)
assistant task (задача, её поток и пределы), tools (инструменты и права), prompt (указание сети), store (документы помощника), settings (пределы)
ui relay (приём окна: порт, токен сессии, методы, события), launch (запуск программы окна и повторное открытие), face (лицо программы, которое попросил запуск), layout (раскладка окон между запусками), library (библиотека: панели программ и скрытое), locales (словари функции и окон), font (файл шрифта для окна), settings (схема ui.* и умолчания для окна); window/ — сама программа окна

Новая команда — строка в таблице методов main.rs и функция в файле своей задачи, а не новый пакет кода. Новый файл появляется, когда у функции появляется новая задача.

Общий код — в core/protocol, по файлу на задачу; lib.rs только перечисляет их:

Программа окна подключает этот же код, кроме частей для Unix, — так предел строки и другие константы у окна те же, что у всех.

А.4 Мастерская — functions/ui

Функция ui работает в WSL, программа окна — в Windows. Устройство окна — Мастерская, раздел 4.

functions/ui/
  src/           функция ui (Linux): main, relay, launch, face, layout, library, locales, font, settings
  window/        программа окна (Windows, Tauri 2): свой набор пакетов Cargo, цель x86_64-pc-windows-msvc
    src/         main.rs — окно Windows и команды страницы; link.rs — связь с функцией ui: ждущие ответа вызовы,
                 состояние связи; connect.rs — соединение и знакомство, чтение ответов и событий, конец связи
    tauri.conf.json, capabilities/, icons/
    cdp.py       проверка страницы из WSL средствами отладки WebView2 (только для разработки)
    ui/          страница, встроенная в исполняемый файл
      index.html, style.css, app.js   вход в страницу: связывает части между собой
      start.js     запуск страницы, когда есть связь: вид, данные платформы, события, отложенные настройки
      desk.js      перерисовка: вид и надпись о связи, раскладка после замера хоста, окна
      keys.js      клавиатура страницы
      shell.js     области: марка, полоса сверху, бары по краям, хост; окна и перетаскивание
      faces.js     общие формы: бар в трёх состояниях, вкладка окна
      windows.js   окна на хосте: размер, прилипание, разворот, свёртка
      events.js    события платформы → состояние; пропуск событий → запрос всего состояния
      lib/         dom (обновление страницы), rpc (запросы), look (`ui.*` → CSS), glyphs (значки), labels (тексты), font,
                   units (размеры словами)
      state/       общее состояние мастерской — то, что читают или делают несколько окон, по файлу на задачу: session,
                   documents (документы процесса в правке и шаги назад), process (открытый процесс: документы от хозяев,
                   программа, сохранённое, проверка), processes (переход к другому процессу, создание, ввоз и вывоз),
                   pulpit (полоса пульта и её ячейки), run (программа в работе), overlay (состояние прогона), settings,
                   modules (каталог модулей), workspace (данные платформы вокруг процесса), parts (какие части платформы
                   не работают и почему), layout
      host/        окна на хосте; каждое — своя папка (правило 2.10): index.js — описание окна (название, знак, бар, части платформы,
                   которые окно показывает, свои поля сессии, крючки),
                   view.js — вид, state.js — то, что делает только это окно, locales/ — слова, которые говорит только оно,
                   style.css — свой вид, tests.js — свои проверки;
                   index.js — единственный список окон; frame.js — тело окна по Мастерская, 5.1; controls.js — то, что показывают несколько окон;
                   окна — по папке на окно, их список — host/index.js, их состав — Мастерская, таблица 1
      tests/       проверки общего состояния и каркаса и их приспособления (fixtures.js); run.js запускает и их, и проверки окон; всё — в WebView2 окна
      fonts/       встроенный шрифт (DejaVu Sans) и его лицензия

Новое окно на хосте — новая папка в host/ и строка о ней в host/index.js, единственном списке окон: геометрия окон и каркас берут виды окон оттуда, а не держат свои списки. Соседнее окно при этом не правится (правило 2.10). Текст, который говорит одно окно, лежит в его locales/; общий словарь functions/ui/locales — для оболочки, общих частей страницы и самой функции, и make ci проверяет, что в нём нет текстов одного окна. Тело окна собирается из host/frame.js, а не рисуется заново. В бар окно встаёт по своему описанию (bar, order), и голову бара открывает окно, которое её назвало (heads); новый бар — элемент в shell.js; новая кнопка вкладки — элемент списка в файле этого окна.

Марка для ярлыка — assets/ogas-mark.svg (используется в ogas.desktop); в окне — window/ui/mark.svg, значок программы — window/icons/icon.ico.

А.5 Модуль — modules/<id>/

modules/<id>/
  manifest.json          порты и параметры модуля
  main.py                точка входа: разбор сообщения и вызов своей задачи
  locales/{ru,en}.json   название, описание и подсказки модуля
  test_<id>.py           проверки модуля без платформы, если они есть
sdk/                      OGAS SDK
  ogas-sdk               команда автора: new, check, try, pack, status, catalog, run
  python/                SDK для Python; лежит на PYTHONPATH модуля
    ogas_runtime.py      модуль на Python: протокол, чтение шага, ответ, отказ, слова, память узла
    ogas_models.py       общее модулей с нейросетями и картинками
    ogas_assistant.py    общее сетей помощника
    ogas_check.py        проверка модуля без платформы: договор по файлам и разговор по протоколу
    ogas/                пакет для программ снаружи: вход в платформу, программа сценарием, команда ogas-sdk
  rust/                  пакет ogas-module: то же для модуля на Rust
  templates/             шаблоны модулей
  networks/              сети помощника — готовые модули
  examples/              примеры модулей и программ
  tests/                 проверки самого SDK: отказ, сбой в работе шага, падение, шум в stdout, отмена
    doubles/<id>/        тестовые модули: устроены как модуль человека, но не ставятся и не едут в поставку
    live/<задача>/       испытание на живой задаче: modules/<id>/ — его модули, process/ — процессы, samples/ или make_reference.py — исходные данные;
                         не ставятся, в поставку не едут, весов моделей не содержат, make ci их не запускает

Модуль не подключает код соседнего модуля. Общее — только OGAS SDK (sdk/) и обмен по stdin / stdout. Что лежит в папке модуля — Модули, раздел 2.

А.6 Документы

Состав документации — карта документации. Документация частью платформы не является и в поставку не входит (Правила разработки, 2.11).

Оформление мастерской — токены в lib/look.js и style.css внутри functions/ui/window/ui/; рамку окна рисует каркас (shell.js), окно на хосте — только своё содержимое. Правило — Мастерская, раздел 7, «Единый вид оболочки».

А.7 Ограничения структуры

Приложение Б (справочное). Допущения