---
id: w2/m2/t001
title: Deploy verb over Core.Create — map {repo, bex.yml} onto Render's create surface
worker: worker2
status: done
estimate: 30m
depends_on: [w2/m4/t003, w1/m5/t003]
---

## Objective

Make "deploy this" ride the Render-shaped create surface instead of a bespoke endpoint: a mapping layer translates `{repo, bex.yml}` into a `Core.Create` request (repo-backed service), so one agent call takes code to a live URL through the same verb every other client uses. No `POST /v1/deploy` — that was replaced by w2/m4's `POST /v1/services` / `create_web_service` (amended 2026-07-08 from `/pm-brainstorm for w2`).

## Context

- w2/m4 ships `Core.Create` + `POST /v1/services` + MCP `create_web_service`; this task adds only the `bex.yml` → create-request mapping (fields → `App.spec`: plan, env, health path, hosts), plus create-or-update semantics for redeploys of an existing service.
- Build-from-git must work in-cluster first — w1/m5. `scripts/app-apply.sh` already maps `bex.yml` → App CR shape; reuse its field mapping as the reference.
- Keep the mapping in the apps feature so REST, GraphQL, and MCP all share it.

## Steps

1. Add the `bex.yml` parser/mapper (`bex.yml` fields → create/update request), validating against the same rules as `Core.Create`.
2. Wire create-or-update: existing service + same repo → update spec (redeploy); new name → create.
3. Document in `docs/ADR006-bex-api.md` that deploy-from-chat is `create_web_service` with a repo body — no separate deploy endpoint.

## Files

- `lego/backend/internal/apps/` (mapper + service wiring)
- `docs/ADR006-bex-api.md`

## Acceptance criteria

- [ ] A `{repo, bex.yml}` call through the create surface yields an `App` CR whose `status.url` eventually resolves (with w1/m5 builds).
- [ ] Repeating the call for the same service updates it (redeploy), not a duplicate.

## Out of scope

- MCP exposure of a distinct deploy verb (t002 re-evaluates against `create_web_service`), webhook (t003), the create surface itself (w2/m4).
