Files
windmill/system_prompts/auto-generated/cli/cli-commands.md
T
d60dd745e4 feat(forks): handle triggers and schedules in workspace forks (#8976)
* feat(forks): strip operational state from triggers/schedules on git-sync export

When the source workspace is a fork (`wm-fork-*`), the tarball export now
omits `mode` from triggers and `enabled` from schedules. The trigger update
handler also preserves the existing DB `mode` when both fields are absent
from the request, instead of falling back to the BaseTriggerData default.

This prevents a fork's git-sync round-trip from flipping the parent
workspace's enabled/disabled state when a merge applies the fork's YAML
back to main.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(forks): opt-in fork_triggers flag clones triggers/schedules disabled

Adds `workspace.fork_triggers` (default false) and a matching field on
CreateWorkspaceFork. When the user opts in, fork creation also runs
clone_triggers_and_schedules: every row in schedule and the ten
*_trigger tables is copied to the fork with mode='disabled' /
enabled=false. Listener identifiers (group_id, replication_slot_name,
subscription_name, …) are copied verbatim — the runtime suffix that
prevents the fork from competing with the parent ships in a follow-up
PR.

native_trigger is intentionally skipped: those triggers manage external
webhook state we don't want duplicated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(forks): warn before enabling triggers/schedules that conflict with parent

set_trigger_mode and schedule's set_enabled now check whether the parent
workspace has the same path actively enabled. If so, the call is rejected
with a `fork-conflict:<kind>:<parent_id>` error unless the request includes
`force=true`. The frontend interprets the prefix to surface a confirm-to-
proceed dialog.

This is the placeholder safety net until the Phase 3 listener-suffix work
removes the conflict for the namespaceable kinds (Kafka/MQTT/NATS/Postgres/
Azure/GCP-CreateNew). For SQS, GCP-Existing, and schedules — where there's
no namespacing fix — the warning is the durable solution.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(forks): UI: opt-in clone-triggers checkbox + confirm-on-fork-conflict

Adds the user-facing surface for the fork-trigger work:

- CreateWorkspaceInner: new "Clone triggers and schedules" toggle in the
  fork-creation dialog (default off). Sends fork_triggers in the request.

- forkConflict utility: detects the `fork-conflict:<kind>:<parent_id>`
  error string from the backend, shows a confirm() dialog explaining
  why the action is blocked, retries with `force: true` if accepted.

- Wires withForkConflictRetry into every trigger setMode and the
  schedule setEnabled call, both in the per-kind editor components and
  the +page.svelte list views (HTTP, websocket, kafka, NATS, SQS, MQTT,
  GCP, Azure, Postgres, email, schedule).

OpenAPI spec gains the `force` field on each setmode/setenabled body.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(forks): CLI --fork-triggers flag, fork-trigger docs, skill update

- Adds --fork-triggers boolean to wmill workspace fork; passes
  fork_triggers through to the create_fork API call.
- New docs/fork-triggers.md describing the model end-to-end (default,
  opt-in clone, merge-direction filter, conflict warning, future
  runtime-suffix work).
- Updates the adding-a-trigger SKILL.md to mention the fork-export
  ignore-keys participation and the clone_triggers_and_schedules
  block that new trigger kinds must extend.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: regenerate sqlx offline query cache for fork-trigger SQL

* fix(forks): replace browser confirm() with ConfirmationModal for fork conflict

The fork-conflict warning previously used the browser's native confirm()
which doesn't match Windmill's design system. Switches to a singleton
ConfirmationModal mounted at the (logged) layout root, driven by a new
forkConflictModal store. The withForkConflictRetry helper now sets the
store and awaits the user's choice via a Promise, instead of blocking
on window.confirm.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(forks): filter unchanged triggers in merge UI, add diff view, surface parent-only ones

The fork merge UI listed every trigger from the fork as a deployable item
regardless of whether it differed from the parent — so a fork created with
fork_triggers=true (which clones triggers in disabled state, otherwise
identical) showed every trigger as a "Fork-only" change. The 'Update
current' tab also missed triggers newly created in the parent that the
fork hadn't pulled yet.

This refactor:

- fetchAllTriggers now lists both fork and parent in parallel for each
  trigger kind, then merges by path.
- Computes a per-trigger `changeKind` (new / modified / deleted-in-source)
  using a JSON comparison that strips runtime + fork-local fields
  (mode/enabled/server_id/last_server_ping/edited_at/edited_by/etc.) so
  the disabled-on-clone difference doesn't show up as a change.
- Filters the trigger items in deployableItems by the current direction:
  Deploy mode shows fork-side new/modified, Update mode shows parent-side
  new/modified.
- Replaces the always-on "Fork-only" badge with proper New/Modified
  badges and surfaces a Diff button (modal Drawer + Monaco DiffEditor)
  for modified triggers — the diff strips the same ignored fields so
  users see only the meaningful config differences.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(forks): always clone triggers/schedules disabled, drop opt-in flag

Disabled triggers and schedules are inert — no listener attaches, no cron
fires — so cloning them by default is safe by construction. Drops the
fork_triggers opt-in flag introduced earlier in this PR:

- Drops workspace.fork_triggers column (migration removed)
- Removes fork_triggers from CreateWorkspaceFork (API + OpenAPI)
- Removes the conditional in create_workspace_fork — clone always runs
- Removes the toggle from the fork-creation dialog
- Removes --fork-triggers from `wmill workspace fork`
- Updates docs/fork-triggers.md and adding-a-trigger SKILL.md

The merge UI continues to exclude triggers from the deploy/update default
selection, so a routine merge from a fork doesn't accidentally push
trigger config the user hasn't intentionally changed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(http-triggers): scope route exists check by workspace, skip non-workspaced clones in forks

The non-CLOUD branch of `route_path_key_exists` self-excluded by trigger
path alone, which silently masked cross-workspace collisions once forks
started cloning trigger rows verbatim. Tighten it to exclude only the
exact `(workspace_id, path)` row.

Fork creation also now skips non-workspaced HTTP triggers — their URL
has no workspace prefix, so a clone collides with the parent at the
matchit router (which silently drops one of two duplicates) and there is
no namespacing escape hatch. The clone copies all rows when CLOUD_HOSTED
or HTTP_ROUTE_WORKSPACED_ROUTE forces every route workspaced regardless.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(forks-ui): silent cancel on enable conflict, clean up trigger rows in compare view

forkConflict helper now returns undefined when the user dismisses the
modal instead of throwing, so the redundant 'Cannot enable: undefined'
toast no longer appears.

CompareWorkspaces trigger rows now mirror the script row layout: drop
the redundant Disabled badge and the Trash/Details buttons (both belong
on the dedicated trigger pages, not in the deploy/compare view); pass
triggerKind through so RowIcon picks the right kind-specific icon; move
extraLabel into the summary line; replace the yellow Modified badge
with the same green ↗ ahead / blue ↘ behind treatment scripts use.

Trigger diff drawer: switch JSON → YAML for parity with DiffDrawer, fix
zero-height monaco render with className=!h-full, drop the redundant
Original/Modified label banner above the diff.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(email-trigger): scope local_part exists check, skip non-workspaced clones in forks

Mirrors the HTTP route fix for the email-trigger non-CLOUD `email_exists`
check (in EE) which had the same path-only self-exclusion bug, and the
fork clone of `email_trigger` rows which copied non-workspaced
`local_part` verbatim. Skip non-workspaced rows in the clone unless the
instance is CLOUD_HOSTED (where lookup is workspace-scoped natively).

EE companion change in windmill-trigger-email/src/handler_ee.rs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref to 78512dd73b4a1c9f70574cff863374179e3a621b

This commit updates the EE repository reference after PR #554 was merged in windmill-ee-private.

Previous ee-repo-ref: 1ac77f50747b58e720a11162dfd309bc252a24ab

New ee-repo-ref: 78512dd73b4a1c9f70574cff863374179e3a621b

Automated by sync-ee-ref workflow.

* fix(forks): always-warn on parent row, kind-specific modal copy, cancel-aware toggles

- Conflict check now fires whenever the parent has the path (regardless of
  parent's mode), since the cloned upstream identifier is shared by
  construction; closes the Postgres slot-takeover gap when the parent is
  disabled. Schedule's set_schedule_enabled gets the same treatment.
- Skip the warning entirely for HTTP and Email via a new
  TriggerCrud::FORK_CONFLICT_ON_ENABLE const — both kinds are workspace-
  scoped at runtime so cloned rows can't collide with the parent.
- Modal copy branches by failure family: split-events (Kafka/NATS/MQTT/SQS/
  GCP/Azure), duplicate-firing (Websocket/Schedule), slot-takeover
  (Postgres). Generic fallback for unknown kinds.
- withForkConflictRetry now returns boolean (true=committed, false=
  cancelled). TriggerModeToggle reuses its existing innerTriggerMode local
  state via a function binding for the regular Toggle, snapping back to
  the prop when onToggleMode signals a cancel — needed because the native
  bind:checked diverges from the parent's prop after a click and Svelte's
  reactivity won't re-push a same-valued prop down. Schedule list page
  uses {#key} on a reset version since it renders Toggle directly.
- Editor inners revert mode = previousMode on cancel; list pages skip the
  re-fetch (loadTriggers/loadSchedules) on cancel to avoid pointless
  network traffic and the schedule "Job stats loading..." flash.
- Drop withForkConflictRetry from HTTP and Email editors + list pages
  since the backend never emits the conflict for those kinds.

* fix(forks-ui): widen onToggleMode types, scope schedule toggle reset by path

- TriggerEditorToolbar and TriggerSuspendedJobsModal forwarded
  onToggleMode as `(mode) => void`, dropping the new boolean return so
  any caller wired through them would silently no-op the cancel-revert.
  Match the wider TriggerModeToggle signature.
- Schedule list page used a single resetVersion counter for every row's
  {#key}, so cancelling on any one schedule remounted every <Toggle> on
  the page. Switch to a per-path Record<string, number> bumped only for
  the affected row.

* chore: bump ee-repo-ref to c3a4553 (email FORK_CONFLICT_ON_ENABLE override)

* fix(forks): include Suspended in conflict gate, use parent_workspace_id for fork detection

Three fixes from the Claude review on PR #8976:

- Suspended mode still attaches the listener (it just pauses auto-run of
  queued jobs); two suspended fork+parent listeners would still split
  Kafka events / share a PG slot. Gate set_trigger_mode on
  `mode != Disabled` instead of `mode == Enabled` so Suspended also
  surfaces the warning.
- workspaces_export.rs::fork_*_ignore_keys keyed off the wm-fork-* prefix
  while set_trigger_mode and set_schedule_enabled key off
  parent_workspace_id. Switch the export filter to query
  parent_workspace_id once at the top of tarball_workspace and pass
  is_fork through. The column is the contract; the prefix is a
  creation-time naming convention that could in principle drift.
- TriggerModeToggle's suspend-dropdown action reassigned the non-bindable
  `triggerMode` prop instead of the local `innerTriggerMode` mirror,
  leaking inconsistent state if the dispatch was cancelled. Now writes
  to innerTriggerMode like the Toggle's on:change handler does.

* fix(cli): skip setScheduleEnabled when local YAML lacks `enabled`

Tarball export from a fork strips `enabled` from schedules so the
fork→parent git-sync round-trip can't flip the parent's operational
state. The CLI's pushSchedule called setScheduleEnabled whenever
`localSchedule.enabled != schedule.enabled`, which evaluates truthy
when local is undefined (fork-pulled YAML) and remote is true/false —
sending `{ enabled: undefined }` that serializes to `{}` and gets
rejected by the backend (`SetEnabled.enabled` is required).

Skip the call when `localSchedule.enabled === undefined` so a sync push
of fork-pulled YAMLs preserves the target's existing enabled state
instead of erroring out. Trigger updates were already safe — the
backend's update_trigger preserves `mode` when the request omits it.

* Revert "fix(cli): skip setScheduleEnabled when local YAML lacks `enabled`"

This reverts commit 23ba7e72fc.

* feat(cli): --force flag and friendlier error on fork-conflict for schedule enable

`wmill schedule enable foo/bar` against a fork whose parent has the same
path used to surface the raw `fork-conflict:schedule:<parent>` error
body. The CLI now:

- accepts `--force` to bypass the warning (mirrors the API field and the
  UI's "Enable anyway" confirmation),
- detects the `fork-conflict:` prefix on errors and prints a one-screen
  explanation pointing at --force instead of the raw body.

Disable doesn't trigger the warning (the gate fires only on transitions
to listener-attaching modes), so no flag there. Trigger enable/disable
isn't exposed as a standalone CLI command — sync push goes through
updateTrigger which has its own backend mode-preservation, so no
fork-conflict surfaces from the CLI for those.

* chore: regenerate cli-commands docs after adding --force to schedule enable

* chore: update ee-repo-ref to 967f961f0a88b027d894aebd03977181129477a8

This commit updates the EE repository reference after PR #555 was merged in windmill-ee-private.

Previous ee-repo-ref: c3a4553296473932e15392a06415dd7fb9aa6591

New ee-repo-ref: 967f961f0a88b027d894aebd03977181129477a8

Automated by sync-ee-ref workflow.

* fix(forks): address CI dead-code, claude/cubic review feedback

- backend: cfg-gate `fork_trigger_ignore_keys` to match its already-gated
  callsite. CI compiles with `-D warnings`, so the unused-fn under feature
  combos that disable all trigger crates was breaking check_oss/check_ee/
  cargo_test/test-linux/test-windows.
- cli: re-apply the `pushSchedule` undefined-skip (originally 23ba7e7,
  reverted in 4d172a1). Tarball export from forks strips `enabled`, so
  fork-pulled YAMLs that get sync-pushed back via `wmill schedule push`
  would otherwise serialize `{ enabled: undefined }` → `{}` and the
  backend's required `SetEnabled.enabled` rejects the body. Skipping
  preserves the target's existing flag, which is the round-trip-safe
  behavior. (`wmill workspace merge` extension to triggers/schedules is
  tracked in #9001 — until then sync push is the only CLI path.)
- TriggerModeToggle suspend-dropdown action awaits onToggleMode and
  resets `innerTriggerMode = triggerMode` on cancel, matching the Toggle
  on:change handler. Without this, dismissing the fork-conflict modal on
  a Suspend transition leaves the toggle stuck in 'suspended'.
- forkConflict: when a new modal opens with a previous resolver still
  pending, resolve the older promise to false. Avoids a dangling promise
  if the user clicks toggles on two rows in quick succession.
- schedules list: bump `toggleResetVersions[path]` on the
  permission-denied branch so the Toggle re-mounts back to the prop's
  `enabled` value. Without this, a user without write permission could
  click the toggle and have it stick visually flipped.
- docs/fork-triggers.md: switch the merge-direction filter description
  from `wm-fork-*` prefix to `parent_workspace_id IS NOT NULL` (matches
  the code after 4dd38fe). Drop the misleading "merge-direction filter
  strips identifier columns too" line in Future Work — the runtime
  suffix is applied at listener attach, the stored column never carries
  it, so no export filtering is needed there.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-05-01 20:55:24 +00:00

32 KiB

Windmill CLI Commands

The Windmill CLI (wmill) provides commands for managing scripts, flows, apps, and other resources.

Global Options

  • --workspace <workspace:string> - Specify the target workspace. This overrides the default workspace.
  • --debug --verbose - Show debug/verbose logs
  • --show-diffs - Show diff informations when syncing (may show sensitive informations)
  • --token <token:string> - Specify an API token. This will override any stored token.
  • --base-url <baseUrl:string> - Specify the base URL of the API. If used, --token and --workspace are required and no local remote/workspace already set will be used.
  • --config-dir <configDir:string> - Specify a custom config directory. Overrides WMILL_CONFIG_DIR environment variable and default ~/.config location.

Commands

app

app related commands

Options:

  • --json - Output as JSON (for piping to jq)

Subcommands:

  • app list - list all apps
    • --json - Output as JSON (for piping to jq)
  • app get <path:string> - get an app's details
    • --json - Output as JSON (for piping to jq)
  • app push <file_path:string> <remote_path:string> - push a local app
  • app dev [app_folder:string] - Start a development server for building apps with live reload and hot module replacement
    • --port <port:number> - Port to run the dev server on (will find next available port if occupied)
    • --host <host:string> - Host to bind the dev server to
    • --entry <entry:string> - Entry point file (default: index.ts for Svelte/Vue, index.tsx otherwise)
    • --no-open - Don't automatically open the browser
  • app lint [app_folder:string] - Lint a raw app folder to validate structure and buildability
    • --fix - Attempt to fix common issues (not implemented yet)
  • app new - create a new raw app from a template
    • --summary <summary:string> - App summary (short description). Skips the prompt when provided. Triggers non-interactive mode.
    • --path <path:string> - App path (e.g., f/folder/my_app or u/username/my_app). Skips the prompt when provided. Triggers non-interactive mode.
    • --framework <framework:string> - Framework template: react19 | react18 | svelte5 | vue. Skips the prompt when provided. Triggers non-interactive mode.
    • --datatable <datatable:string> - Datatable to wire up. Without this flag in non-interactive mode, no datatable is configured.
    • --schema <schema:string> - Schema to use with --datatable. Created (CREATE SCHEMA IF NOT EXISTS) if it doesn't already exist.
    • --overwrite - Overwrite the target directory if it already exists, without prompting.
    • --no-open-in-desktop - Do not prompt to open the new app in Claude Desktop.
  • app generate-agents [app_folder:string] - regenerate AGENTS.md and DATATABLES.md from remote workspace
  • app set-permissioned-as <path:string> <email:string> - Set the on_behalf_of_email for an app (requires admin or wm_deployers group)

audit

View audit logs (requires admin)

Subcommands:

  • audit list - List audit log entries
  • audit get <id:string> - Get a specific audit log entry
    • --json - Output as JSON (for piping to jq)

config

Show all available wmill.yaml configuration options

Options:

  • --json - Output as JSON for programmatic consumption

Subcommands:

  • config migrate - Migrate wmill.yaml from gitBranches/environments to workspaces format

dependencies

workspace dependencies related commands

Alias: deps

Subcommands:

  • dependencies push <file_path:string> - Push workspace dependencies from a local file

dev

Watch local file changes and live-reload the dev page for preview. Does NOT deploy to the remote workspace — use wmill sync push for that.

Options:

  • --includes <pattern...:string> - Filter paths given a glob pattern or path
  • --proxy-port <port:number> - Port for a localhost reverse proxy to the remote Windmill server
  • --path <path:string> - Watch a specific windmill path (e.g., u/admin/my_script or f/my_flow)
  • --no-open - Do not open the browser automatically

docs

Search Windmill documentation.

Arguments: <query:string>

Options:

  • --json - Output results as JSON.

flow

flow related commands

Options:

  • --show-archived - Enable archived flows in output
  • --json - Output as JSON (for piping to jq)

Subcommands:

  • flow list - list all flows
    • --show-archived - Enable archived flows in output
    • --json - Output as JSON (for piping to jq)
  • flow get <path:string> - get a flow's details
    • --json - Output as JSON (for piping to jq)
  • flow push <file_path:string> <remote_path:string> - push a local flow spec. This overrides any remote versions.
    • --message <message:string> - Deployment message
  • flow run <path:string> - run a flow by path.
    • -d --data <data:string> - Inputs specified as a JSON string or a file using @ or stdin using @-.
    • -s --silent - Do not ouput anything other then the final output. Useful for scripting.
  • flow preview <flow_path:string> - preview a local flow without deploying it. Runs the flow definition from local files and uses local PathScripts by default.
    • -d --data <data:string> - Inputs specified as a JSON string or a file using @ or stdin using @-.
    • -s --silent - Do not output anything other then the final output. Useful for scripting.
    • --remote - Use deployed workspace scripts for PathScript steps instead of local files.
  • flow new <flow_path:string> - create a new empty flow
    • --summary <summary:string> - flow summary
    • --description <description:string> - flow description
  • flow bootstrap <flow_path:string> - create a new empty flow (alias for new)
    • --summary <summary:string> - flow summary
    • --description <description:string> - flow description
  • flow history <path:string> - Show version history for a flow
    • --json - Output as JSON (for piping to jq)
  • flow show-version <path:string> <version:string> - Show a specific version of a flow
    • --json - Output as JSON (for piping to jq)
  • flow set-permissioned-as <path:string> <email:string> - Set the on_behalf_of_email for a flow (requires admin or wm_deployers group)

folder

folder related commands

Options:

  • --json - Output as JSON (for piping to jq)

Subcommands:

  • folder list - list all folders
    • --json - Output as JSON (for piping to jq)
  • folder get <name:string> - get a folder's details
    • --json - Output as JSON (for piping to jq)
  • folder new <name:string> - create a new folder locally
    • --summary <summary:string> - folder summary
  • folder push <name:string> - push a local folder to the remote by name. This overrides any remote versions.
  • folder add-missing - create default folder.meta.yaml for all subdirectories of f/ that are missing one
    • -y, --yes - skip confirmation prompt
  • folder show-rules <name:string> - Show default_permissioned_as rules for a folder. Use --test-path to see which rule matches a given item path.
    • --test-path <path:string> - Test which rule matches this item path (e.g. f/prod/jobs/my_script)
    • --json - Output as JSON

generate-metadata

Generate metadata (locks, schemas) for all scripts, flows, and apps

Arguments: [folder:string]

Options:

  • --yes - Skip confirmation prompt
  • --dry-run - Show what would be updated without making changes
  • --lock-only - Re-generate only the lock files
  • --schema-only - Re-generate only script schemas (skips flows and apps)
  • --skip-scripts - Skip processing scripts
  • --skip-flows - Skip processing flows
  • --skip-apps - Skip processing apps
  • --strict-folder-boundaries - Only update items inside the specified folder (requires folder argument)
  • -i --includes <patterns:file[]> - Comma separated patterns to specify which files to include
  • -e --excludes <patterns:file[]> - Comma separated patterns to specify which files to exclude

Subcommands:

  • generate-metadata rehash [folder:string]
    • --skip-scripts - Skip processing scripts
    • --skip-flows - Skip processing flows
    • --skip-apps - Skip processing apps
    • -i --includes <patterns:file[]> - Comma separated patterns to specify which files to include
    • -e --excludes <patterns:file[]> - Comma separated patterns to specify which files to exclude

gitsync-settings

Manage git-sync settings between local wmill.yaml and Windmill backend

Subcommands:

  • gitsync-settings pull - Pull git-sync settings from Windmill backend to local wmill.yaml
    • --repository <repo:string> - Specify repository path (e.g., u/user/repo)
    • --default - Write settings to top-level defaults instead of overrides
    • --replace - Replace existing settings (non-interactive mode)
    • --override - Add branch-specific override (non-interactive mode)
    • --diff - Show differences without applying changes
    • --json-output - Output in JSON format
    • --with-backend-settings <json:string> - Use provided JSON settings instead of querying backend (for testing)
    • --yes - Skip interactive prompts and use default behavior
    • --promotion <branch:string> - Use promotionOverrides from the specified branch instead of regular overrides
  • gitsync-settings push - Push git-sync settings from local wmill.yaml to Windmill backend
    • --repository <repo:string> - Specify repository path (e.g., u/user/repo)
    • --diff - Show what would be pushed without applying changes
    • --json-output - Output in JSON format
    • --with-backend-settings <json:string> - Use provided JSON settings instead of querying backend (for testing)
    • --yes - Skip interactive prompts and use default behavior
    • --promotion <branch:string> - Use promotionOverrides from the specified branch instead of regular overrides

group

Manage workspace groups

Options:

  • --json - Output as JSON (for piping to jq)

Subcommands:

  • group list - List all groups in the workspace
    • --json - Output as JSON (for piping to jq)
  • group get <name:string> - Get group details and members
    • --json - Output as JSON (for piping to jq)
  • group create <name:string> - Create a new group
    • --summary <summary:string> - Group summary/description
  • group delete <name:string> - Delete a group
  • group add-user <name:string> <username:string> - Add a user to a group
  • group remove-user <name:string> <username:string> - Remove a user from a group

hub

Hub related commands. EXPERIMENTAL. INTERNAL USE ONLY.

Subcommands:

  • hub pull - pull any supported definitions. EXPERIMENTAL.

init

Bootstrap a windmill project with a wmill.yaml file

Options:

  • --use-default - Use default settings without checking backend
  • --use-backend - Use backend git-sync settings if available
  • --repository <repo:string> - Specify repository path (e.g., u/user/repo) when using backend settings
  • --bind-profile - Automatically bind active workspace profile to current Git branch
  • --no-bind-profile - Skip workspace profile binding prompt

instance

sync local with a remote instance or the opposite (push or pull)

Subcommands:

  • instance add [instance_name:string] [remote:string] [token:string] - Add a new instance
  • instance remove <instance:string:instance> - Remove an instance
  • instance switch <instance:string:instance> - Switch the current instance
  • instance pull - Pull instance settings, users, configs, instance groups and overwrite local
    • --yes - Pull without needing confirmation
    • --dry-run - Perform a dry run without making changes
    • --skip-users - Skip pulling users
    • --skip-settings - Skip pulling settings
    • --skip-configs - Skip pulling configs (worker groups)
    • --skip-groups - Skip pulling instance groups
    • --include-workspaces - Also pull workspaces
    • --folder-per-instance - Create a folder per instance
    • --instance <instance:string> - Name of the instance to pull from, override the active instance
    • --prefix <prefix:string> - Prefix of the local workspaces to pull, used to create the folders when using --include-workspaces
    • --prefix-settings - Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance
  • instance push - Push instance settings, users, configs, group and overwrite remote
    • --yes - Push without needing confirmation
    • --dry-run - Perform a dry run without making changes
    • --skip-users - Skip pushing users
    • --skip-settings - Skip pushing settings
    • --skip-configs - Skip pushing configs (worker groups)
    • --skip-groups - Skip pushing instance groups
    • --include-workspaces - Also push workspaces
    • --folder-per-instance - Create a folder per instance
    • --instance <instance:string> - Name of the instance to push to, override the active instance
    • --prefix <prefix:string> - Prefix of the local workspaces folders to push
    • --prefix-settings - Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance
  • instance whoami - Display information about the currently logged-in user
  • instance get-config - Dump the current instance config (global settings + worker configs) as YAML
    • -o, --output-file <file:string> - Write YAML to a file instead of stdout
    • --show-secrets - Include sensitive fields (license key, JWT secret) without prompting
    • --instance <instance:string> - Name of the instance, override the active instance
  • instance connect-slack
    • --bot-token <bot_token:string> - Slack bot token (xoxb-...)
    • --team-id <team_id:string> - Slack team id
    • --team-name <team_name:string> - Slack team name
    • --instance <instance:string> - Instance profile to connect against (defaults to the active instance)

job

Manage jobs (list, inspect, cancel)

Subcommands:

  • job list - List recent jobs
  • job get <id:string> - Get job details. For flows: shows step tree with sub-job IDs
    • --json - Output as JSON (for piping to jq)
  • job result <id:string> - Get the result of a completed job (machine-friendly)
  • job logs <id:string> - Get job logs. For flows: aggregates all step logs
  • job cancel <id:string> - Cancel a running or queued job
    • --reason <reason:string> - Reason for cancellation

jobs

Pull completed and queued jobs from workspace

Arguments: [workspace:string]

Options:

  • -c, --completed-output <file:string> - Completed jobs output file (default: completed_jobs.json)
  • -q, --queued-output <file:string> - Queued jobs output file (default: queued_jobs.json)
  • --skip-worker-check - Skip checking for active workers before export

Subcommands:

  • jobs pull
  • jobs push

lint

Validate Windmill flow, schedule, and trigger YAML files in a directory

Arguments: [directory:string]

Options:

  • --json - Output results in JSON format
  • --fail-on-warn - Exit with code 1 when warnings are emitted
  • --locks-required - Fail if scripts or flow inline scripts that need locks have no locks
  • -w, --watch - Watch for file changes and re-lint automatically

queues

List all queues with their metrics

Arguments: [workspace:string] the optional workspace to filter by (default to all workspaces)

Options:

  • --instance [instance] - Name of the instance to push to, override the active instance
  • --base-url [baseUrl] - If used with --token, will be used as the base url for the instance

resource

resource related commands

Options:

  • --json - Output as JSON (for piping to jq)

Subcommands:

  • resource list - list all resources
    • --json - Output as JSON (for piping to jq)
  • resource get <path:string> - get a resource's details
    • --json - Output as JSON (for piping to jq)
  • resource new <path:string> - create a new resource locally
  • resource push <file_path:string> <remote_path:string> - push a local resource spec. This overrides any remote versions.

resource-type

resource type related commands

Options:

  • --json - Output as JSON (for piping to jq)

Subcommands:

  • resource-type list - list all resource types
    • --schema - Show schema in the output
    • --json - Output as JSON (for piping to jq)
  • resource-type get <path:string> - get a resource type's details
    • --json - Output as JSON (for piping to jq)
  • resource-type new <name:string> - create a new resource type locally
  • resource-type push <file_path:string> <name:string> - push a local resource spec. This overrides any remote versions.
  • resource-type generate-namespace - Create a TypeScript definition file with the RT namespace generated from the resource types

schedule

schedule related commands

Options:

  • --json - Output as JSON (for piping to jq)

Subcommands:

  • schedule list - list all schedules
    • --json - Output as JSON (for piping to jq)
  • schedule get <path:string> - get a schedule's details
    • --json - Output as JSON (for piping to jq)
  • schedule new <path:string> - create a new schedule locally
  • schedule push <file_path:string> <remote_path:string> - push a local schedule spec. This overrides any remote versions.
  • schedule enable <path:string> - Enable a schedule
    • --force - Bypass the fork-conflict warning when the parent workspace has the same schedule (acknowledges that both crons will fire)
  • schedule disable <path:string> - Disable a schedule
  • schedule set-permissioned-as <path:string> <email:string> - Set the email (run-as user) for a schedule (requires admin or wm_deployers group)

script

script related commands

Options:

  • --show-archived - Show archived scripts instead of active ones
  • --json - Output as JSON (for piping to jq)

Subcommands:

  • script list - list all scripts
    • --show-archived - Show archived scripts instead of active ones
    • --json - Output as JSON (for piping to jq)
  • script push <path:file> - push a local script spec. This overrides any remote versions. Use the script file (.ts, .js, .py, .sh)
    • --message <message:string> - Deployment message
  • script get <path:file> - get a script's details
    • --json - Output as JSON (for piping to jq)
  • script show <path:file> - show a script's content (alias for get)
  • script run <path:file> - run a script by path
    • -d --data <data:file> - Inputs specified as a JSON string or a file using @ or stdin using @-.
    • -s --silent - Do not output anything other then the final output. Useful for scripting.
  • script preview <path:file> - preview a local script without deploying it. Supports both regular and codebase scripts.
    • -d --data <data:file> - Inputs specified as a JSON string or a file using @ or stdin using @-.
    • -s --silent - Do not output anything other than the final output. Useful for scripting.
  • script new <path:file> <language:string> - create a new script
    • --summary <summary:string> - script summary
    • --description <description:string> - script description
  • script bootstrap <path:file> <language:string> - create a new script (alias for new)
    • --summary <summary:string> - script summary
    • --description <description:string> - script description
  • script set-permissioned-as <path:string> <email:string> - Set the on_behalf_of_email for a script (requires admin or wm_deployers group)
  • script history <path:string> - show version history for a script
    • --json - Output as JSON (for piping to jq)

sync

sync local with a remote workspaces or the opposite (push or pull)

Subcommands:

  • sync pull - Pull any remote changes and apply them locally.
    • --yes - Pull without needing confirmation
    • --dry-run - Show changes that would be pulled without actually pushing
    • --plain-secrets - Pull secrets as plain text
    • --json - Use JSON instead of YAML
    • --skip-variables - Skip syncing variables (including secrets)
    • --skip-secrets - Skip syncing only secrets variables
    • --include-secrets - Include secrets in sync (overrides skipSecrets in wmill.yaml)
    • --skip-resources - Skip syncing resources
    • --skip-resource-types - Skip syncing resource types
    • --skip-scripts - Skip syncing scripts
    • --skip-flows - Skip syncing flows
    • --skip-apps - Skip syncing apps
    • --skip-folders - Skip syncing folders
    • --skip-workspace-dependencies - Skip syncing workspace dependencies
    • --skip-scripts-metadata - Skip syncing scripts metadata, focus solely on logic
    • --include-schedules - Include syncing schedules
    • --include-triggers - Include syncing triggers
    • --include-users - Include syncing users
    • --include-groups - Include syncing groups
    • --include-settings - Include syncing workspace settings
    • --include-key - Include workspace encryption key
    • --skip-branch-validation - Skip git branch validation and prompts
    • --json-output - Output results in JSON format
    • -i --includes <patterns:file[]> - Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Overrides wmill.yaml includes
    • -e --excludes <patterns:file[]> - Comma separated patterns to specify which file to NOT take into account. Overrides wmill.yaml excludes
    • --extra-includes <patterns:file[]> - Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Useful to still take wmill.yaml into account and act as a second pattern to satisfy
    • --repository <repo:string> - Specify repository path (e.g., u/user/repo) when multiple repositories exist
    • --promotion <branch:string> - Use promotionOverrides from the specified branch instead of regular overrides
    • --branch, --env <branch:string> - [Deprecated: use --workspace] Override the current git branch/environment
  • sync push - Push any local changes and apply them remotely.
    • --yes - Push without needing confirmation
    • --dry-run - Show changes that would be pushed without actually pushing
    • --plain-secrets - Push secrets as plain text
    • --json - Use JSON instead of YAML
    • --skip-variables - Skip syncing variables (including secrets)
    • --skip-secrets - Skip syncing only secrets variables
    • --include-secrets - Include secrets in sync (overrides skipSecrets in wmill.yaml)
    • --skip-resources - Skip syncing resources
    • --skip-resource-types - Skip syncing resource types
    • --skip-scripts - Skip syncing scripts
    • --skip-flows - Skip syncing flows
    • --skip-apps - Skip syncing apps
    • --skip-folders - Skip syncing folders
    • --skip-workspace-dependencies - Skip syncing workspace dependencies
    • --skip-scripts-metadata - Skip syncing scripts metadata, focus solely on logic
    • --include-schedules - Include syncing schedules
    • --include-triggers - Include syncing triggers
    • --include-users - Include syncing users
    • --include-groups - Include syncing groups
    • --include-settings - Include syncing workspace settings
    • --include-key - Include workspace encryption key
    • --skip-branch-validation - Skip git branch validation and prompts
    • --json-output - Output results in JSON format
    • -i --includes <patterns:file[]> - Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string)
    • -e --excludes <patterns:file[]> - Comma separated patterns to specify which file to NOT take into account.
    • --extra-includes <patterns:file[]> - Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Useful to still take wmill.yaml into account and act as a second pattern to satisfy
    • --message <message:string> - Include a message that will be added to all scripts/flows/apps updated during this push
    • --parallel <number> - Number of changes to process in parallel
    • --repository <repo:string> - Specify repository path (e.g., u/user/repo) when multiple repositories exist
    • --branch, --env <branch:string> - [Deprecated: use --workspace] Override the current git branch/environment
    • --lint - Run lint validation before pushing
    • --locks-required - Fail if scripts or flow inline scripts that need locks have no locks
    • --auto-metadata - Automatically regenerate stale metadata (locks and schemas) before pushing
    • --accept-overriding-permissioned-as-with-self - Accept that items with a different permissioned_as will be updated with your own user

token

Manage API tokens

Options:

  • --json - Output as JSON (for piping to jq)

Subcommands:

  • token list - List API tokens
    • --json - Output as JSON (for piping to jq)
  • token create - Create a new API token
    • --label <label:string> - Token label
    • --expiration <expiration:string> - Token expiration (ISO 8601 timestamp)
  • token delete <token_prefix:string> - Delete a token by its prefix

trigger

trigger related commands

Options:

  • --json - Output as JSON (for piping to jq)

Subcommands:

  • trigger list - list all triggers
    • --json - Output as JSON (for piping to jq)
  • trigger get <path:string> - get a trigger's details
    • --json - Output as JSON (for piping to jq)
    • --kind <kind:string> - Trigger kind (http, websocket, kafka, nats, postgres, mqtt, sqs, gcp, azure, email). Recommended for faster lookup
  • trigger new <path:string> - create a new trigger locally
    • --kind <kind:string> - Trigger kind (required: http, websocket, kafka, nats, postgres, mqtt, sqs, gcp, azure, email)
  • trigger push <file_path:string> <remote_path:string> - push a local trigger spec. This overrides any remote versions.
  • trigger set-permissioned-as <path:string> <email:string> - Set the email (run-as user) for a trigger (requires admin or wm_deployers group)
    • --kind <kind:string> - Trigger kind (required: http, websocket, kafka, nats, postgres, mqtt, sqs, gcp, azure, email)

user

user related commands

Subcommands:

  • user add <email:string> [password:string] - Create a user
    • --superadmin - Specify to make the new user superadmin.
    • --company <company:string> - Specify to set the company of the new user.
    • --name <name:string> - Specify to set the name of the new user.
  • user remove <email:string> - Delete a user
  • user create-token - Create a new API token for the authenticated user
    • --email <email:string> - Specify credentials to use for authentication. This will not be stored. It will only be used to exchange for a token with the API server, which will not be stored either.
    • --password <password:string> - Specify credentials to use for authentication. This will not be stored. It will only be used to exchange for a token with the API server, which will not be stored either.

variable

variable related commands

Options:

  • --json - Output as JSON (for piping to jq)

Subcommands:

  • variable list - list all variables
    • --json - Output as JSON (for piping to jq)
  • variable get <path:string> - get a variable's details
    • --json - Output as JSON (for piping to jq)
  • variable new <path:string> - create a new variable locally
  • variable push <file_path:string> <remote_path:string> - Push a local variable spec. This overrides any remote versions.
    • --plain-secrets - Push secrets as plain text
  • variable add <value:string> <remote_path:string> - Create a new variable on the remote. This will update the variable if it already exists.
    • --plain-secrets - Push secrets as plain text
    • --public - Legacy option, use --plain-secrets instead

version

Show version information

worker-groups

display worker groups, pull and push worker groups configs

Subcommands:

  • worker-groups pull - Pull worker groups (similar to wmill instance pull --skip-users --skip-settings --skip-groups)
    • --instance - Name of the instance to push to, override the active instance
    • --base-url - Base url to be passed to the instance settings instead of the local one
    • --yes - Pull without needing confirmation
  • worker-groups push - Push worker groups (similar to wmill instance push --skip-users --skip-settings --skip-groups)
    • --instance [instance] - Name of the instance to push to, override the active instance
    • --base-url [baseUrl] - If used with --token, will be used as the base url for the instance
    • --yes - Push without needing confirmation

workers

List all workers grouped by worker groups

Options:

  • --instance [instance] - Name of the instance to push to, override the active instance
  • --base-url [baseUrl] - If used with --token, will be used as the base url for the instance

workspace

workspace related commands

Alias: profile

Subcommands:

  • workspace switch <workspace_name:string:workspace> - Switch to another workspace
  • workspace add [workspace_name:string] [workspace_id:string] [remote:string] - Add a workspace
    • -c --create - Create the workspace if it does not exist
    • --create-workspace-name <workspace_name:string> - Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.
    • --create-username <username:string> - Specify your own username in the newly created workspace. Ignored if --create is not specified, the workspace already exists or automatic username creation is enabled on the instance.
  • workspace remove <workspace_name:string> - Remove a workspace
  • workspace whoami - Show the currently active user
  • workspace list - List local workspace profiles
  • workspace list-remote - List workspaces on the remote server that you have access to
  • workspace list-forks - List forked workspaces on the remote server
  • workspace bind - Create or update a workspace entry in wmill.yaml from the active profile
    • --workspace <name:string> - Workspace name (default: current branch or workspaceId)
    • --branch <branch:string> - Git branch to associate (default: workspace name)
  • workspace unbind - Remove baseUrl and workspaceId from a workspace entry
    • --workspace <name:string> - Workspace to unbind
  • workspace fork [workspace_name:string] [workspace_id:string] - Create a forked workspace
    • --create-workspace-name <workspace_name:string> - Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.
    • --color <color:string> - Workspace color (hex code, e.g. #ff0000)
    • --datatable-behavior <behavior:string> - How to handle datatables: skip, schema_only, or schema_and_data (default: interactive prompt)
    • -y --yes - Skip interactive prompts (defaults datatable behavior to 'skip')
  • workspace delete-fork <fork_name:string> - Delete a forked workspace and git branch
    • -y --yes - Skip confirmation prompt
  • workspace merge - Compare and deploy changes between a fork and its parent workspace
    • --direction <direction:string> - Deploy direction: to-parent or to-fork
    • --all - Deploy all changed items including conflicts
    • --skip-conflicts - Skip items modified in both workspaces
    • --include <items:string> - Comma-separated kind:path items to include (e.g. script:f/test/main,flow:f/my/flow)
    • --exclude <items:string> - Comma-separated kind:path items to exclude
    • --preserve-on-behalf-of - Preserve original on_behalf_of/permissioned_as values
    • -y --yes - Non-interactive mode (deploy without prompts)
  • workspace connect-slack - Non-interactively connect Slack to the active workspace using a pre-minted bot token (xoxb-...). Produces the same artifacts as the UI OAuth flow: workspace_settings fields, g/slack group, f/slack_bot folder, and the encrypted bot token variable + resource at f/slack_bot/bot_token.
    • --bot-token <bot_token:string> - Slack bot token (xoxb-...)
    • --team-id <team_id:string> - Slack team id
    • --team-name <team_name:string> - Slack team name
  • workspace disconnect-slack