Reference
Platform support
What ota supports well on Linux, macOS, and Windows.
referenceautomation buildersintermediatestable2026-05-30
Recommended next
When to use this page
Use this page to understand where ota is first-class today and where the behavior is narrower.
This is the page that tells you what to expect before you assume a repo will behave the same everywhere.
- Linux is the strongest supported target
- macOS is also first-class
- Windows is supported, but with narrower shell and portability guarantees
- the support boundary matters most when a task body, healthcheck, or service command depends on shell syntax
Compatibility in practice
Compatibility is about whether the declared contract and the current runtime match well enough to trust the result.
- a repo can be valid without being fully portable everywhere
- a command can be supported on a platform without behaving identically to every other platform
- ota should call out when behavior is narrower instead of pretending it is universal
- the contract should tell you what will work before you run it
Platform support
- Linux: first-class target
- macOS: first-class target
- Windows: supported, but not identical to Unix-like shells
What this means in practice
- use Linux or macOS when you want the smoothest default path
- use Windows when the repo contract explicitly handles its shell differences
- split tasks into variants when one shell syntax cannot cover every platform cleanly
- expect ota to warn when the declared behavior is narrower than the platform implies
What ota accepts
- explicit platform declarations in the contract
- task variants when different shells need different bodies
- backend selection when the repo needs native, container, or remote execution
- supported shell syntax for the declared platform
- healthchecks and service commands that fit the current shell model
What ota rejects or warns about
- shell syntax that only works on a different platform than the one declared
- contract fields that imply portability ota does not actually provide
- service or task commands that assume Bash-only behavior on Windows
- hidden fallback behavior that would make the runtime look more capable than it is
Shell semantics
- Unix-like systems use
sh -lc - Windows uses
cmd /C - there is no per-task shell selection in V1
- if the command body assumes Bash behavior, that assumption must be explicit in the task or service design
Lifecycle semantics
Lifecycle tells you how ota treats execution reuse and isolation, not whether a repo is logically ready.
persistentreuses a named container when container execution is configuredephemeraluses a fresh container when container execution is configuredephemeralmeans fresh for this invocation, not reused- explicit task-execution options are capability requests, not hints;
ota runand task-backedota uprefuse any accepted option that the selected task path cannot enforce - this fail-closed admission covers mode and lifecycle across both commands, plus command-specific options such as host-port, memory, and dependency overrides
- native and remote task paths without a managed shared backend reject
--ephemeraland--persistentinstead of silently continuing with advisory lifecycle behavior --sandbox-target oci_localrequests provider-enforced sandbox application for a compatible explicit-platform ephemeral container lane; in agent mode Ota selects that target automatically when authoritative runtime controls require it and no other enforcing target is valid--grantis separate from sandbox selection:prebound_filerequires an exact signed grant ID, while Unixauthority_brokerresolves the one protected binding matching the contract and treats an optional--grant <authority-id>only as a non-secret label check. Broker dry-run reportsrequires_live_authorizationwithout launcher contact; real governed execution consumes one exact lease after deterministic admission and before provisioning or work. Selected workflow instance, ordered prerequisite-instance closure, and ordinaryota up --ready-timeoutchange authority scope. Receipts bind runner-derived closure/effect/resource breadth without exposing raw resource values and retain a public verification binding without the live launcher descriptor. Proof scope includes every selected invocation by role and declaration order, lifecycle selected-service closure, target platform, host-port, memory, dependency selection, and normalized runtime readiness timeout. Runtime and lifecycle proof retain one transaction across that complete proof scope and cleanup, and their archives re-derive terminal authority- real granted execution creates a runner-owned crossing transaction before selected-lane mutation and archives its terminal outcome; dry-run verifies admission without creating a transaction or crossing record
- refused task dry-run and workflow-refusal receipts carry typed prebound-file authority-source, selected authority/grant, stable reason, and execution-not-started evidence without minting crossing authority. When Ota derived the selected scope, they also carry scope and contract identities, boundary family, and classification for external issuance; workflow receipts keep their refusal boundary distinct through
scope_boundary_familyandscope_classification - the first local transaction carrier is
runner_local_content_addressed: Ota locks and internally reconciles it, but does not claim independent authentication against same-user writes to.ota/state - the repository names only
governance.crossing_authority.authority_id; it must not carry trust keys, signed bundle paths, monotonic sequence state, or caller-selectable trust overrides - a grant never bypasses
--agentsafety, and the first signed-file carrier refuses free-form task inputs rather than hashing or exposing potentially secret values container.platformapplies to variants, inputs, environment, service bindings, requirements, and every execution-backend container creation, not only sandbox execution; the current backend accepts Linux OCI targets only, andoci_localrequires the explicit pin so the runner host platform cannot silently replace it- the first OCI adapter admits finite
run,script, andcommandbodies only; typed prepare/action/Compose/launch/attach bodies, requirements, services, conditional checks, and authoritative lifecycle-proof closures refuse before execution - the stock OCI target enforces a read-only repository root, the exact declared mount set, existing writable carve-outs, protected-path write refusal, bounded external IP-network denial, terminal reinspection, and cleanup of Ota's exact boundary; unsupported targeted egress, inherited service networks, image-declared volumes, undeclared mounts, runtime-control sockets, native lanes, and unsafe path aliases refuse before setup
--native,--container, and--remoteare backend shorthands for the mode-bearing repo commands, includingota run,ota up,ota doctor, andota receiptota run --ephemeralstill provisions only the missing or mismatched contract requirements in that fresh container; it does not reinstall everything from scratch--ephemeralis the shorthand for--lifecycle ephemeralonota run,ota up,ota doctor, andota receipt--persistentis the shorthand for--lifecycle persistentonota run,ota up,ota doctor, andota receipt- use
ota cleanwhen a container-backed task left stale runtime state behind; ota removes current and drifted repo-owned persistent containers plus dependency-isolation volumes - outside task-backed execution, service diagnosis may still describe lifecycle as advisory; explicit
ota runand task-backedota uplifecycle requests never silently degrade - ordinary ephemeral container execution and provider-enforced
oci_localexecution both use invocation-scoped boundaries; only the provider-enforced lane carries inspected policy-application and confirmed-cleanup evidence - dry-run never starts a provider boundary merely to probe runtime/tool availability; real OCI execution binds each provider-backed precondition probe to the exact admitted requirement-owning segment, records it as a cleanup-confirmed
precondition_probeinvocation, retains terminal evidence on a blocking refusal, and never lets it substitute for task-execution evidence
What users should expect
- expect the best behavior today on Linux and macOS
- expect Windows to work, but with more explicit shell syntax and fewer portability assumptions
- expect support warnings when the contract uses behavior the current platform cannot honor cleanly
- use task variants when one task name needs different bodies on different platforms
- treat shell behavior as part of the contract, not an invisible compatibility layer
- treat support policy as a boundary, not as a promise that every command will behave the same everywhere
When this matters
- a repo has Windows users but shell bodies were written for Unix syntax
- a task works locally but fails in CI because the runner shell differs
- a service healthcheck uses shell features the current platform does not support
- a maintainer needs to decide whether to split a task into variants
What this is not
- not a promise of identical shell behavior on every OS
- not per-task shell selection
- not automatic shell portability translation
- not isolated ephemeral workspace creation in V1
- not a guarantee that any shell snippet copied between platforms will work unchanged
Relationship to other surfaces
contractdefines the repo’s execution intentshell-semanticsdefines the actual command invocation modeldoctorshould explain support and compatibility failures clearly and earlyrunandupshould honor the platform boundary instead of hiding itsupport policytells you what platform boundaries ota expects you to respect