Call (Embedded Runs)

Embedded runs let you compose and coordinate multiple run definitions. Orchestrating your CI and CD workflows is one situation where this functionality shines.

Like leaves, runs can be embedded using the call key. Before diving into the details, let's consider the following example:

      if: ${{ event.git.branch == "main" }}
        git-ref: ${{ event.git.ref }}
        only-at-the-top-level: some-value

  - key: ci
    call: ${{ }}/ci.yaml
      git-ref: ${{ init.git-ref }}

  - key: cd
    call: ${{ }}/cd.yaml
    after: ci
      git-ref: ${{ init.git-ref }}
      image-id: ${{ }}

There's a lot to consider in this small example. Let's dive in.


Runs can be embedded via the call key. To do so, you can provide a value that starts with ${{ }}. This expression represents the .mint directory that was present when your run was triggered. Following ${{ }}, you provide the filename of the run definition you'd like to embed.

When your run is triggered, either via an event or with the CLI, Mint keeps track of the files in the .mint directory and exposes them to you for use in embedded runs.

If you want to embed a run from a definition that is not in the Mint directory, you can reference an artifact produced by a task instead of referencing ${{ }}.


Rather than providing parameters via with (like you would in leaves), you use init for embedded runs, just like you would if you were configuring a trigger for a run.

Embedded runs only have access to the init parameters which you explicitly provided. In the example above, init.only-at-the-top-level is not available to either embedded run and init.image-id is only available within the cd embedded run.


Embedded runs are isolated from one another. They do not share filesystems to ensure that they behave the same way they would when run in isolation. Because of this, embedded run tasks cannot use another task and other tasks cannot use an embedded run task.

Instead, if you need to share information between embedded runs, you can access subtasks of embedded runs in expressions. In the example above, the ci embedded run has a subtask named build-image which produces an image-id value. The cd embedded run can access that value because it runs after ci. Leaves continue to be encapsulated and their subtasks are inaccessible (to provide better guarantees around breaking changes in leaves).


Even though use is not permitted with embedded runs, you can still configure order of execution and dependencies via after. In the example above, the cd embedded run will only run after the ci embedded run has successfully run.

Tool Caches

When using tool caches, embedded runs will not share the same tool cache as the triggered run. Runs should declare their own tool caches to ensure they can run while embedded and in isolation. When a run is embedded, the subtasks of that run respect the tool cache declared in the embedded run's definition.

Concurrency Pools

When your embedded run definition uses a concurrency pool, Mint respects that definition and acquires a lease within that pool prior to starting any tasks within the embedded run.

Dynamic Embedded Runs

Mint supports dynamic embedded runs in addition to referencing another run definition in your .mint directory. To do so, first run a task that writes a run definition to a file and upload it as an artifact. Then, you can reference that artifact in the call expression: call: ${{ tasks.generate-run-definition.artifacts.definition }}. For a full example, take a look at the following tasks:

  - key: generate-run-definition
    run: |
      cat << EOF > definition.yml
        - key: my-embedded-task
          run: echo "I'm embedded"
        - key: definition
          path: definition.yml

  - key: embed-dynamic-run
    call: ${{ tasks.generate-run-definition.artifacts.definition }}