run — script and task manager

# run installation
go install github.com/pt-main/run/cmd/run@latest
# tal installation
go install github.com/pt-main/run/cmd/tal@latest
run 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.
Why run?
| 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.
| 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.
Installation
As a binary
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 PATH
Via go install
go install github.com/pt-main/run@latest
On 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.
Syntax
run [--<lm/localmode>/--<gm/globalmode>] <cmd> <args...>
Commands
| 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.
Flags
--force with -add – replaces an existing script with the same name.
--tagged="tag1;tag2" with -r – run by tags.
--ll / --localmode / --gm / --globalmode right after run – run in local/global mode, restores the mode set by run -localmode after completion.
Local mode
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 state
This is useful for projects: scripts live in the repository and don't interfere with the global config.
Language support
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 |
Project structure
~/run/
├── config.tycl # TYCL config (strict contract)
├── scripts/ # Lua wrappers for execution
│ └── myscript.lua
└── base/ # Original scripts
└── myscript.py
TYCL config
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"],
}
],
}
Built‑in Lua
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 via run_script_parallel to 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 finish
Examples
Adding a script
run -add ~/projects/tools/deploy.py deploy "Deploy to production"
run -list
# ╭─────── Scripts
# ⎬─ deploy (.py):
# │ Deploy to production
# ╰───────
Running
run -r deploy --env=prod
# or
run deploy --env=prod # when the script name doesn't conflict with run commands
run -tag deploy prod utils
run -r --tagged="prod" # runs all scripts with the prod tag
Local mode
cd ~/myproject
run -localmode true
run -add script.py build
# now the script is saved in .run/
or
run --localmode add script.py build
Important: the --localmode flag must appear right after run to work correctly.
By Pt, 2026 – written using lc, tap, pack, tycl.