Skip to main content
Run these commands from the Isox repository after development setup. For your own plugin package, use plugin packaging.

Building and running packages

Packages have Isox project.json files with build, lint, and test commands. Run pnpm bootstrap once to bootstrap the local CLI, then use Isox itself:
The syntax is isox <command> <project>: build is the target, and cli is the project. Any command defined in that project’s targets object can be used. isox run cli:build also works. init, add, run, reset, affected, plan, and run-many are reserved CLI commands; use isox run <project>:<command> for project commands with those names. Package builds use @isox-sh/js:tsc, written as js:tsc in our project files. Compiler settings stay in each package’s tsconfig.build.json; there are no scripts.build entries. Lint commands use eslint:lint; test commands use vitest:test. The root tsconfig.json covers all package sources with noEmit: true. Editors use this workspace config without a package-level rootDir boundary. Internal package imports use the root tsconfig.base.json paths, which point to the original sources in packages/*/src. Package build configs keep rootDir: "./src" so emitted files stay directly under dist/<package>. The js:tsc executor creates a temporary build config that maps dependencies to their compiled declarations. Build prerequisites first; editor navigation and workspace discovery use the source aliases without needing a build. Root development dependencies keep the local plugins available to Node and the CLI; TypeScript paths do not rewrite emitted imports. Most internal dependencies are inferred from source imports during package generation. Explicit dependencies remain where code resolves a package by name, such as the E2E helper’s CLI dependency. On-demand dependency analysis infers project edges, so package project definitions do not duplicate these imports. For individual build commands, build prerequisites first: core before JS and the other packages. Multi-project stages with cached outputs order their selected projects by dependency. This repository’s build targets do not declare dependsOn, so their unselected prerequisites still need to be built explicitly. See execution ordering. pnpm bootstrap seeds core and the JS executor with TypeScript, then runs the package build commands through Isox. It also refreshes project discovery. After editing project definitions, run isox reset before single-project commands. Dependency requests from affected selection or the TypeScript builder validate .isox/discovery.json and reuse valid entries. Its source fingerprint uses file metadata, so editing a source or test file can reanalyze that project’s included sources on the next request. Commands that need neither dependencies nor task caching leave this analysis cache alone. Reusing analysis does not itself skip compilation; a task-result cache hit can. See cache behavior.

Build outputs

All repository packages build into <repository>/dist/<package>, including dist/core, dist/js, dist/eslint, dist/vitest, dist/nx, dist/e2e, dist/semver, and dist/cli. These directories contain runnable package artifacts: JavaScript, declarations, rewritten package manifests, executor manifests, and schemas. Source files and tests stay under packages/<package>. Each package’s tsconfig.build.json declares the root output path. Its Isox build enables generatePackageJson, and executor schemas are copied using assets. Generated manifests use paths within the output package and resolve workspace dependency versions. publishConfig.directory selects this output for packaging; pnpm’s linkDirectory makes local workspace imports resolve to it after installation. Run pnpm install after changing these settings, then pnpm bootstrap before running the CLI or tests. Publish or globally install the built package directory when using npm directly. See trying the local CLI for the global installation commands. Bootstrap seeds the metadata and schemas needed to compile core and JS, prepares shared dependency links under dist/node_modules, then rebuilds every package through Isox. The TypeScript executor tracks ownership of bootstrap metadata so it can safely replace it during the build. Bootstrap refreshes outdated dependency links and the workspace discovery cache while retaining output ownership, so subsequent builds can remove outputs from deleted source files. Build directories are ignored by Git.

Plugin source layout

Keep executors in src/executors/<name>/<name>.executor.ts and their options schemas beside them as <name>.schema.json. Put project initializers in src/generators and reusable helpers in src/helpers. Tests belong to the package’s tests directory. In packages/<plugin>/executors.json, reference the compiled implementation and copied schema under ../../dist/<plugin>/executors/<name>/. Add executor schemas to the build’s assets option and enable generatePackageJson. Package generation copies the manifest and rewrites its paths relative to the output package. Publish dist/<plugin> using publishConfig.directory, as described in build outputs. See plugin layout and packaging for an alternative layout with a package-local dist directory.

Trying the local CLI

After installing dependencies with pnpm install, run these commands from the Isox repository root to build your checkout and install its CLI globally:
To test the published package layout instead of a development link, pack both packages and install the resulting archives together into an isolated prefix:
The package-local integration test automates local and global installation, checks the installed binary, and runs a core command outside this checkout:
It needs npm registry access for external dependencies. Both packages are tested from their actual tarballs; nothing is published and the user’s global install is untouched. The foundation matrix enables this check when that job is re-enabled. The global isox command links to this checkout’s built CLI. --install-links=false keeps the local package linked. After changing source code, rerun node ./scripts/bootstrap.cjs from the repository root to update the build used by the global command. Executor plugins still resolve from the workspace where you run Isox. A workspace-installed core also takes precedence over the CLI’s copy, so testing a local CLI alone does not replace that workspace’s plugins. Use it from a workspace containing isox.json, project.json files, and installed executor plugins:
You can also invoke the built CLI directly:
Back to contributing.