Relationships
#3578 workflow placement: run a workflow transparently on a specified host, local or via swamp workers (incl. nested child workflows)
Opened by svendowideit · 10/17/2026
Problem
A workflow that must run on a specific host has to declare placement (target/labels/platform) in its YAML. Placement presence is static, and hasPlacement() (src/domain/remote/scheduler.ts) treats a non-undefined target/platform — even an empty string — or a non-empty labels as active. When placement is active but no dispatcher is running (a plain local swamp workflow run), the run fails:
Step requests remote placement but no worker dispatcher is active — remote execution
requires running under 'swamp serve' with enrolled workersSo one workflow file cannot transparently:
- run locally (standalone swamp, break-glass/dev on a single host), and
- be routed to a worker host when the same repo is served by
swamp servewith workers.
This is worse for reuse via nested workflows: a nested type: workflow step does not inherit the caller's placement — the child run uses its own workflow.placementFields only (src/domain/workflows/execution_service.ts). A shared child workflow therefore cannot be written once and used by parents that run in different deployment configs.
What we want
A way to control where a child workflow's steps run such that:
- a high-level workflow can reuse other workflows (component architecture), and
- all of them run on the same specified host, and
- the same workflow file works unchanged whether run by a standalone swamp, a standalone
swamp serve, or a distributedswamp servewith workers doing different jobs — i.e. a workflow written for one deployment config runs on the others transparently.
Is there — or can there be — such a mechanism?
What we tried (swamp 20261017.001604.0)
- Nest a child that declares its placement from an input:
target: ${{ inputs.target }}.- Under serve with
inputs.target=figy-eieio: works — the child's model-method steps dispatch to that worker (and a grandchild too, when the input is forwarded). - Standalone with the input defaulting to
"": fails —hasPlacement("")is true, so it still demands a dispatcher. - No default and no
--input: CEL errorNo such key: target. null: schema rejects (target: Invalid input: expected string, received null).
- Under serve with
labels: ${{ inputs.labels }}(object input, default{}): works under serve; an empty object correctly means "no placement" (runs locally). But standalone it fails at load:labels: Invalid input: expected record, received string— record-valued placement fields reject expression strings (only serve resolves runtime selectors).- Static
labels: {}runs locally — but it is static, so it cannot also route to a worker.
Conclusion: there is currently no way to write one child workflow that is placed on a worker under serve and runs locally otherwise. Reusing a shared child across deployment configs requires forking a placed copy kept in lockstep, or an all-or-nothing migration of every caller.
Proposed
Any of:
- Inherit placement into nested runs when the child declares none (child-wins merge), so a child runs wherever its caller is placed — and the caller's absence of placement keeps it local. (Lab #2465)
- A serve-side default placement, applied only when a dispatcher is active and only to steps whose merged placement is empty. (Lab #2344)
- A fallback-to-local for placement when no dispatcher is active, behind an opt-in workflow field (e.g.
placementFallback: local), so a placed workflow still runs locally.
Related: #2344, #2465.
Open
No activity in this phase yet.
svendowideit commented 10/17/2026, 1:16:37 PM
hmmm, i've been pondering this for a while, and still am not sure if this is intentional for security like reasons, but ... it's hard for me to work out what the reuse development flow is going to be.
assuming a user is building nested workflows on a non-clustered swamp (or even a non-swamp-serve setup) - I suspect they're likely (like i was hoping) to expect that when a workflow calls another workflow, that the child runs where the parent does - for eg the caddy workflow calls the systemd-service workflow to make a service with it's bits - on whatever host the caddy workflow was told to do so on.
but ... idk - I just feel unsure - and i hope that whatever solution is planned makes it in everyone's face obvious how something built with an understanding of one swamp topology will function in the other topologies that the author might not yet be aware of.
Sign in to post a ripple.