[2026-06-18] taiga-vault: family/how-to/hermes-eagle-mac.md family/how-to/kraken-access.md family/how-to/switch-emulation-rom-infra.md personal/projects/balda/balda-valera.md personal/projects/balda/claudio-klaudiy.md personal/projects/balda/fast-rlm-integration.md personal/projects/balda/setup.md personal/projects/hermes-configs/eagle-config.example.yaml personal/projects/hermes-configs/whale-config.example.yaml personal/projects/personal-os/eagle-dashboard.md

This commit is contained in:
Taiga
2026-06-18 03:03:22 +00:00
parent 4c85079e13
commit 68090c8df7
14 changed files with 1034 additions and 301 deletions
+62 -166
View File
@@ -1,188 +1,84 @@
# Balda Setup & Status
# Balda Setup & Config
> Last updated: 2026-06-11
_Последнее обновление: 2026-06-16_
## Runtime
## Хост
| Item | Value |
|------|-------|
| Binary | `~/Developer/balda/balda` (built from source) |
| Process | Managed by launchd (`com.normahq.balda`) |
| Log | `/private/tmp/balda.log` |
| Config | `~/Developer/balda/.config/balda/config.yaml` |
| State dir | `~/Developer/balda/.config/balda/` |
| Sessions | SQLite persistence |
| Provider | `deepseek` (openai type, model: `deepseek-chat`, via `https://api.deepseek.com/v1`) |
Mac (Eagle), Docker Desktop (arm64 native). Контейнеры собираются из исходников в `~/Developer/balda/`.
Balda is managed by launchd. Full restart (reloads plist env vars):
## Компоненты
| Бот | Порт | Провайдер | Dockerfile |
|-----|------|-----------|------------|
| **Валера** (`balda-agent-valera-1`) | `:8091` | DeepSeek | `Dockerfile` (одинаковый) |
| **Клавдий** (`claudio-agent-claudio-1`) | `:8092` | Claude (через proxy :3457) | `Dockerfile.claudio` (тот же + arm64 target) |
## Расположение
| Item | Валера | Клавдий |
|------|--------|---------|
| Compose | `~/Docker/balda-agent/docker-compose.yaml` | `~/Docker/claudio-agent/docker-compose.yaml` |
| Config volume | `~/Docker/balda-agent/.config/balda/` | `~/Docker/claudio-agent/.config/balda/` |
| Env | `~/Docker/balda-agent/.env` | `~/Docker/claudio-agent/.env` |
| Dev repo (общий) | `~/Developer/balda/` | `~/Developer/balda/` |
**Важно:** оба бота собираются из одного репозитория `~/Developer/balda/` (normahq/balda fork). Разница — только в config.yaml (провайдер) и .env (Zulip credentials).
## Образ
- Собирается локально из `Dockerfile` (Go, multi-stage: golang:1.26 → alpine:3)
- Target: `linux/arm64` (статический Go бинарник)
- Image name: `balda-agent-valera:latest` / `claudio-agent-claudio:latest` (по имени compose проекта)
- Entrypoint: `/usr/local/bin/balda` (ELF arm64)
- Сеть: `balda_default` (bridge, внешняя, создаётся через docker network create)
## Запуск / рестарт
**Валера:**
```bash
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.normahq.balda.plist
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.normahq.balda.plist
cd ~/Docker/balda-agent
docker-compose restart # без пересборки, без перечитывания .env
docker-compose up -d # пересоздаёт контейнер с текущим .env
docker-compose build && docker-compose up -d # после изменений в коде
```
Quick restart (does NOT reload plist env vars — use bootout/bootstrap for env changes):
**Клавдий:**
```bash
launchctl kickstart -k gui/$(id -u)/com.normahq.balda
cd ~/Docker/claudio-agent
# те же команды
```
## Zulip Webhook
**После изменений кода**`~/Developer/balda/`): `build && up -d` в каждом compose.
| Item | Value |
|------|-------|
| Status | ENABLED |
| Listen address | `0.0.0.0:8091` |
| Path | `/zulip/webhook` |
| Webhook bot URL | `http://host.docker.internal:8091/zulip/webhook` |
## .env (общие переменные)
Port was **changed from 8090 → 8091** on 2026-06-07 (see Port Conflict below).
## Architecture
Balda uses the **outgoing webhook** mechanism — Zulip pushes events to Balda's
HTTP endpoint. This differs from Eagle/Kit which use polling.
- Zulip runs in Docker (container: `zulip-zulip-1`), exposed on `127.0.0.1:8000`
- Balda runs natively on Mac (not in Docker)
- Colima maps `host.docker.internal:PORT → 127.0.0.1:PORT` on the Mac host,
so the bot URL uses `host.docker.internal` to reach Balda from inside Docker
## Soul / Prompt
The `global_instruction` field in `config.yaml` defines Balda's persona (Валера).
The canonical source is `soul.md` in this folder — sync manually to config after edits,
then restart Balda.
Provider-level `system_instructions` are documented in `workspace-context.md`.
---
## Bug Fixed 2026-06-07 — Context Canceled on First DB Operation
**File:** `zulip_handler.go`, line 236
**Root cause:** The message-processing goroutine was launched with the HTTP
request context:
```go
// Before (broken)
go h.processMessage(r.Context(), payload)
```env
OPENAI_BASE_URL=https://api.deepseek.com/v1 # обязательна для deepseek provider
# для claude provider не нужна
```
When the handler returns HTTP 200, Go cancels `r.Context()`. The goroutine then
hits its first database operation and fails with `context canceled`.
**Важно:** `docker-compose restart` не перечитывает `.env`. Только `docker-compose up -d`.
**Fix:**
## Известные грабли
```go
// After (fixed)
go h.processMessage(context.WithoutCancel(r.Context()), payload)
### 1. OPENAI_BASE_URL — обязательна для DeepSeek
Norma не читает `base_url` из config.yaml для `provider: deepseek`. Читает env `OPENAI_BASE_URL`.
Без неё запросы уходят на `api.openai.com` (401).
### 2. DOCKER_OPTS — пустая строка убивает старт
```env
DOCKER_OPTS={"max_tokens": 2048, "temperature": 0.7}
```
Не пустая строка! Иначе `strconv.ParseFloat: parsing ""` при старте.
`context.WithoutCancel` creates a copy of the parent context that is never
canceled when the parent is — so the goroutine lives past the HTTP handler return.
### 3. exec format error на arm64
Симптом: контейнер в crash-цикле, логи повторяют `exec /usr/local/bin/balda: exec format error`.
Docker показывает `Up N hours` (накопленное время рестартов), но exec не работает.
---
**Причина:** контейнер создан с `Platform: linux/amd64` (старый Docker Desktop или первый run без platform). Образ arm64, контейнер amd64 — несовместимость.
## Port Conflict 2026-06-07 — Moved 8090 → 8091
**Фикс:** `docker-compose down; docker-compose up -d` — удаляет старый контейнер и создаёт новый с правильной платформой.
**Root cause:** Colima (Docker runtime) maps `host.docker.internal:PORT →
127.0.0.1:PORT` on the Mac host. `openclaw/claude-proxy` was occupying
`127.0.0.1:8090`, intercepting Balda's webhook traffic before it reached Balda.
**Solution:** Changed Balda's listen port from `8090` to `8091` in `config.yaml`.
### Resolution
Webhook bot URL updated in Zulip DB via `docker exec psql` on 2026-06-07:
`http://host.docker.internal:8090/zulip/webhook``http://host.docker.internal:8091/zulip/webhook`
---
## Smokescreen SSRF Proxy — Allow Private Ranges (Fixed 2026-06-11)
**Symptom:** Zulip outgoing webhook to Balda fails with HTTP 407.
Zulip logs: `client: OutgoingWebhookResponse` + "Failure! Third party responded with 407".
**Root cause:** Zulip runs Smokescreen (SSRF proxy) for all outgoing HTTP.
`host.docker.internal` resolves to a private IP (`192.168.5.x`), which Smokescreen
blocks by default. A `docker restart` does NOT recreate containers, so env vars
added to docker-compose aren't picked up — must use `docker compose up -d`.
**Fix:** Added to `~/Developer/zulip/docker-compose.yml` under the `zulip` service env:
```yaml
PROXY_ALLOW_RANGES: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
```
Then recreated containers:
```bash
cd ~/Developer/zulip
docker compose up -d
```
Smokescreen now starts with `--allow-range` flags for all RFC1918 ranges.
Verify with: `docker exec zulip-zulip-1 ps aux | grep smokescreen`
**Note:** `SETTING_ALLOW_BOTS_TO_MAKE_REQUESTS_TO_PRIVATE_ADDRESSES: "True"` was already
set but doesn't affect Smokescreen's `--allow-range` flags — it controls a different
check. `PROXY_ALLOW_RANGES` is the correct env var.
---
## DeepSeek Provider via norma-local Fork
Balda's `openai` provider type in norma hardcoded `api.openai.com`. To support
DeepSeek (or any OpenAI-compatible API), the norma source was forked locally:
- Fork path: `~/Developer/norma-local`
- Patched files:
- `pkg/runtime/hostedagent/openai.go` — added `openAIBaseURL()` reading `OPENAI_BASE_URL` env var
- `pkg/runtime/agentfactory/agentfactory.go` — removed MCP restriction for `openai` type
- Env var `OPENAI_BASE_URL=https://api.deepseek.com/v1` is set in the launchd plist
- go.mod `replace` directive (`normahq/norma v0.0.6 → ../norma-local`) is local only
(not committed to the PR branch — needs a separate norma upstream PR or fork)
To rebuild after patching norma:
```bash
cd ~/Developer/balda
go build -o balda ./cmd/balda/
```
---
## CLAUDECODE Environment Bug (Fixed 2026-06-07)
When launched from an Eagle terminal session, Balda inherited `CLAUDECODE=1`,
which caused the Claude Code CLI to refuse to start (it detected a nested invocation).
**Fix:** Use `launchctl bootout + bootstrap` to start Balda clean — launchd does
not inherit parent shell env vars.
---
## Config Snippet (key sections)
```yaml
balda:
global_instruction: |
<contents of soul.md>
runtime:
providers:
deepseek:
type: openai
openai:
api_key: "<DeepSeek API key>"
model: deepseek-chat
zulip:
webhook:
enabled: true
listen: "0.0.0.0:8091"
path: /zulip/webhook
allowed_owners:
- amartemyanov@duckduckgo.com
```
### 4. После перезапуска нужно @mention для создания сессии
Events API polling подхватывает сообщения только если есть активная сессия в теме.
После рестарта: написать `@Валера <текст>` (или `@Клавдий`).