Nx task execution and cache
EOS uses Nx to execute package scripts and repository tasks.
Tool responsibilities
| Tool | Responsibility | Examples |
|---|---|---|
| mise | Install and select repository tool versions | mise install |
| pnpm | Install dependencies, manage workspaces, and maintain the lockfile | pnpm install, pnpm --filter @tillo/scout add <package> |
| Nx | Select project tasks, run their declared dependencies, and manage the task cache | nx run @tillo/scout:test, nx affected -t test |
| Ultracite | Check and fix source files with the Oxlint and Oxfmt presets | nx run eos:lint, nx run eos:fmt |
mise.toml pins the tool versions. package.json and pnpm-lock.yaml define
the repository's local Nx dependency. The mise-installed Nx launcher uses that
local version. An Nx upgrade updates both declarations together.
Mise package task inference is disabled. The repository has one project task
interface through Nx. The repository no longer installs the ni and nr
aliases.
Commands
These commands assume a complete setup with mise install and an active mise
shell. Mise installs Nx 23.2.1 through its npm backend. The Nx launcher uses
the repository's local Nx version
for task execution.
| Command | Scope |
|---|---|
nx run-many -t build typecheck test test:e2e lint fmt:check | All build, typecheck, E2E, test, lint, and format-check targets |
nx run @eos/docs:build | The docs build and its declared dependencies |
nx affected -t test test:e2e --base=origin/main --head=HEAD | Unit, functional, and E2E tests for changed projects |
nx graph | The project graph |
nx show target inputs @eos/plugin-tests:test | Resolved inputs for the shared plugin tests |
nx reset | Clear local Nx state and cache |
The affected example uses the local origin/main ref. Nx does not fetch it.
Root aliases such as pnpm build, pnpm test, and pnpm check call Nx for
compatibility. They use the same task graph and cache as direct Nx commands.
Direct workspace commands such as pnpm --filter @tillo/scout test execute the
package script without the Nx dependency graph or task cache. Scout package test
scripts require an existing build. The standard project task commands use Nx.
Repository maintenance commands remain pnpm scripts. Examples include
pnpm registry:login and pnpm changeset. The
finalise-change guide uses nx affected with
the complete verification target set. Direct CLI commands use pnpm when the CLI
belongs to a workspace dependency, such as pnpm exec wrangler from the Figma
MCP directory.
Ultracite uses one root configuration for the monorepo. The
eos project maps the root check and
fix scripts to Nx targets. Packages do not define duplicate lint or format
scripts. The configuration follows the
Oxlint migration guide. The
pre-commit hook applies Ultracite fixes to supported staged files. Lefthook then
runs the affected Nx checks. See the
Git hook guide.
Task configuration
nx.json defines shared inputs and task defaults. Each project.json defines
workspace exceptions. Package scripts remain the executable commands.
The root excludes its package scripts from Nx task inference to prevent
recursive task execution. Explicit targets on the eos project provide the root
lint and format tasks.
| Project | Target | Check |
|---|---|---|
eos-apm | apm:audit | Current tracked and untracked local APM files |
eos-documentation | docs:check | Depends on Markdown format, lint, and offline links |
eos-documentation | docs:format:check, docs:lint, docs:links | Individual documentation checks |
eos-scripts | test:scripts | Repository script and Nx configuration tests |
eos-release | changeset:status | Changesets release metadata |
eos | lint, lint:all, fmt:check, fmt | Ultracite source check and fix for the monorepo |
@eos/plugin-tests | docs:skills:check | Generated marketplace skills reference |
The marketplace reference, repository lint, repository format, Markdown lint,
and Markdown format checks use the cache. The other repository checks do not.
The Changesets target runs changeset status when metadata files exist.
Otherwise, it reports that no files need validation. The changesets skill still
assesses release impact. The status command depends on Git state and the local
main ref. APM audits use the mise-installed APM version and skip deleted
files. Nx calls the check tools directly. Lefthook passes staged or pushed
filenames to Nx through --stdin. Nx owns task selection and parallel
execution. The tools read their existing exclusions and include untracked source
files.
Nx selects projects, then their requested targets. Target inputs determine cache validity and can mark a project affected by shared files. They do not select individual targets within an affected project. Documentation-only and test-only changes can select all requested workspace targets. The former finalise-change command applied narrower rules.
The eos:lint target uses NX_BASE and NX_HEAD when CI supplies them. The
Git hook supplies its staged paths through the Nx process. The target passes
these paths to Ultracite. It checks the full repository when no path scope is
available or when a shared Ultracite input changes. The affected target does not
use the cache because its path scope can change. Use eos:lint:all for an
explicit cached full check.
Build, test, typecheck, full lint, and format-check targets use the local cache. Build, test, typecheck, and mutation targets require dependency builds. Incremental mutation targets use the local cache. Full mutation targets do not use the cache. Nx runs one mutation target at a time on each machine. Format commands change files and do not use the cache.
Development and preview targets are continuous and uncached. The docs build also remains uncached because it reads external documentation sources.
Inputs and outputs
Shared inputs include package and tool configuration, the pnpm lockfile, the Node.js version, and root Ultracite configuration. Workspace inputs also include declared dependency inputs. Mutation inputs include project files, dependency production files, and the shared baseline helper.
The shared plugin tests include child plugin files and documentation. Each child plugin has an explicit dependency relationship with the test workspace. Harbourmaster tests include the root workflows and shared scripts that they read.
Build targets restore their declared output directories. Scout tests also
restore dist, because their package script builds the CLI. Figma MCP tests
restore coverage output. Incremental mutation targets restore the Stryker state
and mutation reports from the local Nx cache.
CI cache
CI installs Node.js and pnpm through the setup action. It uses pnpm exec nx to
select the repository's local Nx binary. This prefix does not add another task
runner. Local shells use the Nx launcher that mise installs.
Build, typecheck, lint, test, and mutation jobs use nx affected. Each job
fetches the full Git history. nrwl/nx-set-shas@v5 selects the base and head
from GitHub workflow history. The action fails if it cannot find a successful
base workflow. Its GitHub API access does not require Nx Cloud. Repository
script tests run on every CI execution.
The mutation job restores trusted Stryker reports before Nx starts the affected
targets. Pull requests can read the main reports. Only successful main and
scheduled jobs publish new reports. The scheduled workflow uses nx run-many to
refresh all full mutation targets.
Each CI job uses its own local Nx cache. Jobs do not share Nx artifacts across machines or workflow runs. The pnpm dependency cache and Stryker baseline artifacts remain separate.
The setup action does not start a Turbo cache server or require cache secrets. Fork pull requests use the same local cache behaviour as other jobs.
Remote cache configuration remains separate work. The former R2 resources and secrets remain available for rollback but current workflows do not use them. Nx Cloud is disabled in this configuration. Nx analytics is also disabled.
Migration reference
The Nx migration guide describes the configuration conversion. Nx deprecated its former S3 cache package. See the self-hosted cache notice.