Архітектура Evolving Intelligence

Phase 21.5–40.12 — система скілів Arc OS, що самовдосконалюється. Статус: Production-ready. Sage Worker (автономне покращення) + бенчмарки (A/B-тестування) + Marketplace Discovery + семантичний пошук NotebookLM.


Огляд

Arc OS працює на федеративній архітектурі ботів, де child-боти проксюють повідомлення користувача до Claude CLI. Phase 21.1 запровадила відстеження якості (логи виконання, кнопки фідбеку). Phase 21.5 замикає цикл: тепер система валідує власний вивід, запам'ятовує корекції, фокусує контекст та автономно пропонує покращення.

Інтелектуальний шар тримається на семи опорах:

User Message
    │
    ├─► Context Router ──► SKILLS_HINT (top 5 relevant skills)
    │
    ├─► Learnings ──► LEARNINGS block (past corrections)
    │
    ▼
buildGsdPrompt() ──► Claude CLI ──► Response
                                        │
                                        ├─► Binary Evals ──► Warning footnotes
                                        │
                                        └─► Quality Tracker ──► Metrics
                                                                   │
                                                          Nightly Improve ──► CEO Approval

Опора 1: Binary Eval Engine

Модуль: shared/evals.ts Spec-файли: skills/<name>/<name>.evals.json

Що робить

Кожен скіл може декларувати правила валідації у JSON-файлі. Після того як Claude згенерував відповідь, eval-двигун перевіряє її на всі застосовні правила. Невдачі породжують неблокуючі попередження-виноски, які додаються до повідомлення в Telegram.

Типи правил

Тип Що перевіряє Приклад використання
string_contains Відповідь містить літеральний рядок Перевірити, що JSON-вивід має поле "verdict"
string_not_contains Відповідь НЕ містить рядка Заблокувати --force в інструкціях git
regex_match Відповідь відповідає regex-патерну Переконатися, що system audit згадує disk/RAM/CPU
regex_not_match Відповідь НЕ відповідає regex Запобігти витоку credentials
max_length Довжина відповіді <= N символів Тримати вивід стислим
min_length Довжина відповіді >= N символів Гарантувати змістовні відповіді

Рівні severity

Як eval-и впливають на метрики

Результати eval-ів логуються разом із подіями якості. Коли нічний цикл покращень виявляє скіл із низьким success rate, патерни помилок eval-ів допомагають визначити root cause без потреби в AI-аналізі.

Приклад eval-файлу

{
  "version": 1,
  "skill": "code-review",
  "rules": [
    { "id": "cr-001", "name": "Must return JSON verdict", "type": "string_contains", "value": "\"verdict\"", "severity": "warning" },
    { "id": "cr-002", "name": "No console.log debug", "type": "regex_not_match", "pattern": "console\\.log\\(", "severity": "warning" }
  ]
}

Принцип дизайну

Натхненний eval-фреймворком Anthropic Skill Creator: декларативні assertions над виводами, без AI-in-the-loop для валідації. Бінарний pass/fail усуває двозначність.


Опора 2: Context Router

Модуль: shared/context-router.ts Джерело даних: skills/_registry.json (поля triggers + keywords)

Що робить

Перед побудовою GSD-prompt роутер оцінює кожен зареєстрований скіл відносно повідомлення користувача. Топ-5 збігів інжектяться як блок SKILLS_HINT, налаштовуючи Claude фокусуватися на релевантних можливостях.

Алгоритм оцінки

For each skill:
  score = 0
  for each trigger:   if message contains trigger  → score += 2
  for each keyword:   if message contains keyword  → score += 1

Sort by score DESC → take top 5

Збіги по triggers оцінюються вище, бо triggers — це явні сигнали виклику (наприклад, "review", "deploy"). Keywords дають ширшу семантичну відповідність (наприклад, "OWASP", "Docker").

Чому advisory, а не filtering

Роутер працює лише як підказка. Claude CLI все одно завантажує всі скіли через CLAUDE.md. Причини:

  1. Безпека: жорстка фільтрація через --allowedTools або мутації симлінків ризикує зламати сесію посередині, якщо роутер хибно класифікує повідомлення.
  2. Стабільність: жодних мутацій файлової системи на робочому процесі.
  3. Graceful degradation: якщо роутер впаде, Claude все одно матиме повний доступ до скілів.

Економія контекстного вікна

Без роутера всі 23 скіли конкурують за увагу в prompt. Блок SKILLS_HINT каже Claude "фокусуйся на цих 3-5" — зменшуючи нерелевантну активацію скілів і утримуючи відповіді на темі. Це context priming, а не context reduction.


Опора 3: Reflect Loop (Persistent Learnings)

Модуль: shared/learnings.ts Сховище: {PROJECT_CWD}/learnings.md

Що робить

