54 KiB
Workspace Gateway — план
Текущее состояние — сверено 2026-10-19 08:06 UTC
| Компонент | Проверенное состояние |
|---|---|
| SSH Manager | 0.3.2, a86df58, 8 MCP-инструментов, 127.0.0.1:17796 |
| Workspace Manager | 0c82b8f, четыре функции, native SMB3, 127.0.0.1:17795; root только developer, recipient balda |
| Balda | eee69fc5, balda-mm-mac, provider pool, permissions ask; старт 2026-10-19T08:05:42.795540715Z |
| Проверка установленного SSH-ключа | Реальный контейнер Balda, registered, client_verified_at=2026-10-19T06:29:15.692883Z; прежний key id сохранён |
| Исходники / runtime | Все три checkout чистые; build metadata обоих исправленных binaries указывает на эти чистые commits; активные hashes/inode проверены |
SSH Manager импортирует существующий Mac SSH alias из native config/Include и доверенных known_hosts, проверяя существующую аутентификацию; повторно присылать server key для такого хоста не требуется. Для клиента отдельно проверяется маршрут: без via сначала pinned no-auth handshake из настроенного client_container; при сетевом отказе выбирается единственный зарегистрированный relay. Неизвестный или неверный pin не вызывает fallback; при нескольких relay нужен явный via. Owner-form включает точную замену relay key line с ограниченным permitopen. Хардкода Kraken или mac-relay в выборе маршрута нет.
Успех ssh_authorize теперь требует свежего SSH-вызова из фактического клиента его установленным dedicated key с проверкой случайного маркера. Ошибка сохраняет installed_unverified и возвращает tool error; удаление host до отзыва такого ключа запрещено. Существующий принятый доступ можно проверить/исправить без замены целевого ключа и sandbox policy. В operator config указан client_container: balda-mm-mac, volume проверяется read-only.
Inventory сейчас: mac, mac-relay, kraken. Kraken добавлен владельцем через Balda в сессии по ссылке ниже; маршрут исправлен самим менеджером на mac-relay → kraken, relay ограничен текущим endpoint. Новый target key при исправлении не устанавливался, прежняя identity и изоляция сохранены. Отдельный независимый SSH-вызов UID 1000 из Balda вернул ожидаемый маркер.
Треды Mattermost DM: eee69fc5 сохраняет root_id пользовательского сообщения в адресе доставки; обычные ответы, progress и вопросы идут в его тред, дальнейшие replies сохраняют этот root. DM/group session IDs остаются прежними. Это поведение транспорта в коде; настройки переключения нет. Отдельный approval-тред не создаётся. 254f3e29 откачен коммитом 3f6a1363: обработчик обычного числового ответа без треда и изменения хранилища удалены. Узкое сопоставление raw user ID для штатного threaded reply исправлено отдельно в eee69fc5. Исправление двойного меню 3e86b995 сохранено. 9018e7a3 исправляет transport routing; c061e266 исправляет выбор pending-вопроса в общем root вместо уже отвеченного; неоднозначные параллельные pending-вопросы не подтверждаются. eee69fc5 сохраняет прежнюю классификацию лички в архиве. Приёмка и ограничения: personal/projects/balda/mattermost-dm-threads-2026-10-19.
Balda: меню подтверждения рендерится один раз — permission layer передаёт готовую presentation, questions layer сохраняет structured options для ответа, но не дописывает второе меню. Regression проходит через permission review, session question delivery и decision resolution. Добавление host и установка ключа остаются двумя разными owner confirmations; дополнительные generic MCP approvals у Codex выключены, native изменения доступа подтверждаются владельцем.
MCP: obsidian, virfield, workspace-manager, ssh-manager и встроенный balda. Legacy Broker/Prism MCP отсутствуют в runtime, plugin execution-broker выключен, оригинальные Prism/Prism Callee 0.7.0 включены. Codex: workspace-write, дополнительный writable root только grants получателя, --mcp-approval-policy=allow.
Workspace: workspace_folders, workspace_connect, workspace_disconnect, workspace_lease; discovery только папок, выдача конкретной папки RO/RW с TTL. Downloads и общий Developer/home mount не включены. Lease journal пуст. Приняты SMB revoke существующих FD/expiry и shared Beads fixture; runtime Workspace в этом исправлении не менялся.
Проверено: SSH race/vet/build; 15 native SSH lifecycle checks и 16 checks на случайных aliases в сети реальной Balda, включая alias-only import без via, автоматический relay, pin failure, retry, restart/revoke/remove. Историческая model-проверка после deployment SSH-маршрута 06:28 UTC: 01a152d9-7d04-7f21-9597-91c259813c7c, ровно одна Owner confirmation существующего key id, без generic MCP approval; client receipt выше. Полный race-прогон Balda: 142 пакета с тестами; golangci-lint и architecture checks — pass; launchd Workspace/SSH/Beads-Dolt running, health/login 200. Внешние тестовые сообщения Mattermost не отправлялись.
Первичный провал приёмки: сессия Mattermost. Причины и исправление: personal/projects/balda/ssh-client-route-2026-10-19. Evidence: ~/.local/share/balda-workspace/candidate/client-route/; backup: ~/.local/share/balda-workspace/backups/client-route-20261019T062059Z.
Оставшийся исходный объём: полноценные удалённые Mac model runs с отдельными CLI credentials/OpenCode network решениями, полный модельный Prism lifecycle и реальные project Beads DB. Host Docker/socket/sudo authority не добавлялась: установленный target key по-прежнему ограничен принятой песочницей. Эти пункты не объявляются выполненными этим исправлением.
Исторический журнал изменений и исходный план
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 не изменён. Session01a1504b-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. Session01a14fd8-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.
Проект: /Users/admin/Developer/workspace-gateway.
Git: main, реализация 00b7e13; актуальные deployment scripts и приёмка 9e5066a (2026-10-18). Четыре MCP-функции реализованы; принят native SMB3 backend с фактическим отзывом открытых FD на Linux и Mac, независимым истечением срока и динамическим подключением без рестарта получателя. Сервис установлен как user launchd job на 127.0.0.1:17795; аутентифицированные вызовы из доверенного образа Balda прошли. Production Balda переключена с явного разрешения владельца и перезапущена 2026-10-18 в 20:13:46 Asia/Bishkek: native ask активен, оба Manager проверены из рабочего контейнера, SSH/Seatbelt прошёл, HTTP health/login — 200. State/home/work, прежний pool и все записи БД сохранены; backup сделан до переключения. Полная модельная приёмка ещё ожидает отдельных решений по существующим CLI credentials и OpenCode localhost binding.
Исправления production: Codex workspace-write принят реальной моделью в обычном workspace и динамическом RW grant, запись вне разрешённых roots запрещена. Пять безопасных Manager-запросов прошли без approval; изменения прав по-прежнему требуют владельца. Старый broker отключён, оригинальные Prism сохранены. Принятые Docker-профили включены только с точного согласия владельца; privileged/SYS_ADMIN не добавлены. Журнал и повторяемый модельный тест включены в 1076b4f; SSH Manager — f876d37.
Корни проектов исправлены по замечанию владельца: только developer: /Users/admin/Developer. downloads был моей лишней настройкой и удалён из рабочего конфига и примера; дополнительные корни нельзя включать из примера без явного выбора владельца.
Приёмка 9e5066a: из рабочего контейнера получены 139 папок Developer, 8 дочерних папок workspace-gateway, регистронезависимый поиск имени — 2 мс. query фильтрует текущий уровень, глубокий обход включается только recursive: true; прежний неявный обход всех файлов/зависимостей упирался в лимит. Настоящий Codex сделал пять folder calls и вывел реальные корни/количество/имена, permission requests: 0. Отчёт candidate/project-discovery-acceptance.json, тест tests/balda_discovery_acceptance.py, ACP session 01a14fa7-60f2-7971-81de-b6c838ec1c31. Предыдущее заявление о полной проверке не включало просмотр внутри каждого рабочего root и было преждевременным.
Общий setup Balda: personal/plans/balda-remote-agent.
Назначение и четыре функции
Сервис выдаёт Balda и удалённым агентам доступ к исходным папкам через сетевую файловую систему. Balda и агенты видят одни и те же файлы; копирование Git-репозитория не считается реализацией общего доступа.
- Папки: листинг и навигация по папкам внутри настроенных корней (сейчас только
developer; дополнительные roots включаются по выбору владельца), а также поиск папок по имени; без выдачи списка файлов и их содержимого. - Подключение: выбранная папка появляется в work dir после подтверждения владельцем точного пути, получателя, режима доступа и срока.
- Отключение: фактический отзыв ранее выданного доступа.
- Лизинг: статус и срок действия, автоматический отзыв после истечения срока, продление с подтверждением владельца.
Четыре пользовательские функции — согласованный объём проекта. Обработка ответа владельца, журнал выданных разрешений и таймеры обслуживают эти функции, а не расширяют API прикладными сценариями.
Конфиг корней и поиск папок
Workspace Manager — пользовательское название сервиса; текущие путь проекта и имя этой заметки остаются workspace-gateway.
В конфиге задаются несколько именованных корней; список расширяется без изменения кода. Например:
roots:
developer: /Users/admin/Developer
Корень задаёт область обнаружения папок, а не автоматический доступ Balda или агентов ко всем его файлам. Сервис не монтирует целиком Developer или Downloads только потому, что они указаны в конфиге.
Поиск выполняется по имени папки (полное имя или подстрока, без учёта регистра), в выбранном корне либо во всех настроенных корнях. Результат содержит имя корня и относительный путь папки, чтобы различать одинаковые имена. Имена файлов и содержимое файлов в поиск не входят. Выход за корни через .. и символические ссылки не допускается. Подключение найденной папки по-прежнему требует подтверждения владельца точного пути, получателя, прав и срока.
Порядок реализации: загрузить и проверить roots из конфига; реализовать листинг/навигацию; добавить поиск по имени; включить операции в MCP; проверить поиск в нескольких корнях, одинаковые имена, отсутствующий/недоступный корень и запрет выхода за границы.
Границы
SSH-запуск, ACP-транспорт, исполнение команд на хосте и Seatbelt относятся к настройке Balda и среды, а не к Workspace Gateway. Prism, Callee, Beads, управление задачами и сессиями используются штатно. Сервис не реализует собственные Story workflows, собственный Prism и дублирующий scheduler.
Общий каталог Developer и домашний каталог не выдаются агентам.
Листинг папок даёт возможность запросить конкретный путь, а не право читать его файлы.
Ответ от модели или аргумент approved=true не является подтверждением владельца.
Отзыв и истечение срока должны прекращать реальный доступ, включая существующие соединения и открытые файловые дескрипторы.
Конкретные шаги
- Я проверю готовую сетевую файловую систему на текущем Docker/Colima и целевых средах: исходные файлы видны обоим клиентам, добавление разрешённой папки обходится без перезапуска Balda, соседняя папка недоступна, отзыв закрывает уже выданный доступ.
- Я подключу постоянную точку сетевой файловой системы в work dir; это разовая настройка deployment, последующие выдачи и отзывы происходят в рантайме.
- Я реализую конфиг нескольких именованных корней (сейчас только
developer; дополнительные roots включаются по выбору владельца), листинг/навигацию и поиск папок по имени внутри этих корней; затем запрос подключения, связав подтверждение владельца с точным путём, получателем, правами и сроком. Сначала проверю пригодность штатных взаимодействий Balda. Приёмка поиска включает несколько корней, одинаковые имена папок, недоступный корень и запрет выхода через ссылки или... - Я реализую отключение и временный лизинг, сохранение состояния разрешений и обработку истечения срока после перезапуска сервиса; неполученное подтверждение оставляет доступ закрытым.
- Я проведу приёмку с двумя клиентами: общие файлы, RO/RW, запрет соседних путей и обхода через ссылки, отказ владельца, отзыв, истечение, продление и повторный запуск сервиса.
Выбран и принят SMB3 backend: native Samba, mount.cifs Colima и mount_smbfs macOS. Приняты оригинальные файлы, RO/RW, динамические grants, отзыв открытых FD, независимый expiry и реальный отзыв после перезапуска Manager. Подробности — в актуальном журнале ниже. Принятый backend — SMB3. Общая копия всех репозиториев и ослабление изоляции не заменяют выдачу доступа.
Что уже проверено и что остаётся
- Создан отдельный Git-проект с зафиксированной границей четырёх функций.
- Проверена независимая возможность штатного ACP Balda поверх SSH: personal/projects/balda/ssh-acp-verification-2026-10-18.
- Выбрана и испытана сетевая файловая система: native SMB3, Linux и Mac.
- Реализованы четыре функции, native подтверждения, реальный отзыв открытых FD и независимый срок доступа.
- Shared Beads/Dolt проверен на fixture: параллельное создание/чтение, единственный победитель claim, чтение через принятый SSH/SRT.
- Полная модельная работа реальных агентов через полученный workspace и реальные project Beads DB; fixture не считается миграцией проектов.
Доступ к исходникам и доступ к состоянию Beads — связанные, но отдельные пункты общей установки. Для одновременной работы Balda и нескольких агентов Beads описывает server mode Dolt: официальная архитектура. Сетевой mount сам по себе не считается приёмкой конкурентной работы БД.
Выполнение 2026-10-18 — промежуточный журнал
- Исходники находятся в
/Users/admin/Developer/workspace-gateway: конфиг именованных корней, навигация и поиск только папок; запрет.., выхода через ссылки и выдачи целого корня. - Ровно четыре MCP-инструмента:
workspace_folders,workspace_connect,workspace_disconnect,workspace_lease. Подтверждение через MCP elicitation; путь, получатель, RO/RW и точный срок перечисляются в запросе владельцу. - Написано ядро лизинга: атомарный журнал с fsync, отдельно подтверждаемое продление, видимый отказ отзыва и повторные попытки, закрытие незавершённых/активных разрешений после перезапуска. Это проверено тестовым backend; реальные mounts и отзыв файлового доступа ещё не приняты. В исполняемом сервисе подключение закрыто до выбора проверенного backend.
- В реальном проекте прошли
go test -race ./...,go vet ./..., сборка. Настоящий stdio MCP: initialize, tools/list (4 инструмента), листинг без имён файлов, отказ на traversal и неподтверждённом backend. - HTTP MCP: авторизация проверена локально на Mac,
host.docker.internalразрешён, чужой Host отвергается. Из отдельного контейнера Colima проверены достижимость и HTTP 401 без токена; аутентифицированный MCP из контейнера не проверялся. Рабочий порт для подготовки:17795(7795 занят прежним Broker). - Подготовлены
/private/tmp/workspace-setup-20261018/nfs-admin.pyиnfs-acceptance.py. Полный запуск:sudo /opt/homebrew/bin/python3 /private/tmp/workspace-setup-20261018/nfs-admin.py test. Он предназначен только для fixture/private/tmp/workspace-setup-20261018/nfs/source/allowed, клиентов Colima и восстановления исходного состояния после теста. - Первый ручной
startостановился до изменения системы из-за неверной обработки штатного exit 1 уnfsd status; проверка исправлена на наличие самого процесса nfsd и проверена с mock. Полная NFS-приёмка ещё ожидает ручного sudo. На момент этой записи/etc/exportsотсутствует, nfsd не запущен. - Закрытые отчёты/резервные копии:
/Users/admin/Docker/balda-mm-mac/state/workspace-setup-20261018. Production Balda не переключалась.
NFS: ручной запуск и диагностика сетевого пути
Пользователь выполнил nfs-admin.py start: штатный nfsd реально запущен, RPC NFSv3/2049 и mountd зарегистрированы, showmount -e localhost показывает только fixture. Полный test этим выводом ещё не подтверждён.
Первое подключение обоих контейнеров получило Permission denied. Причина в исходной настройке fixture, не доказательство непригодности NFS: TCP-измерение показало, что Mac видит клиента Colima как 127.0.0.1, тогда как экспорт разрешал 192.168.5.1. Отдельно проверено преобразование reserved port: контейнер привязал исходящий порт 900, на Mac наблюдался 127.0.0.1:64152. Артефакт: /private/tmp/workspace-setup-20261018/nfs/colima-source-address.json.
nfs-admin.py test исправлен: разрешает только fixture для loopback, на время теста учитывает переписывание порта в MOUNT RPC, после проверки восстанавливает исходные байты /etc/nfs.conf, удаляет только собственный экспорт и останавливает тестовый сервер. Логика полного восстановления проверена с mock на успешном и ошибочном пути; реальное RO/RW/открытые FD пока ожидает ручного запуска test с sudo. Отказ обоим клиентам не считается успешной изоляцией получателей: результат теперь null до успешного доступа разрешённого клиента.
NFS: результат полного запуска и установленная причина отказа
Пользователь выполнил полный nfs-admin.py test. Оба клиента завершились на mount с Permission denied, поэтому RO/RW и отзыв FD не проверены. Система после сценария реально восстановлена: /etc/exports отсутствует, nfsd остановлен, /etc/nfs.conf содержит исходный текст.
Дальнейшая диагностика установила блокировку самой операции mount в тестовом клиенте; она не позволяет считать созданным NFS mount, независимо от возможных предварительных RPC: Docker использует AppArmor docker-default; с CAP_SYS_ADMIN обычный mount пустого tmpfs возвращает Permission denied (exit 255). Тот же контроль с apparmor=unconfined только у одноразового fixture-контейнера успешно монтирует tmpfs. Это пропуск в тестовом окружении, а не свидетельство непригодности NFS. Предыдущее объяснение одним адресом Colima было неполным; адрес/порт действительно переписываются, но исходные mount-пробы дополнительно блокировались AppArmor.
Подготовлен минимальный отдельный образ workspace-nfs-client:20261018 с официальным nfs-utils 2.6.4; image ID sha256:5468d8d0555b1658bd7626f0f840269203dac8bde49160261268c03aea8b75f4. Он не содержит пользовательских конфигов, токенов или ключей. Предварительная проверка клиента без Mac sudo реально прошла: стандартный mount.nfs существует, tmpfs монтируется. Исправлены fixture options и fail-fast: при неудачном initial тест больше не прогоняет RO/отзыв на остановленных контейнерах. Восстановление root-сценария снова проверено с mock для успеха и ошибки. Для реальной проверки NFS всё ещё требуется повторный ручной sudo ... nfs-admin.py test.
Принятый SMB backend — 2026-10-18
Финальная реализация закоммичена 00b7e13. Используются готовые Samba SMB3 и штатные клиенты macOS/Colima. На каждый lease выдаётся отдельный server/share с отдельным credential, точным bind только разрешённой папки и RO/RW на сервере. Истечение исполняет сам server supervisor, независимо от процесса Manager. Отзыв удаляет share, reload и close-share закрывают открытые FD, затем снимаются mounts; server ещё 60 секунд отвечает отказом старым клиентам и сам удаляется.
Приняты реальные проверки: динамическое подключение в уже работающий непривилегированный контейнер; чтение/запись оригинала с Linux и Mac; server RO; продление без смены mount; отзыв открытых read/write FD обоих клиентов; истечение без Manager; отказ продлению истёкшего share. Дополнительно Go→встроенный backend и фактический отзыв при перезапуске Manager прошли. Ранний протокольный тест также проверил отказ credentials другого получателя, symlink escape и сохранение другого share при отзыве первого. Сохранённая повторяемая приёмка: tests/smb_acceptance.py; отчёт ~/.local/share/workspace-manager-acceptance/report.json.
Постоянный privileged mount-helper был отклонён автоматической проверкой и исключён. Финальный вариант устанавливает cifs-utils в Colima и выполняет обычные разовые native mount/umount команды; привилегированный Docker daemon/helper не остаётся. Корни Developer/Downloads служат только обнаружению. В recipient монтируется только его mount root /var/lib/workspace-manager/balda, с rslave, по совпадающему абсолютному пути на Mac/в Balda. NFS больше не является зависимостью выбранного backend; повторный ручной sudo тест не требуется.
Сервис установлен на 127.0.0.1:17795, private config/state: ~/.local/share/balda-workspace/workspace; настоящее authenticated MCP initialize/tools/list/folders из доверенного образа Balda прошло. Production конфиг Balda ещё не переключался: candidate и финальная прикладная приёмка отслеживаются в personal/plans/balda-remote-agent.