Rune
Define a command once. Reference it everywhere.

A script runner for JavaScript and TypeScript monorepos, written in Rust. Commands live in one typed config at the repository root, and every package calls them by name.

install
pnpm add -D @giancarlosio/rune

One definition, every package

The command lives in one file at the repository root. Each package references it by name, and that reference never changes again.

rune.config.ts
import { defineConfig } from '@giancarlosio/rune'

export default defineConfig({
  scripts: {
    test: {
      command: 'vitest run --coverage --reporter=dot',
      description: 'Run unit tests',
    },
  },
})
packages/*/package.json
{
  "scripts": {
    "test": "rune run test"
  }
}

// changing a flag is one edit at the root,
// not one edit per package

One config, typed

Commands are declared in rune.config.ts with variables, template strings and imports. Editor autocomplete comes from the published types.

Inheritance

A package extends a root script and appends its own flags. It cannot replace the command, so a shared script stays shared.

npm parity

Every script runs through the platform shell with node_modules/.bin on PATH, inherits the terminal, and exits with the child exit code.

Groups

Run scripts one after another or side by side, with prefixed output, kill-on-failure and a success policy.

Warm runs under 5 ms

The resolved config is cached by the content of its whole import graph. A cache hit reads one JSON file.

Six platform binaries

Windows, macOS and Linux on x64 and arm64, installed as optional dependencies with no postinstall step.