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

Огляд

Arc OS замінює 11 321 рядок кастомної Python/JS-інфраструктури нативними інструментами Claude Code. AI-агент І Є бекендом.

Системна архітектура (Phase 60)

graph TB
    User[👤 User Browser :18888]
    TG[📱 Telegram]
    Local[💻 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 only"
      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 Domain Modules — Phase 48"
        D1[auth · projects · workers]
        D2[skills · sage · chat]
        D3[wiki · files · onboarding]
        D4[billing · invites · analytics]
        D5[+ 7 more]
      end
    end

    subgraph "Federated Bots"
      Master[Master Bot<br/>orchestrator]
      Child[Child Bots<br/>per-project]
      Claude[claude -p CLI]
    end

    subgraph "Intelligence Layer"
      Eval[Binary Evals]
      Ctx[Context Router top-5]
      Learn[Learnings inject]
      Karp[Karpathy nightly loop]
    end

    RAG[shared/rag.ts<br/>Cohere + sqlite-vec]

    DB[(SQLite WAL<br/>50+ tables<br/>migrations 001-050)]
    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.-> RAG
    Child -.auto-sync.-> RAG
    RAG --> DB

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

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

    subgraph "Hetzner arc-cloud-prod 157.180.44.232 — Phase 60"
      HNet[arc-cloud-net bridge]
      C1[arc-user-xxxx<br/>claude CLI + child-bot<br/>2GB RAM / 1.5 CPU]
      C2[arc-user-yyyy<br/>...]
    end

    Router -.SSH hetzner_ed25519.-> HNet
    HNet --> C1 & C2
    TG -.wake + /continue.-> C1

Ключові факти:

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 (Мозок)

Сесія Claude Code замінює:

Уся оркестрація відбувається нативно через Agent Teams.

2. Arc OS Bridge MCP Server (Адаптер стану)

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

MCP-інструменти (сторона Claude Code):

Інструмент Напрям Опис
get_office_state read Читання state/office-state.json
update_agent_state write Оновлення позиції агента, статусу, бульбашки
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-інтерфейс команд (Тактичний UI-шар — Phase 21.0)

Telegram — це основна панель керування всією Arc OS. Два рівні ботів:

Master Bot (@citadel_ceo_bot):

Дочірні боти (@cv2_pt_bot тощо):

Інтеграція з CRM (у розробці):

CRM_BASE_URL = http://62.171.128.248:18888  (dev)
               https://crm.citadel.v2       (future prod)

Усі розкладки клавіатур визначені у shared/ui_templates.ts — єдине джерело для змін UI.

Протокол callback-даних: action:target (макс. 64 байти)

Потік даних

1. Користувач надсилає "/status" через Telegram
2. Сесія Claude Code отримує його через Telegram Channel
3. Rick читає state/office-state.json + TaskList()
4. Rick відповідає через Telegram (edit_message для live-оновлень)
5. Rick викликає update_agent_state() через MCP
6. MCP-сервер пише у state/office-state.json
7. File watcher помічає зміну → пушить SSE-подію
8. Фронтенд отримує SSE → оновлює спрайти агентів

Керування станом

Увесь стан живе у JSON-файлах у state/:

Файл Схема Хто оновлює Хто читає
office-state.json Позиції агентів, статус, бульбашки 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-перевірки, cron
Summer Пам'ять/Рев'ю sonnet-4.5 Code review, безпека
Jerry Обслуговування haiku-4.5 Прибирання, документація
Squanchy Архіваріус haiku-4.5 Індексація файлів
Beth Аналітик sonnet-4.5 Дослідження, аналіз

Ланцюг постачання

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

Забезпечується через:

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

Шар v1 v2
Бекенд FastAPI + Python 3.12 Сесія Claude Code
База даних 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) Офіційний Channel-плагін
Bridge bash + jq (19.6KB) Усунено
MCP Немає Arc OS Bridge (TypeScript)
Деплой Docker Compose Docker Compose

Хуки життєвого циклу

