Files
knowledge-base/decisions/2026-06-08-swarmclaw-lxc135-deploy.md
2026-06-23 13:58:02 +03:00

149 lines
27 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
date: 2026-06-08
type: decision
tags: [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](https://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…` больше не действует) — он же cookie `sc_auth` для API. Хранится в `/opt/swarmclaw/.env.local`; смена = правка файла + `docker compose up -d --force-recreate` + `repatch-ctxwin.sh`.
- 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/doctor``spawn 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.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.
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.
### Встроенный 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` (cron `30 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 обоих агентов добавлена инструкция ходить по IP `100.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`, provider `omniroute`.
- **Полное управление (cron, agent-files SOUL/IDENTITY/.., models, deploy)** — только через UI (Providers → профиль «Antoshka») или SwarmClaw API напрямую (`/api/openclaw/{cron,agent-files,models,...}?profileId=gateway-0eaf65b0` с cookie `sc_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-config `contextWindow` нигде не читается.
- **Фикс — патч каталога окон в бандле:** добавлен `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`, header `x-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` + state `isDragging` + `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 и контейнере чисто (0 `handleDrop`). Патч-файл `/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) они не нужны.
## Обновление версии образа (2026-06-14: 1.9.38 → 1.9.39)
Процедура на LXC 135 (через `pct exec 135`): бэкап БД `cp /opt/swarmclaw/data/swarmclaw.db{,.bak-preXXXX}``cd /opt/swarmclaw && docker compose pull && docker compose up -d`**`bash repatch-ctxwin.sh` ОБЯЗАТЕЛЬНО** (патч `omniroute:2e5`=200K живёт в `/app/.next/server/chunks` контейнера, слетает при recreate; без него `getContextWindowSize` fallback = 8192 → агенты на Opus режутся до 8K). Проверка: `docker exec swarmclaw-swarmclaw-1 grep version /app/package.json`, `auth HTTP=200` ключом из `.env.local` (`OL260380eg`, **не** первичный `4613e7d0…`), `/api/agents` отдаёт список.
- 1.9.39 — packaging-релиз (npm publish pending, Docker готов, macOS desktop zip/нотаризация); функциональных изменений для сервера нет. На ghcr `:latest` == `:v1.9.39`.
- Откат: старый образ 1.9.38 (`sha256:d1d102a4…`) остаётся локально; восстановить из `.bak-pre1939` + запустить прежний образ.
## Схема 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.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_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.
## Связано
- [[openclaw]] — основной бот (LXC 137), теперь под управлением SwarmClaw
- [[2026-05-06-openclaw-opus-4-7-via-max-cliproxy]]