Core Concepts

CLI

Use the RS-X CLI to diagnose environments, create projects, wire framework bootstrap, install tooling, and run rs-x-aware build/typecheck workflows.

What it means

The RS-X CLI is the main way to set up and operate RS-X in an application. Instead of manually wiring bootstrap files, transforms, and scripts, you run clear commands (`init`, `project`, `build`, `typecheck`) that apply the same integration steps every time.

Practical value

Using the CLI simplifies setup and speeds up initial development and keeps configuration consistent. Teams get the same project structure, bootstrap wiring, build flags, and diagnostics flow across Angular, Vue, React, Next.js, and Node.js projects.

Key points

1) Install the CLI

Install `@rs-x/cli` globally so the `rsx` command is available on PATH in your terminal.

# Global (required)
# npm
npm install -g @rs-x/cli

# pnpm
pnpm add -g @rs-x/cli

# yarn
yarn global add @rs-x/cli

# bun
bun add -g @rs-x/cli

# Prerelease (next) - global
npm install -g @rs-x/cli@next
pnpm add -g @rs-x/cli@next
yarn global add @rs-x/cli@next
bun add -g @rs-x/cli@next

2) Initialize an existing app

`rsx init` auto-detects framework context and applies the matching integration flow.

That includes package installation, bootstrap wiring, writing `rsx.config.json`, and adding `build:rsx` / `typecheck:rsx` scripts where the framework integration needs them.

`rsx init` and `rsx project` both create an `rsx.config.json` file with default build and CLI settings that you can override later.

Use `--verify` with `rsx init` when you want an explicit post-mutation sanity check of the resulting files and scripts.

`rsx project` goes further: it creates a new app and verifies the generated starter structure before reporting success. `--verify` can be passed when you want that verification step to be explicit in the command you run.

3) What the CLI installs

Installing `@rs-x/cli` adds the `rsx` command. During package postinstall, the CLI also attempts to install the bundled rs-x VS Code extension automatically when `code` is available on PATH.

`rsx init` installs runtime packages (`@rs-x/core`, `@rs-x/state-manager`, `@rs-x/expression-parser`) and compiler tooling (`@rs-x/compiler`, `@rs-x/typescript-plugin`), then applies framework-specific integration for Angular, React, Next.js, and Vue when detected.

Framework integration installs framework-specific packages when needed (for example `@rs-x/angular` for Angular, `@rs-x/react` for React/Next.js, and `@rs-x/vue` for Vue).

`rsx init` and `rsx project` do not automatically install the VS Code extension. Use `rsx install vscode` when you want to apply the bundled VSIX manually.

Add `--next` to install prerelease versions (dist-tag `next`) when testing upcoming releases.

4) Create new template projects

`rsx project` supports `angular`, `vuejs`, `react`, `nextjs`, and `nodejs` templates.

You can choose by full name, short alias, `--template`, or interactive prompt.

Template-specific extras are included (for example Angular installs `@rs-x/angular`, React/Next install `@rs-x/react`, Vue installs `@rs-x/vue`).

5) VS Code extension features and fallback

The rs-x VS Code extension enables RS-X expression IntelliSense and diagnostics in TypeScript/JavaScript files. It also wires the `@rs-x/typescript-plugin` so expression errors show inside the editor.

If automatic VSIX installation fails, verify the `code` CLI command is available, rerun `rsx install vscode --force`, or install the VSIX manually with `code --install-extension`.

`rsx doctor` is also a good first step when linked/local package setups behave strangely, because it now warns when multiple installed `@rs-x/*` versions are detected inside the current project.

6) Build and validate with rs-x tooling

`rsx build` runs the RS-X transform-aware compilation pipeline.

Use `--prod` with the `build` section in `rsx.config.json` for generated AOT artifacts (preparse/compiled/registration).

Compiled generation is controlled per expression by `rsx(expression, { compiled: true | false })` (default `true`).

`rsx typecheck` adds RS-X semantic validation on top of TypeScript checks for safer CI gates.

