Getting started

First ota.yaml

A minimal contract that still feels operational.

learnmaintainersbasicstable2026-05-30

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: command for long-running service processes
  • use runtime.kind: service with surfaces or listeners for the endpoint and readiness contract
  • use aggregate.tasks for named verification entrypoints that only run other tasks
  • keep run for 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