Files
knowledge-base/decisions/2026-06-08-swarmclaw-lxc135-deploy.md

12 KiB
Raw Blame History

date, type, tags
date type tags
2026-06-08 decision
dttb
swarmclaw
openclaw
orchestrator
lxc
docker

SwarmClaw — оркестратор-надстройка над openclaw (LXC 135)

Контекст

Олег искал «аналог openclaw — оркестратор + удобный + самообучение». По ходу выяснилось:

  1. У openclaw самообучение уже работает (Dreaming, embeddings ready, recall с concept-tagging + spaced repetition — см. правку openclaw). Менять движок не нужно.
  2. 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: 4613e7d05f51229a96d7b1a0dd34b24e — он же cookie sc_auth для API.
  • Auth: POST /api/auth {"key":"..."} → cookie, либо header Cookie: sc_auth=<KEY>. getAccessKey()=process.env.ACCESS_KEY, validateAccessKey сравнивает строкой.

Что настроено

  1. Провайдер OmniRoute (custom, OpenAI-compatible):
    • baseUrl=http://10.0.0.179:20128/v1, requiresApiKey:false (внутренний, отдаёт каталог без ключа).
    • Каталог 58 моделей; инференс cc/claude-opus-4-8 подтверждён (stream chat.completions).
  2. Агент «Dirizhyor» (id 0d388a87) — provider omniroute, model cc/claude-opus-4-8.
  3. openclaw-gateway как control-plane:
    • credential cred_62caf5d0f0de (provider openclaw, зашифрованный gateway-token).
    • gateway profile gateway-0eaf65b0 «Antoshka (openclaw 137)», endpoint http://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.

Грабли (важно для будущего)

  1. ACCESS_KEY жил только в /app/.env.local внутри контейнера (не в volume). Пересоздание/обновление образа → новый ключ → запертый вход. Фикс: скопировал ACCESS_KEY (+CREDENTIAL_SECRET если будет) в хостовый /opt/swarmclaw/.env.local (он env_file в compose) → ключ постоянен через пересоздания. CREDENTIAL_SECRET дополнительно лежит в volume data/credential-secret.
  2. Auth rate-limit: 5 неудачных попыток с IP → лок 15 мин (authRateLimitMap, in-memory). Перебор форматов auth (Bearer/x-api-key — оба неверные) триггерит. Правильный auth — только cookie sc_auth. Сброс лока — docker compose up -d --force-recreate (in-memory обнуляется, ключ из env_file сохраняется).
  3. Подключение 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, scopes operator.admin) проверен рабочим. После approve — connect ok:true, device в Paired.
  4. /api/openclaw/doctorspawn openclaw ENOENT — в контейнере нет bundled openclaw CLI; связь идёт по WS, не через CLI. Безвредно.
  5. DNS-FakeIP не словили (в отличие от LXC 137): github/docker.com резолвятся честно через 1.1.1.1/8.8.8.8 даже без NetBird на 135. NetBird не ставил.
  6. Локаль в LXC не настроена (locale: Cannot set LC_*) — косметика, при желании locale-gen en_US.UTF-8.
  7. Агент отвечал 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).
  8. 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 рестартов).
  9. Дефолтный агент Assistant/«Ассистент» упорно падал Claude CLI not found. Корень в коде: agent-runtime-config.tsprovider = 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.
  10. «Session not found» при тесте через curl — нельзя слать в произвольный agent-chat-* ID; сессия создаётся UI/отдельно. Не баг агента — артефакт диагностики. Реальные сессии (созданные в UI) работают (completed).
  11. 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/files tools.
  • Проверено: на вопрос про 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 pull vault из Gitea. Как kb-pull у openclaw 137.

Схема API (для будущих правок headless)

  • POST /api/providers{id,name,baseUrl,models[],requiresApiKey,isEnabled} (type всегда custom), хранит JSON в таблице provider_configs.
  • POST /api/agents → zod AgentCreateSchema; обяз. 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.ru10.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_forced on, проверено 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). Вход — cookie sc_auth / ACCESS_KEY.

TODO / опционально

  • Снести Mac-app SwarmClaw.app (или оставить как клиент).
  • Маппинг openclaw starter-агентов на gateway (роли/теги) — через UI.
  • Самообучение SwarmClaw (conversation-to-skill) — полуручное (draft→approve), не автономное; для настоящего автообучения остаётся openclaw Dreaming.

Связано