7) Add expressions interactively

`rsx add` walks you through creating or updating expression files without hand-writing the initial boilerplate.

The first prompt is now an explicit mode choice: create a new one-file expression, create a new expression with a separate model, or update an existing expression file.

The default flow keeps the model and expression in the same file, which is usually the simplest starting point.

It also asks for the initial expression string up front, defaulting to `'a'`, so the generated file is closer to what you actually want to evaluate.

When the expression contains simple top-level identifiers such as `price * quantity`, the generated model is seeded with those keys to reduce follow-up editing.

If you choose to update an existing file, the CLI shows matching RS-X expression files from the selected directory first, then falls back to the wider project only when needed.

That wider-project fallback prefers likely source roots such as `src/`, `app/`, and `expressions/` before showing less relevant matches elsewhere in the repository.

You can configure those defaults in `rsx.config.json` under `cli.add`.

You can still opt into a separate model file or reuse an existing model file when that better matches the structure of your app.

8) Build configuration

You can configure the build pipeline in `rsx.config.json` under `build`.

Starter flows now generate `rsx.config.json` so CLI-specific settings and build settings live in one place.

{
  "rsx": {
    "build": {
      "preparse": true,
      "preparseFile": "src/rsx-generated/rsx-aot-preparsed.generated.ts",
      "compiled": true,
      "compiledFile": "src/rsx-generated/rsx-aot-compiled.generated.ts",
      "registrationFile": "src/rsx-generated/rsx-aot-registration.generated.ts",
      "compiledResolvedEvaluator": false
    }
  }
}
OptionWhat it does
preparseEnables generation of the preparsed AST cache during rsx build --prod.
preparseFilePath for the generated preparsed AST cache module.
compiledEnables generation of the compiled-expression plan cache.
compiledFilePath for the generated compiled-plan cache module.
registrationFilePath for the generated registration module that loads the AOT outputs into the runtime cache.
compiledResolvedEvaluatorControls whether the compiled AOT output also embeds the resolved-dependency evaluator function. When false, runtime still uses compiled plans, but more dependency resolution stays in the shared runtime path. When true, more of that work is pushed into the generated compiled evaluator.
Tradeoff:
  • true: less runtime indirection and potentially faster compiled evaluation paths, but larger generated output and a more aggressive AOT build.
  • false: smaller generated output and simpler build artifacts, but more of the dependency-resolution work stays in shared runtime code.

9) Lazy group code splitting

Passing `lazyGroup` to an `rsx()` call assigns that expression to a named code-split group. All expressions sharing the same group name are bundled into a single `.mjs` payload file that the browser only downloads when an expression from that group is first used.

Setting `lazyGroup` implicitly enables `lazy: true`. You do not need to set both.

import { rsx } from '@rs-x/expression-parser';

// All Page1 expressions are bundled into one payload file.
// That file is only downloaded when any Page1 expression is first used.
// Setting lazyGroup implicitly sets lazy: true — no need to add it separately.
rsx<number>('price * quantity', { lazyGroup: 'Page1' })(model);
rsx<string>('user.firstName + " " + user.lastName', { lazyGroup: 'Page1' })(model);

// A separate group file for Page2 expressions.
rsx<boolean>('total > budget', { lazyGroup: 'Page2' })(model);

// Ungrouped lazy expression — lands in the shared lazy payload file.
rsx<number>('a + b', { lazy: true })(model);

During `rsx build --prod`, the CLI emits one `.mjs` file per group into `public/rsx-generated/`, plus a shared payload for ungrouped lazy expressions and a manifest file that registers all group loaders at app startup:

# rsx build --prod emits one .mjs file per lazyGroup into public/rsx-generated/
# plus the shared ungrouped payload and the manifest:

public/rsx-generated/
  rsx-aot-lazy-group-Page1.generated.mjs   # Page1 group payload
  rsx-aot-lazy-group-Page2.generated.mjs   # Page2 group payload
  rsx-aot-lazy.generated.mjs               # ungrouped lazy expressions

