Watch files. Run commands. Stay in flow.
fyr runs a command every time you save a file, debounced, clean, and instant. No duplicate runs, no leftover processes, no noise.
- Tasks - save any watch+command pair by name and run it from anywhere with
fyr run <name> - Project config - drop a
fyr.tomlin your repo and commit your setup alongside your code - Language templates -
fyr init rust,fyr init go, and 14 more to get started in seconds - Zero-config mode - run
fyrwith no arguments and pick a task from an interactive menu - Quiet mode - strip fyr's output entirely so only your command speaks
macOS / Linux
curl -sSf https://raw.githubusercontent.com/opmr0/fyr/main/install.sh | shWindows (PowerShell)
iwr https://raw.githubusercontent.com/opmr0/fyr/main/install.ps1 -UseBasicParsing | iexVia cargo
cargo install fyrFrom source
cargo install --path .fyr -w src -r "cargo run"Every time you save a file inside src, fyr runs cargo run. That's it.
fyr -w <files or dirs> -r "<command>"fyr -w src -r "cargo run"
fyr -w src tests -r "cargo test"
fyr -w main.go -r "go run main.go"Tip: Always wrap your command in quotes so its flags go to your command, not to fyr.
Watch all files with a given extension, recursively from the current directory.
fyr -e rs -r "cargo run"
fyr -e js ts -r "node index.js"| Flag | Short | Description |
|---|---|---|
--watch |
-w |
Files or directories to watch |
--run |
-r |
Command to run on change |
--extensions |
-e |
Watch files by extension |
--debounce |
-d |
Debounce window in ms (default: 150) |
--quiet |
-q |
Suppress fyr's own log output |
--no-clear |
- | Don't clear the screen between runs |
Save a watch + command pair as a named task and run it from anywhere with one word.
fyr task add build -w src -r "cargo build --release"
fyr task add test -w src tests -r "cargo test"
fyr run build
fyr run testTasks are stored globally and available from any directory.
fyr task add <name> -w <paths> -r "<command>" # save a task
fyr task list # list all tasks
fyr task edit <name> -w <new paths> # update watch paths
fyr task edit <name> -r "<new command>" # update command
fyr task rename <name> <new_name> # rename a task
fyr task remove <name> # delete a task
fyr task default # set a default task in the global configYou can also provide -e / --extensions when adding or editing a task. You must provide -w, -e, or both.
Run a task with a different path or command without permanently changing it:
fyr run build -w src/main.rs
fyr run build -r "cargo build"| Flag | Short | Description |
|---|---|---|
--watch |
-w |
Override watch paths |
--run |
-r |
Override command |
--debounce |
-d |
Debounce window in ms |
--global |
-g |
Use global tasks even if fyr.toml exists |
--quiet |
-q |
Suppress fyr's own log output |
--no-clear |
- | Don't clear the screen between runs |
fyr looks for a fyr.toml in your current directory first. If found, tasks are loaded from it instead of your global tasks, useful for committing your fyr setup alongside your project.
fyr init # create a blank fyr.toml
fyr init rust # create one from a language templateSupported templates: Rust, C, C++, Go, Zig, Swift, Haskell, Node.js, Ruby, PHP, Lua, Elixir, Java, Kotlin, CSS/SCSS, Shell
default = "build"
[tasks.build]
watch = ["src"]
run = "cargo build --release"
[tasks.test]
watch = ["src", "tests"]
run = "cargo test"| Situation | What fyr loads |
|---|---|
fyr.toml exists in current dir |
Local tasks |
No fyr.toml |
Global tasks |
--global / -g flag |
Global tasks (always) |
Run fyr or fyr run with no arguments. If a fyr.toml exists, fyr loads it and either runs the default task immediately or shows an interactive picker.
fyr[fyr] loading tasks from 'fyr.toml'
[fyr] default task 'build', running it
[fyr] loading tasks from 'fyr.toml'
? which task do you want to run?
> build
test
lint
Use -g to skip fyr.toml and always load global tasks:
fyr --globalSuppresses fyr's own output and shows only your command's output. Works with fyr, fyr run, and fyr run <name>. Does not suppress errors or task management output.
fyr -w src -r "cargo run" -q
fyr run build -qEditors often write to disk multiple times on a single save. fyr waits 150ms after the last detected change before running, so you always get exactly one run per save, no matter how fast you type.
fyr -w src -r "cargo build" -d 500 # wait 500ms insteadBenchmarked on an Intel i7-9850H against the most popular file watchers.
| Tool | Startup | Idle Memory | Commands fired (50 rapid changes) |
|---|---|---|---|
| fyr | 219ms | 7.6 MB | 27/50 ¹ |
| watchexec | 238ms | 13.5 MB | 51/50 |
| chokidar | 501ms | 37.6 MB | 1/50 ² |
| nodemon | 528ms | 41.2 MB | 102/50 ³ |
Versions tested: fyr v1.0.0, watchexec v2.5.0, chokidar v3.6.0, nodemon v3.1.14
¹ Intentional, fyr debounces and kills stale runs, so rapid saves collapse into one clean run per burst. Adjust with -d.
² chokidar's debounce is too aggressive for rapid changes, causing it to miss most events.
³ nodemon fires duplicate events per change.
bash ./benchmark.sh # run it yourselfRequires watchexec, nodemon, or chokidar for comparison. The script auto-detects what's installed and skips the rest.
- fyr starts watching the paths you provide
- A file changes, fyr waits for the debounce window to pass
- If the previous command is still running, fyr kills it
- fyr runs your command fresh
Found a bug or have an idea? Open an issue or submit a pull request.
MIT - LICENSE
