mise watch
- Usage:
mise watch [FLAGS] [TASK] [ARGS]… - Aliases:
w - Source code:
src/cli/watch.rs
Run tasks and rerun them when files change
Runs the tasks with mise run under watchexec, then reruns them whenever one of their sources changes, including the sources of their dependencies unless you pass --skip-deps. When no selected task declares sources, watchexec watches the current directory. With no task, runs the default task.
Choose what to watch with --watch, --exts, and --filter, and use --print-events to see what triggered a run. Arguments for the task go after --. Requires watchexec, which mise use -g watchexec installs.
To keep a server or database running alongside your tasks, with readiness checks and automatic restarts, see mise daemons (experimental): https://mise.jdx.dev/daemons.html. For cron scheduling and standalone process management, see pitchfork: https://pitchfork.jdx.dev
Arguments
[TASK]— Task to watch (default:default); separate several tasks with:::[ARGS]…— Arguments for the task;:::starts the next task
Flags
-g --glob <GLOB>— Globs to watch instead of the tasks' sources--skip-deps— Run and watch only the named tasks, not the tasks they depend on-o --on-busy-update <MODE>— What to do when files change while the tasks are runningdo-nothing(the default) ignores the change, so files the tasks write do not trigger another run.queueruns the tasks again when the current run finishes.restartstops the running tasks and starts them again.signalsends the--signalsignal and keeps the tasks running, for programs that reload their configuration on a signal.Choices:
queue,do-nothing,restart,signalDefault:
do-nothing-r --restart— Restart the tasks if they are still running when files changeSame as
--on-busy-update=restart.-s --signal <SIGNAL>— Signal to send to the running tasks when files changeImplies
--on-busy-update=signal. Accepts the same forms as--stop-signal. Signals are not supported on Windows, where the tasks are always killed.--stop-signal <SIGNAL>— Signal that stops the tasks before a restart (default on Unix: SIGTERM)Used by the
restartandsignalmodes of--on-busy-updateunless--signalis given. Accepts a full name (SIGTERM), a short name (TERM), or a number (15), in any case. If the tasks have not exited after--stop-timeout, they are killed. On Windows the tasks are always killed.--stop-timeout <TIMEOUT>— How long to wait for the tasks to stop before killing them (default: 10s)Takes a duration such as
5sor1min 20s. Set it to 0 to kill the tasks right away. Has no effect on Windows, where the tasks are always killed.Default:
10s--map-signal <SIGNAL:SIGNAL>— Translate a signal that watchexec receives into one it sends to the tasksTakes two signal names separated by a colon, such as
TERM:INT. Leave out the second name to discard the first signal (TERM:). A mapped SIGINT or SIGTERM no longer stops watching;INT:INTpasses Ctrl-C to the tasks without stopping watchexec. Repeat the flag to map several signals.-d --debounce <TIMEOUT>— How long to wait for more changes before running (default: 50ms)One save can produce several events, and a file can be written in pieces, so watchexec waits this long after an event before running the tasks. Takes a duration such as
500msor2s.Default:
50ms--stdin-quit— Exit when stdin closes-p --postpone— Wait for the first change before running the tasks--delay-run <DURATION>— Wait this long after a change before running the tasks, e.g. 5s--poll [INTERVAL]— Poll for changes instead of using native file watchingUse it on file systems where native events do not work, such as network shares. Takes an optional interval such as
2s(default: 30s). Also accepted as--force-poll.--project-origin <DIRECTORY>— Set the project originWatchexec will attempt to discover the project's "origin" (or "root") by searching for a variety of markers, like files or directory patterns. It does its best but sometimes gets it it wrong, and you can override that with this option.
The project origin is used to determine the path of certain ignore files, which VCS is being used, the meaning of a leading '/' in filtering patterns, and maybe more in the future.
When set, Watchexec will also not bother searching, which can be significantly faster.
The directory must contain every watched task's sources, which mise makes relative to it.
-h --help— Print help
Filtering
-w --watch <PATH>— Watch a file or directoryBy default, mise watches each task's directory and any source directory outside it, and filters events to the tasks'
sources. When no task declares sources, watchexec watches the current directory. Paths given here are added to the task directories, or replace the current-directory default when there are no sources. Events are still filtered to the sources, so use--filterto widen what triggers a rerun.To watch a single file, watch its directory and filter on the file name instead: some editors replace a file when they save it, and some platforms do not report changes to the replacement. Repeat the flag to watch several paths.
-W --watch-non-recursive <PATH>— Watch a directory without recursing into itRepeat the flag to watch several directories.
-F --watch-file <PATH>— Read paths to watch from a file, one per lineEach line is treated like a
--watchvalue. The value-reads from stdin and cannot be combined with--stdin-quit.--no-vcs-ignore— Do not apply Git and other version control ignore filesUse it to watch files that Git ignores. A task can turn this on for itself with
watch = { no_vcs_ignore = true }.--no-project-ignore— Do not apply ignore files in the project, such as.gitignoreand.ignore--no-global-ignore— Do not apply global ignore files, such as~/.gitignoreand~/.config/watchexec/ignore--no-default-ignore— Do not apply watchexec's built-in ignoresThey cover editor swap files,
*.pyc,.DS_Store, and version control directories such as.git.--no-discover-ignore— Do not look for ignore files at allSame as
--no-global-ignore --no-vcs-ignore --no-project-ignore, but faster. Built-in ignores still apply.--ignore-nothing— Ignore nothingSame as
--no-discover-ignore --no-default-ignore. Patterns from--ignoreand--ignore-filestill apply.-e --exts <EXTENSIONS>— Only react to files with these extensions, e.g. js,tsGive extensions with or without the leading dot. Repeat the flag or separate extensions with commas.
-f --filter <PATTERN>— Only react to files that match this globCombined with the patterns mise derives from the tasks'
sources. Repeat the flag for more patterns. Events that do not come from files, such as signals, pass through.--filter-file <PATH>— Files to load filters fromProvide a path to a file containing filters, one per line. Empty lines and lines starting with '#' are ignored. Uses the same pattern format as the '--filter' option.
This can also be used via the $WATCHEXEC_FILTER_FILES environment variable.
Environment Variable:
WATCHEXEC_FILTER_FILES-J --filter-prog <EXPRESSION>— [experimental] Filter programs./!\ This option is EXPERIMENTAL and may change and/or vanish without notice.
Provide your own custom filter programs in jaq (similar to jq) syntax. Programs are given an event in the same format as described in '--emit-events-to' and must return a boolean. Invalid programs will make watchexec fail to start; use '-v' to see program runtime errors.
In addition to the jaq stdlib, watchexec adds some custom filter definitions:
'path | file_meta' returns file metadata or null if the file does not exist.
'path | file_size' returns the size of the file at path, or null if it does not exist.
'path | file_read(bytes)' returns a string with the first n bytes of the file at path. If the file is smaller than n bytes, the whole file is returned. There is no filter to read the whole file at once to encourage limiting the amount of data read and processed.
'string | hash', and 'path | file_hash' return the hash of the string or file at path. No guarantee is made about the algorithm used: treat it as an opaque value.
'any | kv_store(key)', 'kv_fetch(key)', and 'kv_clear' provide a simple key-value store. Data is kept in memory only, there is no persistence. Consistency is not guaranteed.
'any | printout', 'any | printerr', and 'any | log(level)' will print or log any given value to stdout, stderr, or the log (levels = error, warn, info, debug, trace), and pass the value through (so '[1] | log("debug") | .[]' will produce a '1' and log '[1]').
All filtering done with such programs, and especially those using kv or filesystem access, is much slower than the other filtering methods. If filtering is too slow, events will back up and stall watchexec. Take care when designing your filters.
If the argument to this option starts with an '@', the rest of the argument is taken to be the path to a file containing a jaq program.
Jaq programs are run in order, after all other filters, and short-circuit: if a filter (jaq or not) rejects an event, execution stops there, and no other filters are run. Additionally, they stop after outputting the first value, so you'll want to use 'any' or 'all' when iterating, otherwise only the first item will be processed, which can be quite confusing!
Find user-contributed programs or submit your own useful ones at <https://github.com/watchexec/watchexec/discussions/592>.
Examples:
Regexp ignore filter on paths:
'all(.tags[] | select(.kind == "path"); .absolute | test("[.]test[.]js$")) | not'
Pass any event that creates a file:
'any(.tags[] | select(.kind == "fs"); .simple == "create")'
Pass events that touch executable files:
'any(.tags[] | select(.kind == "path" and .filetype == "file"); .absolute | file_meta | .executable)'
Ignore files that start with shebangs:
'any(.tags[] | select(.kind == "path" and .filetype == "file"); .absolute | file_read(2) == "#!") | not'
-i --ignore <PATTERN>— Ignore files that match this globRepeat the flag for more patterns. Events that do not come from files, such as signals, pass through.
--ignore-file <PATH>— Read ignore patterns from a file, one per lineEmpty lines and lines that start with
#are skipped. The patterns use the same format as--ignore. Also read from$WATCHEXEC_IGNORE_FILES.Environment Variable:
WATCHEXEC_IGNORE_FILES--fs-events <EVENTS>— Filesystem events to filter toThis is a quick filter to only emit events for the given types of filesystem changes. Choose from 'access', 'create', 'remove', 'rename', 'modify', 'metadata'. Multiple types can be given by repeating the option or by separating them with commas. By default, this is all types except for 'access'.
This may apply filtering at the kernel level when possible, which can be more efficient, but may be more confusing when reading the logs.
Choices:
access,create,remove,rename,modify,metadataDefault:
create,remove,rename,modify,metadata--no-meta— Don't emit fs events for metadata changesThis is a shorthand for '--fs-events create,remove,rename,modify'. Using it alongside the '--fs-events' option is non-sensical and not allowed.
Output
-c --clear [MODE]— Clear the screen before each runIf the default
clearmode leaves output behind, use--clear=reset. Because the mode is optional,mise watch --clear buildreadsbuildas the mode: put--clearafter the task name, as inmise watch build --clear, or write the mode with=.Choices:
clear,reset--only-emit-events— Only emit events to stdout, run no commands.This is a convenience option for using Watchexec as a file watcher, without running any commands. It is almost equivalent to using
catas the command, except that it will not spawn a new process for each event.This option requires
--emit-events-toto be set, and restricts the available modes tostdioandjson-stdio, modifying their behaviour to write to stdout instead of the stdin of the command.-N --notify— Alert when commands start and endWith this, Watchexec will emit a desktop notification when a command starts and ends, on supported platforms. On unsupported platforms, it may silently do nothing, or log a warning.
--color <MODE>— When to use terminal coloursSetting the environment variable
NO_COLORto any value is equivalent to--color=never.Choices:
auto,always,neverDefault:
auto--timings— Print how long the command took to runThis may not be exactly accurate, as it includes some overhead from Watchexec itself. Use the
timeutility, high-precision timers, or benchmarking tools for more accurate results.--watchexec-quiet— Don't print starting and stopping messagesBy default Watchexec will print a message when the command starts and stops. This option disables this behaviour, so only the command's output, warnings, and errors will be printed.
This is watchexec's '--quiet'. In mise, '-q'/'--quiet' quiets mise's own messages, as it does for every other command.
--bell— Ring the terminal bell on command completion
Command
--shell <SHELL>— Use a different shellBy default, Watchexec will use '$SHELL' if it's defined or a default of 'sh' on Unix-likes, and either 'pwsh', 'powershell', or 'cmd' (CMD.EXE) on Windows, depending on what Watchexec detects is the running shell.
With this option, you can override that and use a different shell, for example one with more features or one which has your custom aliases and functions.
If the value has spaces, it is parsed as a command line, and the first word used as the shell program, with the rest as arguments to the shell.
The command is run with the '-c' flag (except for 'cmd' on Windows, where it's '/C').
The special value 'none' can be used to disable shell use entirely. In that case, the command provided to Watchexec will be parsed, with the first word being the executable and the rest being the arguments, and executed directly. Note that this parsing is rudimentary, and may not work as expected in all cases.
Using 'none' is a little more efficient and can enable a stricter interpretation of the input, but it also means that you can't use shell features like globbing, redirection, control flow, logic, or pipes.
Examples:
Use without shell:
$ watchexec -n -- zsh -x -o shwordsplit scr
Use with powershell core:
$ watchexec --shell=pwsh -- Test-Connection localhost
Use with CMD.exe:
$ watchexec --shell=cmd -- dir
Use with a different unix shell:
$ watchexec --shell=bash -- 'echo $BASH_VERSION'
Use with a unix shell and options:
$ watchexec --shell='zsh -x -o shwordsplit' -- scr
-n— Shorthand for '--shell=none'--emit-events-to <MODE>— Configure event emissionWatchexec can emit event information when running a command, which can be used by the child process to target specific changed files.
One thing to take care with is assuming inherent behaviour where there is only chance. Notably, it could appear as if the
RENAMEDvariable contains both the original and the new path being renamed. In previous versions, it would even appear on some platforms as if the original always came before the new. However, none of this was true. It's impossible to reliably and portably know which changed path is the old or new, "half" renames may appear (only the original, only the new), "unknown" renames may appear (change was a rename, but whether it was the old or new isn't known), rename events might split across two debouncing boundaries, and so on.This option controls where that information is emitted. It defaults to 'none', which doesn't emit event information at all. The other options are 'environment' (deprecated), 'stdio', 'file', 'json-stdio', and 'json-file'.
The 'stdio' and 'file' modes are text-based: 'stdio' writes absolute paths to the stdin of the command, one per line, each prefixed with
create:,remove:,rename:,modify:, orother:, then closes the handle; 'file' writes the same thing to a temporary file, and its path is given with the $WATCHEXEC_EVENTS_FILE environment variable.There are also two JSON modes, which are based on JSON objects and can represent the full set of events Watchexec handles. Here's an example of a folder being created on Linux:
json{ "tags": [ { "kind": "path", "absolute": "/home/user/your/new-folder", "filetype": "dir" }, { "kind": "fs", "simple": "create", "full": "Create(Folder)" }, { "kind": "source", "source": "filesystem" } ], "metadata": { "notify-backend": "inotify" } }The fields are as follows:
tags, structured event data.tags[].kind, which can be:- 'path', along with:
absolute, an absolute path.filetype, a file type if known ('dir', 'file', 'symlink', 'other').
- 'fs':
simple, the "simple" event type ('access', 'create', 'modify', 'remove', or 'other').full, the "full" event type, which is too complex to fully describe here, but looks like 'General(Precise(Specific))'.
- 'source', along with:
source, the source of the event ('filesystem', 'keyboard', 'mouse', 'os', 'time', 'internal').
- 'keyboard', along with:
keycode. Currently only the value 'eof' is supported.
- 'process', for events caused by processes:
pid, the process ID.
- 'signal', for signals sent to Watchexec:
signal, the normalised signal name ('hangup', 'interrupt', 'quit', 'terminate', 'user1', 'user2').
- 'completion', for when a command ends:
disposition, the exit disposition ('success', 'error', 'signal', 'stop', 'exception', 'continued').code, the exit, signal, stop, or exception code.
- 'path', along with:
metadata, additional information about the event.
The 'json-stdio' mode will emit JSON events to the standard input of the command, one per line, then close stdin. The 'json-file' mode will create a temporary file, write the events to it, and provide the path to the file with the $WATCHEXEC_EVENTS_FILE environment variable.
Finally, the 'environment' mode was the default until 2.0. It sets environment variables with the paths of the affected files, for filesystem events:
$WATCHEXEC_COMMON_PATH is set to the longest common path of all of the below variables, and so should be prepended to each path to obtain the full/real path. Then:
- $WATCHEXEC_CREATED_PATH is set when files/folders were created
- $WATCHEXEC_REMOVED_PATH is set when files/folders were removed
- $WATCHEXEC_RENAMED_PATH is set when files/folders were renamed
- $WATCHEXEC_WRITTEN_PATH is set when files/folders were modified
- $WATCHEXEC_META_CHANGED_PATH is set when files/folders' metadata were modified
- $WATCHEXEC_OTHERWISE_CHANGED_PATH is set for every other kind of pathed event
Multiple paths are separated by the system path separator, ';' on Windows and ':' on unix. Within each variable, paths are deduplicated and sorted in binary order (i.e. neither Unicode nor locale aware).
This is the legacy mode, is deprecated, and will be removed in the future. The environment is a very restricted space, while also limited in what it can usefully represent. Large numbers of files will either cause the environment to be truncated, or may error or crash the process entirely. The $WATCHEXEC_COMMON_PATH is also unintuitive, as demonstrated by the multiple confused queries that have landed in my inbox over the years.
Choices:
environment,stdio,file,json-stdio,json-file,noneDefault:
none--watchexec-env <KEY=VALUE>— Add env vars to the commandThis is a convenience option for setting environment variables for the command, without setting them for the Watchexec process itself.
Use key=value syntax. Multiple variables can be set by repeating the option.
This is watchexec's '--env'. In mise, '-E'/'--env' selects the mise environment (
mise.<ENV>.toml), as it does for every other command.--wrap-process <MODE>— How to wrap the task process: group, session, or noneBy default watchexec uses a session on macOS, a process group on other Unix systems, and a Job Object on Windows. Some programs need a session, and some do not work in a process group;
noneruns the command directly. On Windows,groupandsessionboth use a Job Object.Choices:
group,session,none
Debugging
--print-events— Print the events that trigger each runUse it to check which files
--watch,--filter, and the tasks'sourcesare reacting to.--manual— Show the manual pageThis shows the manual page for Watchexec, if the output is a terminal and the 'man' program is available. If not, the manual page is printed to stdout in ROFF format (suitable for writing to a watchexec.1 file).
Examples
Run build and rerun it whenever its sources change
mise watch buildClear the screen before each run
mise watch build --clearStart an API server and restart it when Rust files in ./src change
mise watch serve --watch src --exts rs --restartPass arguments after -- to the task
mise watch test -- --verbose