src/rsx-generated/
  rsx-aot-lazy-manifest.generated.ts       # registers all group loaders at startup
  rsx-aot-preparsed.generated.ts
  rsx-aot-compiled.generated.ts
  rsx-aot-registration.generated.ts        # imported in main.ts; loads all of the above
FileWhat it contains
rsx-aot-lazy-group-{GroupName}.generated.mjsAll preparsed ASTs and compiled evaluators for that group. One file per unique lazyGroup value. Served as a static asset from public/.
rsx-aot-lazy.generated.mjsAll expressions marked { lazy: true } without a lazyGroup. Downloaded when any ungrouped lazy expression is first used.
rsx-aot-lazy-manifest.generated.tsRegisters a dynamic-import loader for every group and for the shared lazy payload. Imported by the registration file so all loaders are ready before the first expression is evaluated.

Group names are sanitized for the file system: non-alphanumeric characters are replaced with `-`. Expressions from different source files can share the same group name — they will all land in the same payload file.

The payload files are plain JavaScript (`.mjs`) with no bare npm specifiers. Registration functions are injected by the manifest at runtime, so the files can be fetched and executed directly by the browser without a bundler or import map.

When an expression from a group is first evaluated, the runtime calls `startLazyGroupPreload`, which fires the dynamic import for that group's `.mjs` file and resolves the preparsed ASTs and compiled plans into the expression cache. Subsequent evaluations in the same group reuse the in-flight or already-resolved result.

The recommended pattern for Angular is to place `lazyGroup` expressions inside lazy-loaded route components. The group payload is only fetched when the route is first activated:

// In Angular: lazyGroup expressions are typically placed inside
// lazy-loaded route components. The group payload is downloaded
// when the component is first rendered — not at app startup.

// page1.component.ts
import { rsx } from '@rs-x/expression-parser';

const page1Price = rsx<number>('price * qty', { lazyGroup: 'Page1' });

@Component({ ... })
export class Page1Component {
  result$ = page1Price(this.model);
}

// page2.component.ts
const page2Check = rsx<boolean>('total > budget', { lazyGroup: 'Page2' });

@Component({ ... })
export class Page2Component {
  result$ = page2Check(this.model);
}

10) Full command reference

Use `rsx help` or `rsx help <command>` to print command-specific usage at any time.

The command matrix below is the complete current surface of the CLI.

11) CLI configuration (rsx.config.json)

The CLI reads `rsx.config.json` from the project root for build and interactive workflow defaults.

Both the `build` section (tsconfig path, AOT output paths, preparse/compiled flags) and the `cli` section (package manager, install tag, add defaults) live in the same file.

`rsx init` and `rsx project` generate a starter `rsx.config.json` automatically.

The CLI validates the file at runtime. The VS Code extension contributes a JSON schema for editor validation and completions.

See the rsx.config.json reference for a description of every field, its type, default, and when to use it.
{
  "build": {
    "tsconfig": "tsconfig.app.json",
    "outDir": "dist",
    "preparse": true,
    "preparseFile": "src/rsx-generated/rsx-aot-preparsed.generated.ts",
    "compiled": true,
    "compiledFile": "src/rsx-generated/rsx-aot-compiled.generated.ts",
    "registrationFile": "src/rsx-generated/rsx-aot-registration.generated.ts",
    "compiledResolvedEvaluator": false
  },
  "cli": {
    "packageManager": "pnpm",
    "installTag": "next",
    "init": {
      "verify": true
    },
    "project": {
      "verify": true
    },
    "add": {
      "defaultDirectory": "src/expressions",

12) Help and version

Use `rsx help` to print the main command list, or `rsx help <command>` to print command-specific usage and flags.

Use `rsx version`, `rsx v`, `rsx -v`, or `rsx --version` to print the current CLI version.

This is the quickest way to confirm which command surface is available in the installed CLI before following docs or examples.

rsx help [command]
rsx version
rsx v
rsx -v
rsx --version

13) doctor

`rsx doctor` runs environment checks before you mutate a project.

It validates Node.js >= 20, the VS Code CLI (`code`), and the presence of a supported package manager (`pnpm`, `npm`, `yarn`, or `bun`).

Use it first when installs, editor integration, or local linking behave unexpectedly.

rsx doctor

14) add

