# Phase 05: MVP Deployment — Context **Gathered:** 2026-04-27 **Status:** Ready for planning ## Phase Boundary Подготовить Matrix-бот к реальному деплою на lambda.coredump.ru: 1. Перейти на single-chat архитектуру (chat_id=0, один контекст на пользователя) 2. Упростить онбординг: DM-first без Space/rooms provisioning, welcome-сообщение при invite 3. Расширить config/matrix-agents.yaml — добавить user_agents (Matrix user_id → agent_id) и per-agent base_url/workspace_path 4. Обновить AgentRegistry и _build_platform_from_env для per-agent URL routing 5. Реализовать file transfer через shared volume /agents/: входящие → incoming/{filename}, исходящие через MsgEventSendFile 6. Добавить !clear (сброс контекста через переподключение AgentApi) 7. Написать docker-compose.prod.yml с полным стеком (matrix-bot + placeholder agent + named volume agents) 8. Удалить legacy: !agent, !new, !archive, !rename, !save, !load, Space-creation, C1/C2/C3 room provisioning НЕ входит: - Конфигурация агентских контейнеров (платформа) - Telegram-адаптер - E2EE - platform-master интеграция - !save / !load (ненадёжны без persistent memory в агенте) ## Implementation Decisions ### Single-chat архитектура - **D-01:** chat_id=0 для всех сообщений. Один контекст агента на пользователя. Изоляции между разными разговорами нет — вместо этого `!clear` сбрасывает контекст. - **D-02:** Удалить всю multi-room инфраструктуру: C1/C2/C3, `!new`, `!archive`, `!rename`, Space-creation, room provisioning. Matrix-бот работает только в DM-комнате (личка с ботом). - **D-03:** Удалить `!save` и `!load` — ненадёжны без persistent memory в агенте (MemorySaver сбрасывается на рестарте). ### Онбординг (DM-first) - **D-04:** При получении invite в DM-комнату — принять, отправить welcome-сообщение: "Привет! Я Lambda AI-агент. Просто напиши — и я отвечу. `!clear` чтобы начать новый разговор, `!context` чтобы посмотреть статус." - **D-05:** Никакого Space, никаких дочерних комнат. Вся переписка в одной DM-комнате. ### !clear (новая команда) - **D-06:** Сбросить контекст агента — закрыть текущий AgentApi connection и создать новый (`await agent.close()` + `await agent.connect()`). Это сбрасывает MemorySaver. Подтвердить пользователю: "Контекст сброшен. Начнём с чистого листа." ### !agent команда - **D-07:** Удалить полностью. Маппинг user→agent теперь статический из config. Пользователь не может менять агента. ### Конфиг агентов (config/matrix-agents.yaml) - **D-02:** Расширить текущий matrix-agents.yaml — добавить user_agents dict и поля base_url/workspace_path к каждому агенту. Один файл, один парсер. Формат по docs/deploy-architecture.md: ```yaml user_agents: "@user0:matrix.lambda.coredump.ru": agent-0 "@user1:matrix.lambda.coredump.ru": agent-1 agents: - id: agent-0 label: "Agent 0" base_url: "ws://lambda.coredump.ru:7000/agent_0/" workspace_path: "/agents/0/" ``` - **D-03:** AgentDefinition расширяется полями base_url (str) и workspace_path (str). AgentRegistry добавляет user_agents dict (Matrix user_id → agent_id) и метод get_agent_id_by_user(matrix_user_id). ### Роутинг user → agent в _build_platform_from_env - **D-04:** Вместо глобального AGENT_BASE_URL — per-agent URL из конфига. _build_platform_from_env строит delegates с правильным base_url для каждого агента. RoutedPlatformClient._resolve_delegate использует user_agents из registry для определения delegate по Matrix user_id. ### Входящие файлы (пользователь → агент) - **D-05:** Путь внутри workspace агента: `incoming/{filename}`. Абсолютный путь: `{workspace_path}/incoming/{filename}` (например `/agents/0/incoming/photo.jpg`). Обновить files.py: `build_workspace_attachment_path` принимает workspace_path агента и строит путь `incoming/{filename}`. Передавать в agent.send_message() как attachments=["incoming/{filename}"] (относительно /workspace). - **D-06:** workspace_path агента берётся из AgentDefinition по agent_id пользователя. ### Исходящие файлы (агент → пользователь) - **D-07:** При получении MsgEventSendFile(path="output/report.pdf") — читать файл из `{workspace_path}/{path}`. Отправлять как Matrix file message. Обработчик в Matrix bot.py при обработке stream-ответов от агента. ### docker-compose для prod - **D-08:** `docker-compose.prod.yml` включает полный стек: Matrix-бот + агент-контейнер (placeholder image `lambda-agent:latest` — уточнить у платформы) + named volume `agents`. Это позволяет тестировать полный стек самостоятельно. Платформа берёт отсюда схему интеграции для своего деплоя. - **D-09:** Named volume `agents` монтируется в Matrix-бот как `/agents/` и в агент-контейнер как `/workspace`. Env vars из `.env.prod`. Запуск: `docker compose -f docker-compose.prod.yml up`. ### Неавторизованные пользователи - **D-10:** Если Matrix user_id не найден в `user_agents` — принять invite, отправить сообщение: "К вашему аккаунту не привязан агент. Напишите @og_mput в Telegram для получения доступа." Дальнейшие сообщения игнорировать (или повторять то же сообщение). ### !clear - **D-11:** Без диалога подтверждения — сбрасывает немедленно. Закрыть текущий AgentApi connection, создать новый. Ответ пользователю: "Контекст сброшен." ### !settings и прочие команды настроек - **D-12:** Удалить `!settings`, `!settings soul`, `!settings skills`, `!settings safety` — agent_api не предоставляет настроек, всё равно возвращало "недоступно в MVP". ### Claude's Discretion - MATRIX_AGENT_REGISTRY_PATH — оставить как env var для пути к конфигу (уже существует) - Формат .env.prod - Group room invites (не-DM) — отклонять автоматически - Существующие Space+rooms у старых пользователей — игнорировать, не мигрировать ## Canonical References **Downstream agents MUST read these before planning or implementing.** ### Deployment architecture (PRIMARY) - `docs/deploy-architecture.md` — Топология, формат конфига, AgentApi lifecycle, file transfer protocol, открытые вопросы ### Существующий код (изменяем) - `adapter/matrix/agent_registry.py` — AgentRegistry, AgentDefinition, load_agent_registry — расширяем - `adapter/matrix/bot.py` — _build_platform_from_env, _load_agent_registry_from_env — обновляем роутинг - `adapter/matrix/routed_platform.py` — RoutedPlatformClient._resolve_delegate — обновляем логику - `adapter/matrix/files.py` — build_workspace_attachment_path, download_matrix_attachment — меняем путь - `adapter/matrix/handlers/agent.py` — удаляем или делаем no-op (!agent handler) - `config/matrix-agents.yaml` — расширяем формат - `docker-compose.yml` — существующий dev compose (за основу для prod варианта) ### SDK (используем как есть) - `sdk/real.py` — RealPlatformClient — base_url теперь per-instance, но сам класс не меняется - `sdk/upstream_agent_api.py` — AgentApi, MsgEventSendFile — читаем MsgEventSendFile в стриме ## Existing Code Insights ### Reusable Assets - `adapter/matrix/files.py::build_workspace_attachment_path` — уже строит путь к файлу, нужно заменить логику `surfaces/matrix/...` на `incoming/{filename}` - `adapter/matrix/files.py::download_matrix_attachment` — скачивает файл, нужно передавать workspace_path агента - `adapter/matrix/agent_registry.py::load_agent_registry` — парсер YAML, расширяем без переписывания ### Established Patterns - `RoutedPlatformClient` + delegates: dict[agent_id, RealPlatformClient] — паттерн уже есть, нужно только per-agent URL при создании delegates - `MATRIX_PLATFORM_BACKEND=real` активирует prod-path — сохраняем - `MATRIX_AGENT_REGISTRY_PATH` — env var для пути к конфигу — сохраняем ### Integration Points - `_build_platform_from_env` создаёт delegates — здесь меняется источник URL (из конфига, не из env) - `RoutedPlatformClient._resolve_delegate` — здесь добавляется lookup по user_agents - Matrix bot stream handler — здесь добавляется обработка MsgEventSendFile ## Specific Ideas - AgentApi конструктор в master ветке: `AgentApi(agent_id, base_url, on_disconnect=..., chat_id=0)` — base_url это ws:// URL агента - Входящий файл: bot скачивает из Matrix → пишет в `{workspace_path}/incoming/{filename}` → вызывает `agent.send_message(text, attachments=["incoming/{filename}"])` (путь relative to /workspace) - Исходящий файл: при `MsgEventSendFile(path="output/report.pdf")` → читаем `{workspace_path}/output/report.pdf` → отправляем в Matrix через `client.upload()` → `client.room_send(m.file)` - docker-compose.prod.yml монтирует volume: `volumes: ["/agents/:/agents/"]` — хост обеспечивает директорию ## Deferred Ideas - platform-master интеграция (динамический get_agent_url через POST /api/v1/create) — когда feat/storage будет готов - !agent как admin-override — не нужен для MVP, можно добавить позже если потребуется - Per-chat context isolation через разные chat_id (сейчас chat_id=0 для всех) — ждём platform сигнал --- *Phase: 05-mvp-deployment* *Context gathered: 2026-04-27*