Files
obsidian-vault/personal/plans/balda-remote-agent.md
T

249 lines
52 KiB
Markdown
Raw 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.
# Balda — удалённый агент по SSH
## Текущий статус — 2026-10-19 22:19 UTC+6 (Asia/Bishkek)
SSH Manager **0.4.0**, `d2806ac`, 13 MCP-инструментов, развёрнут и проверен. Есть постоянное изменение профиля и разовое расширение на точный вызов с native owner confirmation и серверной однократностью. Network, файлы, Docker read/manage и sudo разделены. Действующие ключи/маршруты сохранены; initial migration существующего fixed/operator профиля требует отдельного явного подтверждения.
Balda — чистый upstream `138cc4a7`, start `2026-10-19T16:15:26.785581969Z`, config/env/mounts сохранены, health/login 200 и Mattermost websocket connected. Кэш MCP обновлён перезапуском; все 49 sessions/metadata и пользовательские bindings сохранены. Workspace Manager остаётся `0c82b8f`, только root developer.
Реальный Balda ACP и SSH установленным fixture-ключом прошли приёмку; после restart production ключи Mac/Kraken также работают. Все изменения прав идут через менеджер, без ручного изменения host config и без хардкода хоста. Произвольный remote model/Prism lifecycle и реальные project Beads DB не объявляются выполненными этой работой.
Актуальный contract, 22/10/14 проверки, receipts/backup и ограничения: [[personal/projects/balda/ssh-permissions-2026-10-19]]. Текущий runtime/setup: [[personal/projects/balda/setup]].
## История установки
Датированные записи ниже — предыдущие этапы; текущие версии и границы приёмки приведены выше.
## Исторический журнал изменений и исходный план
## 2026-10-19 — существующий SSH-доступ Mac без повторной передачи ключа
Исправлен оставшийся дефект 0.3.0: обязательный public_host_key заставлял Balda просить ключ сервера даже для уже настроенного SSH alias. SSH Manager **0.3.1** развёрнут, коммит afa3813; для импорта достаточно alias. Hostname/user/port/public_host_key необязательны и берутся из native SSH config с Include и существующих known_hosts, включая hashed записи. Пароль/private key оператора не передаются модели и не копируются в Balda.
Менеджер проверяет аутентификацию существующим доступом Mac с доверенным pinned server key. Auto сначала использует операторский маршрут, затем при необходимости пробует только адреса, уже связанные с тем же доверенным ключом, с приоритетом локальных сетей. Каждый выбранный адрес должен пройти pinned SSH auth. Сетевого сканирования, доверия к keyscan или accept-new нет; unknown/revoked/changed trust не принимается. В owner-form показываются полученный endpoint, fingerprint и источник доверия. Для действительно нового доверия остаётся explicit verified public key.
Проверено:
- race/vet/build; native Include/defaults, hashed known_hosts, revoked/unknown keys, нестандартный port syntax и безопасный разбор путей.
- Настоящие два sshd, исходный operator Include + hashed trust + сломанный proxy/hostname: alias-only import без адреса/логина/ключа; native isolation, ProxyJump, wrong pin, restart/revoke/remove — pass.
- Реальная модель Balda добавила и авторизовала fixture, получив только alias/via. Session 01a152a5-8b64-7dc1-be62-d007ff3a09c5.
- После deployment модель получила запрос настроить Kraken через существующий Mac доступ. Менеджер сам прочёл доверенный ключ и подтвердил SSH auth на рабочем LAN endpoint; модель дошла до одной обычной формы добавления без запроса ключа у пользователя. Session 01a152a8-1659-7860-bc63-ea9e8a2d92ba. Тест выбрал Decline: новая запись/ключ/пакеты Kraken не устанавливались.
- Хеши личных ~/.ssh/config, known_hosts, authorized_keys, Manager inventory/journal и Balda compose/config совпадают с backup. Чужие доступы сохранены.
- Balda restart 2026-10-19T05:34:41.958112077Z; Mattermost websocket connected; /backoffice/healthz и /backoffice/login — 200. Активный Manager inode совпадает с установленным binary SHA256 f46fb2f4040ac33e94440f95556052e65f3c4e98d9b88b48c9db18d952749376; runtime source hashes совпадают с HEAD.
Это общее использование существующих SSH-настроек, без захардкоженного адреса или отдельной ручной настройки Kraken. Нативные подтверждения изменения доступа и приёмка filesystem isolation сохраняются. Внешние Mattermost сообщения от имени владельца не отправлялись.
Приёмка: /Users/admin/Developer/ssh-manager/docs/operator-ssh-import-2026-10-19.md. Evidence: ~/.local/share/balda-workspace/candidate/operator-import.json. Backup: /Users/admin/.local/share/balda-workspace/backups/operator-import-20261019T053314Z.
## 2026-10-19 — добавление произвольных SSH-хостов через Balda
SSH Manager **0.3.0** развёрнут, коммит 85227c4, рабочее дерево чистое. Теперь доступны восемь MCP-инструментов, включая ssh_host_add и ssh_host_remove. Новые хосты добавляются через Balda: alias, адрес, пользователь, проверенный public host key, при необходимости port/via/bootstrap alias. Ручная правка операторского JSON для добавления не требуется.
Подтверждение добавления показывает endpoint/login, fingerprint и public host key, выбор bootstrap и точную замену relay-строк. Для каждого нового alias создаётся отдельная identity; inventory и актуальный SSH config сохраняются сразу и переживают restart. Затем ssh_authorize подтверждает и выполняет native подготовку изоляции и установку ключа. Существующий bootstrap SSH доступ оператора остаётся необходимым; пароли/private bootstrap keys в инструменты и чат не передаются.
Удаление требует предварительно отозвать registered/pending ключи и убрать зависимые jump hosts. Relay permissions обновляются вместе с inventory; при отсутствии целей forwarding отключается. Чужие authorized_keys сохраняются, существующие сессии не завершаются. Файлы private identity при удалении inventory сохраняются. Ошибки sync откатывают inventory и восстанавливают relay/client config либо явно сообщают о неподтверждённом откате.
Частная запись Kraken удалена штатным ssh_host_remove; её прежний permitopen тоже убран. Сохранились два исходных Mac host/relay alias, их ключи и журнал регистраций. Прямой ручной настройки самого Kraken не выполнялось. У менеджера нет привязки к этому хосту.
Проверено:
- race/vet/native build; tests отмены, сохранения/удаления, stale config, rollback, unsafe input, защиты от подмены alias, guards revocation/dependants и read-only public identity.
- Два настоящих временных sshd с пустым начальным inventory, случайными alias/портами: add, relay update, native isolation, ProxyJump command, wrong pin rejection, restart, revoke/auth denial/remove; 12 проверок passed.
- Реальная модель Balda сама добавила и авторизовала новый fixture-хост, ровно две Owner confirmation, затем прошли настоящий SSH и lifecycle. Session 01a15295-479a-7123-b64d-9ee46465b5dd.
- Рабочий production ssh_host_add через модель: одна форма, тест Decline, inventory/keys/journal неизменны. Session 01a15297-3e86-7fd3-831a-8283d0a2a64a.
- Рабочая модель после restart: четыре SSH lookup и workspace discovery без approvals, workspace RW и отказ вне него. Session 01a15298-98b7-7de0-9274-b2cd63c61958.
- Прежний Mac execution через обязательный SRT работает; пустой relay аутентифицируется и административно отказывает forwarding.
- /backoffice/healthz и /backoffice/login — 200; Mattermost websocket connected. Balda restart: 2026-10-19T05:16:18.960287594Z. Compose/config и registration journal сохранены.
Активный native Manager inode совпадает с установленным бинарником; SHA256 d3a9b63570932782942d8b3e2e2c92fabead5a5551f3b3d8c330922d9ec58d98. Source HEAD и runtime source hashes сверены. Внешние Mattermost сообщения от имени владельца не отправлялись. Полная исходная установка с отдельными решениями по личным CLI credentials этим исправлением не объявляется завершённой.
Приёмка: /Users/admin/Developer/ssh-manager/docs/host-inventory-2026-10-19.md. Evidence: ~/.local/share/balda-workspace/candidate/generic-host-manager.json. Backup: /Users/admin/.local/share/balda-workspace/backups/generic-hosts-20261019T051417Z.
## 2026-10-19 — исправлен тайм-аут bootstrap Kraken
SSH Manager **0.2.1**, коммит fbbc867. В операторский конфиг добавлен явный bootstrap_direct: существующий ключ доступа и pinned host key сохраняются, у выбранного хоста отключается наследуемый ProxyCommand/ProxyJump. По умолчанию маршруты остальных хостов не меняются. Описание ssh_authorize разделяет bootstrap менеджера и клиентский relay.
У существующей записи Kraken выбран уже документированный и проверенный по pinned host key адрес 192.168.1.14:22 вместо неразрешимого имени и мёртвого WG-пути 10.99.1.2. В существующем явно разрешённом relay-ключе Mac через native MCP обновлён только permitopen на тот же проверенный Kraken. Ключ, запрет shell, остальные authorized_keys и журнал регистраций сохранены. Личный ~/.ssh/config не менялся.
Проверено: race/vet/build; настоящий sshd/MCP fixture с намеренно сломанным наследуемым proxy; production ssh_authorize дошёл до Linux bubblewrap owner-form; настоящий UID 1000 Balda получил SSH banner Kraken через relay. Реальная модель Balda, session 01a15249-fb40-7593-89b8-afefb628ebae, получила ровно одно Owner confirmation, без generic MCP approvals, и вернула OWNER_DECLINED после тестового отказа. Этот тест не устанавливал ключ/пакеты на Kraken; его execution-регистрация и приёмка изоляции не объявляются завершёнными.
Balda перезапущена 2026-10-19T03:52:04.641738976Z; websocket Mattermost подключён; /backoffice/healthz и /backoffice/login — 200. Активный native Manager использует установленный inode; binary SHA256 7e72c8e3fd2b251a39bc94a1e7f980cc8152c323fe5abe975db633a0e3eaaf72. Рабочее дерево чистое.
Приёмка: /Users/admin/Developer/ssh-manager/docs/bootstrap-route-2026-10-19.md. Evidence: ~/.local/share/balda-workspace/candidate/ssh-route-fix.json. Backup: /Users/admin/.local/share/balda-workspace/backups/ssh-route-20261019T035049Z.
## 2026-10-19 — SSH Manager: подготовка через менеджер
Исправление закоммичено в `ssh-manager`: `e490774`. Рабочий Manager 0.2.0 обновлён, MCP-кеш Balda обновлён разрешённым перезапуском. Последний запуск Balda: `2026-10-18T18:32:13.106914568Z` UTC. Финальный бинарник Manager: SHA256 `059d6c9c79a67893a9772a34c7a103919d2ba7a5e3faa7171af781dd3ec81160`; проверено совпадение inode реально слушающего процесса с этим файлом. Рабочее дерево SSH Manager чистое.
Прежнее изменение текста ошибки не решало задачу. Теперь `ssh_hosts` показывает регистрацию и следующее действие по назначению ключа; зарегистрированному `mac-relay` не требуется execution-подготовка. Для обычного непринятого execution-хоста `ssh_authorize` сам планирует native filesystem isolation через существующий pinned bootstrap SSH, получает **одно** подтверждение владельца на подготовку и точную строку authorized_keys, подготавливает и проверяет изоляцию, затем устанавливает ключ. Операторский флаг в JSON вручную не переключается. Guard принятой изоляции и AGENTS.md сохранены.
Принятые проверки:
- `go test -race ./...`, `go vet ./...`, build, Python compile — pass.
- Настоящие macOS sshd + MCP: Cancel не меняет ключи; намеренно сломанная подготовка не устанавливает ключ; повтор после исправления fixture создаёт private policy, регистрирует только fixture-key через bootstrap SSH и проходит реальную аутентификацию. Проверен нестандартный HOME под `/private/var/tmp`, не покрытый обычными read-deny roots.
- Native Linux bubblewrap в Colima: RW private workspace; отказ чтения/записи снаружи; отказ symlink escape; ограничения наследуются дочерним процессом; host loopback недоступен. Свежий `/proc`, user/PID/network namespaces и запрет вложенных user namespaces сохранены. Ограничение Docker на fresh `/proc` не обходилось ослаблением политики.
- Реальная модель после финального перезапуска: пять безопасных Manager-вызовов без generic MCP approvals, запись в workspace и отказ вне него. Session `01a1504b-b585-7360-841a-877c588ae679`.
- Реальный Codex ACP внутри рабочей Balda: сначала `ssh_hosts`, затем `ssh_authorize` непринятого fixture-хоста; одно Owner confirmation с планом native подготовки. Тест выбрал Decline, получен OWNER_DECLINED; production SSH state не изменён. Session `01a1504b-b5fa-7f22-80a6-fe3c4c3cedee`. Сообщение/подтверждение от имени владельца в Mattermost не отправлялось.
- HTTP health/login — 200; прежний настоящий SSH к Mac по-прежнему проходит обязательный SRT. Хеши Mac authorized_keys, SSH host config и registration journal совпадают с исходными. Compose/config Balda сохранены.
Bootstrap использует `/usr/bin/python3 -I`: read-only preparation script завершался SIGKILL под Homebrew Python, а тот же script под системным интерпретатором прошёл. Причина отмены контекста и безопасная категория ошибки bootstrap теперь сохраняются без возврата raw proxy stderr/credentials.
Default private policies имеют изолированную сеть; API/proxy/credentials агента относятся к настройке runtime. Существующая принятая Mac SRT/network policy не менялась. Непринятый custom forced command не заменяется молча. Для операции по-прежнему нужен реально доступный bootstrap-хост; программный флаг не подменяет сеть или права установки native dependencies.
Это исправление продукта SSH Manager, **не ручная настройка Kraken**: его адрес/конфигурация и регистрация не переписывались. Прежняя запись о необходимости вручную включить `execution_ready` для обычного хоста больше не описывает текущий Manager. Отдельные нерешённые решения исходного плана по личным Mac CLI credentials/OpenCode localhost этим исправлением не считаются закрытыми.
Приёмка: `/Users/admin/Developer/ssh-manager/docs/acceptance-2026-10-19.md`. Подробный runtime evidence: `~/.local/share/balda-workspace/candidate/ssh-manager-flow-fix.json`. Consistent backup: `/Users/admin/.local/share/balda-workspace/backups/ssh-manager-flow-20261018T181430Z`.
## 2026-10-18 — исправлены MCP approvals и ответы `1`
Лишний `MCP tool-call approval` убран в активных Codex-профилях штатным флагом моста `--mcp-approval-policy=allow`. Режим Balda остаётся `ask`. Точные подтверждения Workspace Connect/Renew и SSH Authorize/Revoke остаются обязательными. Подключённые MCP-серверы и их credentials не расширялись.
Upstream Codex ACP 1.11.0 требует elicitation capability, которой нет у текущего клиента Balda. В закреплённой сборке добавлен узкий fallback пустой confirmation-only формы на существующий ACP RequestPermission. Форма с полями и неподдержанные режимы без capabilities не принимаются автоматически. Explicit accept/decline/cancel и неизвестные ответы покрыты тестами. Чистая повторная сборка закреплённого source + patch прошла race/lint и дала одинаковый хеш.
Исторический патч `254f3e29` **откачен** в `3f6a1363`; описанное далее поведение больше не действует. Тогда обычный `1` в DM относится к единственному доставленному действующему вопросу той же беседы/сессии; ID отвечающего совпадает с исходным ID автора запроса, без добавления `mattermost:` только к ответу. Проверяются права отвечающего, expiry и время сообщения. Старый `1`, в том числе в пределах той же секунды, не разрешает новый вопрос. Общие каналы и несколько pending-вопросов требуют ответа в треде.
Проверено:
- Настоящая цепочка Mattermost adapter → ChatFX → questions → SQLite: `1` разрешает, `2` отклоняет; продолжение сохраняется для штатного возобновления. Wrong requester/session/conversation, expiry, недоставленный/неоднозначный вопрос, обычный текст и старое сообщение не выдают разрешение.
- Полный `go test -race ./...`: 173 пакета, exit 0; golangci-lint — 0 issues; go-arch-lint — OK.
- Реальный Codex внутри production Balda: пять Manager lookup, запись в workspace и запрет записи вне него; generic permission requests = 0. Session `01a14fd8-a855-7bb2-ae76-77d5449db219`.
- Реальный `ssh_authorize` с возможностями клиента Balda дошёл до одного окна Owner confirmation; тест выбрал Decline и получил OWNER_DECLINED. Session `01a14fd8-a84d-75d0-9624-ec816c3de844`. Approved authorized_keys и registration journal не изменились.
- Балda реально запущена из проверенной сборки: hash `/proc/1/exe` совпал со staged binary. Последний запуск: `2026-10-18T16:41:07.023505736Z`. HTTP health/login — 200; native SSH к Mac через обязательный Seatbelt — pass. State/home/work mounts сохранены; SQLite/compose/config backup — `/Users/admin/.local/share/balda-workspace/backups/direct-reply-20261018T162446Z`.
Коммиты: Balda `254f3e29`; Workspace Manager/deployment `0c82b8f` (основное MCP-исправление `a5c0b66`); SSH Manager `8739b1e`. Рабочие деревья проверены отдельно. Подтверждение в реальном Mattermost-чате не отправлялось от имени владельца; приёмка входящего ответа выполнена сквозным тестом. Runtime evidence: `~/.local/share/balda-workspace/candidate/direct-reply-fix.json`.
Kraken остаётся **не настроен для execution**: его filesystem isolation не provisioned/accepted; `execution_ready=false` сохранён. Инструмент теперь явно говорит, что chat approval не может подготовить хост, вместо ложного совета подтвердить несуществующее окно. Из Mac имя `kraken` не разрешается через DNS, оба IP из существующего SSH ProxyCommand (`10.99.0.2`, `10.99.1.2`) не ответили на TCP 22; bootstrap SSH истёк на banner exchange. Запрошен доступный адрес/восстановление маршрута. Регистрация нового target-ключа и приёмка этого хоста не заявляются выполненными.
Ранее остававшиеся отдельные решения по личным Mac CLI credentials/OpenCode localhost этим исправлением не подменяются. Полная исходная настройка не помечена принятой.
Исторический снимок: **2026-10-18**.
Отдельный проект доступа к папкам: [[personal/plans/workspace-gateway|Workspace Gateway]], `/Users/admin/Developer/workspace-gateway`, начальный коммит `2bc6743`.
Дополнительная проверка SSH и Seatbelt: [[personal/projects/balda/ssh-seatbelt-2026-10-18]].
Исходная задача: Balda работает с оригинальными Prism/Beads по подключённым проектам и запускает штатного агента в другой среде; подключение нового репозитория требует подтверждения владельца.
Проверка: [[personal/projects/balda/ssh-acp-verification-2026-10-18]].
Рабочая установка: [[personal/projects/balda/setup]].
## Исторический статус 2026-10-18
Уточнение по поиску проектов, коммит `9e5066a`: рабочий root только `developer` (`/Users/admin/Developer`). Ошибочно включённый мной `downloads` удалён. Его зависший параллельный вызов скрывал от модели успешный ответ Developer; фактически Developer уже отвечал за 12 мс. Default query больше не обходит всё дерево исходников и dependencies: фильтруется выбранный уровень; глубокий поиск остаётся явным `recursive: true`. Проверены 139 папок корня, 8 вложенных папок workspace-gateway и поиск имени. Реальный Codex получил результаты и вывел их в ответе без approval (session `01a14fa7-60f2-7971-81de-b6c838ec1c31`). Это конкретная новая проверка; прежнее заявление о полной приёмке было преждевременным. Системные TCC/FDA permissions не выдавались и не обходились.
Исправления после production feedback закоммичены: Workspace Manager `1076b4f`, SSH Manager `f876d37`. Старые `execution-broker`/`execution-prism` MCP и broker-инструкция удалены из активного конфига; broker plugin отключён без удаления его файлов/ревизий. Оригинальные `prism` и `prism-callee` включены.
Codex работает с `workspace-write` и дополнительным writable root только для grants получателя. После точного согласия владельца активированы отдельные Docker seccomp/AppArmor profiles для bubblewrap; privileged/SYS_ADMIN не включались. Root grants остаётся operator-owned; пустые защищённые metadata targets позволяют собрать sandbox без права создавать произвольные grants.
Реальная модель внутри рабочей Balda успешно вызвала `workspace_folders`, `ssh_hosts`, `ssh_identity`, `ssh_config`, `ssh_registrations`, записала файл в `/workspace/work` и в настоящую динамически подключённую RW fixture. Запись вне workspace отвергнута (EROFS), **permission requests: 0**. Подготовка identity/config перенесена в запуск SSH Manager, поэтому их MCP lookup действительно read-only. Подтверждения выдачи/продления доступа и SSH authorize/revoke сохранены. Тестовые маркеры убраны, synthetic grant отозван/отмонтирован. Приёмка: `01a14f89-d937-78a0-b93d-71d70ef48179`, `candidate/model-policy-acceptance.json`, `candidate/review-fixes.json`. Повторяемый тест: `tests/balda_policy_acceptance.py`. Оба Go-проекта: race/vet/build — pass; HTTP health/login — 200. State/home/work тома и backup сохранены.
Workspace Manager (`9e5066a`) и SSH Manager (`f876d37`) реализованы, проверены и работают как user launchd services на loopback. Владелец явно подтвердил два новых SSH-ключа: настоящий вход из Balda к Mac через обязательный Seatbelt принят; relay shell отвергается. Native SMB backend отзывает открытые FD и истекает независимо от Manager. Все 14 оригинальных Prism Role runtimes прошли `callee doctor` через SSH в совпадающем workspace. Native Beads 1.3.1/Dolt 2.5.0 прошли общие параллельные записи/чтение и гонку claim; из SSH+Seatbelt тот же bd работает через точный Unix socket без wildcard loopback.
**Production переключение завершено с явного разрешения владельца на перезапуск.** Balda и Web UI перезапущены 2026-10-18 в 20:13:46 Asia/Bishkek (14:13:46 UTC); активен штатный `ask`, сохранён прежний pool. Из настоящего рабочего контейнера прошли authenticated MCP initialize/list/read вызовы обоих Manager (4 и 6 tools) и SSH-команда через обязательный Seatbelt. `/backoffice/healthz` и `/backoffice/login` — HTTP 200; Mattermost websocket подключился. Сохранены все 49 sessions, 1926 events, 2 users и 87 execution jobs, прежние state/home/work тома. До переключения сделан consistent SQLite backup и копии compose/config в `~/.local/share/balda-workspace/backups/20261018T141324Z`; отчёт `candidate/activation.json`. Коммит приёмки `51a63af`, SSH Manager `d9c19ee`.
**Полная модельная приёмка остаётся открытой.** Ожидаются два отдельных решения: использование существующих CLI credentials на Mac и OpenCode v2 localhost binding. Автоматическая проверка отклонила эти действия без отдельного согласия; разрешение перезапуска их не заменяет. Manager-токены remote Mac агентам не передаются. Реальные project Beads databases не мигрировались.
Подробная приёмка: `/Users/admin/Developer/workspace-gateway/docs/acceptance-2026-10-18.md`; закрытый кандидат: `~/.local/share/balda-workspace/candidate`. Исторический план и промежуточные неуспешные проверки ниже сохранены как журнал.
## Принятая граница
Максимально использовать штатный стек Balda: провайдеры ACP, сессии, управление задачами, MCP, skills и подтверждения.
Prism, Prism Callee, Callee и Beads — оригинальные, с сохранением их собственных контрактов.
```text
Balda → штатный generic_acp → ssh -T → штатный ACP-агент в другой среде
```
Единый способ связи — SSH: контейнер, VM или физический хост отличаются окружением, а не протоколом запуска.
macOS-окружения предоставляет Virfield через его MCP.
Штатный агент выполняет работу в выданном workspace; Balda сохраняет управление беседой и сессией.
## Что проверено
- [x] Штатная фабрика Balda запускает `ssh` через `generic_acp.cmd` и передаёт ACP.
- [x] Реальный OpenCode создаёт и возобновляет сессию после повторного SSH.
- [x] Контрольный ACP-агент получает штатное решение Balda разрешить или отклонить действие.
- [x] Контрольный удалённый агент вызывает настоящий MCP-инструмент.
- [x] Штатные тесты Balda подтверждают Mattermost review, защиту от чужого ответа и timeout.
- [x] Воспроизведены локальная проверка cwd и требования к достижимости MCP.
Для передачи ACP новая реализация `broker-acp` не требуется: базовый путь уже проверен.
Дополнительный код допустим только для конкретного воспроизведённого пробела интеграции; прикладные сценарии и учёт фаз Prism остаются в штатном стеке.
## Первоначальный план действий — история 2026-10-18
1. Я реализую и приму Workspace Manager (проект `workspace-gateway`) в отдельном проекте: настраиваемые именованные корни (`developer`, `downloads` и другие), листинг и поиск папок по имени без файлов, подключение после подтверждения владельца, отключение и временный лизинг; сетевая файловая система обеспечит одни и те же исходные файлы Balda и агентам без перезапуска Balda при каждой выдаче. Указание корня в конфиге разрешает обнаружение папок, но не выдаёт доступ ко всем его файлам.
2. Я настрою авторизованный SSH из контейнера в реальные среды, проверку host key, ограниченные credentials и штатный `generic_acp` с командой SSH; доступность порта и проверка протокола уже подтверждены, рабочая авторизация ещё не принята.
3. Я настрою запуск агентов и обычных команд на Mac под Seatbelt, начиная со штатных sandbox и готового `anthropics/sandbox-runtime`, и проверю запрет доступа к соседним проектам, секретам и обхода через другой SSH command.
4. Я настрою согласованные пути workspace, достижимые MCP, оригинальные skills/tools и единое состояние Beads для Balda и одновременных агентов, затем включу запросы разрешений у агентов и штатный `ask` Balda.
5. Я проведу реальную приёмку выбранных Codex/Claude/OpenCode и оригинального Prism: статус проекта, подтверждение и отказ, выполнение, отмена, продолжение сессии и прекращение доступа после отзыва или истечения лизинга.
Это исходная формулировка плана; выполненные действия и оставшийся объём сверены в текущей сводке в начале заметки.
SSH/Seatbelt/ACP и настройка Beads не расширяют четыре функции Workspace Gateway.
## Что подтверждено дополнительно
- Docker работает через Colima, а не Docker Desktop.
- Из основного контейнера получены SSH banners Mac и внешнего GitHub на TCP/22; логин и команды при этом не выполнялись.
- Seatbelt на Mac 26.7.1 реально заблокировал чтение и запись в контрольную папку, в том числе дочерним shell; это не готовый production профиль.
- Документация Beads описывает Dolt server mode для нескольких одновременных записывающих агентов: [первичный источник](https://github.com/gastownhall/beads/blob/main/docs/architecture/index.md).
- Политика файлов и сети для реальных агентов, native approvals и полная работа Prism остаются открытыми.
## Права и репозитории
Подтверждение подключения репозитория, подтверждение действия агента и файловая изоляция — три отдельные проверки.
Агент не получает полномочий самостоятельно выдавать себе доступ к новому проекту.
Весь каталог `Developer` не передаётся Balda или исполнителю.
Исходная БД Beads соответствующего проекта остаётся источником статусов; Git-клон сам по себе не доказывает наличие актуального состояния Beads.
Механизм выдачи доступа к реальным проектам и их БД ещё требует настройки и приёмки.
## Историческое состояние и границы — 2026-10-18
Основная Balda получила оригинальные Prism/Prism Callee, `bd`, Callee и прямой Virfield MCP; это установка инструментов, а не приёмка удалённого исполнения.
В рабочем конфиге остаётся `permissions.mode: allow_all`; SSH-проверка production-конфиг, историю и авторизацию не меняла.
Полный Prism lifecycle с моделью и реальные удалённые Claude/Codex этой проверкой не приняты.
Новый сервис создаётся в отдельном проекте `workspace-gateway`; его объём ограничен четырьмя функциями доступа к папкам.
Прежняя ветка `broker-rebuild` в `/Users/admin/.codex/worktrees/broker-rebuild/execution-broker` — оставшийся каркас предыдущего обсуждения, а не место реализации Workspace Gateway.
Старые `execution-broker`, `execution-prism` и plugin остаются в действующей Balda; очистка новой ветки не удаляла их из deployment.
Историческая приёмка прежнего брокера: [[personal/plans/balda-callee-prism-plan]].
## Выполнение 2026-10-18 — промежуточный журнал
- Создан отдельный Git-проект `/Users/admin/Developer/ssh-manager`, исходники и README записаны. Учёт настроенных оператором хостов/пользователей/проверенных public host keys, отдельная Ed25519-идентичность, `ssh_config`/`known_hosts`, ProxyJump, подтверждение регистрации/удаления управляемой строки authorized_keys через штатный MCP elicitation. Private key не возвращается инструментами; bootstrap credentials остаются у оператора.
- Relay-ключ ограничен штатными OpenSSH options, `/usr/bin/false` запрещает shell, `permitopen` ограничивает переход заданными адресами. Execution до принятой файловой изоляции отвергается. Это каркас подготовки доступа; **production Mac/VM ещё не авторизованы и удалённые реальные агенты не приняты**.
- Существующие пользовательские SSH-ключи и authorized_keys не менялись. Отдельный sshd на loopback-порту с fixture-файлом подтвердил вход по закреплённому ключу, отказ при подмене host key и отказ нового входа после удаления fixture-ключа. Полный ProxyJump и production SSH/ACP остаются открытыми.
- SSH Manager: `go test -race ./...`, `go vet ./...`, сборка — успешно. Настоящий stdio MCP отдал 6 инструментов; отказ через elicitation остановил регистрацию. Локальная HTTP-авторизация и Host allowlist приняты; Colima получила 401 без токена. HTTP-порт подготовки `17796`; 7796 занят прежним Broker.
- Готовый `@anthropic-ai/sandbox-runtime@0.0.80` установлен только в тестовый каталог. Проверка на Mac прошла: разрешённая папка читается/пишется, соседняя закрыта, открытие SSH private key блокируется без чтения его содержимого, ограничения наследуются дочерним shell, SSH-обход блокируется. **Это тестовый профиль, не приёмка Codex/Claude/OpenCode с реальными авторизациями и сетью.**
- Подготовлена отдельная копия конфига Balda: `permissions.mode: ask`, MCP Workspace/SSH Manager, отдельный профиль `workspace-setup` на штатном Codex, существующий pool не изменён. `balda --profile workspace-setup validate` в новом одноразовом контейнере завершился exit 0; provider runtime/модели/каналы не запускались. Это проверка конфигурации, не preflight или сквозной Prism.
- Копия конфига, приватный env новых manager-токенов, оригинальный backup и отчёты находятся в `/Users/admin/Docker/balda-mm-mac/state/workspace-setup-20261018`. Внешние сообщения не отправлялись. Рабочая Balda не переключалась; перезапуск остаётся отдельным подтверждаемым действием после реальной приёмки.
- При автоматической проверке был отклонён тест с передачей manager-токенов в отдельный Python Docker-образ. Его заменили безопасной проверкой: токены остаются в локальных Mac-процессах; контейнер проверяет только достижимость/401 без авторизации. Аутентифицированный вызов из Balda ещё открыт.
- Ближайшая зависимость: полный fixture-тест штатного NFS (`sudo /opt/homebrew/bin/python3 /private/tmp/workspace-setup-20261018/nfs-admin.py test`). Файловый backend, реальный отзыв открытых дескрипторов, согласованные mounts, общий Beads/Dolt и полный Prism/удалённые агенты не заявляются выполненными.
### Дополнительная приёмка SSH Manager: реальный ProxyJump
`/private/tmp/workspace-setup-20261018/ssh-jump-acceptance.py` запустил два настоящих локальных sshd, получил отдельный public key и клиентский конфиг через настоящий stdio MCP SSH Manager и проверил SSH roundtrip через ProxyJump. Четыре проверки успешны: roundtrip; отказ shell на relay; отказ forwarding к незаданному адресу (подтверждён журналом sshd); отклонение подменённого host key конечного сервера через jump. Менеджер использовал обычный OpenSSH, без нового транспортного launcher. Пользовательский `.ssh` и системный sshd не менялись, тестовые sshd остановлены. Это приёмка транспорта/конфига на локальных fixture-серверах, не production авторизация Mac/VM и не ACP с моделями. Отчёт: `/private/tmp/workspace-setup-20261018/ssh-jump-acceptance.json`.
## Фактическое продолжение 2026-10-18
- Workspace Manager закоммичен: `00b7e13`; SSH Manager: `d6323b5`. Оба прошли `go test -race ./...`, `go vet ./...`, build. Это реальные отдельные проекты, не изменения execution-broker.
- Финальный файловый backend — готовые Samba SMB3, native `mount.cifs` в Colima и `mount_smbfs` на Mac. Постоянного privileged Docker helper нет. Linux recipient — обычный контейнер с `rslave` только своего пустого mount root. Приняты новые grants без его рестарта, общие оригинальные файлы, RW, server RO, продление, отзыв уже открытых read/write FD обоих native клиентов, независимое от Manager истечение и запрет продления истёкшего share. Go→встроенный backend и реальный отзыв при перезапуске Manager также прошли.
- Два Manager установлены как user launchd jobs, слушают только `127.0.0.1:17795` и `:17796`. Из одноразового доверенного `balda-prism:20261018`, UID node, read-only/cap-drop=ALL реально прошли authenticated initialize, 4/6 tools/list и readonly tool calls. Новые bearer tokens находятся вне Balda `/state`: `~/.local/share/balda-workspace/managers.env` (0600).
- Владелец явно подтвердил два новых SSH fingerprints и передачу только Balda. Они установлены через SSH Manager с сохранением прочих authorized_keys; private identities находятся в отдельном Docker volume `balda-ssh-manager` (UID 1000), а не в общем host .ssh. Native SSH из доверенного контейнера к Mac реально выполнил команду через обязательный SRT; relay shell реально отвергнут. Альтернативная SSH команда открыть личный SSH ключ Mac получила PermissionError без чтения содержимого.
- Исправлен конфликт relay/execution на одном хосте: отдельные identity names. Native ProxyJump, ограниченный permitopen, отказ relay shell и подменённому target key повторно прошли. Kraken есть в inventory по существующему known_hosts, его execution остаётся закрытым до отдельной принятой изоляции.
- Подготовлены закрытые candidate config/compose: `~/.local/share/balda-workspace/candidate`; `docker-compose ... config --quiet` прошёл. В нём `ask`, два Manager MCP, одинаковые абсолютные workspace пути и native generic_acp профили Mac Codex/Claude/OpenCode через `ssh -T`. Рабочая Balda пока не перезапущена.
- Реальные Codex и Claude ACP на Mac под SRT уже проходят initialize и session/new через этот SSH. Это ещё не подтверждение вызова модели: CLI authorizations запрошены у владельца отдельным native input после отказа автоматической проверки доступа к credentials. OpenCode v2 падает при готовности standalone server; его узкий IPC runtime диагностируется без открытия общего loopback.
- Оригинальный Callee с правильным `--agent-root /home/node/.config/callee` успешно отдал весь native Prism graph. Полный модельный Prism lifecycle и общее состояние Beads/Dolt пока не заявляются принятыми.
### Исторический итог выполненной части — 2026-10-18
- Workspace HEAD `e99f043`, SSH HEAD `d9c19ee`; оба Git working tree чистые. Исходники, tests, scripts и точная приёмка закоммичены. Полная модельная работа не помечена выполненной.
- User jobs `local.balda.workspace-manager`, `local.balda.ssh-manager`, `local.balda.beads-dolt` реально running. Manager listeners только 127.0.0.1:17795/17796, native Dolt только 127.0.0.1:13307 плюс точный Unix socket в agent-home.
- Original Beads/Dolt: Mac и trusted Balda одновременно создали разные задачи в одной fixture DB, оба прочли оба ID; при одновременном claim exit codes 1/0 — ровно один победитель. Metadata — один и тот же оригинальный файл через SMB. Native bd внутри реального SSH+Seatbelt прочитал ту же БД через Unix socket и explicit native credentials file. Свои fixture credentials не дают доступа к реальным проектам; их БД не переинициализировались.
- Broad localhost binding по-прежнему выключен. OpenCode требует отдельного решения владельца. Уже работающие Codex/Claude ACP initialize/session-new не считаются модельной приёмкой; Claude на prompt вернул Authentication required при закрытых существующих CLI credentials.
- Передача Manager bearer tokens Mac была отклонена автоматической проверкой и исключена из схемы. Manager MCP подключены управляющей Balda; remote executors получают approved filesystem и native Beads. Для необходимых Balda HTTP callbacks штатный SRT proxy работает с очищенным NO_PROXY; unauthenticated Mac→Manager probe получил ожидаемый HTTP 401 без раскрытия токенов.
- Собственный synthetic ACP grant после проверок отозван и снят. Привилегированных постоянных mount helpers нет. Исходный Docker Dolt volume сохранён как резерв fixture; рабочий server теперь native Mac, чтобы Beads использовал Unix socket внутри sandbox.
- Кандидат включает original Prism assets с неизменёнными workflow bodies; изменены только native provider settings, убран отвергавшийся runtime pin gpt-5.4, включён ask. Полный runtime doctor всех 14 ролей exit 0. Production restart остаётся финальным отдельным подтверждением после model acceptance.