Arc OS — Архитектура

Обзор

Arc OS заменяет 11 321 строку кастомной Python/JS-инфраструктуры нативными инструментами Claude Code. AI-агент и есть бэкенд.

Системная архитектура (Phase 52.1)

graph TB
    User[👤 Браузер пользователя :18888]
    TG[📱 Telegram]
    Local[💻 Локальная IDE]

    subgraph "Edge"
      Nginx[Nginx :18888<br/>basic-auth + deny-list]
      FE[React CRM + Phaser<br/>frontend container]
    end

    subgraph "Master Bot Bun :19210 — только 127.0.0.1"
      ApiSrv[api-server.ts<br/>196 LOC]
      Routes[master-bot/routes/<br/>auth · internal · cli · websocket]
      Router[shared/routes/router.ts<br/>373 LOC dispatcher]

      subgraph "19 доменных модулей — Phase 48"
        D1[auth · projects · workers]
        D2[skills · sage · chat]
        D3[wiki · files · onboarding]
        D4[billing · invites · analytics]
        D5[+ 7 других]
      end
    end

    subgraph "Федеративные боты"
      Master[Master Bot<br/>оркестратор]
      Child[Child Bots<br/>на каждый проект]
      Claude[claude -p CLI]
    end

    subgraph "Слой интеллекта"
      Eval[Binary Evals]
      Ctx[Context Router top-5]
      Learn[Learnings inject]
      Karp[Karpathy nightly loop]
    end

    NB[NotebookLM Bridge<br/>FastAPI :19213 localhost]
    Google[(Google NotebookLM)]

    DB[(SQLite WAL<br/>21+ таблиц<br/>migrations 001-021)]
    Vault[(AES-256-GCM Vault<br/>config/vault.json)]
    Bridge[Local Bridge CLI<br/>WebSocket relay]

    User -->|HTTPS| Nginx
    Nginx --> FE
    Nginx -->|/api/crm/*| ApiSrv
    Nginx -->|/api/sse/*| ApiSrv
    Nginx -->|/ws/terminal| ApiSrv
    ApiSrv --> Routes
    Routes --> Router
    Router --> D1 & D2 & D3 & D4 & D5

    TG --> Master
    TG --> Child
    Master -.spawns via tmux.-> Child
    Child --> Claude
    Claude --> Eval & Ctx & Learn

    Router -.queries.-> NB
    Child -.auto-sync.-> NB
    NB --> Google

    Router --> DB
    Router --> Vault
    Child --> Vault

    Local --> Bridge
    Bridge -.ws relay.-> ApiSrv
    Karp -.nightly.-> DB

Ключевые факты:

LEGACY (v1):
User → Telegram Bot (Python 111KB) → HybridEngine → command_queue.json
       → bridge_processor.sh → Claude → command_responses.json
       → FastAPI EventBus → WebSocket → Phaser UI

V2 (NATIVE-FIRST):
User → Official Telegram Channel → Claude Code Session
       ↓                                ↓
       reply/edit_message          Agent Teams (TaskCreate/SendMessage)
                                        ↓
                                   Write state → JSON files
                                        ↓
                                   Arc OS Bridge MCP → HTTP/SSE → Phaser UI

Сокращение кода: 11 321 строка → ~3 700 строк (67% меньше)

Компоненты

1. Claude Code Session (Мозг)

Claude Code session заменяет:

Вся оркестрация происходит нативно через Agent Teams.

2. Arc OS Bridge MCP Server (State Adapter)

TypeScript MCP-сервер (Bun), который связывает состояние Claude Code с фронтендом.

MCP Tools (со стороны Claude Code):

Инструмент Направление Описание
get_office_state read Читает state/office-state.json
update_agent_state write Обновляет позицию, статус и bubble агента
get_tasks read Читает файлы задач Agent Teams
get_knowledge read Читает индекс знаний

HTTP API (со стороны фронтенда):

Эндпоинт Метод Описание
/api/state GET Полное состояние офиса
/api/tasks GET Список задач
/api/knowledge GET Индекс знаний
/api/events GET SSE-стрим

3. Phaser Frontend (Визуальный слой)

Phaser 3.80 + Vite. Подключается к MCP-серверу через HTTP/SSE.

Ключевое отличие от v1: нет WebSocket — заменён SSE от MCP-сервера. Нет UI для ввода команд — Telegram является командным интерфейсом.

4. Telegram Command Interface (Тактический слой UI — Phase 21.0)

Telegram — основная панель управления всем Arc OS. Два уровня ботов:

Master Bot (@citadel_ceo_bot):

Child Bots (@cv2_pt_bot и т.д.):

Интеграция с CRM (разработка):

CRM_BASE_URL = http://62.171.128.248:18888  (dev)
               https://crm.citadel.v2       (будущий prod)

Все раскладки клавиатур определены в shared/ui_templates.ts — единый источник изменений UI.

Протокол callback data: action:target (макс. 64 байта)

Поток данных

1. Пользователь отправляет "/status" через Telegram
2. Claude Code session получает через Telegram Channel
3. Rick читает state/office-state.json + TaskList()
4. Rick отвечает через Telegram (edit_message для обновлений в реальном времени)
5. Rick вызывает update_agent_state() через MCP
6. MCP-сервер пишет в state/office-state.json
7. Файловый вотчер обнаруживает изменение → пушит SSE-событие
8. Фронтенд получает SSE → обновляет спрайты агентов

Управление состоянием

Всё состояние хранится в JSON-файлах в state/:

Файл Схема Обновляется Читается
office-state.json Позиции агентов, статус, bubble Claude (через MCP) Фронтенд (через HTTP)
knowledge.json Индексированные метаданные файлов Агент Squanchy Фронтенд, Beth
reports/*.json Результаты анализа Beth, Summer Фронтенд

Задачи Agent Teams управляются Claude Code нативно в ~/.claude/tasks/citadel-v2/.

Агенты (6)

Агент Роль Модель Активация
Rick CEO/Оркестратор opus-4.6 Всегда активен (тимлид)
Morty SRE/Мониторинг haiku-4.5 Health checks, cron
Summer Память/Ревью sonnet-4.5 Code review, безопасность
Jerry Обслуживание haiku-4.5 Очистка, доки
Squanchy Архивариус haiku-4.5 Индексация файлов
Beth Аналитик sonnet-4.5 Исследования, анализ

Supply Chain

CEO → Rick (декомпозиция) → Agent Team (выполнение)
                          → Cross-Review (Summer валидирует)
                          → Rick (синтез)
                          → CEO (финальный результат)

Обеспечивается через:

Технологический стек

Слой v1 v2
Бэкенд FastAPI + Python 3.12 Claude Code session
База данных SQLite (8 таблиц) JSON-файлы + Agent Teams
Сообщения WebSocket + EventBus Agent Teams SendMessage
Состояние SQLite + JSON bridge JSON-файлы (state/)
Фронтенд Phaser 3.86 + WebSocket Phaser 3.80 + SSE
Telegram Кастомный бот (111KB) Official Channel plugin
Bridge bash + jq (19.6KB) Устранён
MCP Нет Arc OS Bridge (TypeScript)
Деплой Docker Compose Docker Compose

Lifecycle Hooks

Claude Code hooks (~/.claude/settings.json) автосинхронизируют состояние агентов:

SubagentStop event → subagent-stop.sh → office-state.json (agent=idle)
                                              ↓
                                   StateManager (fs.watch) → SSE → Phaser UI

Stop event → session-end.sh → latest_wrapup.txt + all agents=idle

Скрипты: scripts/citadel-hooks/subagent-stop.sh, scripts/citadel-hooks/session-end.sh

Ключевые поля: subagentName (SubagentStop), stopReason (Stop), cwd (оба).

NotebookLM Bridge (Phase 36.3)

Настоящий семантический поиск через Google NotebookLM, заменивший ручную загрузку файлов:

Cloud PM Chat → Bun Master Bot (:19210)
                    │
         executeAskNotebooklm()
                    │
         HTTP → FastAPI Bridge (:19213, только localhost)
                    │
              notebooklm-py async client
                    │
              Google NotebookLM (бесплатный семантический поиск)

         Fallback: локальный поиск по ключевым словам (существующий код)

Экспорт на основе файлов (legacy: /citadel-wrapup, /citadel-recall) по-прежнему доступен как fallback.

Политика маршрутизации данных и задач

Трёхуровневая система. У каждого уровня строгое назначение. Смешивать уровни — значит создавать хаос.

┌─────────────────────────────────────────────────────────────────┐
│  УРОВЕНЬ 1: Рабочая память (горячий)                            │
│  office-state.json + state/tasks/                               │
│  CLI: /citadel-task, /citadel-status                            │
│                                                                 │
│  Ежедневные задачи агентов. Живёт во время сессии. Исчезает.   │
│  Завершённая задача → /citadel-wrapup → Уровень 3.             │
├─────────────────────────────────────────────────────────────────┤
│  УРОВЕНЬ 2: Стратегический бэклог (тёплый)                     │
│  GitHub Issues (репозитории Claude-CEO + citadel-v2)           │
│                                                                 │
│  Только эпики: Phase 20, Phase 21, глобальные баги.            │
│  Никаких ежедневных задач. Никаких "fix typo" задач.           │
│  Один Issue = одна многонедельная инициатива или критический дефект. │
├─────────────────────────────────────────────────────────────────┤
│  УРОВЕНЬ 3: Долгосрочная память (холодный)                     │
│  docs/library-export/ → Google Drive → NotebookLM              │
│  CLI: /citadel-wrapup, /citadel-recall                          │
│                                                                 │
│  Энциклопедия. Результаты сессий, архитектурные решения, RAG.  │
│  Архив только для чтения. Без активных задач. Без трекинга.    │
└─────────────────────────────────────────────────────────────────┘

Правила маршрутизации

Тип данных Уровень Пример
"Исправить скрипт деплоя" 1 — Рабочая память /citadel-task "Fix deploy script"
"Phase 20: Multi-Tenant SaaS" 2 — GitHub Issues gh issue create --title "Phase 20: ..."
"Итог сессии: хуки внедрены" 3 — Библиотека /citadel-wrapup → NotebookLM
"Архитектурное решение: выбрали SSE вместо WS" 3 — Библиотека Архивируется в wrapup после сессии
"Баг: SSE обрывается на VPS" 2 — GitHub Issues Только если межсессионный / блокирующий
"Rick работает над хуками" 1 — Рабочая память office-state.json статус агента

Жизненный цикл

CEO ставит задачу → Уровень 1 (агент работает над ней)
                         ↓ выполнено
                     /citadel-wrapup → Уровень 3 (архивируется)
                         ↓ если стратегическое
                     gh issue create → Уровень 2 (отслеживается долгосрочно)

Антипаттерны (НЕ ДЕЛАТЬ)

Инфраструктура (Phase 20.5)

Структурированное логирование (shared/logger.ts)

Формат JSONL, двойной вывод (файл + консоль), ежедневное разбиение файлов по категориям.

/var/log/citadel/
├── master/
│   ├── system-2026-04-02.log   ← lifecycle, конфиг, health
│   ├── dialog-2026-04-02.log   ← (master не использует)
│   └── error-2026-04-02.log    ← ошибки (также в system)
├── citadel-v2/
│   ├── system-2026-04-02.log
│   ├── dialog-2026-04-02.log   ← сообщения user ↔ Claude
│   └── error-2026-04-02.log
└── <project-name>/             ← на каждый онбордированный проект

Ротация логов: config/logrotate-citadel.conf/etc/logrotate.d/citadel (ежедневно, хранение 7 дней).

Secrets Vault (shared/vault.ts)

Зашифрованное AES-256-GCM хранилище для токенов ботов.

Источник ключа: SECRET_ENCRYPTION_KEY env → файл config/vault-key → автогенерация
Хранение:       config/vault.json (атомарные записи: tmp + mv)
Кэш:            В памяти после initVault() — нет I/O диска при getSecret()
Fallback:       getSecret("FOO") → vault cache → process.env.FOO
Именование:     child:<project-name>:token

Собственный токен Master-бота остаётся в .env (vault загружается внутри процесса master).

Self-Healing Watchdog (master-bot/watchdog.ts)

Фоновый монитор для дочерних ботов. Запускается внутри процесса master-бота.

Каждые 30с: HTTP health check → /api/child/health (таймаут 5с)
  Здоров → сбрасывает счётчик ошибок
  Нездоров → увеличивает счётчик ошибок
  3+ ошибки + бэкофф истёк → автоперезапуск (kill tmux → новый старт с vault-токеном)
  Бэкофф: 30с → 1м → 5м → 15м → 60м (предел)
  10 последовательных ошибок → постоянное отключение + уведомление CEO

Состояние сохраняется в config/watchdog-state.json (переживает перезапуск master). Уведомления CEO через Telegram: первый перезапуск, ошибка перезапуска, постоянное отключение. Команда /watchdog: статус всех дочерних ботов в реальном времени.

Протокол удаления проекта (Phase 20.4 + 21.0)

/remove_project <name> → тройное подтверждение → полная очистка:

1. Убить tmux-сессию: child-<name>
2. Массовое уничтожение призраков: ps aux | grep child-<name> → kill -9 all PIDs
3. Проверка порта: ss -tlnp | grep :<port> → принудительное освобождение при занятости
4. Удалить из bot_registry.json + перезагрузить в памяти
5. Удалить /opt/repos/<name>/ (безопасность: путь должен быть под /opt/repos/, мин. 3 сегмента)
6. Удалить /var/log/citadel/<name>/

Защищённые имена: citadel-v2, citadel, claude-ceo, claude-CEO — удаление заблокировано.

Проблема призрачных процессов (урок): после kill tmux сиротские процессы bun могут занимать порты. Массовый kill + проверка порта предотвращают "фантомных ботов", которые отвечают на health check, но игнорируют Telegram.

Управление скиллами (Phase 21.0)

Дочерние боты загружают скиллы из двух источников при запуске, дедуплицируя через Set:

Источник 1: MANIFEST.md (JSON)
  → manifest.skills[]          (сопоставлено при онбординге)
  → manifest.library_skills[]  (сопоставлены .md-файлы библиотеки)

Источник 2: директория skills/
  → *.md файлы → имя файла без расширения

Merge: Set<string>(manifest.skills + manifest.library_skills + skills/*.md)

Пример (проект PT): 5 из manifest + 7 из skills/ = 12 уникальных скиллов.

Скиллы отображаются как:

Безопасность (Phase 42 — аудит Sentinel 2026-04-23, 4 прохода, 13 патчей)

Полный обзор: SECURITY.md. Отчёт об аудите: security/audit-2026-04-23.md.

Секреты и хранение:

Auth:

Мультитенантность (Phase 42):

Сетевой периметр:

Безопасность ввода и путей:

Регрессионное покрытие: scripts/vps-sync.sh запускает 7+ post-deploy smoke-тестов после каждого деплоя (loopback bind, path traversal, валидация chat/save, proxy canary, SSE ?token=, fail-closed валидация, SSRF-блок при наличии CEO_TOKEN).

Модули Master Bot (Phase 25 — решение DEBT-1)

Master-бот организован в специализированные модули:

master-bot/
├── bot.ts               ← Bootstrap: vault, реестр, контекст, всё связывает (106 строк)
├── context.ts           ← Тип MasterContext + доменные интерфейсы
├── api-server.ts        ← Bun.serve() — HTTP, WebSocket, SSE, CRM-маршруты
├── tg-api.ts            ← Обёртка Telegram Bot API (sendMessage, getUpdates и т.д.)
├── child-state.ts       ← Читает состояние дочернего бота, health, heartbeat, tmux, bridge
├── telegram-commands.ts ← Все обработчики /команд, роутер callback-запросов, маршрутизатор сообщений
├── telegram.ts          ← Минималистичный polling loop + реэкспорты для обратной совместимости
├── watchdog.ts          ← Self-healing монитор дочерних ботов
└── onboarding.ts        ← Интерактивный мастер создания проектов

bot.ts импортирует только из telegram.ts и api-server.ts. Все остальные модули — детали внутренней реализации.

Bridge CLI (Phase 25 — Local Gateway)

bridge/
├── bin/citadel-bridge.ts    ← CLI entry (commander.js): connect, pull, push, status, disconnect
├── src/
│   ├── auth.ts              ← Валидация JWT через CRM
│   ├── config.ts            ← Персистентность ~/.citadel/bridge.json
│   ├── inject.ts            ← Маркеры CLAUDE.md <!-- CITADEL:START/END -->
│   ├── sync.ts              ← Pull skills-bundle + learnings, push local learnings
│   └── heartbeat.ts         ← Репортёр активности сессии
├── package.json
└── tsconfig.json

CRM API Endpoints (50+ всего)

Core CRM (Phase 22)

Эндпоинт Метод Назначение
/api/master/health GET Health master-бота (публичный)
/api/crm/projects GET Список всех проектов + live health
/api/crm/projects/:name GET Детали проекта
/api/crm/projects/:name/logs GET Tail JSONL-логов
/api/crm/projects/:name/files GET Безопасный листинг директории
/api/crm/projects/:name/files/upload POST Загрузка файлов
/api/crm/projects/:name/files/mkdir POST Создание папки
/api/crm/projects/:name/files/create POST Создание файла
/api/crm/projects/:name/files/delete DELETE Удаление файла/папки
/api/crm/projects/:name/files/clone POST Клонирование git-репозитория
/api/crm/projects/:name/files/read GET Чтение содержимого файла
/api/crm/projects/:name/wiki/tree GET Список .md-файлов вики
/api/crm/projects/:name/wiki/file GET Чтение файла вики
/api/crm/projects/:name/skills GET Установленные скиллы
/api/crm/projects/:name/metrics GET Временной ряд качества
/api/crm/projects/:name/restart POST Перезапуск дочернего бота
/api/crm/projects/:name/specs GET Список спеков
/api/crm/projects/:name/specs/:id/approve POST Одобрить спек
/api/crm/projects/:name/specs/:id/reject POST Отклонить спек
/api/crm/projects/:name/active-role GET/POST Роль агента
/api/crm/projects/:name/message POST Поставить сообщение в очередь воркера
/api/crm/projects/:name/workers GET/POST CRUD реестра воркеров
/api/crm/projects/:name/workers/:id PUT/DELETE Обновить/удалить воркер
/api/crm/projects/:name/workers/generate-prompt POST AI-генерация system prompt
/api/crm/projects/:name/skills-bundle GET Скиллы + evals для bridge
/api/crm/projects/:name/learnings GET/POST Синхронизация learnings
/api/sse/logs/:name GET SSE-стрим логов (?category=)

Дашборд и вики (Phase 32)

Эндпоинт Метод Назначение
/api/crm/projects/:name/wiki/save PUT Сохранить/создать страницу вики
/api/crm/projects/:name/skills/save PUT Сохранить файл скилла
/api/crm/projects/:name/skills/delete DELETE Удалить файл скилла

Мультитенантность (Phase 33)

Эндпоинт Метод Назначение
/api/crm/account/settings GET/PUT API-ключи на уровне аккаунта
/api/crm/projects/create POST Облегчённое создание проекта
/api/crm/onboarding/setup POST Полный мастер онбординга

MCP и CLI (Phase 34)

Эндпоинт Метод Назначение
/api/mcp/issues/:project POST/GET CRUD задач
/api/mcp/issues/:project/:id PUT Обновить задачу
/api/mcp/wiki/:project PUT Синхронизация вики через MCP
/api/mcp/roadmap/:project GET/PUT Чтение/синхронизация roadmap
/api/cli/init/:project/:mode GET Облачный контекст для CLI
/api/mcp/skills/:project/:skill GET Получить скилл для MCP
/api/mcp/report/:project POST Mission report
/api/mcp/learnings/:project GET Получить learnings для MCP

Живой терминал (Phase 35)

Эндпоинт Метод Назначение
/api/crm/projects/:name/terminal/log POST Получение терминального JSONL от ARC CLI

Cloud PM и знания (Phase 36)

Эндпоинт Метод Назначение
/api/crm/projects/:name/chat POST SSE chat proxy к Anthropic API
/api/crm/projects/:name/skills/generate POST Neural Skill Generator (NotebookLM)
/api/crm/projects/:name/notebooks GET Связанные ноутбуки NotebookLM

Auth и OAuth (Phase 37)

Эндпоинт Метод Назначение
/api/auth/register POST Регистрация email/password
/api/auth/login POST Вход email/password
/api/auth/google GET Редирект OAuth Google
/api/auth/callback/google GET Callback OAuth Google
/api/auth/github GET Редирект OAuth GitHub
/api/auth/callback/github GET Callback OAuth GitHub
/api/auth/providers GET Доступные OAuth-провайдеры

Закреплённые заметки (Phase 41.8)

Эндпоинт Метод Назначение
/api/crm/projects/:name/pins GET Список закреплённых заметок (сначала новые)
/api/crm/projects/:name/pins POST Закрепить сообщение воркера в Context Rail (body: worker_id, body, опц. title, author)
/api/crm/projects/:name/pins/:id DELETE Удалить закреплённую заметку

Бэкенд: migration 009 (таблица pinned_notes), pinnedNoteQueries в shared/db.ts. Фронтенд: ContextRail.jsx получает данные при монтировании, слушает CustomEvent crm-pin-created, оптимистичный DELETE.

Слой защиты данных (Phase 45)

Гибридное шифрование at-rest — клиентский крипто-фундамент + серверное vault-шифрование.

Клиентская сторона (браузер)

Серверная сторона (Bun + SQLite)

Заголовки безопасности

PII-санитизация

Эндпоинты ключа восстановления

Эндпоинт Метод Назначение
/api/crm/account/recovery POST Создать ключ восстановления (сохраняет зашифрованный master key)
/api/crm/account/recovery GET Список активных ключей восстановления
/api/crm/account/recovery DELETE Отозвать ключ(и) восстановления
/api/crm/account/recovery/restore GET Получить зашифрованный master key для восстановления

Полные детали безопасности: docs/SECURITY.md, docs/architecture/PHASE_45_E2EE.md.