Архітектура 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
- warning: показано як
⚠️у виносці. Сигналізує про проблему якості. - info: показано як
ℹ️у виносці. Рекомендаційне, некритичне.
Як 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. Причини:
- Безпека: жорстка фільтрація через
--allowedToolsабо мутації симлінків ризикує зламати сесію посередині, якщо роутер хибно класифікує повідомлення. - Стабільність: жодних мутацій файлової системи на робочому процесі.
- 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
Що робить
- Читає
config/bot_registry.json, щоб перерахувати всі child-боти - Для кожного child-а: читає
quality-metrics.jsonз його state-директорії - Викликає
findUnderperformingSkills()— фільтрує скіли, де:applied_count >= 3(мінімальний розмір вибірки)- І АБО
success_rate < 80%, АБОfeedback_negative > feedback_positive
- Читає
learnings.mdдля пов'язаних патернів корекцій - Генерує пропозиції на основі шаблонів (детерміновано, без AI)
- Надсилає підсумковий звіт CEO у Telegram
- Надсилає індивідуальні картки пропозицій із 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-бот створює версіоновані бекапи:
skill.md→skill.v1.md(поточний → бекап)skill.v1.md→skill.v2.md(ротація)- Максимум 3 бекап-версії на скіл
Принцип дизайну
Натхненний 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:
- Lazy-завантажується по PR (фетчиться при розгортанні)
- Підсумок: wins/losses/ties/verdict/improvement_pct
- По сценаріях: Old vs New side-by-side, зірочка переможця, score/10, обґрунтування судді
- Кнопка "Run Benchmark" на вкладці Content (sky blue)
- Якірна кнопка на кожному PR для повторного запуску бенчмарків
Карта файлів
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