`rsx add` is the interactive scaffolder for expression files. It also supports the aliases `rsx -a` and `rsx -add`.

The flow prompts for the export name, the initial expression string, whether to use kebab-case, the output directory, and whether you want a one-file expression, a separate model file, or an update to an existing file.

It respects `rsx.config.json` under `cli.add` for defaults such as the preferred directory and search roots.

rsx add
rsx -a
rsx -add

15) install vscode

Use `rsx install vscode` to install the bundled RS-X VS Code extension manually.

`--force` reinstalls the extension even if it is already present.

`--local` builds or installs the VSIX from the local repository workspace instead of using the normal packaged path. This is mainly useful while developing RS-X locally.

`--dry-run` prints the install actions without executing them.

rsx install vscode [--force] [--local] [--dry-run]

16) install compiler

Use `rsx install compiler` when you only want to install the RS-X compiler tooling into the current project.

`--pm` forces the package manager instead of letting the CLI infer it from the project.

`--next` installs prerelease builds from the `next` dist-tag.

`--dry-run` prints the package install plan without mutating the project.

rsx install compiler [--pm <pnpm|npm|yarn|bun>] [--next] [--dry-run]

17) init

`rsx init` is the main command for integrating RS-X into an existing app.

It auto-detects the framework context, installs runtime and compiler packages, wires bootstrap, writes `rsx.config.json`, and applies framework-specific integration for Angular, React, Next.js, and Vue when detected.

`--pm` forces the package manager. `--entry` forces the application entry file when automatic detection is wrong or ambiguous.

`--next` installs prerelease package versions. `--skip-install` skips package installation when you only want to apply file mutations. `--skip-vscode` is accepted for compatibility but does not change current behavior because VS Code is not auto-installed.

`--verify` runs a post-mutation sanity check. `--dry-run` prints the plan without writing files. `--force` and `--local` are accepted compatibility flags alongside the shared CLI option surface.

rsx init [--pm <pnpm|npm|yarn|bun>] [--entry <path>] [--next] [--skip-install] [--skip-vscode] [--verify] [--force] [--local] [--dry-run]

18) project

`rsx project` scaffolds a brand-new starter project instead of mutating an existing one.

It supports `angular`, `vuejs`, `react`, `nextjs`, and `nodejs`, plus their short aliases shown in the examples on this page.

`--name` sets the target folder and package name. `--template` selects the template explicitly when you do not want to rely on the positional framework name or interactive prompt.

`--pm`, `--next`, `--skip-install`, and `--skip-vscode` behave the same way they do in the rest of the CLI.

`--tarballs-dir` points the scaffold at a directory of local `*.tgz` RS-X packages, which is useful while testing unpublished builds. `--verify` re-runs starter checks explicitly after generation. `--dry-run` prints the actions without creating files.

rsx project [angular|vuejs|react|nextjs|nodejs] [--name <project-name>] [--pm <pnpm|npm|yarn|bun>] [--next] [--template <angular|vuejs|react|nextjs|nodejs>] [--tarballs-dir <path>] [--skip-install] [--skip-vscode] [--verify] [--dry-run]

19) build

`rsx build` runs the RS-X-aware compilation pipeline for a TypeScript project.

`--project` selects the tsconfig file. `--out-dir` overrides the output directory for the build.

`--prod` enables the production profile and the configured AOT outputs. `--no-emit` performs the analysis without writing JavaScript output.

`--aot-preparse` and `--aot-preparse-file` control generation of the preparse cache module. `--aot-compiled` and `--aot-compiled-file` control generation of the compiled-expression cache module.

