bex is the open-source Render alternative — AI-native (ADR008). A Go Kubernetes operator reconciles App CRs (app.bex.co/v1alpha1, bex-system) into running services. All Go lives in lego/ (Latin legō, "I assemble") — one image, four workspace modules: types/ (CRD contract, leaf), operator/ (mechanism, DB-free manager), backend/ (bex-api on :8090 + SSH gateway), cli/ (Render CLI launcher, bex-cli/v* train). operator → types ← backend; cli imports none.
lego/— all Go, self-contained (go.work,Dockerfile; contextlego/). README, workspace rules.lego/types/—App/DatabaseCRD typeslego/operator/— manager → Deployment/Service/Ingress; ownsconfig/+ codegen. operator guidelego/backend/— bex-api (REST/GraphQL/MCP + OpenFGA) + ssh-gateway. backend guidelego/cli/—bexCLI launcher (pinnedrender-oss/cli). README
dashboard/— TanStack Start + Apollo + shadcn, client of bex-api GraphQL. dashboard guideinfra/— day-0: Terraform + Cluster API (local-capd⇄hetzner-caph)deploy/gitops/— day-1: Argo CD platform infra (not user deploys)examples/—whoami-app.yaml,hello-go/scripts/— cluster helpers (mock-cluster.sh,app-apply.sh,deploy-sample.sh)docs/— one file per topic. Full catalog in docs/AGENTS.md.pm/— internal PM board (may be stale). Conventions in .pm/AGENTS.md
All make targets live in lego/operator/; see lego/AGENTS.md for workspace Go-version split + codegen. CI gates:
make test(operator, fromlego/operator/) — CRD/RBAC codegen + envtestcd lego/backend && go test ./...— backend (real Postgres + OpenFGA in CI)make lint(all four modules) — golangci-lint + whole-program dead-code analysis; depguard guards theidconventioncd lego/cli && go test ./...— CLI launcher
All three platform suites + dashboard/yarn test must pass before deploy.yml builds.
bash scripts/mock-cluster.sh— kind infra + CAPI + CAPD app cluster; kubeconfiginfra/local/bex.kubeconfig(gitignored)bash scripts/mock-cluster.sh scale N— add/remove workersscripts/app-apply.sh <bex.yml>—render.yaml-shapedbex.yml→ App CR (DRY_RUN=1preview)scripts/deploy-sample.sh/kubectl get apps.app.bex.co— deploy + status
Inventories live with the code (cascading):
- operator / activator / pg-sni-proxy / kv-sni-proxy / egress-meter / static-server → lego/operator/AGENTS.md
- bex-api / ssh-gateway → lego/backend/AGENTS.md
- dashboard SSR → dashboard/AGENTS.md
Full ADR/ledger catalog with one-line summaries: docs/AGENTS.md (cascading — loaded only when working in docs/).
Key entry points:
- Vision/roadmap: ADR008 · Architecture: ADR002 · Control plane: ADR003
- API core + parity: ADR006 · ADR018 · ADR049
- IDs: ADR020 · Auth: ADR012 · Members: ADR024
- Deploy/custom-domain: ADR004 · ADR005
- Managed data: ADR009 · ADR021 · ADR029
- Billing/pricing: ADR040 · ADR030
- GitHub/members/infra-creds: ADR026 · ADR019
- Tenant isolation/networking: ADR043 (replaces ADR022 option B)
- Security review lineage: ADR028 → ADR072 … ADR083 (see docs/AGENTS.md for full chain)
- Never
git commit/pushunless user runs/ship(Claude) or$ship(Codex), or explicitly requests anrt-*routine run. A routine request authorizes planning, fixing, verification, and invoking ship in the same run without first filing a.pmmilestone. Honor explicit audit-only or no-ship limits; follow the ship skill’s safety rules. - Never commit/print
.envor*.kubeconfig. - Local dev environments are pre-approved (user decision 2026-09-09).
scripts/dev-env.sh <N> {up,down,status,clean,env}for anydev-N, andscripts/mock-cluster.sh(bring-up, reprovision,scale N) on the local kind/CAPD cluster, never require user approval — run them whenever the work needs it, including destructive recovery (reprovision,clean) when the harness's own diagnostics point there. Still respect each harness's isolation boundaries (owndev-Nnamespaces/ports; read-only on other workstreams' stacks), and report what was rebuilt. - Skill layout: canonical
.claude/skills/<name>/SKILL.md;.agents/skills/<name>is../../.claude/skills/<name>symlink; no.claude/commands/. Validate:bash scripts/skill-layout-validate.sh. .env.examplemirrors.envnames (no values).cp .env.example .envmust never fall out of date;scripts/gh-secrets.shpushes.env→ GitHub secrets.- Markdown CI:
npx prettier@3.4.2 --write "**/*.md"before finishing. - Go ids: mint only via
lego/backend/internal/id(id.New(kind)), hyphen not underscore; boilerplate header perlego/operator/hack/boilerplate.go.txt. See lego/AGENTS.md. .pmdone: move folder todone/(tasktNNN.md→done/tNNN.md; milestonemN/→wN/done/mN/), leave no stub; sync status in workstream README + milestone README + frontmatter. See .pm/AGENTS.md.- Dashboard preloading skeletons must match their post-loading contents. A skeleton is a structural preview of the exact ready state at the same responsive breakpoint: preserve its outer bounds, padding, max-width, columns, headings/actions, tabs, and major content regions with stable heights. Do not substitute a generic list/form/detail skeleton when the destination geometry differs. Verify pending and ready states side by side at desktop and narrow-mobile widths; see dashboard/AGENTS.md.
- Playwright MCP: writes to
.playwright-mcp/(--output-dirin.mcp.json); use bare filenames for screenshots.