Skip to main content

moon v2.2 - Daemon, AI skills, async graph building, async affected tracking, and more

· 8 min read
Miles Johnson
Founder, developer

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

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:

$ 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.

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

Thanks to 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:

.moon/workspace.yml
unstable_daemon: true

Or test it with an environment variable first:

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, stop, restart, status, and 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 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.

.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!

BenchmarkAverage timeTotal suite timeSpeedup
SyncAsyncSyncAsync
100 projects / 400 tasks78ms51ms9.7s5.1s41.8%
1,000 projects / 4,000 tasks514.5ms119ms57.4s12s125%
5,000 projects / 20,000 tasks5.7s457ms602.6s46s170%

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.

.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.

BenchmarkAverage timeTotal suite timeSpeedup
SyncAsyncSyncAsync
10 projects47.9ms47.3ms4.2s4.2s0%
30 tasks105.08ms61.75ms10.4s5.6s+51.9%
100 projects60.02ms60.41ms6s6s0%
300 tasks585.62ms131.43ms58.6s13.1s+126.6%
1,000 projects202.14ms199.52ms21.6s20s+1.3%
3,000 tasks5.5s901ms553.4s88.5s+143.75%
5,000 projects1.1s1s127.8s111.3s+13.8%
15,000 tasks29s4.5s2,866s (47m)476s (7.9m)+146%

Other changes

View the official release 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.