`--compiled-resolved-evaluator` controls whether the compiled AOT output also embeds the resolved-dependency evaluator function. `--dry-run` prints the build plan without emitting files.

When `preparse` is enabled and any expression uses `lazyGroup`, `rsx build --prod` also emits one `.mjs` payload file per group and an updated lazy manifest. No extra flags are needed — lazy group files are generated automatically.

rsx build [--project <path-to-tsconfig>] [--out-dir <path>] [--prod] [--no-emit] [--aot-preparse <true|false>] [--aot-preparse-file <path>] [--aot-compiled <true|false>] [--aot-compiled-file <path>] [--compiled-resolved-evaluator <true|false>] [--dry-run]

20) typecheck

`rsx typecheck` validates both TypeScript correctness and RS-X expression semantics without emitting build output.

`--project` selects the tsconfig file to analyze.

`--dry-run` prints the typecheck plan without executing the full run.

Use this command in CI when you want semantic RS-X failures to block merges even if you are not producing JavaScript output in the same step.

rsx typecheck [--project <path-to-tsconfig>] [--dry-run]

Init vs Project example

Choose the right command depending on whether you are wiring an existing app or scaffolding a new starter.
# init: auto-detect the framework and apply integration in the current app
rsx init

# project: scaffold a full RS-X starter
rsx project react --name my-rsx-react-app

Command Reference example

Complete command surface including framework variants and build/typecheck flags.
rsx help [command]
rsx doctor
rsx add [-a]
rsx install vscode [--force] [--local] [--dry-run]
rsx install compiler [--pm <pnpm|npm|yarn|bun>] [--next] [--dry-run]
rsx init [--pm <pnpm|npm|yarn|bun>] [--entry <path>] [--next] [--skip-install] [--skip-vscode] [--verify] [--force] [--local] [--dry-run]
rsx project <angular|a|vuejs|v|react|r|nextjs|nx|nodejs|js> [--name <n>] [--template <...>] [--pm <pnpm|npm|yarn|bun>] [--next] [--skip-install] [--skip-vscode] [--verify] [--dry-run]
rsx build [--project <tsconfig>] [--out-dir <path>] [--prod] [--no-emit] [--aot-preparse <true|false>] [--aot-preparse-file <path>] [--aot-compiled <true|false>] [--aot-compiled-file <path>] [--compiled-resolved-evaluator <true|false>] [--dry-run]
rsx typecheck [--project <tsconfig>] [--dry-run]
rsx version | v | -v | --version

Install CLI example

Install the CLI globally so `rsx` commands are available on PATH.
# Global (required)
# npm
npm install -g @rs-x/cli

# pnpm
pnpm add -g @rs-x/cli

# yarn
yarn global add @rs-x/cli

# bun
bun add -g @rs-x/cli

# Prerelease (next) - global
npm install -g @rs-x/cli@next
pnpm add -g @rs-x/cli@next
yarn global add @rs-x/cli@next
bun add -g @rs-x/cli@next

Bootstrap Existing Project example

Use `init` when you already have an app and want rs-x packages, bootstrap wiring, and framework integration.
# Auto-detect framework and wire bootstrap
rsx init

# Or force a specific entry file
rsx init --entry src/main.ts

Create Template Project example

Generate a new RS-X-ready app directly from CLI templates (full names or short aliases).
# Full template names
rsx project angular --name my-rsx-angular-app
rsx project vuejs --name my-rsx-vue-app
rsx project react --name my-rsx-react-app
rsx project nextjs --name my-rsx-next-app
rsx project nodejs --name my-rsx-node-app

# Short aliases
rsx project a --name my-rsx-angular-app
rsx project v --name my-rsx-vue-app
rsx project r --name my-rsx-react-app
rsx project nx --name my-rsx-next-app
rsx project js --name my-rsx-node-app

Framework Integration example

Apply framework-specific integration in an existing app repository.
# Auto-detect framework and apply integration
rsx init --verify

Install VS Code Extension example

