The config file

Rune reads one file: rune.config.ts. It is TypeScript, it default-exports an object with a scripts map, and it may import other files in the repository.

rune.config.ts
import { defineConfig } from '@gio-labs/rune';

export default defineConfig({
  scripts: {
    build: { command: 'tsc --build' },
    test: { command: 'vitest run', description: 'Run unit tests' },
  },
});

defineConfig is an identity function that supplies the types. A config that exports the object literal directly behaves identically and loses editor autocomplete.

Discovery

Rune walks up from the working directory looking for rune.config.ts, and stops at the first directory containing a .git entry or at the filesystem root.

The boundary matters. Without it, a run from a scratch directory keeps walking and picks up an unrelated config from somewhere else on the machine, and the result depends on whose machine it is.

The walk records every rune.config.ts it passes, not only the first. Two of them matter: the root config, the last one found before the boundary, and the package config, the nearest one at or above the working directory when that is not the root config itself.

Two directories come out of the same walk:

NameDefinition
Config rootThe directory holding the root config
Package directoryThe nearest ancestor of the working directory containing a package.json, or the working directory

When no config is found, the message says which of the two ends the walk reached, because they need opposite answers.

$ rune list
no rune.config.ts found

searched upward from /repo/packages/ui and stopped at /repo, the top of this repository.

create one at the top of this repository with:

  rune init

Reaching the filesystem root instead means there is no repository above you at all, and the message says to change into your project first. And because the walk only goes up, a config in a subfolder would be invisible: when there is one, the message names it rather than telling you to create a second.

The default export

The export is an object with one key.

KeyTypeRequired
scriptsRecord<string, Script>Yes

Script names are arbitrary strings. rune list prints them sorted, so the order in the file has no effect on output.

A missing default export, or one that is not an object, is an error naming the file.

Package-level configs

A package may hold its own rune.config.ts. Rune uses the nearest one, and a script defined there may extend a root script but never replace it. See Inheritance and narrowing.

Sections