Коли CEO натискає "Fix It" або "👎", система фіксує learning-правило та зберігає його в markdown-файл. На кожному наступному повідомленні накопичені learnings інжектяться в GSD-prompt як блок LEARNINGS.

Пайплайн Event → Learning

CEO presses 🛠️ Fix It
    │
    ├─► addLearning(source: "fixit", rule: "Fix requested for: <context>")
    │
    └─► projectLearnings reloaded from disk

CEO presses 👎
    │
    ├─► addLearning(source: "negative", rule: "Negative feedback on: <context>")
    │
    └─► qualityTracker.logFeedback(positive: false)

Формат файлу learnings

# Learnings

> Auto-generated. Injected into GSD prompt at session start.

## Rules

- [2026-04-03T14:22:00Z] [fixit] Always use t-call for translations in Odoo QWeb
- [2026-04-03T15:10:00Z] [negative] Avoid sudo in deployment scripts

Інжекція в prompt

Функція formatForPrompt() бере найсвіжіші learnings (до 2000 символів), реверсує їх (найновіші першими) та форматує як:

LEARNINGS (past corrections — follow these rules):
- Avoid sudo in deployment scripts
- Always use t-call for translations in Odoo QWeb

Принцип дизайну

Натхненний Claude Reflect System: корекції не просто виправляють поточну відповідь — вони стають persistent rules, що запобігають регресії. Система з часом будує "імунну пам'ять".


Опора 4: Karpathy Loop (Nightly Self-Improvement)

Модуль: scripts/nightly-improve.ts Розклад: щодня о 03:00 UTC через cron Стан: mcp-server/state/improvement-proposals.json

Що робить

  1. Читає config/bot_registry.json, щоб перерахувати всі child-боти
  2. Для кожного child-а: читає quality-metrics.json з його state-директорії
  3. Викликає findUnderperformingSkills() — фільтрує скіли, де:
    • applied_count >= 3 (мінімальний розмір вибірки)
    • І АБО success_rate < 80%, АБО feedback_negative > feedback_positive
  4. Читає learnings.md для пов'язаних патернів корекцій
  5. Генерує пропозиції на основі шаблонів (детерміновано, без AI)
  6. Надсилає підсумковий звіт CEO у Telegram
  7. Надсилає індивідуальні картки пропозицій із inline-кнопками Approve/Reject

Потік схвалення CEO

Nightly script ──► Telegram: Proposal Card
                        │
           ┌────────────┼────────────┐
           ▼                         ▼
    ✅ Approve                  ❌ Reject
           │                         │
    Backup skill.md              Mark rejected
    as skill.v1.md              in proposals.json
    (max 3 versions)
           │
    Mark approved
    in proposals.json

Версіонування скілів

При схваленні master-бот створює версіоновані бекапи:

Принцип дизайну

Натхненний Karpathy's AutoResearch Loop: modify → verify → keep/discard → repeat. Критична відмінність: пропозиції шаблонні та потребують схвалення людини. Жодного автономного переписування скілів — CEO залишається фінальним авторитетом.


Phase 36+ — Семантичний шар NotebookLM

Phase 36.3 додала п'ятий канал зворотного зв'язку: Google NotebookLM як довгострокову семантичну пам'ять.

CRM Events (issue close, wiki update)
    │
    └─► fire-and-forget POST to bridge /sync
                                    │
                                    ▼
                          NotebookLM Bridge (:19213)
                            ├── SyncWorker (asyncio.Queue, 3 retries)
                            └── notebooklm-py → Google NotebookLM
                                    │
                                    ▼
                          Notebook updated with new source
                                    │
              ┌─────────────────────┤
              ▼                     ▼
    ask_notebooklm tool     Neural Skill Generator
    (Cloud PM chat, 15s)    (POST /skills/generate, 30s)
              │                     │
              ▼                     ▼
    Semantic answer in      Markdown skill for
    project context         review + save (Phase 36.6)

Phase 36.6 додала Neural Skill Generator: CEO визначає ціль екстракції, bridge опитує NotebookLM зі структурованим AI Architect prompt і повертає строгий Markdown Rulebook, який можна зберегти як скіл.

Phase 36.7 показала ноутбуки у sidebar UI (зелена/червона status-точка, лічильник джерел, зовнішнє посилання).


Опора 6: Sage Worker (Phase 40.11c)

Модуль: shared/sage.ts Тригер: POST /api/crm/sage/analyze або scripts/nightly-improve.ts

Що робить

Sage — це автономний рушій покращення скілів. Він аналізує скіли, використовуючи метрики якості + фідбек користувача (learnings), і потім генерує конкретний покращений контент через Anthropic API (модель Haiku для економії). Результати зберігаються як skill_update_requests (PR) у базі даних для перегляду CEO.

Потік

