26 KiB
date, type, tags
| date | type | tags | ||||||
|---|---|---|---|---|---|---|---|---|
| 2026-06-08 | decision |
|
SwarmClaw — оркестратор-надстройка над openclaw (LXC 135)
Контекст
Олег искал «аналог openclaw — оркестратор + удобный + самообучение». По ходу выяснилось:
- У openclaw самообучение уже работает (Dreaming, embeddings ready, recall с concept-tagging + spaced repetition — см. правку openclaw). Менять движок не нужно.
- SwarmClaw (github.com/swarmclawai/swarmclaw) — это не замена, а control-plane НАД openclaw: рой агентов, делегирование, расписания, дашборд, и подключение существующих openclaw-gateway. Ровно «оркестратор» из запроса, без миграции стека.
Решение: поставить SwarmClaw на Proxmox (не Mac-app — тот умирает с ноутом) как постоянный дирижёр над Антошкой.
Где живёт
| Параметр | Значение |
|---|---|
| Proxmox LXC | 135 (hostname swarmclaw) |
| IP | 10.0.0.135/24, gw 10.0.0.1 |
| ОС | Debian 12, unprivileged + nesting=1,keyctl=1 |
| Ресурсы | 2 vCPU / 4 GB RAM / 16 GB (rootfs на work) |
| Рантайм | Docker 29.5 + compose, образ ghcr.io/swarmclawai/swarmclaw:latest |
| Каталог | /opt/swarmclaw (репо), данные volume ./data:/app/data |
| Доступ | pct exec 135 -- bash; dashboard http://10.0.0.135:3456 |
Доступ к UI/API
- URL:
http://10.0.0.135:3456(LAN/NetBird), слушает0.0.0.0:3456-3457. - ACCESS_KEY:
OL260380eg(сменён 2026-06-12 по просьбе Олега; первичный4613e7d0…больше не действует) — он же cookiesc_authдля API. Хранится в/opt/swarmclaw/.env.local; смена = правка файла +docker compose up -d --force-recreate+repatch-ctxwin.sh. - Auth:
POST /api/auth {"key":"..."}→ cookie, либо headerCookie: sc_auth=<KEY>.getAccessKey()=process.env.ACCESS_KEY,validateAccessKeyсравнивает строкой.
Что настроено
- Провайдер OmniRoute (
custom, OpenAI-compatible):baseUrl=http://10.0.0.179:20128/v1,requiresApiKey:false(внутренний, отдаёт каталог без ключа).- Каталог 58 моделей; инференс
cc/claude-opus-4-8подтверждён (stream chat.completions).
- Агент «Dirizhyor» (id
0d388a87) — provideromniroute, modelcc/claude-opus-4-8. - openclaw-gateway как control-plane:
- credential
cred_62caf5d0f0de(provideropenclaw, зашифрованный gateway-token). - gateway profile
gateway-0eaf65b0«Antoshka (openclaw 137)», endpointhttp://10.0.0.239:18789,isDefault:true. - openclaw gateway token:
20bfbdfed25b87b211a6faa60db3ab8fac75fb5100958ac8(gateway.auth.mode=tokenна LXC 137). - device спарен и approved на openclaw (
openclaw devices→ 10.0.0.135,operator.admin). - connect
ok:true.
- credential
Грабли (важно для будущего)
- ACCESS_KEY жил только в
/app/.env.localвнутри контейнера (не в volume). Пересоздание/обновление образа → новый ключ → запертый вход. Фикс: скопировалACCESS_KEY(+CREDENTIAL_SECRETесли будет) в хостовый/opt/swarmclaw/.env.local(онenv_fileв compose) → ключ постоянен через пересоздания.CREDENTIAL_SECRETдополнительно лежит в volumedata/credential-secret. - Auth rate-limit: 5 неудачных попыток с IP → лок 15 мин (
authRateLimitMap, in-memory). Перебор форматов auth (Bearer/x-api-key — оба неверные) триггерит. Правильный auth — только cookiesc_auth. Сброс лока —docker compose up -d --force-recreate(in-memory обнуляется, ключ из env_file сохраняется). - Подключение openclaw требует approve device-pairing. SwarmClaw
manualConnectхардкодитuseDeviceAuth=true(протокол v4,auth:{token}+ device-signature). openclaw в token-mode создаёт pending pairing → пока не сделатьopenclaw devices approve <requestId>на LXC 137, connect молча{"ok":false}. Token-only handshake (proto4,auth.token, scopesoperator.admin) проверен рабочим. После approve — connectok:true, device в Paired. /api/openclaw/doctor→spawn openclaw ENOENT— в контейнере нет bundledopenclawCLI; связь идёт по WS, не через CLI. Безвредно.- DNS-FakeIP не словили (в отличие от LXC 137): github/docker.com резолвятся честно через
1.1.1.1/8.8.8.8даже без NetBird на 135. NetBird не ставил. - Локаль в LXC не настроена (
locale: Cannot set LC_*) — косметика, при желанииlocale-gen en_US.UTF-8. - Агент отвечал
Error: Missing credentials … OPENAI_API_KEYхотя OmniRoute ключ не требует. Причина: OpenAI-совместимый клиент внутри SwarmClaw отказывается слать запрос без непустогоapiKey. Фикс: создать dummy-credential (POST /api/credentials {provider:omniroute, apiKey:"omniroute-noauth-dummy"}→cred_0d2feda42f7b) и привязать к провайдеру (requiresApiKey:true+credentialId) И к агенту (PUT /api/agents/<id>— PATCH даёт 405). OmniRoute ключ игнорирует. После — агент Dirizhyor отвечает на Opus 4.8 (проверено: «работает», + сам диагностировал второй агент через tools). - UI «No agents yet» + циклический логин в Chrome = браузер держал старый JS-бандл (в логах
Failed to find Server Action), ломались Server Actions (вход и загрузка). Сервер исправен (REST API через NPM HTTPS отдаёт auth+agents). Лечится чистым браузером (Yandex/инкогнито сработали сразу) или Clear site data в Chrome. SW/PWA нет, контейнер стабилен (0 рестартов). - Дефолтный агент Assistant/«Ассистент» упорно падал
Claude CLI not found. Корень в коде:agent-runtime-config.ts→provider = seed.provider || 'claude-cli'(хардкод-фоллбек). У default слетал/пустел provider → фоллбек на claude-cli (в контейнере нет).POST /api/agentsне даёт задать фиксированныйid,PUT /api/agents/defaultдля пустого не помог. Фикс: прямойINSERT OR REPLACE INTO agentsвdata/swarmclaw.db— id=default, data = копия Dirizhyor (omniroute/opus/cred). App подхватывает без рестарта (loadAgents читает свежо). Теперь оба агента на OmniRoute/Opus. - «Session not found» при тесте через curl — нельзя слать в произвольный
agent-chat-*ID; сессия создаётся UI/отдельно. Не баг агента — артефакт диагностики. Реальные сессии (созданные в UI) работают (completed). - Gateway health «не обновлялась 30 мин / статус неизвестно» — у RPC
/api/openclaw/gatewayесть только connect/disconnect/reload-mode; health-поле профиля (status,lastCheckedAt) обновляет фоновый probe, не RPC.gateway.connect{profileId}→ok:true(связь рабочая), но индикатор остаётсяunknown. Косметика мониторинга, на работу не влияет.
База знаний (vault) подключена к агентам — 2026-06-08
Олег: «подключить базу данных так же, как у code-server и openclaw». SwarmClaw НЕ имеет folder-RAG как openclaw (memorySearch.extraPaths) — его memory это agent-memory (dream/graph). Поэтому путь = как у code-server: агент через файловые tools работает в каталоге vault.
- Vault склонирован в volume:
git clone https://oleg:***@git.dttb.ru/oleg/knowledge-base→/opt/swarmclaw/data/knowledge-base(1286 md, 19M). Именно вdata/(volume), иначе контейнер/app/dataего не видит. - Агенты настроены на vault:
PUT /api/agents/<id>→workspace=/app/data/knowledge-base(Dirizhyor + Ассистент).workspaceAccessчерез PUT не сохранился, но не нужен — агент читает черезshell/filestools. - Проверено: на вопрос про openclaw агент сам сделал
grep -ril openclaw /app/data/knowledge-base/projects/dttb→ прочиталopenclaw.md→ ответил точно (LXC 137, 10.0.0.239, 100.70.167.54). RAG-доступ работает. - Автообновление:
/root/kb-pull-swarm.sh(cron*/15на LXC 135) —git pullvault из Gitea. Как kb-pull у openclaw 137.
Встроенный Knowledge-раздел (доп. путь, по запросу Олега)
SwarmClaw имеет раздел Knowledge (/api/knowledge), и агент использует его автоматически: prompt-builder + selectKnowledgeCitations инжектят релевантные куски в контекст с цитатами (отдельного tool нет; knowledge_search/knowledge_store как tools удалены). Поиск — текстовое сходство (jaccard, не embeddings) — для фактов норм.
- Импортировано 189 entries (
projects,decisions,snippets,claude-memory,templates— безdaily/notesшума): скрипт POST/api/knowledge {title,content,sourcePath}по каждому .md. 0 ошибок. - Ре-синк:
/root/kb-knowledge-sync.sh(cron30 3 * * *) — git pull + удалить наши entries (поsourcePathпрефиксу) + импорт заново. Иначе POST плодит дубли (нет upsert). - Итог — два механизма: (1) Knowledge entries → авто-контекст с цитатами (UI-раздел); (2) файловый workspace → агент grep'ает всю базу (свежее,
*/15). Дополняют друг друга.
OmniRoute «out of usage» = баг версии (2026-06-09)
Агенты на cc/claude-opus-4-8 начали падать 400 You're out of extra usage. Оказалось — НЕ лимит Max, а баг устаревшего OmniRoute (стоял 3.8.7, актуально 3.8.16). Обновление вылечило. Грабля апдейта: entry-point переехал app/server.js→dist/server.js → поправлен ExecStart в omniroute.service (иначе crash-loop). Подробно — ../claude-memory/omniroute + memory feedback_omniroute_update. Агенты SwarmClaw остаются на Opus 4.8 (Sonnet Олега не устроил).
iPad/iPhone Safari — чаты не отвечали (2026-06-09)
На Mac (Chromium/Yandex) чаты работали, на iPad Safari открывалось, но ответы агента не приходили. Причина — чат отдаёт ответ через SSE (text/event-stream из POST /api/chats/[id]/chat), а NPM (nginx) по умолчанию буферизирует proxy → Safari iOS/iPadOS строг к буферизированному стриму. Фикс — advanced_config у NPM-хоста #32:
proxy_buffering off;
proxy_request_buffering off;
proxy_set_header X-Accel-Buffering no;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
После reload — чаты на iPad заработали. Покрывает и iPhone. (Применять к любому SSE/стрим-сервису за NPM.)
NetBird-доступ для агентов (2026-06-09)
Чтобы агенты SwarmClaw дотягивались до хостов в NetBird-сети (100.70.x: openclaw, серверы клиентов и т.д.).
- NetBird-клиент на LXC 135 (host):
curl -fsSL https://pkgs.netbird.io/install.sh | sh(v0.72.2). Работает в unprivileged-LXC черезnesting=1+ kernel WireGuard (wt0;/dev/net/tunНЕ нужен, как на 137). Autostart (systemctl enable). - setup-key создан через API (PAT из этого же файла, группа Claude-Diag
d7jra32fadhs73dmqv5g):netbird up --setup-key <KEY>. IP 100.70.95.183,swarmclaw.netbird.cloud. - Docker-контейнер дотягивается до 100.70.x БЕЗ доп. настройки — контейнер → default gw (host) → host route
100.70.0.0/16 dev wt0+ Docker bridge MASQUERADE. Проверено: контейнер →100.70.167.54:18789(openclaw) → http 200. Интернет (github/docker для kb-pull) работает одновременно, DNS не сломан (resolv.conf остался 1.1.1.1/8.8.8.8). - ГРАБЛЯ: только по IP, не по именам. Magic-DNS
*.netbird.cloudв контейнере НЕ резолвится —search dttb.ru+ wildcard*.dttb.ruпревращаютopenclaw.netbird.cloud→openclaw.netbird.cloud.dttb.ru→10.0.0.195(NPM) → connect fail. Агент, ходивший по имени, «не мог работать с NetBird». Фикс: в systemPrompt обоих агентов добавлена инструкция ходить по IP100.70.x(адреса в базе), не по*.netbird.cloud. По IP — http 200 (проверено агентом через shell). Если нужен доступ по именам — настраивать NetBird magic-DNS в контейнере (пока не делали, по IP достаточно).
Управление Антошкой агентом — что реально может (2026-06-10)
Device SwarmClaw (10.0.0.135) спарен на openclaw с operator.admin (approve сделан при настройке gateway, pending больше нет — агент Дирижёр советовал повторный approve зря).
- Агентские openclaw-tools:
openclaw_nodes(список openclaw-узлов + exec-команды; НЕ cron —action cron→ «Unknown nodes action») иopenclaw_workspace(backup/rollback/history конфига). Их надо явно включить вagent.tools— по умолчанию у агента их нет (поэтому Дирижёр сначала не мог рулить Антошкой). Включены для Dirizhyor + Ассистента. - Грабля:
agent.gatewayProfileIdпереключает chat-модель агента на gateway-провайдера (openclaw model «default») →MODEL_NOT_FOUND 404, агент перестаёт отвечать. НЕ ставитьgatewayProfileIdна агенте; openclaw_nodes сам берёт дефолтный gateway-профиль. ОставлятьgatewayProfileId: null, provideromniroute. - Полное управление (cron, agent-files SOUL/IDENTITY/.., models, deploy) — только через UI (Providers → профиль «Antoshka») или SwarmClaw API напрямую (
/api/openclaw/{cron,agent-files,models,...}?profileId=gateway-0eaf65b0с cookiesc_auth). Через агентский чат cron/файлы НЕ редактируются.
Окно контекста агента = 8192 (баг!) → патч на 200K (2026-06-12)
Дирижёр жаловался на «ограничение окна» и просил пересадить себя на claude-cli + Anthropic-ключ. Корень — НЕ модель и НЕ Max-лимит: getContextWindowSize(provider, model) (src/lib/server/context-manager.ts) для незнакомого custom-провайдера omniroute не находит его ни в PROVIDER_CONTEXT_WINDOWS[model] (там claude-opus-4-6, нет cc/claude-opus-4-8), ни в PROVIDER_DEFAULT_WINDOWS[provider] (есть anthropic/openclaw/google, нет omniroute) → fallback 8_192. При 4.8k токенов агент уже «на 58%» и паникует. OmniRoute при этом реально отдаёт context_length: 1000000 для cc/claude-opus-4-8.
- Чистого API-пути нет — окна зашиты в бандл,
model_overridesпро подмену модели (heartbeat), provider-configcontextWindowнигде не читается. - Фикс — патч каталога окон в бандле: добавлен
omniroute:2e5вPROVIDER_DEFAULT_WINDOWS(чанк/app/.next/server/chunks/src_lib_server_06.*.js, паттернgoose:2e5,openclaw:128e3→...,omniroute:2e5,openclaw:128e3). Проверено:context-status→contextWindow: 200000. Бэкап чанка.bak-ctxwin. - 200K, не 1M: консервативно (гарантированно для Opus). 1M ставить только после проверки, что Max-тракт
cc/*реально принимает >200K (иначе переполнение → ошибка). - Устойчивость: патч в бандле образа — слетает при
--force-recreate/обновлении. Скрипт/opt/swarmclaw/repatch-ctxwin.shпереприменяет (idempotent). Запускать после каждогоdocker compose pull/update SwarmClaw. - Вывод про claude-cli: не нужен. Ключ Anthropic не давать.
НАСТОЯЩИЙ корень «контекст кончается за 2-3 запроса» (2026-06-12)
Размер окна оказался вторичен. Олег: «было 200, всё равно за 2-3 запроса кончается». Замер по OmniRoute call_logs (/root/.omniroute/storage.sqlite, поле tokens_in): простой запрос «привет» = ~33-36K tokens_in (из них cache_read ~33K — кэшируется, но занимает окно). А SwarmClaw context-status показывал лишь 5.6K — он НЕ учитывает в индикаторе системный промпт + схемы инструментов + knowledge-инжект. Отсюда иллюзия «3%» при реальных 16-18% на пустой запрос, и окно тает в ~6× быстрее.
- Главный пожиратель — схемы 24 инструментов в каждом запросе (browser, replicate, image_gen, google_workspace, swarmdock, manage_* — жирные JSON-схемы). Урезал tools 24→9 (ядро: shell, execute, files, edit_file, web, memory, delegate, openclaw_nodes, schedule_wake) → tokens_in упал 33K → 3K (×11). Проверено замером.
- Knowledge (189 записей, ~270K ток суммарно) инжектится чанками по релевантности (CHUNK_TARGET_CHARS=2200), на «привет» не грузится — не постоянный оверхед, не трогал.
- Как мерить:
sqlite3 /root/.omniroute/storage.sqlite "SELECT tokens_in,tokens_cache_read FROM call_logs WHERE model LIKE '%opus-4-8%' ORDER BY timestamp DESC LIMIT 5"на LXC 132. - Урезаны Dirizhyor (0d388a87) + Ассистент (default, был сломан 0 tools — восстановлен через БД-INSERT). Прочие агенты Олега (Pochtalion/Бухгалтер/Бенелюкс/НИИКН-Ассистент/Nastavnik) — по 7 tools, не трогал.
Картинки/скриншоты в чат (2026-06-12)
- Канал vision работает — проверено end-to-end: upload PNG (
POST /api/upload, headerx-filename, →data/uploads/,resolveImagePathчитает файл → base64 →image_urlформат → OmniRoute →cc/claude-opus-4-8(input_modalities text+image) → агент описал картинку. - Из коробки работают: вставка
Cmd+V(handlePasteловитimage/*из clipboard) + кнопка «Add image». Vision-гейта по провайдеру НЕТ (не блокирует custom omniroute). - Drag&drop НЕ был реализован (в
chat-input.tsxне былоonDrop). Допатчил: добавилhandleDrop/handleDragOver/handleDragLeave+ stateisDragging+onDropна корневой div (переиспользуетuploadAndAdd). Патч сохранён:/opt/swarmclaw/dragdrop.patch(git apply). - Требует пересборки образа (
docker compose build—npm ciиз кэша, переедетnext build~5-10 мин, затемdocker compose up -d). - ОТКАЧЕНО 2026-06-12: сборка
next buildшла слишком долго/молча, Олег не дождался, drag&drop так и не доехал до контейнера →git checkout -- src/components/input/chat-input.tsx, сборку убил. В src и контейнере чисто (0handleDrop). Патч-файл/opt/swarmclaw/dragdrop.patchоставлен — при желании доделать:git apply dragdrop.patch && docker compose build && docker compose up -d. Вставка Cmd+V и кнопка «Add image» работают и без него.
Грабля: урезка tools сломала создание агентов (2026-06-12)
После урезки Дирижёра 24→9 tools (ради контекста) он перестал создавать агентов — был убран manage_platform (именно он управляет агентами: create/assign; «не та ветка» = путаница агента про параллельные branches суб-агентов в subagent.ts, не git). Фикс: вернул Дирижёру manage_platform + spawn_subagent (он оркестратор роя) → tools=11, создание агентов работает (проверено: создал TestBot99). Урок: при урезке tools у агента-оркестратора НЕ убирать manage_platform/spawn_subagent/delegate_to_agent — это его рабочие инструменты. Рядовым агентам (7 tools) они не нужны.
Схема API (для будущих правок headless)
POST /api/providers→{id,name,baseUrl,models[],requiresApiKey,isEnabled}(type всегдаcustom), хранит JSON в таблицеprovider_configs.POST /api/agents→ zodAgentCreateSchema; обяз.name,provider;ollamaModeтолькоlocal|cloud|null(неoff).POST /api/credentials→{provider,name,apiKey}.POST /api/gateways→{name,endpoint,credentialId,isDefault}.POST /api/openclaw/gateway→ RPC{method:"gateway.connect",params:{url,token}|{profileId}}.- БД:
/opt/swarmclaw/data/swarmclaw.db(sqlite, таблицы*_configs/profiles/agents/credentialsкакid+data JSON),memory.db,logs.db.
Домен swarm.dttb.ru (2026-06-08)
- NPM proxy host #32 (LXC 103, 10.0.0.195):
swarm.dttb.ru→10.0.0.135:3456, WSS on, block_exploits. - DNS: wildcard
*.dttb.ruесть только во внутреннем DNS (роутер) — http в LAN/NetBird заработал сразу. Публично wildcard НЕТ (каждый поддомен = отдельная A-запись в SpaceWeb). Добавилswarm A 176.62.183.186через ../snippets/spaceweb-dns-api (add-a, один вызов — зона сверена до/после, 23→24 записи, ничего не задето; бэкап/tmp/dttb_zone_before.txt). - HTTPS/LE — ГОТОВО: DNS пропагировался за ~90 сек, LE cert выпущен (NPM cert id 118, до 2026-09-06),
ssl_forcedon, провереноhttps://swarm.dttb.ru/api/healthz → 200. Грабля NPM API: LE cert принимает толькоmeta:{}(с полями → "additional properties"); email/agree NPM подставляет сам. Challenge падал, пока DNS не пропагировался — не из-за meta. - Итог доступа:
https://swarm.dttb.ru(публично, за NPM+auth) иhttp://swarm.dttb.ru(LAN/NetBird). Вход — cookiesc_auth/ ACCESS_KEY.
TODO / опционально
- Снести Mac-app
SwarmClaw.app(или оставить как клиент). - Маппинг openclaw starter-агентов на gateway (роли/теги) — через UI.
- Самообучение SwarmClaw (
conversation-to-skill) — полуручное (draft→approve), не автономное; для настоящего автообучения остаётся openclaw Dreaming.
Связано
- openclaw — основной бот (LXC 137), теперь под управлением SwarmClaw
- 2026-05-06-openclaw-opus-4-7-via-max-cliproxy