Operate
Runtime Surfaces
Reusable endpoint definitions with explicit task attachments for native and container service runtimes.
Recommended next
What runtime surfaces are
A runtime surface is a reusable endpoint definition for something a task actually runs.
Use a runtime surface when the same endpoint appears across multiple tasks or workflows and the endpoint shape should stay one source of truth.
A surface is declarative until a service-task runtime attaches it.
- A surface defines one reusable endpoint such as
backend,frontend,api,admin, orworker-metrics. - Use top-level
surfacesto own the endpoint shape once (protocol, port, path, and optional readiness). - Attach reused endpoints through
tasks.<name>.runtime.surfacesso each publishing task claims what it actually serves. - Use workflow readiness against the run task so checks reflect the selected operational path.
- Use workflow
exposeswith surface references first; reserve literal URLs for services you do not own in the contract. - Use literal URL probes for third-party or external endpoints that are not produced by an Ota task or service.
Why runtime surfaces exist
Listener shorthand makes one listener easier to write. It does not remove repeated endpoint meaning across a large repo.
Runtime surfaces solve the multi-front-door problem: the same backend or frontend endpoint is usually repeated across tasks, readiness checks, and workflow exposes.
- Define
backendonce whendev,backend,worker, andstartall expose the same endpoint. - Define
frontendonce when frontend entry points stay stable across tasks. - Keep readiness paths attached to the same surface that proves that endpoint.
- Let workflows decide which endpoint is in scope so host URLs stay derived, not hardcoded.
- Reduce duplication while keeping
execution topologyand readiness semantics stable.
Surfaces, shorthand, and full listeners
Surfaces, shorthand, and full listeners
Listener shorthand
A compact one-off listener on a task.
Surfaces, shorthand, and full listeners
Runtime surface
A reusable endpoint meaning shared by tasks and workflows.
Surfaces, shorthand, and full listeners
Attachment override
A task-level publication shape for a reusable surface.
Surfaces, shorthand, and full listeners
Full listener
The explicit advanced runtime topology shape.
Basic HTTP surface
Use this when one app endpoint has a stable local port and one meaningful health path.
The surface owns the endpoint shape and readiness meaning. A task still has to attach it before Ota can run or observe it.
surfaces: backend: kind: http port: 5678 path: / readiness: kind: http path: /healthz/readiness success: status: [200] timeout: 10000Attach surfaces to tasks
Surfaces are reusable definitions, not automatic attachments.
Every task that publishes a surface must attach it explicitly. That is the runtime claim that this task exposes the already-defined endpoint.
Attached surfaces normalize into the same listener/readiness machinery as explicit runtime listeners.
- do not attach a surface to a non-service task
- do not attach an unknown surface
- do not declare a runtime listener with the same name as an attached surface on the same task
- if one runtime attaches exactly one surface, has no inline runtime readiness, and that surface declares readiness, ota derives the equivalent runtime readiness automatically
- if a runtime attaches multiple surfaces, has no inline runtime readiness, and exactly one attached surface is marked
project.host.primary: true, ota derives runtime readiness from that primary surface - keep task-specific advanced topology in full listeners when the reusable surface defaults are not true
tasks: dev: run: pnpm dev runtime: kind: service surfaces: - backend - frontend backend: run: pnpm dev:backend runtime: kind: service surfaces: - backend frontend: run: pnpm dev:frontend runtime: kind: service surfaces: - frontendWhy attachments stay explicit
Automatic inheritance would make the contract less trustworthy.
A repo can define backend, but that does not mean every task publishes the backend. Build, test, setup, frontend, worker, and production runtime tasks can all have different endpoint behavior.
surfaces.backendmeans what the backend endpoint isruntime.surfaces: [backend]means this task publishes that endpointruntime.surfaces.backendmeans this task publishes that endpoint with runtime-specific publication details- workflow surface readiness must resolve through the selected workflow run task, not through a global surface catalog
- this explicit opt-in keeps Ota from claiming a task exposes an endpoint it does not actually run
Native list form
Use list form for native or simple host-facing services where the surface defaults are true.
This is the compact path: the task opts into the reusable endpoint without repeating listener or readiness details.
- use this when bind and host projection can safely follow the surface defaults
- use this when the task is native or otherwise already host-facing on the canonical port
- do not use list form to hide container publication requirements
surfaces: backend: kind: http port: 5678 path: / readiness: kind: http path: /healthz/readiness tasks: backend: context: host run: pnpm dev:backend runtime: kind: service surfaces: - backendContainer attachment override
Container-backed tasks often need runtime-specific publication.
Keep that publication shape at the task attachment because container bind address, host projection, host port mode, and primary URL selection are facts about this runtime, not the semantic endpoint definition.
- object form is an attachment override, not a different surface definition
- the attachment may shape
bindandproject - the attachment may select
project.host.primarywhen a task publishes multiple surfaces - the attachment must not override surface
kind, readiness, or endpoint identity - use full
runtime.listenerswhen publication needs behavior outside the surface attachment model - do not move container bind or projection details to the top-level surface because those details belong to the runtime that publishes it
surfaces: backend: kind: http port: 5678 path: / readiness: kind: http path: /healthz/readiness tasks: dev: context: app run: pnpm dev runtime: kind: service surfaces: backend: bind: address: 0.0.0.0 port: mode: fixed value: 5678 project: host: address: 127.0.0.1 port: mode: fixed value: 5678 path: / primary: trueWorkflow readiness with surfaces
Workflow readiness should say which surfaces prove that selected workflow path.
The workflow run task provides the concrete attachment, so a backend workflow can stay scoped to the backend surface and ignore frontend-only readiness.
workflows.backend.readiness.surfacesshould resolve againstworkflows.backend.run.task- a workflow should fail validation if it references a surface that its selected run task does not attach
- surface readiness should remain scoped to the selected workflow instead of falling back to unrelated repo checks
workflows: default: app app: setup: task: setup run: task: dev readiness: surfaces: - backend - frontend backend: setup: task: setup run: task: backend readiness: surfaces: - backendWorkflow exposes with surfaces
Workflow exposes should avoid repeating URLs that already come from attached surfaces.
Use surface exposes when the URL belongs to the selected run task. Keep literal URL exposes for external links or endpoints outside Ota-owned runtime topology.
workflows: backend: run: task: backend exposes: - surface: backend app: run: task: dev exposes: - surface: backend - surface: frontend - https://docs.example.com/external-runbookLiteral external probes
Use literal URL probes when the endpoint is external, third-party, or not produced by an Ota task runtime.
Do not force these endpoints into surfaces. Surfaces are for Ota-owned runtime endpoints that can resolve through task topology.
readiness: probes: billing-api: kind: http url: https://billing.example.com/health expect_status: 200 timeout: 10000 checks: - name: billing-api-ready kind: health severity: warning probe: billing-apiMulti-front-door app example
Some application repos expose more than one useful local front door: a full app, a backend-only server, a frontend-only dev server, a worker path, and a production-style local runtime.
Runtime surfaces let the contract define backend and frontend once, then attach the same surface truth to the tasks that actually publish each endpoint.
surfaces: backend: kind: http port: 5678 path: / readiness: kind: http path: /healthz/readiness success: status: [200] timeout: 10000 frontend: kind: http port: 8080 path: / readiness: kind: http path: / success: status: [200] timeout: 10000 tasks: dev: run: pnpm dev runtime: kind: service surfaces: - backend - frontend backend: run: pnpm dev:backend runtime: kind: service surfaces: - backend frontend: run: pnpm dev:frontend runtime: kind: service surfaces: - frontend worker: run: pnpm dev:worker runtime: kind: service surfaces: - backend start: run: pnpm start runtime: kind: service surfaces: - backendWhen not to use surfaces
- do not use a surface for a one-off listener on one task; use listener shorthand instead
- do not use a surface for a third-party service or external URL; use a literal URL probe or literal expose
- do not use a surface when the endpoint needs behavior beyond publication overrides; use full listeners
- do not use a surface as a generic catalog of docs pages, dashboards, or SaaS URLs
- do not use surfaces to hide weak readiness; if the app does not have a meaningful health path, say that explicitly
Command behavior
ota validateshould reject unknown, duplicate, or unattached surface referencesota tasks --workflow <name>should show which surfaces the selected workflow uses and exposesota execution topologyshould show declared surfaces and the normalized listener shape for each attached taskota up --workflow <name>should prepare and check only the surfaces selected by that workflow- JSON output should stay additive: surface fields can be added, but existing listener output should remain stable
Design rule
Surfaces should remove duplicated endpoint truth without becoming a template system.
The source of operational truth remains concrete task runtime attachment.
- surface defines reusable endpoint meaning
- task attachment makes that endpoint operational
- workflow selects which operational surfaces matter for that path
- readiness proves the selected surface, not a copied URL
- full listeners remain the escape hatch for advanced topology