* fix(cli): keep a raw app's custom_path on sync pull The pull rendered raw_app.yaml without custom_path, so every pull removed the line and every push --dry-run listed the file as modified, while the deployed app still had it and push still sent it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): send custom_path on app update only when it changed The backend requires admin for any update carrying custom_path, so the value a pull now writes into raw_app.yaml made every non-admin push of that app fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): sync an app's custom path as a workspace-specific file Unless app routes are workspace-prefixed, a custom path is unique across the instance, so a value carried in the app file every workspace shares can never be promoted. Sync now renders it as <app>.<workspace>.custom_path.yaml next to the app folder, always workspace-specific. A push applies only the target workspace's file and leaves the deployed custom path alone without one; a checkout that still has custom_path in its app file converges on push, and the next pull moves it out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cli): drop the custom_path rationale repeated from changedCustomPath Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): apply a custom path pushed with its raw app, and converge a cleared one The raw-app bundle collapse kept one change per group and dropped the custom-path file grouped with it, so a push editing both deployed only the app. App files and their custom-path file now group under the app path in both folder layouts, and the collapse keeps the custom-path change. A cleared custom path (custom_path: '') has no file in the export, so the push diff listed it as added forever; an empty value with nothing deployed is now in sync. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): never read a file inside a flow or app folder as workspace-specific The workspace-name segment of the workspace-specific patterns spans '/', so a raw-app asset such as settings.prod.custom_path.json was taken for a workspace's file and dropped from the pull. Like fileset children, files inside a flow or app folder are content of that item, whatever their name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): recognize a custom-path file only beside its app isCustomPathFile excluded app and flow folders but still matched a fileset child such as data.fileset/settings.custom_path.json, so a push dropped edits to it and a pull renamed it. A custom-path file is now identified by where it sits: its name is <app>[.<workspace>].custom_path.<ext> and no part of its directory is an item's folder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Windmill CLI
A simple CLI allowing interactions with windmill from the command line.

You can find more information in Windmill Docs
Installation
Install the wmill CLI tool using npm install -g windmill-cli.
Update to the latest version using wmill upgrade.
Workspaces
To get started run wmill workspace add or use the instructions from the
workspace settings.
Running Flows & Scripts
Run a script or flow using wmill flow/script run u/username/path/to/script and
pass any inputs using --data + Inputs specified as a JSON string or a file
using @ <filename> or stdin using @-.
Curl-style syntax using -d @- for stdin or -d @<filename> is also supported.
Flow Steps and Logs will be streamed during execution automatically.
Pushing Resources, Scripts & More
The CLI can push specifications to a windmill instance. See the examples/ folder for formats.
Switch to a different workspace
wmill workspace switch <workspace_name>
Sync a workspace
Pull
wmill sync pull
Push
wmill sync push
We recommend using the --yaml option to use yaml instead of json as the encoding format. Yaml will be made the default soon.
Pushing individual files
You can push individual resources using
wmill <type> push <file_name> \<remote_name\>. This does not require a special
folder layout or file name, as this is given at runtime.
Listing
All commands support listing by just not providing a subcommand, ie
wmill script will result in a list of scripts. Some allow additional options,
learn about this by specifying --help.
User Management
You can add & remove users via wmill user add/remove, and list them using
wmill user
Pulling
You can pull the entire workspace using wmill pull
Completion
The CLI comes with completions out of the box via wmill completions <shell>.
(Via cliffy)
Bash
To enable bash completions add the following line to your ~/.bashrc:
source <(wmill completions bash)
Fish
To enable fish completions add the following line to your
~/.config/fish/config.fish:
source (wmill completions fish | psub)
Zsh
To enable zsh completions add the following line to your ~/.zshrc:
source <(wmill completions zsh)
Development
AI Guidance Variants
wmill init can now materialize alternate AI guidance bundles without changing
the generated defaults in the repo, but this is exposed as internal env-var
overrides rather than public CLI flags.
Examples:
WMILL_INIT_AI_SKILLS_SOURCE=/path/to/custom/skills wmill init --use-default
WMILL_INIT_AI_SKILLS_SOURCE=/path/to/custom/skills WMILL_INIT_AI_AGENTS_SOURCE=/path/to/AGENTS.md wmill init --use-default
WMILL_INIT_AI_SKILLS_SOURCE=/path/to/custom/skills WMILL_INIT_AI_CLAUDE_SOURCE=/path/to/CLAUDE.md wmill init --use-default
This is the same guidance-writing path used by the benchmark CLI under
ai_evals/, so the benchmark harness and wmill init now generate the same
project guidance shape:
AGENTS.mdCLAUDE.md.agents/skills/*.claude/skills/*
windmill-yaml-validator
wmill lint imports the sibling windmill-yaml-validator package from source rather than
from npm, so its schemas always match the OpenAPI specs of the current checkout. bun install regenerates them through this package's preinstall script; run it again after
editing openflow.openapi.yaml or backend/windmill-api/openapi.yaml:
npm --prefix ../windmill-yaml-validator run gen
Running Tests
Prerequisites:
- PostgreSQL running locally (default:
postgres://postgres:changeme@localhost:5432) - Rust toolchain installed
Run tests locally (full features):
bun test test/
Run tests in CI mode (minimal features, skips EE tests):
CI_MINIMAL_FEATURES=true bun test test/
| Variable | Description |
|---|---|
CI_MINIMAL_FEATURES |
Set to true to skip EE-dependent tests |
DATABASE_URL |
PostgreSQL connection string |
EE_LICENSE_KEY |
Enterprise license key for EE features |
