# run installation
go install github.com/pt-main/run/cmd/run@latest
# tal installation
go install github.com/pt-main/run/cmd/tal@latestrun is a tool for managing scripts, scripting any scenario in a built‑in Lua‑like language with incrementality, storing scripts in a global/local repository, full system and platform independence (runs anywhere Go compiles), and built‑in script distribution methods, e.g., via GitHub.
The project includes Task Lua (tal) – a task runner seamlessly integrated into run. For more details, see the README.
| Problem | run solves |
|---|---|
| Scripts scattered across projects | Global storage ~/run/ |
| Need to remember paths | One command: run -r myscript |
| Different languages | Supports Python, Bash, Batch, Lua – and easily extensible |
| Grouping | Tags for selective execution (--tagged) |
| Project scripts | Local mode with .run/ in the current folder |
| Security | TYCL config with a strict contract |
| Compactness | Small binary with full platform independence |
run gives globality, simplicity, and control without unnecessary complexity.
Why Tal?
| Problem | tal solves |
|---|---|
| Makefiles are hard to read and write | Simple DSL with comments and Lua instead of Shell |
| Incremental builds are flaky | SHA256 hashes instead of modification times |
| No way to call tasks from each other | Built‑in function to invoke tasks |
| File dependencies are verbose | Works out of the box |
tal gives incrementality, modernity, and Lua – all in one tool.
Download the release for your OS/architecture and place it in your PATH:
# Linux/macOS
chmod +x run-linux-amd64
sudo mv run-linux-amd64 /usr/local/bin/run
# Windows
# Just put run-windows-amd64.exe in a folder that's in your PATHgo install github.com/pt-main/run@latestOn first run, run will create the structure in ~/run/:
config.tycl– configuration with the script list.scripts/– Lua wrappers for execution.base/– original script files.
run [--<lm/localmode>/--<gm/globalmode>] <cmd> <args...>| Command | Description | Example |
|---|---|---|
-add <path> <name> [docs] |
Add a script (supports .py, .sh, .bat, .lua) |
run -add script.py mypy |
-remove <name> |
Remove a script | run -remove mypy |
-list |
List scripts | run -list |
-r <name> [args...] |
Run a script | run -r mypy arg1 arg2 |
<name> [args...] |
Run a script (if the name doesn't conflict with a command) | run mypy arg1 |
-tag <name> <tags...> |
Add tags | run -tag mypy deploy prod |
-rm-tag <name> <tags...> |
Remove tags | run -rm-tag mypy prod |
-localmode [true/false] |
Enable/disable local mode, show current state | run -localmode true |
-r --tagged="tag1;tag2;..." |
Run scripts with any of the tags | run -r --tagged="deploy;test" |
-r --tagged="..." --parallel |
Run scripts with the given tag in parallel | run -r --tagged="deploy;build" --parallel |
-r --tagged="..." --args="" |
Pass arguments to the script (useful to avoid conflicts, e.g., with run flags, or to not pass arguments) | run -r --tagged="deploy;build" --args="--tagged dev", run -r --tagged="deploy;build" --parallel --args – passes no arguments, instead of passing --parallel |
-version |
Show version | run -version |
--no_color – disables coloured output for the session.
--forcewith-add– replaces an existing script with the same name.--tagged="tag1;tag2"with-r– run by tags.--ll / --localmode / --gm / --globalmoderight afterrun– run in local/global mode, restores the mode set byrun -localmodeafter completion.
By default, run works globally (config in ~/run/).
Enable local mode – and run will use .run/ in the current folder:
run -localmode true # enable
run -localmode false # disable
run -localmode # false – shows the current stateThis is useful for projects: scripts live in the repository and don't interfere with the global config.
run automatically generates Lua wrappers that call the original scripts with the passed arguments.
| Extension | Language | Notes |
|---|---|---|
.py |
Python | Looks for python3, then python |
.sh |
Bash | Executes via bash |
.bat |
Batch | Executes via cmd /c |
.lua |
Lua | Executes directly (no wrapper) |
.task.lua |
Task Lua (Tal) | Executes via run tal run |
~/run/
├── config.tycl # TYCL config (strict contract)
├── scripts/ # Lua wrappers for execution
│ └── myscript.lua
└── base/ # Original scripts
└── myscript.py
The script configuration is built on Tycl – a typed language with a contract concept (fixed configuration formats).
The config contract:
strict {
scripts: objects = strict {
name: string, // Script name (command)
script: string, // Wrapper file name (matches the Lua script name inside run/scripts, without extension)
description: string, // Description
tags: strings, // Tags
ext: string, // Extension (.py, .sh, .bat, .lua)
},
}
The config is auto‑filled by the run CLI. After the first run it looks like this:
{
scripts: objects = [
{
name: string = "test",
script: string = "test",
description: string = "[?BBK]Simple script for functions test[?RT]",
ext: string = "",
tags: strings = ["__test"],
}
],
}
Each wrapper is a Lua script that provides:
script_path(name)– path to the original script.get_arg(idx)– get an argument by index.get_args()– table of all arguments.run_script(name, ...)– run another script from the wrapper.run_script_parallel(name, ...)– runs the specified script asynchronously in a background thread. Does not block the current script execution. All arguments after the name are passed to the called script.wait()– waits for all background scripts started viarun_script_parallelto finish. It is recommended to call this after starting parallel tasks to ensure they complete before the main script exits.
Example:
run_script_parallel("build", "--release")
run_script_parallel("test")
wait() -- wait for build and tests to finishrun -add ~/projects/tools/deploy.py deploy "Deploy to production"
run -list
# ╭─────── Scripts
# ⎬─ deploy (.py):
# │ Deploy to production
# ╰───────run -r deploy --env=prod
# or
run deploy --env=prod # when the script name doesn't conflict with run commandsrun -tag deploy prod utils
run -r --tagged="prod" # runs all scripts with the prod tagcd ~/myproject
run -localmode true
run -add script.py build
# now the script is saved in .run/or
run --localmode add script.py buildImportant: the --localmode flag must appear right after run to work correctly.
By Pt, 2026 – written using lc, tap, pack, tycl.