---
slug: moon-v2.2
title: moon v2.2 - Daemon, AI skills, async graph building, async affected tracking, and more
authors: [milesj]
tags: [daemon, performance, async, graph, affected, workspace, ai, agent, skill, debug, tasks]
image: ./img/moon/v2.2.png
---

In this release, we focused entirely on performance improvements, with the introduction of a daemon,
and refactoring core components to be asynchronous.

<!--truncate-->

## New `debug-task` AI agent skill

We're shipping a new AI agent skill called `debug-task` that helps you systematically diagnose
failing or misbehaving moon tasks. If you've ever spent time hunting down why a task is producing
stale results, getting unexpected cache misses, or behaving differently in CI, this skill is for
you.

To install this skill, run the following command:

```shell
$ npx skills add moonrepo/moon --skill debug-task
```

The skill walks you through a 5-step diagnostic workflow:

1. Inspect the resolved task configuration (after inheritance merging)
2. Run with maximum verbosity to see exactly what moon is doing
3. Inspect cache state and hash manifests
4. Match symptoms to root causes using a built-in decision tree
5. Validate that the fix actually resolves the issue

It covers 15+ specific problem types across cache issues, configuration mistakes, execution
problems, and CI vs local discrepancies. Most issues resolve by step 3, with deeper reference
material available on demand.

To use it, simply describe your task problem in Claude Code, Codex, OpenCode, or another compatible
AI agent — mention the task target, what you expected, and what actually happened. The skill will
take it from there.

```shell
/debug-task Help me debug why the `app:build` task is not being cached
```

