Operate
Defining Readiness
How env vars, services, verify, checks, and proof fit together so readiness stays explicit instead of collapsing into one vague setup story.
Recommended next
Why this page exists
Teams often say a repo is ready when they really mean several different things at once.
One person means the right env vars exist. Another means Postgres is reachable. Another means the app boots. Another means the verification task passed. Another means there is evidence the whole path worked on a clean boundary.
Ota keeps those truths separate on purpose so readiness stays explainable.
- env vars are config truth
- services are dependency truth
- checks are diagnostic truth
- verify is completion truth
- proof is evidence truth
The wrong model
The weak model is to collapse everything into one vague setup command and one vague success claim.
That is how repos end up with drift between README steps, shell scripts, CI, and agent behavior.
Problem
Config gets hidden in local state
The repo depends on env values, but nobody can tell whether they are required, optional, secret, defaulted, or sourced from a declared file.
Problem
Dependencies get smuggled into shell
A setup script implicitly assumes a database, queue, or sibling service is already running.
Problem
Success becomes guesswork
A command exits zero, but nobody can tell whether the repo is diagnosable, runnable, verified, or actually proven ready on a clean path.
Env vars define config truth
Readiness starts with configuration truth. If the repo needs a value to operate, that fact should have a home.
In ota, env.vars defines the requirement layer and env.sources defines which files ota is allowed to read. That keeps config reviewable instead of hiding it in shell folklore.
- use
env.varsfor required, secret, default, and allowed-value truth - use
env.sourcesonly when file-backed loading is intentional repo truth - use task-scoped env requirements when a value belongs to one path, not the whole repo
- use
ota envandota doctorwhen you need to explain who won and what is missing
env: vars: DATABASE_URL: required: true secret: true WEB_ORIGIN: default: "http://127.0.0.1:3000" sources: - kind: dotenv path: .env.localServices define dependency truth
A repo can be configured correctly and still not be ready because a dependency is missing or unreachable.
That truth belongs under services when the repo depends on infrastructure such as Postgres, Redis, Compose services, or workspace-produced endpoints.
- declare services when the dependency should be visible to doctor, up, workflows, and agents
- attach readiness where the dependency is owned instead of hiding it in setup shell
- use service endpoints and structured readiness so hostnames, ports, and protocol truth do not drift
- scope required services per workflow when one repo has more than one runtime path
services: postgres: required: true manager: kind: compose name: local file: compose.yaml service: postgres endpoints: app: address: postgres port: 5432 readiness: from: app kind: tcpChecks define diagnostic truth
Checks answer: what should ota be able to test directly without turning that logic into a business task or a human-only note.
They are the right surface for named readiness gates used by ota check, ota doctor, workflow readiness, and CI.
- use checks for repeatable diagnostic gates
- prefer structured kinds like
precondition,file, andenvwhen ota already owns the assertion surface - keep shell
runchecks for logic that still does not fit the structured lanes - use
severityto make the difference between blocking and advisory truth explicit
checks: - name: backend-config kind: env severity: error file: .env.local key: DATABASE_URL state: present - name: app-ready kind: health severity: error probe: backend-readyVerify defines completion truth
Readiness is not only about whether the app can start. It is also about whether the repo's declared work is complete.
That is where verification tasks and aggregate verification flows matter. They prove the repo's own quality bar, not just bootability.
- use declared tasks for lint, test, build, and other completion gates
- use aggregate verification when the repo wants one canonical verify surface composed from smaller tasks
- keep verify truth explicit instead of assuming command success means the change is acceptable
- teach agents and CI the same verification path the maintainers trust
tasks: lint: command: exe: npm args: [run, lint] test: command: exe: npm args: [run, test] verify: aggregate: tasks: - lint - testProof defines evidence truth
Proof is the surface for when someone needs more than a claim that a task ran.
Use proof when you need artifact-backed evidence that a selected workflow really became ready on a fresh boundary, or when a failure should preserve machine-readable evidence instead of dying as terminal scrollback.
- use
ota proof runtimefor clean-machine workflow proof - use receipts when task execution needs durable machine-readable evidence
- keep proof separate from diagnosis and verification so operators can tell what was actually demonstrated
- treat proof as evidence truth, not as a replacement for the contract itself
ota doctorota checkota run verify --receiptota proof runtime --workflow appThe mental model
These surfaces work best when each one owns the narrowest truthful question.
- env vars answer what configuration must exist
- services answer which dependencies must be reachable
- checks answer which diagnostic gates should run directly
- verify answers which declared work proves completion
- proof answers what evidence shows the path actually worked