Operate
Local Topology Patterns
How to adopt target bindings, target activation, shared local backends, and backend fulfillment without repo-local glue.
Recommended next
When to use this page
Use this page when the repo problem is not language setup alone, but how one local workload should truthfully target or share execution with another.
This is the adoption page for the shipped local-topology surface: first-class task target bindings, target activation, shared local backends, and backend-scoped run-path fulfillment.
- use it when a helper app, probe, or SDK harness should target a repo-managed service by service identity instead of a guessed URL
- use it when multiple long-running container tasks should intentionally share one ota-managed backend boundary
- use it when the shared backend itself needs preparation on the
ota runpath and repo-local bootstrap glue would be the wrong fix
Pattern 1: Task target bindings
Start here when one task should follow another repo-managed app by service identity.
Keep the topology truth in tasks.<name>.targets.<target>. This is the shipped service-target-default surface; there is no separate default_from.service field. Only use task input as the explicit operator override channel.
- choose
address_view: hostwhen the consumer may run in another execution plane and should target the producer's published host URL - use
service.repowhen that producer is owned by another repo in the sameota.workspace.yaml; keepservice.memberfor monorepo member producers - keep
override_inputonly when operators genuinely need to point the task at staging, preview, or another local target - use
activation.mode: ensure_startedwhen ota should hand producer startup off immediately,restart_readywhen ota should bounce a reachable producer and verify it again,ensure_runningwhen ota should make the declared listener reachable first, andensure_readyonly when ota should also wait for deeper declared readiness - today the workspace cross-repo slice is host-view only:
service.reporequiresaddress_view: hostplus one fixedproject.hostendpoint on the producer listener - read activation evidence as plain language:
started_started/reused_startedmean startup handoff,started_running/reused_runningmean listener reachability, andrestarted_ready/started_ready/reused_readymean deeper readiness - omit
override_inputwhen the task should just consumeOTA_TARGET_<TARGET>directly
tasks: sandbox: inputs: base_url: description: Override the API base URL when needed targets: api: service: task: dev listener: http address_view: host override_input: base_url run: pnpm dev:sandboxPattern 1b: Target activation
Use target activation when target resolution alone is not enough and ota should also ensure the local producer service is up before the consumer runs.
Keep activation separate from target identity. targets.<name> still declares what the consumer talks to; activation.mode only declares whether ota should make that producer ready first.
- ship
manual,ensure_started,restart_ready,ensure_running, andensure_ready - when the producer service task declares
runtime.readiness, ota waits for that readiness contract instead of treating an open listener socket as sufficient - explicit operator override inputs skip producer auto-start and preserve the override value
ensure_startedhands startup off immediately,restart_readyrestarts a currently reachable producer before verifying it again,ensure_runningwaits only for the declared target listener plane, andensure_readywaits for declaredruntime.readinesswhen one exists- the current shipped slice auto-starts only producer tasks ota can own honestly: persistent container service backends, unix native producer services, built-in remote producer services only when caller and producer share one declared remote backend binding, and backend-provider remote producer services only when the matching
backend_providerextension declaresactivation.provider_managed_cleanup: true; built-in shared-remoteaddress_view: host/address_view: topology/address_view: internalmay probe the remote plane, and backend-provider remote activation now covers those same shared-remote views when ota can call provider-owned cleanup first;ensure_startedhands startup off immediately,restart_readycan bounce a reachable producer before waiting again,ensure_runningobserves listener reachability, andensure_readymay observetcporhttpreadiness - stream-mode runs show an explicit activation wait phase while ota is starting or waiting on the producer readiness contract
- if activation started the producer for this run, ota cleans it up on interrupt; reused producers are left running intentionally
- unsupported producer shapes fail clearly instead of guessing orchestration
tasks: sandbox: inputs: base_url: description: Override the API base URL when needed targets: api: service: task: dev listener: http address_view: host override_input: base_url activation: mode: ensure_ready run: ./scripts/sandbox/start.shPattern 3: Run-path fulfillment
Turn this on when ota should make the declared execution environment real on the run path instead of asking the repo to bootstrap missing tools itself.
Use the shared-backend form when multiple tasks intentionally share one backend boundary, or the direct context form when one container context should be prepared inside the actual execution container before the task body runs.
requirementsdeclare what the environment needs;fulfillmentdeclares whether ota should try to make that true on the run path- use
fulfillment: nonewhen the contract should fail clearly if the backend is missing prerequisites - use
fulfillment: runwhen ota should prepare the backend on the actual run path fulfillment: runstill depends on org policy for approved sources and versions; it is opt-in runtime intent, not a policy bypass- if org policy enables
strict_versions, ota also treats repo-satisfying but policy-noncompliant installed versions as gaps thatfulfillment: runmay repair with an approved exact version - for direct container contexts,
fulfillment: runnow prepares the real ephemeral execution container before the task body instead of provisioning a separate throwaway backend - read receipt/result vocabulary in plain language:
requirements_satisfiedmeans nothing had to be installed,fulfilledmeans ota provisioned successfully,missing_requirementsmeans fulfillment was not allowed/selected, andfailedmeans ota tried to prepare the backend but did not complete successfully
execution: shared_backends: workbench: scope: local backend: container lifecycle: persistent context: app fulfillment: runexecution: contexts: tooling: backend: container lifecycle: ephemeral fulfillment: run container: image: node:24-bookwormPattern 4: Policy-governed backend environment
Use this when the repo should declare backend environment intent and let policy resolve the effective image honestly.
This keeps shared-backend shape and fulfillment attached to one approved profile or alias instead of hardcoding raw images everywhere.
- use
environment.profilefor a named approved backend profile - use
environment.image_aliaswhen policy should map one repo-facing alias to the approved image - use literal
environment.imageonly for compatibility or intentionally ungoverned local cases - use
environment: {}when policydefault_profileshould choose the effective backend image - read receipts and
ota execution planto compare declared intent versus the effective image/source/registry ota actually selected
execution: shared_backends: workbench: scope: local backend: container lifecycle: persistent context: app fulfillment: run environment: profile: java-node-workbenchCurrent constraints
The current design is the right long-term foundation, but the shipped surface is intentionally strict where ota cannot yet prove more.
- shared backends currently ship as local
container, localnative, and remoteremote - bound tasks must resolve one deterministic backend shape, but workload-local listeners/readiness/publications may differ
- ota rejects conflicting in-backend bind endpoints and conflicting fixed host publications inside one shared backend boundary
address_view: topologyfor container callers resolves only when ota can prove shared locality through the declared backend binding- direct-context run-path fulfillment currently applies to
containercontexts only;nativeandremotecontexts must not declarefulfillment - ephemeral direct container contexts support non-service task execution today; service-runtime fulfillment in that shape is still rejected
- backend fulfillment currently acts on the effective shared backend requirement union for container, native, and remote shared backends
Canonical examples
Use these examples as the adoption baseline instead of rebuilding the patterns from scratch in each repo.