Skip to main content
info

Documentation is currently for moon v2 and latest proto. Documentation for moon v1 has been frozen and can be found here.

Execution plan

v2.1.0

An execution plan is a JSON file that declaratively configures how moon exec (and derived commands) runs tasks. Instead of passing many command line options, you can define your execution settings in a file and pass it with a single flag — keeping your commands short and your configuration version-controlled.

Usage

Pass an execution plan to moon exec with the --plan (or -p) flag:

$ moon exec --plan plan.json

Or set the MOON_EXEC_PLAN environment variable:

MOON_EXEC_PLAN=plan.json moon exec

The path can be relative (resolved against the working directory) or absolute. The file must be valid JSON.

When both a plan and CLI options are provided, plan values take priority. If targets are defined in both the plan and the command line, the plan's targets are used and a warning is logged.

Structure

A plan is a JSON object with four top-level blocks. All blocks are optional and default to safe values when omitted. Unknown fields are rejected.

{
"affected": {},
"graph": {},
"pipeline": {},
"targets": []
}

targets

Defines which tasks to run. Accepts the same target syntax as the moon exec command line (project:task, :task, ~:task, #tag:task, globs, etc).

In its simplest form, targets is an array of target strings:

{
"targets": ["app:build", "lib:build"]
}

For advanced use cases, targets can be an object with one of two strategies:

  • Filtered — Run only the targets that match the include list (excluding coming soon):
{
"targets": {
"include": ["app:build", "#frontend:test"]
}
}
  • Partitioned — Split targets into groups for parallel CI jobs. Each inner array is one partition:
{
"targets": {
"jobs": [
["app:build", "app:test"],
["lib:build", "lib:test"]
]
}
}

Use in combination with pipeline.job to select which partition to run.

pipeline

Controls how the pipeline executes tasks.

  • ci (boolean) - Force enable CI mode. Same as --ci.
  • concurrency (number) - Maximum number of tasks to run in parallel.
  • ignoreCiChecks (boolean) - Ignore "run in CI" task checks. Same as --ignore-ci-checks.
  • noActions (boolean) - Skip sync and setup actions. Same as --no-actions.
  • onFailure ("bail" | "continue") - When a task fails, either bail the pipeline immediately or continue running other tasks. Same as --on-failure.
  • job (number) - Index of the current job (0-based). Used with partitioned targets; errors if targets are not partitioned. Same as --job.
  • jobTotal (number) - Total number of jobs. Used with partitioned targets. Same as --job-total.

graph

Controls how deeply the dependency graph is traversed when building the task graph.

  • downstream (none | direct | deep) - Depth of downstream dependents to include. Defaults to none. Same as --downstream.
  • upstream (none | direct | deep) - Depth of upstream dependencies to include. Defaults to none. Same as --upstream.

affected

Restricts execution to tasks affected by changed files. When this block is omitted, affected filtering is disabled and all matched targets run.

  • base (string) - Base branch, commit, or revision to compare against. Same as --base.
  • head (string) - Current branch, commit, or revision to compare with. Defaults to HEAD. Same as --head.
  • includeRelations (boolean) - Include graph relations for affected checks, instead of just changed files. Same as --include-relations.
  • source (string) - Source of affected files. Determines which git commands are used to detect changes. Accepts local or remote.
  • status (string[]) - Filter changed files by status. Same as --status.
  • stdin (boolean) - Accept changed files from stdin. Same as --stdin.

Examples

Run specific targets

The simplest plan — just list the targets to run:

{
"targets": ["app:build", "lib:build"]
}

CI with affected filtering

Only run tests affected by changes between the base branch and HEAD:

{
"affected": {
"base": "main",
"source": "remote"
},
"pipeline": {
"ci": true
},
"targets": [":test"]
}

Partitioned CI jobs

Split targets across 3 CI jobs. Each job runs with --plan plan.json and sets its own job index via the CLI or an environment variable:

{
"pipeline": {
"ci": true,
"jobTotal": 3
},
"targets": {
"jobs": [["app:build", "app:test"], ["lib:build", "lib:test"], ["docs:build"]]
}
}

Then in CI, run each partition:

# Job 0
$ moon exec --plan plan.json --job 0

# Job 1
$ moon exec --plan plan.json --job 1

# Job 2
$ moon exec --plan plan.json --job 2

Continue on failure

Run all lint tasks, continuing past failures so you get the full list of issues:

{
"pipeline": {
"concurrency": 4,
"onFailure": "continue"
},
"targets": [":lint"]
}

Deep dependency graph

Build a target along with all of its upstream dependencies and downstream dependents:

{
"graph": {
"upstream": "deep",
"downstream": "deep"
},
"targets": ["core:build"]
}

Full example

Combine all blocks — run affected tests in CI across partitioned jobs, with full graph traversal:

{
"affected": {
"base": "main",
"head": "HEAD",
"includeRelations": true,
"source": "remote",
"status": ["modified", "added"]
},
"graph": {
"upstream": "deep",
"downstream": "direct"
},
"pipeline": {
"ci": true,
"concurrency": 8,
"jobTotal": 3,
"onFailure": "continue"
},
"targets": {
"jobs": [["app:test", "app:lint"], ["#frontend:test"], ["lib:test", "core:test"]]
}
}