# # █████ # ░░███ # ██████ ███████ ██████ # ███░░███░░░███░ ░░░░░███ # ░███ ░███ ░███ ███████ # ░███ ░███ ░███ ███ ███░░███ # ░░██████ ░░█████ ░░████████ # ░░░░░░ ░░░░░ ░░░░░░░░ # # Copyright (C) 2026 — 2026, Ota. All Rights Reserved. # # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # Licensed under the Apache License, Version 2.0. See LICENSE for the full license text. # You may not use this file except in compliance with that License. # Unless required by applicable law or agreed to in writing, software distributed under the # License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, # either express or implied. See the License for the specific language governing permissions # and limitations under the License. # # If you need additional information or have any questions, please email: os@ota.run version: 1 project: name: basic-services description: Service-backed app example with explicit setup, run, and managed dependency boundaries type: application toolchains: node: version: "22" package_managers: pnpm: "10.0.0" fulfillment: source: corepack mode: run execution: default_context: host contexts: host: backend: native requirements: tools: docker: "*" env: vars: APP_ENV: default: local allowed: - local - ci DATABASE_URL: required: true REDIS_URL: required: true sources: - kind: dotenv path: .env.local services: api: manager: kind: compose name: local file: docker-compose.yml service: api endpoints: host: address: 127.0.0.1 port: 3000 readiness: from: host kind: http method: GET path: /health headers: Accept: application/json success: status: [200] body: contains: '"ok":true' interval: 5s timeout: 3s retries: 5 start_period: 10s postgres: manager: kind: compose name: local file: docker-compose.yml service: postgres endpoints: host: address: 127.0.0.1 port: 5432 readiness: from: host kind: tcp interval: 5s timeout: 3s retries: 5 start_period: 10s redis: manager: kind: compose name: local file: docker-compose.yml service: redis endpoints: host: address: 127.0.0.1 port: 6379 readiness: from: host kind: tcp interval: 5s timeout: 3s retries: 5 start_period: 10s tasks: setup:env:local: internal: true description: Materialize a local env overlay when the repo has not created one yet action: kind: copy_if_missing from: .env.example to: .env.local setup: context: host description: Hydrate application dependencies on the host through the declared pnpm lane depends_on: - setup:env:local prepare: kind: dependency_hydration medium: package_dependencies source: kind: node_package_manager cwd: . manager: pnpm mode: install frozen_lockfile: true requirements: toolchains: - node effects: writes: - node_modules - .pnpm-store network: true network_kind: dependency_hydration dev: context: host description: Start the app once the managed services are ready env_files: - .env.local env: APP_ENV: local run: pnpm dev depends_on: - setup requires_services: - api - postgres - redis requirements: toolchains: - node env: - DATABASE_URL - REDIS_URL workflows: default: app app: intent: local_development description: Canonical app path with explicit setup, services, and run task boundaries prepare: task: setup:env:local setup: task: setup run: task: dev notes: | Use this when you want one front door that prepares local env state, waits for services, and starts the app. checks: - name: node-installed kind: precondition severity: error run: node --version agent: entrypoint: setup default_task: dev safe_tasks: - setup verify_after_changes: - dev writable_paths: - node_modules - .pnpm-store - src - infra - docs protected_paths: - ota.yaml notes: | Use `ota workflows` to inspect the service-backed app path before running direct tasks. Use `ota up --workflow app` when you want Ota to prepare `.env.local`, verify env requirements, wait for services, and start the app through one declared path. Use `ota up` before starting the service stack. Keep `toolchains.node` as the owner for Node plus pnpm, and keep service startup and readiness in the contract instead of in README prose.