[2026-09-26] eagle: personal/plans/balda-mm-phase4-agents.md personal/tech/agents-bridge.md personal/tech/balda-executor-mcp.md personal/tech/music-tags-final-review.md personal/tech/music-tags-repair-truenas.md
This commit is contained in:
1 parent
8199307531
commit
b00eb549bf
5 files changed
+469
-25
No files matched your search
@@ -12,9 +12,9 @@
|
||||
|---|---|---|
|
||||
| 1 | `~/agents` + `~/cli-auth` + контейнер | ✅ собрано, запущено |
|
||||
| 2 | Мост FastAPI :8790 | ✅ работает под launchd |
|
||||
| 3 | Сеть (Cloudflare Tunnel) | ⏳ **на Alex** — CF-панель |
|
||||
| 4 | Секция «Agents» в Dashboard | ✅ API + вкладка |
|
||||
| 5 | Связка Балда → мост | ⏳ не начато |
|
||||
| 3 | Сеть Kraken → Mac | ✅ **LAN напрямую**, туннель не нужен |
|
||||
| 4 | Секция «Agents» в Dashboard | ✅ активирована и проверена |
|
||||
| 5 | Связка Балда → мост | 🟡 **связка работает**, конфиг Балды ждёт переключения на `type: http` |
|
||||
| 6 | Приёмка от аккаунта Alex | 🔴 блокер: авторизация CLI |
|
||||
|
||||
---
|
||||
@@ -27,7 +27,7 @@
|
||||
| 2 | Подтверждения | Full access → `permissions.mode: allow_all` |
|
||||
| 3 | Управление линками в `~/agents` | Секция «Agents» в Eagle Dashboard |
|
||||
| 4 | Auth CLI (claude/codex) | на хосте, `~/cli-auth`, **вне** `~/agents`; логинит **Alex вручную** |
|
||||
| 5 | Сеть Kraken → Mac | Cloudflare Tunnel (существующий cloudflared на Mac) |
|
||||
| 5 | Сеть Kraken → Mac | ✅ **LAN напрямую** (`http://192.168.1.57:8790`); Cloudflare Tunnel — резерв |
|
||||
| 6 | Провайдер исполнителя | `claude` (дефолт в `.env`); `codex` собирается в том же образе, переключается переменной |
|
||||
|
||||
---
|
||||
@@ -58,8 +58,11 @@ Mattermost (Alex)
|
||||
Балда-оркестратор (Kraken, DeepSeek, allow_all)
|
||||
│ читает Obsidian, формирует ТЗ, /goalkeeper → work → validate
|
||||
▼
|
||||
Cloudflare Tunnel: agents-bridge.qentra.top → localhost:8790 ⏳
|
||||
│ (существующий cloudflared на Mac, PID + LaunchAgent)
|
||||
MCP-сервер balda-executor-mcp (Kraken, контейнер в mattermost_mm-net) :8890
|
||||
│ инструменты executor_run / executor_status / executor_health
|
||||
│ HTTP + X-Bridge-Secret
|
||||
▼
|
||||
LAN: http://192.168.1.57:8790 ← Kraken и Mac в одной сети, туннель не нужен
|
||||
▼
|
||||
Мост (Mac, FastAPI :8790) — под launchd com.agents.bridge
|
||||
│ idempotency key, таймаут 900 с, лимит 1 задача, shared secret
|
||||
@@ -74,6 +77,8 @@ Cloudflare Tunnel: agents-bridge.qentra.top → localhost:8790 ⏳
|
||||
diff + тесты + коммит → Балда → Mattermost
|
||||
```
|
||||
|
||||
Детали MCP-сервера: [[personal/tech/balda-executor-mcp]].
|
||||
|
||||
### Auth CLI на хосте
|
||||
|
||||
| Данные | Хост | В контейнере | Права |
|
||||
@@ -97,14 +102,22 @@ diff + тесты + коммит → Балда → Mattermost
|
||||
| `~/Docker/balda-executor/agents-mounts.yaml` | манифест внешних проектов |
|
||||
| `~/Docker/balda-executor/tools/render-mounts.py` | манифест → `compose.override.yaml` |
|
||||
| `~/Developer/agents-bridge/` | мост: `app.py`, `store.py`, `executor.py`, `config.py` |
|
||||
| `~/Library/LaunchAgents/com.agents.bridge.plist` | автозапуск + KeepAlive |
|
||||
| `~/Library/LaunchAgents/com.agents.bridge.plist` | автозапуск + KeepAlive, `--host 0.0.0.0` |
|
||||
| `~/Developer/eagle-dash/agents.py` | роутер секции «Agents» |
|
||||
| `~/Developer/balda-executor-mcp/` | MCP-сервер: `server.py`, `Dockerfile`, `docker-compose.yml` |
|
||||
| `/home/kraken/mcp/docker-compose.yml` (Kraken) | запуск контейнера MCP |
|
||||
|
||||
**Известные питфоллы (пройдены):**
|
||||
- `docker compose` в этом окружении **отсутствует** — только `docker-compose` (v5.1.3);
|
||||
- `docker compose` на Mac **отсутствует** — только `docker-compose` (v5.1.3);
|
||||
**на Kraken наоборот**: `docker compose`, а `docker-compose` → `command not found`;
|
||||
- `compose.override.yaml` обязателен при старте, иначе `up` падает на монтировании;
|
||||
- компайл: `node:24-bookworm` вместо `scratch` (CA-сертификаты — иначе TLS-фейл);
|
||||
- `psutil` не установлен в venv дашборда → supervisor не может трекать мост по PID; health для моста — `type: http`.
|
||||
- образ исполнителя: `node:24-bookworm` вместо `scratch` (CA-сертификаты — иначе TLS-фейл);
|
||||
- `psutil` не установлен в venv дашборда → supervisor не может трекать мост по PID; health для моста — `type: http`;
|
||||
- `--host` берётся из `ProgramArguments` plist, **`.env` его не перебивает**;
|
||||
смена аргументов требует `bootout`+`bootstrap`, не `kickstart`;
|
||||
- образ Балды из `scratch`: **нет shell**, `docker exec … sh` не работает;
|
||||
`docker.sock` в контейнер Балды **не смонтирован** → `docker run` изнутри невозможен;
|
||||
- на Kraken в sshd `AllowTcpForwarding no` → обратный SSH-туннель поставить нельзя.
|
||||
|
||||
---
|
||||
|
||||
@@ -177,13 +190,62 @@ diff + тесты + коммит → Балда → Mattermost
|
||||
|
||||
---
|
||||
|
||||
## 7. Сеть (шаг 3) — на Alex
|
||||
## 7. Сеть Kraken → Mac — ✅ РЕШЕНО, туннель НЕ нужен
|
||||
|
||||
Cloudflare Tunnel: добавить published route `agents-bridge.qentra.top` → HTTP `localhost:8790` +
|
||||
Access Application. Токен и процесс cloudflared не трогаются.
|
||||
⚠️ hostname — **одноуровневый** (двухуровневые дают TLS handshake failure).
|
||||
### Итог: обычный HTTP по локальной сети
|
||||
|
||||
Проверка после настройки: `curl https://agents-bridge.qentra.top/healthz`.
|
||||
Kraken и Mac **стоят в одной LAN и видят друг друга напрямую** — проверено
|
||||
`ping` с Kraken на `192.168.1.57` (RTT ~2.4 мс, 0% потерь). Никакой туннель,
|
||||
никакой проброс и никакая Access Application не нужны.
|
||||
|
||||
```
|
||||
BRIDGE_URL=http://192.168.1.57:8790
|
||||
```
|
||||
|
||||
Проверки, подтвердившие связь:
|
||||
|
||||
| Проверка | Результат |
|
||||
|---|---|
|
||||
| `ping` Kraken → `192.168.1.57` | 2/2, RTT 2.4 мс ✅ |
|
||||
| `curl` с Kraken на `:8790/healthz` | `status: ok` ✅ |
|
||||
| `curl` из контейнера в `mattermost_mm-net` на `:8790/healthz` | `status: ok` ✅ |
|
||||
|
||||
### Что НЕ сработало и почему (чтобы не повторять)
|
||||
|
||||
| Путь | Почему отпал |
|
||||
|---|---|
|
||||
| Cloudflare Tunnel (`agents-bridge.qentra.top`) | Требует правки маршрута в CF-панели — ручная работа Alex, а LAN работала сразу. Остаётся резервным вариантом, если Mac уедет из этой сети |
|
||||
| Обратный SSH-туннель (`ssh -R`) | 🔴 **На Kraken в sshd стоит `AllowTcpForwarding no`.** Симптом: `Error: remote port forwarding failed for listen port 18790`, в verbose — `debug1: Remote: Server has disabled port forwarding.` Не диагностировать как «порт занят»: порт свободен, форвард выключен администратором |
|
||||
|
||||
📌 Если понадобится туннель в будущем — сначала проверить `AllowTcpForwarding` на Kraken,
|
||||
потом уже ставить форвард. Cloudflare Tunnel этот запрет обходит (исходящее соединение,
|
||||
не SSH-форвард).
|
||||
|
||||
### Мост теперь слушает всю сеть — это осознанное изменение
|
||||
|
||||
| Было | Стало | Почему |
|
||||
|---|---|---|
|
||||
| `BRIDGE_HOST=127.0.0.1` | `BRIDGE_HOST=0.0.0.0` | иначе Kraken не достучится |
|
||||
|
||||
⚠️ **Порт 8790 теперь открыт в локальной сети.** Защита — `X-Bridge-Secret` (обязателен,
|
||||
иначе `POST /task` отдаёт 503). При уходе Mac в недоверенную сеть — вернуть `127.0.0.1`
|
||||
и поднимать туннель.
|
||||
|
||||
🔴 **Питфолл: `.env` не перебивает plist.** Я поменял `BRIDGE_HOST` в `.env`, но мост
|
||||
продолжал слушать `127.0.0.1` — потому что `--host` **жёстко задан в `ProgramArguments`**
|
||||
plist. Симптом: `lsof` показывает `127.0.0.1:8790` после «перезапуска с новым конфигом».
|
||||
Исправлять надо **в plist**, а не в `.env`.
|
||||
|
||||
```bash
|
||||
# применить: правка plist → перезагрузка сервиса (не kickstart!)
|
||||
launchctl bootout gui/$(id -u)/com.agents.bridge
|
||||
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.agents.bridge.plist
|
||||
# проверка: должно быть *:8790, а не 127.0.0.1:8790
|
||||
lsof -nP -iTCP:8790 -sTCP:LISTEN
|
||||
```
|
||||
|
||||
`kickstart` перечитывает только программу, но **не** изменённый `ProgramArguments` —
|
||||
для смены аргументов нужен `bootout` + `bootstrap`.
|
||||
|
||||
---
|
||||
|
||||
@@ -201,14 +263,41 @@ Access Application. Токен и процесс cloudflared не трогают
|
||||
|
||||
## 9. Открыто
|
||||
|
||||
1. Cloudflare Tunnel (шаг 3) — нужен доступ к CF-панели
|
||||
2. Связка Балда → мост (шаг 5) — MCP-инструмент
|
||||
3. Логин CLI (Alex вручную) — без него сквозная приёмка невозможна
|
||||
1. **Переключить конфиг Балды на HTTP-MCP** — сейчас там stdio-вариант с `docker run`,
|
||||
который не может работать (нет `docker.sock` и нет shell в образе Балды).
|
||||
Нужен `type: http` → `http://balda-executor-mcp:8890/mcp`. См. [[personal/tech/balda-executor-mcp]] §7.
|
||||
2. Проверить, что инструменты видны в сессии Балды (после перезапуска).
|
||||
3. Логин CLI (Alex вручную) — без него сквозная приёмка невозможна.
|
||||
4. Cloudflare Tunnel — **не нужен** на текущей схеме; держать как резерв, если Mac
|
||||
уедет из LAN.
|
||||
|
||||
## 10. Шаг 5 — связка Балда → мост (что сделано 2026-09-26)
|
||||
|
||||
| Компонент | Где | Статус |
|
||||
|---|---|---|
|
||||
| MCP-сервер `balda-executor-mcp` | `~/Developer/balda-executor-mcp/` | ✅ код + образ |
|
||||
| Образ | `balda-executor-mcp:0.1.0`, загружен на Kraken | ✅ |
|
||||
| Контейнер MCP | Kraken, `/home/kraken/mcp/docker-compose.yml` | ✅ Up |
|
||||
| Конфиг Балды | `runtime.mcp_servers.executor-mcp` + `balda.mcp_servers` | 🟡 ждёт `type: http` |
|
||||
| `.env` Балды | `+ BRIDGE_URL`, `+ BRIDGE_SECRET` | ✅ |
|
||||
|
||||
Бэкапы на Kraken: `config.yaml.bak-mcp-20260926-194313`, `.env.bak-mcp-*`, `.env.bak-url-*`.
|
||||
|
||||
Проверено живьём: MCP-handshake (stdio и HTTP), `tools/list` с 3 инструментами,
|
||||
`executor_health` из docker-сети Kraken вернул живые данные моста на Mac,
|
||||
Балда после правки конфига стартовала без ошибок.
|
||||
|
||||
📌 **Ключевой вывод по архитектуре:** MCP-сервер обязан быть **отдельным контейнером
|
||||
с HTTP-транспортом**. Вариант «stdio + `docker run` изнутри Балды» нерабочий:
|
||||
в образе Балды нет shell и не смонтирован `docker.sock`.
|
||||
|
||||
## Связанные заметки
|
||||
- [[personal/projects/balda/balda-mm-delegation-plan]] — общий план (Фазы 4-5)
|
||||
- [[personal/projects/balda/balda-kraken-mm-deploy]] — Фаза 3 (✅)
|
||||
- [[personal/plans/balda-mm-pr-plan]] — Фаза 2 (PR #8)
|
||||
- [[personal/tech/balda-executor-mcp]] — MCP-сервер делегирования (шаг 5)
|
||||
- [[personal/tech/agents-bridge]] — мост :8790 (шаг 2)
|
||||
- [[personal/tech/eagle-dashboard-agents-tab]] — секция «Agents» в дашборде (шаг 4)
|
||||
- [[personal/tech/macos-docker-virtiofs-mount-limits]] — ограничения macOS Docker
|
||||
- [[personal/tech/balda-go-fx-pitfalls]] — fx-питфоллы, дельта-апплаер
|
||||
- [[family/how-to/kraken-portainer-access]] — cloudflared, routes
|
||||
|
||||
@@ -73,7 +73,7 @@ GET /tasks?limit=N → последние задачи (для дашбор
|
||||
|
||||
| Ключ | Дефолт | Смысл |
|
||||
|---|---|---|
|
||||
| `BRIDGE_HOST` | `127.0.0.1` | слушать только локально (наружу — через туннель) |
|
||||
| `BRIDGE_HOST` | `0.0.0.0` | слушать всю LAN (Kraken ходит по LAN). Было `127.0.0.1` |
|
||||
| `BRIDGE_PORT` | `8790` | порт |
|
||||
| `BRIDGE_SECRET` | — | **обязателен**, 64 симв. `secrets.token_urlsafe(48)` |
|
||||
| `EXECUTOR_CONTAINER` | `balda-executor` | имя контейнера |
|
||||
@@ -93,7 +93,7 @@ GET /tasks?limit=N → последние задачи (для дашбор
|
||||
|---|---|
|
||||
| Label | `com.agents.bridge` |
|
||||
| Plist | `~/Library/LaunchAgents/com.agents.bridge.plist` |
|
||||
| Program | `~/Developer/eagle-dash/.venv/bin/python -m uvicorn app:app --host 127.0.0.1 --port 8790` |
|
||||
| Program | `~/Developer/eagle-dash/.venv/bin/python -m uvicorn app:app --host 0.0.0.0 --port 8790` |
|
||||
| WorkingDirectory | `/Users/admin/Developer/agents-bridge` |
|
||||
| `RunAtLoad` / `KeepAlive` | `true` / `true` |
|
||||
| Логи | `~/Library/Logs/agents-bridge.log` (+ `.err.log`) |
|
||||
@@ -166,10 +166,30 @@ auth-файлов из `~/.claude`/`~/.codex` отклонено, не пред
|
||||
`EnvironmentVariables.PATH` с `/opt/homebrew/bin` первым. Симптом без него:
|
||||
`docker не найден в PATH процесса моста` в `stderr` задачи.
|
||||
|
||||
### 6. Мост слушает только `127.0.0.1`
|
||||
### 6. Мост слушает `0.0.0.0` — изменение 2026-09-26
|
||||
|
||||
`BRIDGE_HOST=127.0.0.1` — намеренно. Наружу выставляется туннелем (шаг 3), не пробросом
|
||||
порта. Не менять на `0.0.0.0` без Access Application на стороне Cloudflare.
|
||||
**Было:** `BRIDGE_HOST=127.0.0.1` («наружу — через туннель»).
|
||||
**Стало:** `0.0.0.0` — иначе Kraken не достучится по LAN.
|
||||
|
||||
Причина: Kraken и Mac в одной сети, `ping` 2.4 мс. Туннель не нужен (см.
|
||||
[[personal/plans/balda-mm-phase4-agents]] §7). Kraken обращается к
|
||||
`http://192.168.1.57:8790`.
|
||||
|
||||
⚠️ Порт 8790 теперь открыт в LAN. Защита — `X-Bridge-Secret` (без него `POST /task` → 503).
|
||||
Уходя в недоверенную сеть — вернуть `127.0.0.1` и поднимать туннель.
|
||||
|
||||
🔴 **`--host` задаётся в plist, `.env` его НЕ перебивает.** Симптом: поменял `.env`,
|
||||
перезапустил — `lsof` всё равно показывает `127.0.0.1:8790`. Правка — в
|
||||
`ProgramArguments` plist. И применять через `bootout` + `bootstrap` (не `kickstart`).
|
||||
|
||||
### 7. Обратный SSH-туннель на Kraken невозможен
|
||||
|
||||
`ssh -R` падает: `Error: remote port forwarding failed for listen port 18790`,
|
||||
в verbose — `debug1: Remote: Server has disabled port forwarding.`
|
||||
|
||||
Причина: на Kraken в sshd `AllowTcpForwarding no`. Не путать с «порт занят» —
|
||||
порт свободен, форвард выключен администратором. Обход — Cloudflare Tunnel
|
||||
(исходящее соединение, не SSH-форвард).
|
||||
|
||||
---
|
||||
|
||||
@@ -191,6 +211,7 @@ curl -s -o /dev/null -w "%{http_code}\n" -X POST http://127.0.0.1:8790/task \
|
||||
## Связанное
|
||||
|
||||
- [[personal/plans/balda-mm-phase4-agents]] — план Фазы 4 (шаги 1-2 ✅)
|
||||
- [[personal/tech/balda-executor-mcp]] — MCP-сервер, который ходит в этот мост
|
||||
- [[personal/tech/macos-docker-virtiofs-mount-limits]] — почему bind-mount вместо symlink
|
||||
- [[personal/projects/balda/balda-mm-delegation-plan]] — общий план делегирования
|
||||
- `~/Developer/agents-bridge` — код моста
|
||||
@@ -201,3 +222,10 @@ curl -s -o /dev/null -w "%{http_code}\n" -X POST http://127.0.0.1:8790/task \
|
||||
- **2026-09-26** (продолжение): переведён под launchd (`com.agents.bridge`,
|
||||
`RunAtLoad` + `KeepAlive`, pid 3063), добавлен `EnvironmentVariables.PATH`.
|
||||
Шаг 3 разблокирован; проверка `KeepAlive` при падении не выполнена (отклонён `kill -9`).
|
||||
- **2026-09-26** (шаг 5): `BRIDGE_HOST` → `0.0.0.0` (в plist, не в `.env`),
|
||||
сервис переставлен через `bootout`+`bootstrap`. Проверено с Kraken: `curl` с хоста и
|
||||
из контейнера в `mattermost_mm-net` дают `status: ok`. Туннель не потребовался —
|
||||
Kraken и Mac в одной LAN. Обратный SSH-туннель на Kraken невозможен
|
||||
(`AllowTcpForwarding no`).
|
||||
- **2026-09-26** (MCP): `executor_health` из контейнера `balda-executor-mcp`
|
||||
(docker-сеть Kraken) вернул живые данные моста — связка Kraken→Mac работает.
|
||||
@@ -0,0 +1,190 @@
|
||||
# balda-executor-mcp — MCP-сервер делегирования задач (шаг 5 Фазы 4)
|
||||
|
||||
> Создан 2026-09-26. Шаг 5 плана [[personal/plans/balda-mm-phase4-agents]].
|
||||
> Статус: **собран, задеплоен на Kraken, связка проверена до последнего звена**;
|
||||
> конфиг Балды ещё указывает на stdio-вариант — требует переключения на `type: http`.
|
||||
> Связка: Балда (Kraken) → MCP → мост (Mac :8790) → контейнер-исполнитель.
|
||||
|
||||
---
|
||||
|
||||
## 1. Зачем отдельный MCP-сервер
|
||||
|
||||
Балда **не может** сама запустить CLI на Mac: Mac за NAT, а `runtime.mcp_servers` —
|
||||
это либо stdio-процесс внутри контейнера Балды, либо HTTP по сети.
|
||||
|
||||
Схема выбрана такая:
|
||||
|
||||
```
|
||||
Балда (Kraken, контейнер balda-mm)
|
||||
│ runtime.mcp_servers.executor-mcp
|
||||
▼
|
||||
MCP-сервер balda-executor-mcp (Kraken, контейнер в mattermost_mm-net) ← HTTP
|
||||
│ X-Bridge-Secret
|
||||
▼
|
||||
мост agents-bridge (Mac, 192.168.1.57:8790) ← обычный HTTP по LAN
|
||||
│ docker exec
|
||||
▼
|
||||
контейнер balda-executor (Mac) → CLI claude/codex
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Расположение и файлы
|
||||
|
||||
| Что | Путь |
|
||||
|---|---|
|
||||
| Проект | `~/Developer/balda-executor-mcp/` |
|
||||
| Сервер | `server.py` (stdio + HTTP в одном файле) |
|
||||
| Образ | `balda-executor-mcp:0.1.0` (python:3.12-slim-bookworm) |
|
||||
| Dockerfile | `~/Developer/balda-executor-mcp/Dockerfile` |
|
||||
| Compose (Kraken) | `/home/kraken/mcp/docker-compose.yml` |
|
||||
| Контейнер на Kraken | `balda-executor-mcp` (сеть `mattermost_mm-net`) |
|
||||
| Порядковый порт | `:8890` внутри docker-сети, **наружу не публикуется** |
|
||||
|
||||
---
|
||||
|
||||
## 3. Инструменты MCP
|
||||
|
||||
| Инструмент | Аргументы | Что делает |
|
||||
|---|---|---|
|
||||
| `executor_run` | `prompt` (обяз.), `provider?` (`claude`/`codex`), `idempotency_key?` | ставит задачу, возвращает `task_id` немедленно |
|
||||
| `executor_status` | `task_id` | статус + stdout/stderr/exit_code |
|
||||
| `executor_health` | — | живость моста и контейнера-исполнителя |
|
||||
|
||||
Ошибки возвращаются как `isError: true` с человеческим текстом:
|
||||
- 429 → «Исполнитель занят (лимит одновременных задач)»
|
||||
- 404 → «задача … не найдена»
|
||||
- прочие → «мост вернул N: …»
|
||||
|
||||
---
|
||||
|
||||
## 4. Переменные окружения
|
||||
|
||||
| Ключ | Смысл |
|
||||
|---|---|
|
||||
| `BRIDGE_URL` | базовый URL моста (например `http://192.168.1.57:8790`) |
|
||||
| `BRIDGE_SECRET` | общий секрет, уходит в `X-Bridge-Secret` |
|
||||
| `BRIDGE_TIMEOUT` | таймаут обычных вызовов (по умолчанию 60 с) |
|
||||
| `MCP_HOST` / `MCP_PORT` | адрес HTTP-режима (по умолчанию `127.0.0.1:8890`) |
|
||||
|
||||
---
|
||||
|
||||
## 5. Два режима запуска
|
||||
|
||||
```bash
|
||||
# stdio (Балда сама запускает процесс)
|
||||
python3 server.py
|
||||
|
||||
# HTTP (отдельный контейнер, Балда ходит по URL)
|
||||
python3 server.py --http --host 0.0.0.0 --port 8890
|
||||
```
|
||||
|
||||
⚠️ **Использовать надо HTTP-режим.** Причины — §7.
|
||||
|
||||
---
|
||||
|
||||
## 6. Приёмка (2026-09-26) — что именно проверено
|
||||
|
||||
| Проверка | Результат |
|
||||
|---|---|
|
||||
| stdio: `initialize` → `tools/list` | 3 инструмента возвращены ✅ |
|
||||
| stdio: `tools/call` health | живые данные моста ✅ |
|
||||
| stdio: 429 / 500 / 404 | корректные `isError` с текстом ✅ |
|
||||
| образ: тот же handshake внутри контейнера | ✅ |
|
||||
| образ на Kraken: загрузка | `Loaded image: balda-executor-mcp:0.1.0` ✅ |
|
||||
| Kraken → мост по LAN (curl из docker-сети) | `status: ok` ✅ |
|
||||
| MCP в docker-сети → `executor_health` через мост | живые данные Mac ✅ |
|
||||
| контейнер `balda-executor-mcp` | Up ✅ |
|
||||
|
||||
Тестовые скрипты: `/tmp/test-mcp-server.sh` (мок моста + stdio-проба),
|
||||
`/tmp/kraken-test-mcp.sh` (ручной handshake из docker-сети Kraken).
|
||||
|
||||
---
|
||||
|
||||
## 7. 🔴 Питфолл: stdio-вариант нерабочий в этом окружении
|
||||
|
||||
Изначальный план был `type: stdio` + `cmd: ["docker", "run", ...]` — то есть Балда
|
||||
сама запускает MCP-контейнер. **Это не работает по двум причинам:**
|
||||
|
||||
1. **`docker.sock` в контейнер Балды не смонтирован.** Проверено:
|
||||
`docker inspect balda-mm` даёт только три тома (config/state/workspace) — сокета нет.
|
||||
Значит `docker run` изнутри Балды невозможен.
|
||||
2. **В образе Балды нет shell.** `docker exec balda-mm sh -c ...` →
|
||||
`OCI runtime exec failed: exec: "sh": executable file not found in $PATH`
|
||||
(образ из `scratch`). Отладка и запуск подпроцессов через shell недоступны.
|
||||
|
||||
**Решение:** MCP-сервер вынести в **отдельный контейнер** с HTTP-транспортом.
|
||||
Конфиг Балды тогда:
|
||||
|
||||
```yaml
|
||||
runtime:
|
||||
mcp_servers:
|
||||
executor-mcp:
|
||||
type: http
|
||||
url: "http://balda-executor-mcp:8890/mcp"
|
||||
|
||||
balda:
|
||||
mcp_servers:
|
||||
- executor-mcp
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 🔴 Питфолл: `--chmod=644` для файла, запускаемого не-root
|
||||
|
||||
Dockerfile изначально делал `COPY server.py /app/server.py` + `USER mcpsvc` → при
|
||||
запуске: `python3: can't open file '/app/server.py': [Errno 13] Permission denied`.
|
||||
|
||||
Фикс: `COPY --chmod=644 server.py /app/server.py`. Не-root пользователь должен уметь
|
||||
**читать** код, иначе контейнер падает ещё до handshake.
|
||||
|
||||
Симптом обманчив — выглядит как поломка образа, а не как права файла.
|
||||
|
||||
---
|
||||
|
||||
## 9. Питфолл: `docker-compose` на Mac, `docker compose` на Kraken
|
||||
|
||||
| Хост | Как вызывать |
|
||||
|---|---|
|
||||
| Mac (Colima) | **`docker-compose`** (v5.1.3, отдельный бинарь) |
|
||||
| Kraken | **`docker compose`** (плагин v5.1.3); `docker-compose` → `command not found` |
|
||||
|
||||
Одна и та же версия, но на разных хостах **разный способ вызова**. Скрипты деплоя
|
||||
для двух хостов нельзя копировать без правки этой строки.
|
||||
|
||||
---
|
||||
|
||||
## 10. HTTP-transport: ручная проба (streamable)
|
||||
|
||||
```bash
|
||||
docker run --rm --network mattermost_mm-net curlimages/curl:latest \
|
||||
-s --max-time 10 -X POST http://balda-executor-mcp:8890/mcp \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json, text/event-stream" \
|
||||
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"0"}}}' -i
|
||||
```
|
||||
|
||||
⚠️ Заголовок `Accept: text/event-stream` **обязателен** — сервер отвечает SSE.
|
||||
Без него — отказ. Ответ отдаётся как `event: message\ndata: {...}`.
|
||||
|
||||
`GET /healthz` у MCP-сервера отдаёт `{"status":"ok","bridge_url":...,"secret_set":true}`.
|
||||
|
||||
---
|
||||
|
||||
## 11. Что осталось
|
||||
|
||||
1. **Переключить `runtime.mcp_servers.executor-mcp` на `type: http`** (сейчас там stdio-вариант с `docker run`).
|
||||
2. Перезапустить Балду, убедиться, что инструменты видны в сессии.
|
||||
3. Сквозная приёмка: `executor_run` из чата → задача на Mac → результат.
|
||||
4. Логин CLI внутри `balda-executor` — делает **Alex вручную**.
|
||||
|
||||
---
|
||||
|
||||
## Связанное
|
||||
|
||||
- [[personal/plans/balda-mm-phase4-agents]] — план Фазы 4 (шаг 5)
|
||||
- [[personal/tech/agents-bridge]] — мост :8790, к которому ходит этот MCP
|
||||
- [[personal/projects/balda/balda-kraken-mm-deploy]] — деплой Балды на Kraken (конфиг, `.env`, сети)
|
||||
- [[personal/tech/macos-docker-virtiofs-mount-limits]] — ограничения macOS Docker
|
||||
- `~/Developer/balda-executor-mcp` — код
|
||||
- скилл `native-mcp` — handshake streamable-http, питфоллы
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
title: Music Tags — сводки для финального аппрува
|
||||
created: '2026-09-26'
|
||||
updated: '2026-09-26'
|
||||
type: tech
|
||||
namespace: personal
|
||||
tags:
|
||||
- music
|
||||
- jellyfin
|
||||
- metadata
|
||||
- approval
|
||||
related:
|
||||
- '[[personal/tech/music-tags-repair-truenas]]'
|
||||
- '[[family/how-to/jellyfin-config]]'
|
||||
---
|
||||
|
||||
# Чистка тегов Music: сводки для финального аппрува
|
||||
|
||||
_Обновлено: 2026-09-26. Источник: `~/Downloads/music-tags/tag-fix-plan.csv`._
|
||||
|
||||
> ⚠️ **Статус: НЕ ФИНАЛЬНЫЙ аппрув.** Блок строк 6402–7906 (1505 строк, ~19%) прочитан
|
||||
> скриптами, но НЕ глазами. См. «Что НЕ покрыто». Полный контекст волн —
|
||||
> `personal/tech/music-tags-repair-truenas.md`.
|
||||
|
||||
## Состав файлов
|
||||
|
||||
| Файл | Строк | Что это |
|
||||
|---|---|---|
|
||||
| `tag-fix-plan.csv` | 7906 | Главный план правок, 11 колонок |
|
||||
| `artists-single-track.csv` | 3223 | Разбивка: треки БЕЗ номера (artist/title/album/path) |
|
||||
| `artists-multi-track.csv` | 4667 | Разбивка: треки С номером (artist/album/track/title/path) |
|
||||
| | **7890** | = сумма сводок (16 строк отфильтрованы: AppleDouble + skip) |
|
||||
|
||||
## Действия
|
||||
|
||||
| action | строк | смысл |
|
||||
|---|---|---|
|
||||
| `fix` | 6934 | теги будут перезаписаны |
|
||||
| `no_change` | 957 | теги корректны, файл не трогаем |
|
||||
| `skip` | 15 | AppleDouble-мусор `._*`, не трогаем |
|
||||
|
||||
## Источник правки (`source`)
|
||||
|
||||
| строк | источник |
|
||||
|---|---|
|
||||
| 3173 | номер трека из имени файла |
|
||||
| 1384 | title из имени файла |
|
||||
| 1311 | **ручное решение (user decision)** |
|
||||
| 756 | только кодировка/очистка |
|
||||
| 882 | (пусто — правка не требуется) |
|
||||
|
||||
## Проверки перед аппрувом
|
||||
|
||||
- 0 битых строк (все 11 колонок на месте), 0 разъехавшихся запятыми
|
||||
- 0 пустых `new_title` среди `fix`
|
||||
- 0 сайтов-водяных знаков в `new_title`/`new_artist`/`new_album`
|
||||
- 0 нечисловых номеров треков
|
||||
- 0 дублей-артистов (регистр/ё/латиница-кириллица), кроме сведённых
|
||||
- 577 строк без artist — из них **562 это `!Детские/Сказки`** (artist пуст намеренно)
|
||||
|
||||
## Приёмка (глазами)
|
||||
|
||||
1. Открой `artists-single-track.csv` — треки без номера, отсортированы по артисту
|
||||
2. Открой `artists-multi-track.csv` — альбомы с нумерацией
|
||||
3. Найди свой артист, проверь названия
|
||||
4. Скажи «go» → бэкап в `Music/backup/` → применение → приёмка в UI Jellyfin
|
||||
|
||||
## Что НЕ покрыто
|
||||
|
||||
Блок **строк 6402-7906** главного файла разобран скриптами (кодировка, номера, album из папки),
|
||||
но **не прочитан построчно глазами**. Крупные артисты блока: Агата Кристи (244), ДДТ (205),
|
||||
Rammstein (134), Би-2 (128), Ночные Снайперы (96), Muse (91), Пикник (69), Захар Май (67),
|
||||
Ундервуд (66), Чиж & Со (63).
|
||||
|
||||
Отдельные «не определить без прослушивания»: `ty_49` (`!Radio/y OOF/пакет.mp3`).
|
||||
@@ -4,7 +4,7 @@ created: '2026-09-26'
|
||||
updated: '2026-09-26'
|
||||
type: tech
|
||||
namespace: personal
|
||||
wave: 25
|
||||
wave: 26
|
||||
tags:
|
||||
- music
|
||||
- jellyfin
|
||||
@@ -20,7 +20,69 @@ related:
|
||||
|
||||
# Music Tags Repair — TrueNAS (7906 файлов)
|
||||
|
||||
> **Статус: ДВАДЦАТЬ ПЯТАЯ ВОЛНА (2026-09-26). ИДЁТ РУЧНОЕ ЧТЕНИЕ ПО ВСЕМУ СПИСКУ.**
|
||||
> **Статус: ДВАДЦАТЬ ШЕСТАЯ ВОЛНА (2026-09-26). ПРОЧИТАНО ПОСТРОЧНО 2402–6401 ИЗ 7906 (~81%).**
|
||||
> Продолжение требования Alex: «Проходить весь список руками и валидировать» + «Хули встал»
|
||||
> (без пауз). В этой волне закрыты блоки **2402–6401** (11 блоков по 200 строк).
|
||||
>
|
||||
> ✅ **НОВОЕ (26-я волна) — построчное чтение 2402–6401.** ~230 правок, найденное детекторами
|
||||
> НЕ ловится:
|
||||
> | Класс | Строк | Скрипт | Результат |
|
||||
> |---|---|---|---|
|
||||
> | Трофим: транслит-титулы из имён файлов (`#1 10 Aristokratiya pomoyki`) | **58** | `fix_trofim.py` | → кириллица; album `Война и мр`→`Война и мир` |
|
||||
> | Трофим: album-плейсхолдеры `#1`…`#9` | ~30 | `fix_block3000.py` | раскрыты в реальные альбомы (`Аристократия помойки 1`…`Бард-Авангард`) |
|
||||
> | АК-47: артист в title (`Витя АК & Tip - Грубо говоря`) | 19 | `fix_block2600.py` | артист-префикс срезан |
|
||||
> | Eminem: split `title='Shop'`+`artist='Candy'`; `Mile`→`8 Mile` | 3 | `fix_block2600.py` | восстановлено |
|
||||
> | NTL / `!Radio`: префикс `NTL - ` в title | ~15 | `fix_block2800.py` | срезан |
|
||||
> | `!Radio`: битые префиксы `ÿþ` (DOS-кириллица), мусор `NN Track NN` в artist, сайт `WAP.BITMOB.RU` | ~15 | `fix_block3200.py` | вычищено |
|
||||
> | Savant: опечатки в `new_album` (`Unrelesed`) → `Unreleased`; `Bit Lightsaber`→`8-Bit Lightsaber`; `Prorophecy`→`Prophecy`; `Clssical`→`Classical` | ~8 | `fix_block3800/4200.py` | исправлено |
|
||||
> | Банд'Эрос / Потап / Серёга: артист в title (`Серега - Кружим`); `Загубиги`→`Загубили` | 7 | `fix_block4400.py` | исправлено |
|
||||
> | Пилот: `Илья Черт`→`Илья Чёрт`; `Осеннее пора`→`Осенняя`; 4-точечные многоточия; `Тецкатлипокa` (латинская `a`); Prodigy-плейсхолдеры `2002 - Babyes Got a temper N`→`Baby's Got a Temper` | **93** | `fix_block4600/4800.py` | исправлено |
|
||||
> | Звери / Земфира: `для тебя`→`Для тебя`; Меамуры транслит (`stekla`,`V reis`,`na udachu`,`Glubzhe`); album `Земфира ()`→`Земфира (2000)`; `Земфира Рамазанова`→`Земфира` | 16 | `fix_block5000/5200.py` | исправлено |
|
||||
> | Кукрыниксы: полный транслит (`Kukriniksi - 01 Stolknovenie - Serebrianii sentiabr`) | 12 | `fix_block5400.py` | → кириллица |
|
||||
> | Ногу Свело!: **регрессия** — album `Второй Магаданский` разъехался на 4 варианта; `Исскуство`→`Искусство`; `Французкая`→`Французская` | 24 | `fix_block5800.py` | сведено к одному |
|
||||
> | The Used: track все `9` (из `3-9 - Title`); `Geschchte`→`Geschichte`; `ПаникА Киев` split | 11 | `fix_block6200.py` | исправлено |
|
||||
> | AppleDouble `._МИМИКРИЯ.MP3` → `action=skip` | 1 | `fix_block5600.py` | помечено |
|
||||
>
|
||||
> 🔴 **ГЛАВНЫЙ ДЕФЕКТ, НАЙДЕННЫЙ ФИНАЛЬНЫМ АУДИТОМ (26-я волна):** строка **3498** разъехалась
|
||||
> на **12+ полей** — незакавыченная запятая в пути `/!Pop, Club, Любэ/` склеила путь с title,
|
||||
> `new_artist` и `new_track` поменялись местами (`new_track='DJ Иван Silver & Сява'`).
|
||||
> Починено `fix_final.py`. **Это 4-й случай повреждения строки запятой в пути** — паттерн
|
||||
> `!Pop, Club, Любэ/` опасен, проверять его в первую очередь.
|
||||
>
|
||||
> 🛠 **Финальные аудиты (read-only, гонять перед «готово»):**
|
||||
> - `final_audit.py` — воронка: кол-во строк/колонок/битых, `action`, заполненность полей,
|
||||
> сайты-водяные знаки, нечисловые `new_track`, разбор пустых artist по папкам,
|
||||
> near-duplicates артистов (регистр/ё/латиница-кириллица).
|
||||
> - Нашёл и починил: `Fever // By Maddalinio //`→`Fever`; album `Best-Mp3.Ru`→пусто;
|
||||
> `Муммий Троль / Медведица (Dj Ivan Scratchin T` → `Медведица (DJ Ivan Scratchin Trance Mix)`;
|
||||
> `YOJI Biomehanika`→`Yoji Biomehanika`.
|
||||
>
|
||||
> 📊 **ФИНАЛЬНОЕ СОСТОЯНИЕ (26-я волна):**
|
||||
> | Показатель | Значение |
|
||||
> |---|---:|
|
||||
> | Строк в `tag-fix-plan.csv` | 7906 (+голова = 7907), **0 битых** |
|
||||
> | `fix` / `no_change` / `skip` | **6934 / 957 / 15** |
|
||||
> | Пустых `new_title` среди `fix` | **0** |
|
||||
> | Сайтов-воды в `new_*/` | **0** |
|
||||
> | Нечисловых `new_track` | **0** |
|
||||
> | Групп дублей артистов | **0** |
|
||||
> | Строк без artist | **577** (562 = `!Детские`, намеренно) |
|
||||
> | Сводные CSV | `artists-single-track.csv` **3223** + `artists-multi-track.csv` **4667** = **7890** |
|
||||
>
|
||||
> ⚠️ **НЕ ГОТОВ:** блок **6402–7906 (1505 строк, ~19%)** разобран скриптами, но **построчно
|
||||
> глазами НЕ читался**. Крупные артисты блока: Агата Кристи (244), ДДТ (205), Rammstein (134),
|
||||
> Би-2 (128), Ночные Снайперы (96), Muse (91), Пикник (69), Захар Май (67), Ундервуд (66),
|
||||
> Чиж & Со (63), Несчастный случай (53), Краденое Солнце (48), Knorkator (12).
|
||||
> ⏭ **ГДЕ ПРОДОЛЖАТЬ: со строки 6402.** Порядок: `read_file` блоками по 200 → править →
|
||||
> `python3 final_audit.py` → `cp bak-$(date +%H%M%S)-<tag>` перед каждым скриптом.
|
||||
>
|
||||
> 📄 Сводка для аппрува Alex: `personal/tech/music-tags-final-review.md`.
|
||||
> **Бэкапы 26-й волны:** `bak-*-trofim`, `bak-*-blk2600/2800/3000/3200/3400/3600/3800/4000/4200/`
|
||||
> `4600/4800/5000/5200/5400/5600/5800/6000/6200`, `bak-*-presummary`, `bak-*-final`, `bak-*-yoji`.
|
||||
>
|
||||
> ---
|
||||
>
|
||||
> **Статус предыдущей волны: ДВАДЦАТЬ ПЯТАЯ (2026-09-26). Прочитаны и вычищены строки 1–1401.**
|
||||
> Alex потребовал: «Проходить весь список руками и валидировать» (после 3 отказов принять
|
||||
> «всё готово»). Работа в процессе: **прочитаны и вычищены строки 1–1401 из 7906 (~18%)**.
|
||||
> CSV: 7906 строк, 0 битых, 0 дублей артистов, 0 год-префиксов/плейсхолдеров/сайтов.
|
||||
|
||||
Reference in new issue
Block a user