Sage Analyze Request
    │
    ├─► Load active skills from DB (skillQueries)
    ├─► Cross-reference with quality metrics (readMetrics)
    ├─► Prioritize underperformers (findUnderperformingSkills)
    │
    ▼ For each target skill (max 5):
    ├─► Load skill content + fork (if project-scoped)
    ├─► Load quality metrics (success rate, feedback counts)
    ├─► Load related learnings (user corrections)
    ├─► Skip if pending PR already exists
    ├─► Build prompt (content + metrics + learnings)
    ├─► Call Anthropic API (Haiku, 30s timeout)
    ├─► Parse response (NO_CHANGE = skip)
    ├─► Insert skill_update_request (proposed_by: 'sage')
    └─► Auto-run benchmark (Pillar 7) on new PR

Чому CRM-ендпоінт, а не воркер

Sage потребує прямого доступу до БД (skillQueries, benchmarkQueries) — воркери запускаються як підпроцеси без БД-з'єднання. Sage не отримує повідомлення користувача; це фоновий аналізатор, чий вивід = рядки в БД, а не текст у чаті.


Опора 7: Data-Driven Approvals — бенчмарки (Phase 40.11d)

Модуль: shared/sage.ts (runBenchmark()) БД: shared/migrations/005_skill_benchmarks.ts API: POST /api/crm/sage/benchmark, GET /api/crm/skill-updates/:id/benchmarks

Що робить

Перш ніж CEO схвалить Sage PR, система доводить, що зміна працює. Генеруються 3 тестові сценарії, прокатуються старий і новий контент скіла через них (сліпий A/B-тест), а LLM-суддя визначає, який кращий. Combined scoring: eval_rules детерміновано (60%) + LLM-суддя (40%).

Потік бенчмарку

Run Benchmark (requestId)
    │
    ├─► Load skill_update_request (current_content + proposed_content)
    ├─► Load eval_rules from DB
    │
    ▼ Generate 3 test scenarios (Haiku)
    │
    ▼ For each scenario:
    ├─► Run old skill content → old_output
    ├─► Run new skill content → new_output
    ├─► Randomize A/B order (position-bias prevention)
    ├─► LLM Judge scores both (1-10) + reason
    ├─► Deterministic eval_rules scoring (if available)
    ├─► Combined score: eval 60% + LLM 40%
    └─► Save to skill_benchmarks table
    │
    ▼ Update PR metadata
    ├─► verdict: PASSED / FAILED / TIE
    ├─► improvement_pct: ((new_avg - old_avg) / old_avg * 100)
    └─► BenchmarkBadge visible on frontend PR header

Frontend: Battle Mode

SkillEvolution.jsx → компонент BenchmarkReport:


Карта файлів

shared/
├── evals.ts              ← Pillar 1: Binary Eval Engine
├── context-router.ts     ← Pillar 2: Context Router (routeContextFromDb)
├── learnings.ts          ← Pillar 3: Reflect Loop
├── quality.ts            ← Extended: findUnderperformingSkills()
├── sage.ts               ← Pillar 6+7: Sage Worker + Benchmarks (runSageAnalysis, runBenchmark)
├── db.ts                 ← SQLite SSOT: skillQueries, benchmarkQueries, chatQueries
├── migrations/
│   ├── 004_skill_system.ts     ← skills_global, forks, evolution_logs, update_requests
│   └── 005_skill_benchmarks.ts ← skill_benchmarks (A/B test results)
├── crm-routes.ts         ← CRM API: 55+ endpoints (Sage + benchmarks + skill evolution)
└── ui_templates.ts       ← Extended: improvementProposal()

scripts/
├── nightly-improve.ts    ← Pillar 4: Karpathy Loop (now uses Sage + DB)
└── migrate-skills-to-db.ts ← Nuclear migration: files → DB

clients/
├── arc-cli.ts            ← ARC CLI (Phase 31.5): login, start, projects
└── knowledge-mcp.ts      ← Deprecated (Phase 38 → CLI subcommands)

services/
└── notebooklm-bridge/    ← Pillar 5: NotebookLM semantic search (Phase 36.3)
    ├── main.py           ← FastAPI (:19213), /query, /sync, /notebooks/init, /health
    └── seed_knowledge.py ← Bulk import existing knowledge

frontend/src/crm/pages/
└── SkillEvolution.jsx    ← Two-panel UI: explorer + detail (Content/Evals/Evolution/PRs)
                             BenchmarkBadge, BenchmarkReport, Battle Mode, Sage analyze button

child-bot/bot.ts          ← Integration: startup + GSD prompt + eval footnotes + /learnings
child-bot/ingest-watcher.ts ← Auto-ingest: fs.watch on raw/ → CRM inbox (Phase 28)
master-bot/bot.ts         ← Integration: Sage nightly cron trigger