conventions/programming_general/infra_manifest.yaml
Natalie f2242e969a feat(infra_manifest): optional .infra.<env>.yaml dev/prod variants (v0.3.0)
Add an optional 'environment' field (default prod) and document sibling
.infra.dev.yaml manifests (same schema) so a project can declare a distinct
non-prod deployment — e.g. a local mac operator instance alongside the DO prod
service. Run-only/access config (passcodes, bind addrs) stays out of the manifest.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 10:20:12 -04:00

65 lines
3.7 KiB
YAML

apiVersion: conventions/v1
version: 0.3.0
updated: "2026-06-29"
name: infra_manifest
title: Per-project infra manifest (.infra.yaml)
scope: general
status: draft
summary: Every deployable project declares its infrastructure in a root .infra.yaml; `service.host` must be a host in net-tools mesh-hosts.json, so the infra-net reconciler can build the live picture. A project with a distinct non-prod deployment may add a sibling .infra.dev.yaml (same schema, environment:dev) — e.g. a local operator instance on a mac host. The reconciler reads every .infra*.yaml. A future infra-apply renders the DO parts.
appliesTo: ["@applications/*", "@projects/@cocottetech", "@projects/@magic-civilization"]
rules:
- id: own_db
level: must
text: A project needing a database declares its own logical DB + dedicated user on the shared managed cluster (data-sourced), never reusing another service's creds.
rationale: own-DB-per-service + credential separation.
- id: http_coupling
level: must
text: Cross-service dependencies are HTTP only (declared in depends_on), never shared databases.
- id: gpu_ondemand
level: should
text: GPU workloads are on-demand — provision, keep warm while the queue is deep, release on idle. Never a standing GPU.
- id: host_in_mesh
level: must
text: "`service.host` is a host name from net-tools mesh-hosts.json (lime, fennel, redroid, …) — the infra-net reconciler validates this and regenerates the mesh-hosts services map from all .infra.yaml."
- id: env_variants
level: should
text: "Default manifest is `.infra.yaml` (prod, environment defaults to prod). A distinct non-prod deployment lives in a sibling `.infra.<env>.yaml` (currently only `.infra.dev.yaml`) with the same schema + `environment` set. One project may thus appear as multiple services (e.g. prod on a DO droplet + a local mac instance). Keep run-only/access config (passcodes, bind addresses) out of the manifest — it is not mesh infra."
providesFile:
path: .infra.yaml # plus optional .infra.<env>.yaml siblings (same schema)
schema:
$schema: "https://json-schema.org/draft/2020-12/schema"
title: ProjectInfraManifest
type: object
additionalProperties: false
required: [apiVersion, project, provider]
properties:
apiVersion: { type: string, const: "infra/v1", description: "Manifest contract version (independent of the convention's own version)." }
project: { type: string }
environment: { type: string, enum: [dev, prod], default: prod, description: "Deployment environment. Omitted = prod. A project may carry one manifest per environment (.infra.yaml + .infra.dev.yaml)." }
provider: { type: string, enum: [digitalocean, mac, bare-metal, local], description: "Where it physically runs: digitalocean droplet, a mac (e.g. fennel), bare-metal, or local." }
database:
type: object
additionalProperties: false
required: [cluster, name, user]
properties:
cluster: { type: string, description: Shared managed cluster — data-sourced, not owned here. }
name: { type: string }
user: { type: string }
service:
type: object
additionalProperties: false
properties:
host: { type: string, description: "A host name from net-tools mesh-hosts.json (lime, fennel, redroid, …)." }
runtime: { type: string }
port: { type: integer }
systemd_unit: { type: string }
gpu:
type: object
additionalProperties: false
properties:
mode: { type: string, enum: [on-demand] }
droplet: { type: string }
depends_on:
type: array
items: { type: string }
description: Other services consumed over HTTP.