Хуки Claude Code (~/.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 (обидва).

Семантичний пошук — Self-hosted RAG (Phase 71, 2026-06-05)

Власний (self-hosted) retrieval поверх наявного SQLite SSOT. Замінює NotebookLM Bridge з Phase 36 (виведений з експлуатації, порт 19213 вільний, див. services/.archived-notebooklm-bridge-2026-06-05/ + docs/public/architecture/rag-architecture.md).

Chat / arc kb / Cloud PM
        │
        ▼
shared/rag.ts search()
        │
        ▼
shared/embeddings.ts  ──►  Cohere /v2/embed
  embedQuery(text)         (multilingual, 1024-dim float32)
        │
        ▼
embeddings_vec (vec0 virtual)  +  embeddings (metadata)
  KNN (k * 4 overfetch)  →  project + doc_type filter at JOIN  →  top-K passages

Fallback: executeLocalKnowledgeSearch (keyword scan over wiki + issues + roadmap)
          when top-hit distance > 1.6 or zero results (covers brand-new projects).

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

Трирівнева система. Кожен рівень має чітке призначення. Змішування рівнів = хаос.

┌─────────────────────────────────────────────────────────────────┐
│  TIER 1: Working Memory (Hot)                                   │
│  office-state.json + state/tasks/                               │
│  CLI: /citadel-task, /citadel-status                            │
│                                                                 │
│  Щоденні задачі агентів. Живуть під час сесії. Вмирають після.  │
│  Завершена задача → /citadel-wrapup → Tier 3.                  │
├─────────────────────────────────────────────────────────────────┤
│  TIER 2: Strategic Backlog (Warm)                               │
│  GitHub Issues (Claude-CEO + citadel-v2 repos)                  │
│                                                                 │
│  Лише епіки: Phase 20, Phase 21, глобальні баги.                │
│  Жодних щоденних задач. Жодних issue типу "виправити одрук".    │
│  Одне Issue = одна багатотижнева ініціатива або критичний дефект.│
├─────────────────────────────────────────────────────────────────┤
│  TIER 3: Long-term Memory (Cold)                                │
│  docs/library-export/ + вікі проєкту + закриті issue            │
│  → embedded via shared/rag.ts (Cohere + sqlite-vec, Phase 71)   │
│  CLI: /citadel-wrapup, arc kb search "<query>"                  │
│                                                                 │
│  Енциклопедія. Результати сесій, архітектурні рішення, RAG.     │
│  Read-only архів. Жодних активних задач. Без трекінгу статусів. │
└─────────────────────────────────────────────────────────────────┘

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

Тип даних Рівень Приклад
«Полагодити deploy-скрипт» 1 — Working Memory /citadel-task "Fix deploy script"
«Phase 20: Multi-Tenant SaaS» 2 — GitHub Issues gh issue create --title "Phase 20: ..."
«Підсумок сесії: хуки реалізовано» 3 — Library /citadel-wrapup → вікі + автоембединг через хуки Phase 71
«Архітектурне рішення: обрали SSE замість WS» 3 — Library Архівується у wrapup після сесії
«Баг: SSE обривається на VPS» 2 — GitHub Issues Лише якщо крос-сесійний / блокувальний
«Rick працює над хуками» 1 — Working Memory статус агента в office-state.json

Життєвий цикл

CEO дає задачу → Tier 1 (агент працює над нею)
                     ↓ завершено
                 /citadel-wrapup → Tier 3 (заархівовано)
                     ↓ якщо стратегічна
                 gh issue create → Tier 2 (довгостроковий трекінг)

Антипатерни (НЕ РОБИТИ)

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

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

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

/var/log/citadel/
├── master/
│   ├── system-2026-04-02.log   ← lifecycle, config, health
│   ├── dialog-2026-04-02.log   ← (not used by master)
│   └── error-2026-04-02.log    ← errors (also in system)
├── citadel-v2/
│   ├── system-2026-04-02.log
│   ├── dialog-2026-04-02.log   ← user ↔ Claude messages
│   └── error-2026-04-02.log
└── <project-name>/             ← per onboarded project

Ротація логів: config/logrotate-citadel.conf/etc/logrotate.d/citadel (щоденно, зберігання 7 днів).

Сховище секретів (shared/vault.ts)

Сховище токенів ботів, зашифроване AES-256-GCM.

Key source: SECRET_ENCRYPTION_KEY env → config/vault-key file → auto-generated
Storage:    config/vault.json (atomic writes: tmp + mv)
Cache:      In-memory after initVault() — no disk I/O per getSecret()
Fallback:   getSecret("FOO") → vault cache → process.env.FOO
Naming:     child:<project-name>:token

Власний токен майстра залишається в .env (vault завантажується всередині процесу майстра).

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

Фоновий монітор дочірніх ботів. Працює всередині процесу майстер-бота.

Every 30s: HTTP health check → /api/child/health (5s timeout)
  Healthy → reset failures
  Unhealthy → increment failures
  3+ failures + backoff elapsed → auto-restart (kill tmux → start new with vault token)
  Backoff: 30s → 1m → 5m → 15m → 60m (cap)
  10 consecutive failures → permanently disable + notify CEO

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

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

/remove_project <name> → потрійне підтвердження → повне очищення:

1. Kill tmux session: child-<name>
2. Mass Kill ghosts: ps aux | grep child-<name> → kill -9 all PIDs
3. Port check: ss -tlnp | grep :<port> → force-free if occupied
4. Remove from bot_registry.json + in-memory reload
5. Delete /opt/repos/<name>/ (safety: path must be under /opt/repos/, min 3 segments)
6. Delete /var/log/citadel/<name>/

Захищені імена: citadel-v2, citadel, claude-ceo, claude-CEO — видалення заблоковано.

Проблема процесів-привидів (вивчений урок): після kill tmux осиротілі процеси bun можуть тримати порти. Масовий kill + перевірка порту запобігають «фантомним ботам», які відповідають на health-перевірки, але ігнорують Telegram.

Керування навичками (Phase 21.0)

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

Source 1: MANIFEST.md (JSON)
  → manifest.skills[]          (matched during onboarding)
  → manifest.library_skills[]  (library .md files matched)

Source 2: skills/ directory
  → *.md files → filename without extension

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

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

Навички відображаються як:

Безпека (Phase 42 — аудит Sentinel 2026-04-23, 4 проходи, 13 патчів)

Повний огляд: SECURITY.md. Звіт аудиту: security/audit-2026-04-23.md.

Секрети та зберігання:

Автентифікація:

Multi-tenancy (Phase 42):

Мережевий периметр:

Безпека вводу / шляхів:

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

Модулі Master Bot (Phase 25 — закриття DEBT-1)

Майстер-бот організовано у сфокусовані модулі:

master-bot/
├── bot.ts               ← Bootstrap: vault, registry, context, wire everything (106 lines)
├── context.ts           ← MasterContext type + domain interfaces
├── api-server.ts        ← Bun.serve() — HTTP, WebSocket, SSE, CRM routes
├── tg-api.ts            ← Telegram Bot API wrapper (sendMessage, getUpdates, etc.)
├── child-state.ts       ← Read child bot state, health, heartbeat, tmux, bridge
├── telegram-commands.ts ← All /command handlers, callback query handler, message router
├── telegram.ts          ← Slim polling loop + re-exports for backward compat
├── watchdog.ts          ← Self-healing child bot monitor
└── onboarding.ts        ← Interactive project creation wizard

bot.ts імпортує лише з telegram.ts та api-server.ts. Усі інші модулі — внутрішні деталі реалізації.

Bridge CLI (Phase 25 — локальний шлюз)

bridge/
├── bin/citadel-bridge.ts    ← CLI entry (commander.js): connect, pull, push, status, disconnect
├── src/
│   ├── auth.ts              ← JWT validation against CRM
│   ├── config.ts            ← ~/.citadel/bridge.json persistence
│   ├── inject.ts            ← CLAUDE.md <!-- CITADEL:START/END --> markers
│   ├── sync.ts              ← Pull skills-bundle + learnings, push local learnings
│   └── heartbeat.ts         ← Session activity reporter
├── package.json
└── tsconfig.json

Ендпоінти CRM API (50+ загалом)

Основна CRM (Phase 22)

Ендпоінт Метод Призначення
/api/master/health GET Health майстер-бота (публічний)
/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-генерація системного промпту
/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 Видалення файлу навички

Multi-Tenant (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 задач (issues)
/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 Звіт місії
/api/mcp/learnings/:project GET Отримання learnings для MCP

Live Terminal (Phase 35)

Ендпоінт Метод Призначення
/api/crm/projects/:name/terminal/log POST Прийом термінального JSONL від ARC CLI

Cloud PM та знання (Phase 36, оновлення Phase 71)

Ендпоінт Метод Призначення
/api/crm/projects/:name/chat POST SSE-проксі чату до Anthropic API
/api/crm/projects/:name/skills/generate POST Neural Skill Generator. Phase 71.7: переведено з NotebookLM-як-генератора на Claude Sonnet із RAG-доповненим контекстом (top-5 результатів як приклади house-style).
/api/crm/projects/:name/rag/search GET Phase 71.7 (новий): семантичний пошук поверх embeddings + embeddings_vec (Cohere + sqlite-vec). ?q=...&k=6&include_global=true&doc_types=wiki,issue,skill.
/api/crm/projects/:name/notebooks GET Phase 71.8: legacy-заглушка — повертає { notebooks: [], retired: "phase-71.8" }.

Auth та OAuth (Phase 37)

Ендпоінт Метод Призначення
/api/auth/register POST Реєстрація через email/пароль
/api/auth/login POST Логін через email/пароль
/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 Видалити закріплення

Бекенд: міграція 009 (таблиця pinned_notes), pinnedNoteQueries у shared/db.ts. Фронтенд: ContextRail.jsx робить fetch при монтуванні, слухає CustomEvent crm-pin-created, оптимістичний DELETE.

Шар захисту даних (Phase 45)

Гібридне шифрування at-rest — клієнтська криптографічна основа + серверне шифрування сховища.

Клієнтська сторона (браузер)

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

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

Санітизація PII

Ендпоінти ключів відновлення

Ендпоінт Метод Призначення
/api/crm/account/recovery POST Створити ключ відновлення (зберігає зашифрований майстер-ключ)
/api/crm/account/recovery GET Список активних ключів відновлення
/api/crm/account/recovery DELETE Відкликати ключ(і) відновлення
/api/crm/account/recovery/restore GET Отримати зашифрований майстер-ключ для відновлення

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

Standard Cloud — багатосерверний флот (Phase 60)

Повні деталі: docs/architecture/PHASE_60_STANDARD_CLOUD.md.

Сервери

Сервер IP Роль
Contabo 62.171.128.248 API + Master Bot + DB + Nginx
Hetzner arc-cloud-prod 157.180.44.232 Користувацькі Docker-контейнери

SSH Bridge

Усі Docker-операції на Hetzner ініціюються з Contabo через SSH:

Contabo root → ssh -i /root/.ssh/hetzner_ed25519 [email protected] docker <cmd>

CONTAINER_SERVER_IP у vault керує маршрутизацією: 127.0.0.1 = локально, будь-яка інша IP = SSH.

Життєвий цикл контейнера

provision → ready → [idle 30min] → paused → [TG message] → ready
                                                           ↑ wake

Lifecycle-cron: */5 * * * * на Contabo → scripts/cloud-lifecycle-cron.ts.

Хмарний waitlist

Користувачі приєднуються через POST /api/crm/cloud/waitlist. Адмін запрошує через POST /api/crm/cloud/waitlist/invite, що автоматично підвищує план до cloud. Таблиця: cloud_waitlist (міграція 029).