Reference
Everything noodge.yaml understands, and everything the CLI does.
If you are here to get it running, the install section is
shorter.
Getting started
Install noodge, then run noodge init in a project. That writes a starter
noodge.yaml with two working commands so you can check everything before you
write anything of your own.
$ noodge init created ~/dev/my-project/noodge.yaml run 'noodge' to see what it declares
The two fields that matter most are description and output. They are
the point of the whole thing — what the browser shows you when you are trying to remember
which command to run. Write them for whoever joins next month.
Discovery
noodge walks up from your working directory to the nearest noodge.yaml, the same
way git finds .git, and stops at a repository boundary. Commands run in the
directory holding the config, not wherever you happened to be standing, so
noodge build means the same thing from any subdirectory.
Configuration is discovered, not configured. There is no global config file and nothing to register. Two flags override the search when you need them to:
-C, --directory <dir>— start looking in this directory instead of the current one.--file <path>— load this exact config file and skip discovery entirely.
The NOODGE_CONFIG environment variable does the same job as --file.
The noodge.yaml
One file at the root of your project. The modeline on the first line points your editor at the JSON Schema, which gives you completion and inline errors as you type.
# yaml-language-server: $schema=https://wimhaanstra.github.io/noodge/schema/v1/noodge.schema.json version: 1 name: my-api commands: start: description: | Starts the API server against the shared development database. Day-to-day command. Hot-reloads on save. Nothing is written to disk, so it is safe to kill at any time. steps: - node myscript.ts output: | Streams the server log to stdout. Listens on http://localhost:3000.
Top-level fields
| Field | What it does |
|---|---|
| version | Schema version. Always 1 today. |
| name | The project name, shown at the top of the browser and of noodge list. |
| shell | The shell used to run steps, when you need one other than the default. |
| env | Environment variables added to every command in the file. |
| groups | Titles and descriptions for the command families. See Groups. |
| commands | The commands themselves, keyed by name. |
Command fields
| Field | What it does |
|---|---|
| description | What this command is for. Shown in the browser, in --help, in noodge list and in tab completion. |
| steps | What it runs. See Steps. |
| output | What it produces — so someone can decide whether to run it without running it. |
| params | Declared parameters. See Parameters. |
| env | Environment variables for this command only. |
| cwd | Run in this directory instead of the one holding the config. |
| aliases | Other names this command answers to. |
| hidden | Keep it out of the browser and the lists. It still runs when named. |
| confirm | Ask before running. See Confirm. |
| shell | Override the shell for this command. |
Parameters
Declare a parameter and noodge builds the flag, documents it in --help, validates
what you pass, and expands it into the step. Every refusal happens before any process starts.
commands: serve: description: Runs the server. params: - name: host flag: --host type: string default: localhost pattern: '^[a-z0-9.-]+$' description: Hostname to bind to. - name: port flag: --port type: int default: 8080 description: Port to listen on. - name: timeout flag: --timeout type: number default: 2.5 description: Request timeout in seconds. - name: verbose flag: --verbose short: -v type: bool description: Log every request. - name: config flag: --config type: path required: true description: Path to the config file. - name: env flag: --env type: enum values: [dev, staging, prod] default: dev description: Which environment to run against. steps: - node server.js {{flag host}} {{flag port}} {{flag config}} {{flag env}}
| Field | What it does |
|---|---|
| name | How you refer to it in a step, as {{name}} or {{flag name}}. |
| flag | How you type it. Must start with two dashes. |
| short | A single-dash alias, such as -c. |
| type | One of the six above. |
| description | The line that appears in --help and in the browser's form. |
| required | Refuse to run without it. |
| default | The value used when you do not pass one. |
| values | The allowed values, for enum. |
| pattern | A regular expression the value must match. |
Parameter values are always quoted. Every value is shell-quoted on the way
out, so noodge deploy --host 'a && shutdown /s' reaches the wrapped tool as one
literal argument. It is data, and it stays data.
Placeholders
A step refers to its parameters with placeholders. {{flag name}} writes the flag
and its value together, and disappears entirely when the parameter is unset — so no empty
flag is ever left behind. {{name}} writes the bare value.
| Placeholder | When the parameter is | Expands to |
|---|---|---|
| {{flag host}} | set, or defaulted | --host localhost |
| {{flag host}} | optional and unset | nothing at all |
| {{flag verbose}} | a bool, and true | --verbose |
| {{flag verbose}} | a bool, and false | nothing at all |
| {{host}} | set | localhost |
| {{args}} | — | whatever you typed after -- |
Anything after -- is appended to the last step, so
noodge test -- -run TestDiscover -v works without editing the file. Use
{{args}} when you need them somewhere other than the end.
A parameter that no step uses, and a placeholder with no matching parameter, are both errors.
noodge validate catches them with a line number.
Steps
Steps run in order, and each one is its own process — which matters on Windows, where
PowerShell 5.1 has no && at all. A step is a string, an array of arguments when
you want no shell parsing at all, or a parallel: group.
steps: - npm run build - ["npm", "pack", "--pack-destination", "./dist"] - parallel: api: noodge api worker: noodge worker web: npm run dev
Everything in a parallel group starts at the same time, and every line of output is labelled with the key that produced it.
api | listening on :3000 worker | polling for jobs web | vite ready in 412 ms
Everything a group starts goes into one process tree, so stopping it also stops what those
processes started. On Windows, which has no process groups, killing npm normally
leaves node holding the port — noodge uses a Job Object with kill-on-close,
so the whole tree goes.
If any member of a group fails, the group fails.
Confirm
Set confirm: true for the default prompt, or give it a string to write your own.
db:reset: description: Drops and recreates the local database. confirm: true steps: - ./scripts/reset-db.sh deploy:prod: description: Deploys to production. confirm: This deploys to PRODUCTION. Continue? steps: - ./scripts/deploy.sh --env prod
$ noodge db:reset Really run "db:reset"? [y/N] n $ echo $? 2
Declining exits 2, so a script that says no fails rather than carrying on quietly. Pass
--yes to answer every prompt with yes, for CI and scripts.
Groups
A command belongs to the family named by the part of its name before the first colon, so
dev:api and dev:worker are both in the dev family.
Families appear in the browser either way, headed by the bare prefix. Declaring one here adds
a readable title and a line of explanation.
groups: - prefix: dev title: Running it description: The stack you work against day to day. - prefix: db title: Database description: The local Postgres the API develops against.
my-api ~/dev/my-api/noodge.yaml Running it │ Database dev │ dev:api │ The local Postgres the API develops against. > Database │ db:reset │ 2 commands in this group. db:stop │
Environment
Set variables for the whole file with a top-level env:, or for one command with
its own. noodge also injects two of its own into every run, so a script can tell how it was
invoked.
| Injected | Value |
|---|---|
| NOODGE_COMMAND | The name of the command being run. |
| NOODGE_PARAM_<NAME> | One per declared parameter, uppercased. |
start:local would run in ~/dev/my-api: 1. node serve.ts --host "localhost" --certificate "dev.pfx" --verbose with environment: NODE_ENV=local NOODGE_COMMAND=start:local NOODGE_PARAM_CERTIFICATE=dev.pfx NOODGE_PARAM_HOST=localhost NOODGE_PARAM_VERBOSE=true
Variables noodge reads
| Variable | What it does |
|---|---|
| NOODGE_CONFIG | Load this config file instead of discovering one. |
| NOODGE_THEME | light or dark, when the terminal's own is detected wrongly. |
| NOODGE_NO_UPDATE_CHECK | Set to 1 to make noodge do no network requests at all. |
| NOODGE_UPDATE_FEED | Point the update check somewhere else. |
| NOODGE_VERSION | Installers only: the version to install. Defaults to the latest release. |
| NOODGE_INSTALL_DIR | Installers only: where to put the binary. |
| NOODGE_NO_PATH | Installers only, Windows: do not touch PATH. |
CLI commands
| Command | What it does |
|---|---|
| noodge | Open the browser, or list when there is no terminal. |
| noodge <command> | Run a command from noodge.yaml. |
| noodge run <command> | The same, for when the name collides with one below. |
| noodge list [--json] | List commands, optionally machine-readable. |
| noodge validate | Check the config and report problems with line numbers. |
| noodge init | Write a starter noodge.yaml. |
| noodge completion <shell> | Print the completion script. |
| noodge completion install <shell> | Set completion up for you. |
| noodge schema | Print the JSON Schema. |
| noodge upgrade | Install the latest version. |
| noodge version | Print the version. |
Global flags
-C, --directory string start looking for noodge.yaml in this directory instead of the current one --dry-run print the exact command lines that would run, and run nothing --file string load this exact config file instead of discovering a noodge.yaml -h, --help help for noodge --yes answer any confirmation prompt with yes, for CI and scripts
noodge upgrade also takes --check, which reports whether an upgrade
is available and changes nothing, and --force, which upgrades even when a package
manager installed this copy. noodge completion install takes
--print-only and -y, --yes.
Exit codes
A step's exit code passes through untouched. noodge never invents one on a command's behalf, so anything wrapping noodge sees what it would have seen wrapping the tool directly.
| Code | Means |
|---|---|
| 0 | Everything succeeded. |
| anything a step returns | Passed straight through. |
| 2 | noodge itself refused: a bad config, a missing required flag, a value that does not validate, or a declined confirmation. Every one of these happens before any process starts. |
| 10 | noodge upgrade --check found an upgrade available. |
noodge: required flag "--certificate" is not set noodge: --certificate: dev.pfx does not exist noodge: unknown command "nosuchcommand" for "noodge"
Tab completion
Completion is per-directory: it offers the commands this project declares, with their descriptions, and never another project's. noodge will set it up for you.
$ noodge completion install zsh
Supported targets are bash, zsh, fish,
pwsh and windows-powershell. Pass --print-only to see
what it would change and write nothing.
Editor support
The JSON Schema is generated from the doc comments in the source, published with every
release, and shipped inside the binary. noodge init writes the modeline for you;
add it to an existing file and your editor will do the rest.
# yaml-language-server: $schema=https://wimhaanstra.github.io/noodge/schema/v1/noodge.schema.json
Offline, or behind a proxy, noodge schema prints the same document to stdout.
Updating
$ noodge upgrade
noodge checks for a new version in the background and mentions it on stderr when there is
one. NOODGE_NO_UPDATE_CHECK=1 switches that off, and then noodge makes no network
requests at all.
noodge 0.3.0 is available (you have 0.2.3). Run 'noodge upgrade'.
If a package manager installed this copy, upgrading in place would leave that package manager believing the old version is still installed, and its next update would put it back. noodge refuses, and tells you the right command instead.
noodge: this noodge was installed by Scoop, which keeps its own record of the
installed version. Upgrading in place would leave Scoop believing the old
version is still installed, and its next update would put it back.
scoop update noodge