Presets are just functions
Share task setups across projects with a TypeScript function, no new concept.

Twenty libraries with the same build should not mean twenty copies of it. Write a function that returns the tasks and call it in each config.
It is plain TypeScript: parameters, imports and types all work, and the key sees the evaluated result.
// config
// packages/ui/vx.config.ts
import { defineProject } from '@vzn/vx/config'
const lib = (entry: string) => ({
build: {
exec: { command: `tsup ${entry}` },
cache: { inputs: { files: ['src/**'] }, outputs: { files: ['dist/**'] } },
},
})
export default defineProject({ tasks: { ...lib('src/index.ts') } })More in Config

One command per task
A task is a shell command with edges and a cache block; nothing boots in between.

Rules that catch slow configs
Checks for configs that would make runs slow or wrong, on by default, each one optional.

A config that hangs, named
A config whose evaluation runs away fails after a deadline, naming the file.

No runs inside runs
A vx run inside a task of the same workspace is refused, with the reason.

Config with autocomplete
defineProject gives you completion and errors while you type.

Config errors that point
A bad config fails at load with the file, the line and the key, no stack trace.