[feat] update readme.md

This commit is contained in:
Azamat 2026-04-03 09:49:14 +03:00
parent c5b6a84a4b
commit 3293bccc5b
5 changed files with 273 additions and 60 deletions

View file

@ -45,12 +45,12 @@
- Do not use Beads - Do not use Beads
- Do not use `bd` - Do not use `bd`
- Use `uv` for Python commands and dependency management - Use `uv` for Python commands and dependency management
- Do not create commits on your own
- Work on one task at a time
- Prefer delegation for implementation - Prefer delegation for implementation
- Delegate only one task at a time - After implementation, run `Code-Reviewer` agent
- After one task return to the user with result verification and next options - Pass errors to `test-engineer` agent to capture
- Wait for the user before the next task commit or fix - Delegate `Feature-Developer` agent fix the errors
- Repeat the cycle until no errors remain
- Ensure all tests pass
## Makefile ## Makefile
- `make install` install deps with `uv` - `make install` install deps with `uv`

315
README.md
View file

@ -1,36 +1,268 @@
Это шаблон Python-сервиса на чистой архитектуре с заменяемым web-слоем, типизированным конфигом, явным dependency wiring и observability через порты. # master-service
## Что это за проект `master-service` — это control-plane сервис для sandbox-контейнеров с AI-агентом.
Он поднимает и переиспользует sandbox на чат, подключает рабочие volume, восстанавливает state после рестарта и отдает наружу минимальный HTTP API под `/api/v1`.
- Небольшой референсный сервис со слоями `domain/`, `usecase/`, `repository/` и `adapter/` Важно: в локальном `config/app.yaml` исторически еще стоят template-имена `web-python-skelet`.
- Шаблон для сервисов на FastAPI, где FastAPI остается только во внешнем HTTP adapter Если хочешь, чтобы `/health` и OTel service name локально тоже показывали `master-service`, переопредели:
- Проект, где конфиг собирается из `config/app.yaml`, `.env` и env vars в одно дерево dataclass-конфигов - `APP_NAME=master-service`
- Проект, где repository и usecase создаются один раз на старте приложения в composition root - `APP_OTEL_SERVICE_NAME=master-service`
- Проект, где логи, метрики и трейсы скрыты за интерфейсами и могут работать через `stdout`, файл или OpenTelemetry runtime
## Основные идеи Сервис реализован на Python с Clean Architecture:
- `domain/` — сущности и доменные ошибки
- `usecase/` — сценарии приложения и порты
- `repository/` — реализации repository
- `adapter/` — HTTP, config, DI, Docker runtime и observability
- Clean Architecture и границы SOLID ## Что умеет сейчас
- Направление зависимостей только внутрь
- Тонкие adapter-слои и явная сборка зависимостей Текущий sandbox MVP покрывает:
- Заменяемый HTTP-слой - `GET /api/v1/health`
- Observability без протекания OpenTelemetry во внутренние слои - `POST /api/v1/create` с `chat_id: UUID`
- одну активную sandbox на чат
- reuse активной sandbox до истечения TTL
- cleanup просроченных sandbox в фоне
- startup reconciliation по Docker labels после рестарта сервиса
- chat mount `rw`, dependencies mount `ro`, lambda-tools mount `ro`
- логи, метрики и трейсы через порты `Logger`, `Metrics`, `Tracer`
Пока вне scope:
- auth и access control
- p2p/WebSocket lease
- workspace/chat CRUD API
- central DB, artifacts, S3, quota и retention policy
## Как устроен проект
- FastAPI живет только во внешнем adapter слое
- Docker живет только во внешнем adapter слое
- конфиг собирается из `config/app.yaml`, `.env` и env vars в один dataclass tree
- repository и usecase создаются один раз на старте в `adapter/di/container.py`
- observability не протекает во внутренние слои через OpenTelemetry SDK
## Структура
- `domain/` — core model и domain errors
- `usecase/` — use cases и interfaces
- `repository/` — in-memory и другие repository implementations
- `adapter/config/` — typed config models и loader
- `adapter/docker/` — Docker sandbox runtime
- `adapter/observability/` — logger/metrics/tracer runtime factory
- `adapter/otel/` — OpenTelemetry adapters
- `adapter/di/` — composition root
- `adapter/http/fastapi/` — app, middleware, schemas, routers
- `adapter/sandbox/` — sandbox reconciliation logic
- `config/` — YAML config files
- `docs/` — ADR и проектные гайды
## Быстрый старт ## Быстрый старт
### Требования
- Python 3.13
- `uv`
- локальный Docker daemon
- секреты `APP_API_TOKEN` и `APP_SIGNING_KEY`
### Установка
```bash ```bash
make install make install
```
### Локальный запуск
```bash
APP_API_TOKEN=local-api-token APP_SIGNING_KEY=local-signing-key make run APP_API_TOKEN=local-api-token APP_SIGNING_KEY=local-signing-key make run
``` ```
Приложение стартует на `http://0.0.0.0:8123` и публикует versioned API под `/api/v1`. Это поднимет сам API, но для успешного `POST /api/v1/create` локально нужен еще рабочий sandbox runtime:
- Docker daemon должен быть доступен по `docker.base_url`
- образ `sandbox.image` должен существовать локально
- директории `sandbox.dependencies_host_path` и `sandbox.lambda_tools_host_path` должны существовать
В дефолтном `config/app.yaml` это значит:
```bash
mkdir -p var/sandbox/dependencies var/sandbox/lambda-tools
docker image inspect ai-agent:latest >/dev/null
```
Если у тебя нет готового `ai-agent:latest`, проще начать с Docker Compose smoke path ниже.
После старта сервис доступен на:
- `http://127.0.0.1:8123/api/v1/health`
Проверка health:
```bash
curl http://127.0.0.1:8123/api/v1/health
```
Создание или reuse sandbox:
```bash
curl -X POST http://127.0.0.1:8123/api/v1/create \
-H 'Content-Type: application/json' \
-d '{"chat_id":"11111111-1111-1111-1111-111111111111"}'
```
Пример ответа:
```json
{
"session_id": "3701cfe3-e05e-48af-8385-442dcd954ca2",
"chat_id": "11111111-1111-1111-1111-111111111111",
"container_id": "64d839c6007de9396ee08ad4af4a22a59a6410ec5f4892a9277a87eb49c3ff5d",
"status": "running",
"expires_at": "2026-04-02T21:11:38.292893Z"
}
```
## Запуск через Docker Compose
Для локального smoke-run есть `docker-compose.yml`.
Он поднимает:
- `app`
- `docker-engine` в режиме Docker-in-Docker
- `otel-collector`
При этом `app` получает compose-specific config из:
- `config/docker-compose.yml`
Запуск:
```bash
make compose-up
```
Проверка:
```bash
make compose-ps
make compose-logs
```
Остановка:
```bash
make compose-down
```
Важно:
- в `config/docker-compose.yml` сейчас для smoke-проверки стоит `sandbox.image: nginx:1.27-alpine`
- для реального agent runtime замени `sandbox.image` на образ своего sandbox/agent контейнера
- в compose auth env vars нужны для startup config, но текущий MVP API еще не проверяет request token
## Как конфигурировать
### Источники конфига
Конфиг собирается в таком порядке:
1. базовый YAML из `config/app.yaml`
2. значения из `.env`
3. process env vars поверх `.env`
То есть env vars имеют наивысший приоритет.
### Обязательные секреты
Нужны всегда:
- `APP_API_TOKEN`
- `APP_SIGNING_KEY`
Сейчас это startup config, а не активная request auth для `/api/v1/create` и `/api/v1/health`.
То есть в текущем MVP токен не нужно передавать в HTTP headers для вызова этих endpoint.
### Основные секции YAML
В `config/app.yaml` и `config/docker-compose.yml` есть секции:
- `app`
- `http`
- `logging`
- `metrics`
- `tracing`
- `otel`
- `docker`
- `sandbox`
- `security`
### Полезные env overrides
Чаще всего полезны:
#### Общие
- `APP_NAME`
- `APP_ENV`
- `APP_HTTP_HOST`
- `APP_HTTP_PORT`
#### Логирование и observability
- `APP_LOGGING_LEVEL`
- `APP_LOGGING_OUTPUT`
- `APP_LOGGING_FORMAT`
- `APP_LOGGING_FILE_PATH`
- `APP_METRICS_ENABLED`
- `APP_TRACING_ENABLED`
- `APP_OTEL_SERVICE_NAME`
- `APP_OTEL_LOGS_ENDPOINT`
- `APP_OTEL_METRICS_ENDPOINT`
- `APP_OTEL_TRACES_ENDPOINT`
#### Docker runtime
- `APP_DOCKER_BASE_URL`
#### Sandbox
- `APP_SANDBOX_IMAGE`
- `APP_SANDBOX_TTL_SECONDS`
- `APP_SANDBOX_CLEANUP_INTERVAL_SECONDS`
- `APP_SANDBOX_CHATS_ROOT`
- `APP_SANDBOX_DEPENDENCIES_HOST_PATH`
- `APP_SANDBOX_LAMBDA_TOOLS_HOST_PATH`
- `APP_SANDBOX_CHAT_MOUNT_PATH`
- `APP_SANDBOX_DEPENDENCIES_MOUNT_PATH`
- `APP_SANDBOX_LAMBDA_TOOLS_MOUNT_PATH`
#### Security
- `APP_API_TOKEN_HEADER`
- `APP_API_TOKEN`
- `APP_SIGNING_KEY`
### Что важно в sandbox config
- `docker.base_url` — адрес Docker daemon
- `sandbox.image` — образ sandbox контейнера
- `sandbox.ttl_seconds` — TTL sandbox
- `sandbox.cleanup_interval_seconds` — частота cleanup loop
- `sandbox.chats_root` — корень chat directories
- `sandbox.dependencies_host_path` — host path для dependency cache
- `sandbox.lambda_tools_host_path` — host path для read-only lambda-tools
- `sandbox.chat_mount_path` — путь внутри sandbox для chat volume
- `sandbox.dependencies_mount_path` — путь внутри sandbox для dependency cache
- `sandbox.lambda_tools_mount_path` — путь внутри sandbox для lambda-tools
## Основные команды
- `make install` — установить зависимости через `uv`
- `make run` — локальный запуск
- `make run-otel` — запуск с OTel endpoints из env
- `make test``pytest`
- `make lint``ruff`
- `make typecheck``mypy`
- `make pre-commit` — lint + typecheck + test
- `make compose-build` — собрать compose images
- `make compose-up` — поднять локальный stack
- `make compose-down` — остановить stack
- `make compose-logs` — смотреть логи
- `make compose-ps` — смотреть статус сервисов
## Документация ## Документация
### Гайды ### Гайды
- [Правила проекта и ограничения для агента](AGENTS.md) - [Правила проекта и ограничения для агента](AGENTS.md)
- [Кодстайл проекта для AI-агента](docs/CODESTYLE.md) - [Кодстайл проекта](docs/CODESTYLE.md)
- [Чистая архитектура, SOLID, DIP, Protocol и repository](docs/CLEAN_ARCHITECTURE_RU.md) - [Чистая архитектура, SOLID, DIP, Protocol и repository](docs/CLEAN_ARCHITECTURE_RU.md)
- [Логи, метрики и трейсы в этом проекте](docs/OBSERVABILITY_RU.md) - [Логи, метрики и трейсы в этом проекте](docs/OBSERVABILITY_RU.md)
- [Как чистая архитектура реализована здесь](docs/PROJECT_GUIDE_RU.md) - [Как чистая архитектура реализована здесь](docs/PROJECT_GUIDE_RU.md)
@ -43,43 +275,24 @@ APP_API_TOKEN=local-api-token APP_SIGNING_KEY=local-signing-key make run
- [003 Observability Via Interfaces](docs/003-observability-via-interfaces.md) - [003 Observability Via Interfaces](docs/003-observability-via-interfaces.md)
- [004 Versioned HTTP API](docs/004-versioned-http-api.md) - [004 Versioned HTTP API](docs/004-versioned-http-api.md)
- [005 Early FastAPI OTel Instrumentation](docs/005-fastapi-otel-early-instrumentation.md) - [005 Early FastAPI OTel Instrumentation](docs/005-fastapi-otel-early-instrumentation.md)
- [006 MVP Docker Sandbox Orchestration](docs/006-mvp-docker-sandbox-orchestration.md)
- [007 Startup Sandbox Reconciliation](docs/007-startup-sandbox-reconciliation.md)
- [008 Sandbox Lifecycle Observability](docs/008-sandbox-lifecycle-observability.md)
## Структура проекта ## Для AI-агента
- `domain/` - core-сущности и доменные ошибки Если ты меняешь проект как AI-агент, сначала прочитай:
- `usecase/` - прикладные сценарии и порты
- `repository/` - реализации repository
- `adapter/config/` - загрузка и модели типизированного конфига
- `adapter/observability/` - выбор runtime для logger, metrics и tracer
- `adapter/otel/` - OpenTelemetry adapters
- `adapter/di/` - composition root и singleton wiring
- `adapter/http/fastapi/` - HTTP-схемы, dependencies, middleware и routers
- `config/` - YAML-конфиг приложения и локального OTel collector
## Для ИИ 1. [AGENTS.md](AGENTS.md)
2. [docs/CODESTYLE.md](docs/CODESTYLE.md)
3. [docs/PROJECT_GUIDE_RU.md](docs/PROJECT_GUIDE_RU.md)
4. [docs/CLEAN_ARCHITECTURE_RU.md](docs/CLEAN_ARCHITECTURE_RU.md)
5. [docs/OBSERVABILITY_RU.md](docs/OBSERVABILITY_RU.md)
6. релевантные ADR в `docs/`
7. [tasks.md](tasks.md)
Если ты AI-агент и собираешься что-то менять в проекте, сначала прочитай документы в таком порядке: Главные правила:
- сначала определи слой изменения
1. [Правила проекта и ограничения агента](AGENTS.md) - обязательные правила работы в этом репозитории - зависимости только внутрь
2. [Кодстайл проекта для AI-агента](docs/CODESTYLE.md) - границы слоев, стиль кода и правила зависимостей - не тащи FastAPI и OpenTelemetry во внутренние слои
3. [Как чистая архитектура реализована здесь](docs/PROJECT_GUIDE_RU.md) - практическая карта проекта и типовые сценарии изменений - архитектурные решения сверяй с ADR
4. [Чистая архитектура, SOLID, DIP, Protocol и repository](docs/CLEAN_ARCHITECTURE_RU.md) - базовые архитектурные принципы и примеры
5. [Логи, метрики и трейсы в этом проекте](docs/OBSERVABILITY_RU.md) - читать перед любыми изменениями в observability, middleware и runtime wiring
6. [ADR в `docs/`](docs/001-composition-root-and-lifetimes.md) - читать релевантные решения перед изменением архитектуры или startup wiring
7. [План задач и история работ](tasks.md) - понять, что уже сделано, что отложено и какие ограничения были зафиксированы
Перед началом работы:
- Определи, в каком слое будет изменение: `domain/`, `usecase/`, `repository/` или `adapter/`
- Убедись, что зависимости идут только внутрь
- Не тащи FastAPI и OpenTelemetry во внутренние слои
- Сначала изучи существующий код в нужной директории, потом вноси изменения
- Если задача затрагивает архитектурное решение, сначала сверяйся с ADR и проектными правилами
## Запуск и команды
- Для локального запуска нужны `APP_API_TOKEN` и `APP_SIGNING_KEY`
- `make run` запускает приложение локально
- `make run-otel` запускает приложение с локальными OTel endpoints из env vars
- `make pre-commit` запускает `ruff`, `mypy` и `pytest`
- `make compose-up` поднимает приложение и локальный LGTM stack через Docker Compose