Install or reinstall the RS-X VS Code extension from marketplace or local VSIX.
# Marketplace install
rsx install vscode

# Reinstall
rsx install vscode --force

# Build/install local VSIX from repository workspace
rsx install vscode --local --force

VSIX Failure Recovery example

If postinstall or install command cannot apply the VSIX, use this fallback flow.
# 1) Check VS Code CLI is available
code --version

# 2) Retry install through rsx
rsx install vscode --force

# 3) If needed, install VSIX manually
code --install-extension "/absolute/path/to/rs-x-vscode-extension-<version>.vsix"

# 4) Optional: disable postinstall auto-install in CI or restricted environments
RSX_SKIP_VSCODE_EXTENSION_INSTALL=true

Install Compiler Tooling example

Install RS-X compiler packages into your current project.
rsx install compiler
rsx install compiler --next
rsx install compiler --pm pnpm

Doctor and Add example

Run diagnostics and use the improved add flow, which defaults to one-file expressions and can update existing RS-X files.
# Environment diagnostics
rsx doctor

# Interactive expression creator
rsx add

Lazy Group — Expression Usage example

Assign expressions to named groups with lazyGroup. Setting lazyGroup implicitly enables lazy: true.
import { rsx } from '@rs-x/expression-parser';

// All Page1 expressions are bundled into one payload file.
// That file is only downloaded when any Page1 expression is first used.
// Setting lazyGroup implicitly sets lazy: true — no need to add it separately.
rsx<number>('price * quantity', { lazyGroup: 'Page1' })(model);
rsx<string>('user.firstName + " " + user.lastName', { lazyGroup: 'Page1' })(model);

// A separate group file for Page2 expressions.
rsx<boolean>('total > budget', { lazyGroup: 'Page2' })(model);

// Ungrouped lazy expression — lands in the shared lazy payload file.
rsx<number>('a + b', { lazy: true })(model);

Lazy Group — Build Output example

rsx build --prod emits one .mjs payload per group into public/rsx-generated/. Each file is downloaded on demand the first time an expression from that group is evaluated.
# rsx build --prod emits one .mjs file per lazyGroup into public/rsx-generated/
# plus the shared ungrouped payload and the manifest:

public/rsx-generated/
  rsx-aot-lazy-group-Page1.generated.mjs   # Page1 group payload
  rsx-aot-lazy-group-Page2.generated.mjs   # Page2 group payload
  rsx-aot-lazy.generated.mjs               # ungrouped lazy expressions

src/rsx-generated/
  rsx-aot-lazy-manifest.generated.ts       # registers all group loaders at startup
  rsx-aot-preparsed.generated.ts
  rsx-aot-compiled.generated.ts
  rsx-aot-registration.generated.ts        # imported in main.ts; loads all of the above

Lazy Group — Angular Route Components example

Place lazyGroup expressions inside lazy-loaded Angular route components so each group payload is fetched only when that route activates.
// In Angular: lazyGroup expressions are typically placed inside
// lazy-loaded route components. The group payload is downloaded
// when the component is first rendered — not at app startup.

// page1.component.ts
import { rsx } from '@rs-x/expression-parser';

const page1Price = rsx<number>('price * qty', { lazyGroup: 'Page1' });

@Component({ ... })
export class Page1Component {
  result$ = page1Price(this.model);
}

// page2.component.ts
const page2Check = rsx<boolean>('total > budget', { lazyGroup: 'Page2' });

@Component({ ... })
export class Page2Component {
  result$ = page2Check(this.model);
}

Build and Typecheck example

Run rs-x build and semantic checks locally or in CI.
# Build with RS-X transform
rsx build --project tsconfig.json

# Production profile (AOT preparse/compiled outputs when configured)
rsx build --project tsconfig.json --prod

# TypeScript + RS-X semantic checks
rsx typecheck --project tsconfig.json

Help and Version example

Inspect command help and print the current CLI version.
rsx help
rsx help build
rsx help project
rsx v
rsx version
rsx --version