CUE has a package (cue/flow) that has a default implementation but also allows you to build custom tasks on top of the engine & evaluator. The nice thing about this setup is that it infers the dependencies between tasks based on the references to inputs/outputs between them. The main drawback of most of these things is that they don't scale beyond a single machine. That's why people choose tools like Airflow.
https://pkg.go.dev/cuelang.org/go@v0.10.1/tools/flow (cue cmd is the default implementation of this)
https://docs.hofstadter.io/getting-started/task-engine/ (custom example)