Getting started
First ota.yaml
A minimal contract that still feels operational.
learnmaintainersbasicstable2026-05-30
Recommended next
Minimal useful starter
A starter contract should be obvious, stable, and runnable.
Starter contractyaml
version: 1project: name: ota-web type: applicationruntimes: node: "22"tools: pnpm: "10"tasks: setup: internal: true command: exe: pnpm args: [install] build: depends_on: [setup] command: exe: pnpm args: [build] test: depends_on: [build] command: exe: pnpm args: [test] deploy: depends_on: [test] command: exe: pnpm args: [deploy] safe_for_agent: falseagent: entrypoint: setup default_task: test safe_tasks: [setup, build, test] protected_paths: [ota.yaml, .env, .env.local] verify_after_changes: [build, test]What makes it useful
- it names the repo
- it declares the core runtime and tools
- it defines safe tasks and verification tasks
- it gives agents a deterministic entrypoint
When the first task is a service
If the starter contract includes a long-running app server, docs preview, or worker process, prefer launch.kind: command instead of hiding that start path inside raw run shell text.
launch owns process start. runtime plus surfaces owns the reachable URL, listener, and readiness truth.
- use
launch.kind: commandfor long-running service processes - use
runtime.kind: servicewithsurfacesorlistenersfor the endpoint and readiness contract - use
aggregate.tasksfor named verification entrypoints that only run other tasks - keep
runfor finite shell tasks, pipelines, or real escape-hatch cases
Structured service taskyaml
tasks: dev: launch: kind: command exe: bundle args: [exec, rails, server, -b, 0.0.0.0, -p, "3000"] runtime: kind: service surfaces: - api