View file

@ -29,8 +29,8 @@ docker:
sandbox: sandbox:
image: nginx:1.27-alpine image: nginx:1.27-alpine
ttl_seconds: 30 ttl_seconds: 300
cleanup_interval_seconds: 5 cleanup_interval_seconds: 60
chats_root: /var/lib/master-sandbox/chats chats_root: /var/lib/master-sandbox/chats
dependencies_host_path: /var/lib/master-dependencies dependencies_host_path: /var/lib/master-dependencies
lambda_tools_host_path: /var/lib/master-lambda-tools lambda_tools_host_path: /var/lib/master-lambda-tools

View file

@ -353,7 +353,7 @@
### M29. Финальный boundary review для sandbox observability ### M29. Финальный boundary review для sandbox observability
- Субагент: `code-reviewer` - Субагент: `code-reviewer`
- Статус: pending - Статус: completed
- Зависимости: `M28` - Зависимости: `M28`
- Commit required: no - Commit required: no
- Scope: подтвердить, что M27-M28 закрыли remaining M26 замечания - Scope: подтвердить, что M27-M28 закрыли remaining M26 замечания

View file

@ -14,7 +14,7 @@ from adapter.docker.runtime import DockerSandboxRuntime
from adapter.observability.noop import NoopMetrics, NoopTracer from adapter.observability.noop import NoopMetrics, NoopTracer
from domain.error import SandboxError, SandboxStartError from domain.error import SandboxError, SandboxStartError
from domain.sandbox import SandboxSession, SandboxStatus from domain.sandbox import SandboxSession, SandboxStatus
from usecase.interface import AttrValue, Attrs from usecase.interface import Attrs, AttrValue
CHAT_ID = UUID('123e4567-e89b-12d3-a456-426614174000') CHAT_ID = UUID('123e4567-e89b-12d3-a456-426614174000')
NON_CANONICAL_CHAT_ID = '123E4567E89B12D3A456426614174000' NON_CANONICAL_CHAT_ID = '123E4567E89B12D3A456426614174000'