> Thanks to [Yuzu02](https://github.com/Yuzu02) for the amazing contribution!

## Unstable daemon

Continuing the theme of performance, this release introduces an unstable background daemon. The
daemon is a long-lived server process that keeps the workspace graph hot in memory and watches for
file system changes, rebuilding the graph asynchronously only when configuration files change. This
means that after the first `moon` invocation, subsequent commands can skip graph building entirely
and connect to the running daemon instead.

To try it out by enabling it in your workspace configuration:

```yaml title=".moon/workspace.yml"
unstable_daemon: true
```

Or test it with an environment variable first:

```shell
MOON_DAEMON=true moon run :build
```

When enabled, the daemon starts automatically on the first CLI command and stays running in the
background. You can manage it with [`moon daemon start`](/docs/commands/daemon/start),
[`stop`](/docs/commands/daemon/stop), [`restart`](/docs/commands/daemon/restart),
[`status`](/docs/commands/daemon/status), and [`logs`](/docs/commands/daemon/logs) commands. If the
daemon is unavailable for any reason, the CLI falls back to building graphs in-process — so there's
no risk in enabling it.

Since this is unstable, behavior and configuration may change in future releases. Check out the
[daemon guide](/docs/guides/daemon) for full details on how it works, what files are watched, and
troubleshooting tips.

## Experimental async graph building

Project and task building is a critical piece of moon. In previous versions, graph building was
implemented synchronously, which could lead to performance issues in larger workspaces, but was
unnoticeable in smaller workspaces. With this release, graph building is now available with an
experimental async implementation, which must be enabled.

```yaml title=".moon/workspace.yml"
experiments:
  asyncGraphBuilding: true
```

To demonstrate the performance improvements, take the following benchmark results for example. For
every benchmark, we had N projects with 4 tasks per project, iterated 100 times. The "average time"
columns show the average time taken across all iterations, while the "total suite time" columns show
the total time taken for all iterations. The "speedup" column shows the percentage improvement of
the async builder compared to the sync builder.

As you can clearly see, as the number of projects and tasks increase, the performance improvement
becomes more significant, with a speedup of 40-170%. Over time, and with the introducion of the
daemon, this will only get better!

<table>
  <tr>
    <th>Benchmark</th>
    <th colspan="2">Average time</th>
    <th colspan="2">Total suite time</th>
    <th>Speedup</th>
  </tr>
  <tr>
    <td> </td>
    <td>Sync</td>
    <td>Async</td>
    <td>Sync</td>
    <td>Async</td>
    <td> </td>
  </tr>
  <tr>
    <td>100 projects / 400 tasks</td>
    <td>78ms</td>
    <td>51ms</td>
    <td>9.7s</td>
    <td>5.1s</td>
    <td>41.8%</td>
  </tr>
  <tr>
    <td>1,000 projects / 4,000 tasks</td>
    <td>514.5ms</td>
    <td>119ms</td>
    <td>57.4s</td>
    <td>12s</td>
    <td>125%</td>
  </tr>
  <tr>
    <td>5,000 projects / 20,000 tasks</td>
    <td>5.7s</td>
    <td>457ms</td>
    <td>602.6s</td>
    <td>46s</td>
    <td>170%</td>
  </tr>
</table>

### Caveats

While the async graph builder is faster, there are some caveats to be aware of.

- Since this is experimental, it is not enabled by default. You must enable it in your workspace
  configuration to take advantage of the performance improvements.
- The async graph builder does not cache the built graph as this time, so it will be built from
  scratch every `moon` invocation. This is a temporary limitation that we plan to address in the
  future, as caching is a critical piece of the puzzle for performance. With that said, even without
  caching, the async builder is still significantly faster than the sync builder, especially for
  larger workspaces.
- The async graph builder does not support cycles, and will hard error if a cycle is detected. In
  the sync builder, we would attempt to cut edges between nodes when a cycle was detected, which
  could lead to incorrect results, but would not error.

## Experimental async affected tracker

The affected tracker is a core component of moon that determines which projects and tasks are
affected by changes in the codebase. In previous versions, the tracker was implemented
synchronously, which could lead to performance issues for larger projects with many tasks. With this
release, the affected tracker is now available with an experimental async implementation. This new
version is designed to be faster and more efficient (up to 150%), especially for large repositories
with many tasks.

Since this is experimental, it is not enabled by default. To enable the async tracker, you can
configure the following in `.moon/workspace.yml`.

```yaml title=".moon/workspace.yml"
experiments:
  asyncAffectedTracking: true
```

To demonstrate the performance improvements, take the following benchmark results for example. For
every benchmark, we had N projects with 3 tasks per project, iterated 100 times. The "average time"
columns show the average time taken across all iterations, while the "total suite time" columns show
the total time taken for all iterations. The "speedup" column shows the percentage improvement of
the async tracker compared to the sync tracker.

If you'll notice, the improvement for projects is negligible, which is expected as project tracking
is very simple. However, for tasks, the async tracker shows significant improvements as the number
of tasks increases, with a speedup of 50-150%. With that said, we believe that after 5,000 tasks,
the increments diminish, as we're most likely hitting the upper limits of how much we can
parallelize the work.

<table>
  <tr>
    <th>Benchmark</th>
    <th colspan="2">Average time</th>
    <th colspan="2">Total suite time</th>
    <th>Speedup</th>
  </tr>
  <tr>
    <td> </td>
    <td>Sync</td>
    <td>Async</td>
    <td>Sync</td>
    <td>Async</td>
    <td> </td>
  </tr>
  <tr>
    <td>10 projects</td>
    <td>47.9ms</td>
    <td>47.3ms</td>
    <td>4.2s</td>
    <td>4.2s</td>
    <td>0%</td>
  </tr>
  <tr>
    <td>30 tasks</td>
    <td>105.08ms</td>
    <td>61.75ms</td>
    <td>10.4s</td>
    <td>5.6s</td>
    <td>+51.9%</td>
  </tr>
  <tr>
    <td>100 projects</td>
    <td>60.02ms</td>
    <td>60.41ms</td>
    <td>6s</td>
    <td>6s</td>
    <td>0%</td>
  </tr>
  <tr>
    <td>300 tasks</td>
    <td>585.62ms</td>
    <td>131.43ms</td>
    <td>58.6s</td>
    <td>13.1s</td>
    <td>+126.6%</td>
  </tr>
  <tr>
    <td>1,000 projects</td>
    <td>202.14ms</td>
    <td>199.52ms</td>
    <td>21.6s</td>
    <td>20s</td>
    <td>+1.3%</td>
  </tr>
  <tr>
    <td>3,000 tasks</td>
    <td>5.5s</td>
    <td>901ms</td>
    <td>553.4s</td>
    <td>88.5s</td>
    <td>+143.75%</td>
  </tr>
  <tr>
    <td>5,000 projects</td>
    <td>1.1s</td>
    <td>1s</td>
    <td>127.8s</td>
    <td>111.3s</td>
    <td>+13.8%</td>
  </tr>
  <tr>
    <td>15,000 tasks</td>
    <td>29s</td>
    <td>4.5s</td>
    <td>2,866s (47m)</td>
    <td>476s (7.9m)</td>
    <td>+146%</td>
  </tr>
</table>

## Other changes

View the [official release](https://github.com/moonrepo/moon/releases/tag/v2.2.0) for a full list of
changes.

- Temporarily brought back `x86_64-apple-darwin` (Apple Intel) as a supported operating system.
- Greatly reduced memory footprint of the action, project, and task graphs. Nodes in the graph are
  now integers instead of objects.
- Improved plugin registry performance and memory consumption when loading plugins.
- Improved performance of `taskToolchains` and `taskType` fields when querying the project graph.
- Improved performance of task output archiving, by no longer blocking the main thread pool.
- Updated the system toolchain to be built-in instead of an external WASM plugin that needs to be
  downloaded.
