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 script manager that lets you add, remove, and run scripts in various languages with a single command. Scripts are stored in ~/run/ and are accessible from any folder.
The project bundles Task Lua (tal) – a task runner seamlessly integrated into run. See the project's README for more details.
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‑specific scripts |
Local mode with .run/ in the current folder |
| Security |
TYCL config with a strict contract |
| Compactness |
Small binary, fully cross‑platform |
run gives you 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 |
| Incrementality is broken |
SHA256 hashes instead of modification times |
| No way to call tasks from each other |
Tasks can be called via built‑in functions |
| File dependencies are cumbersome |
Works out of the box |
tal gives you incrementality, modernity, and Lua – all in one tool.
Installation
As a binary
Download the release for your OS/architecture and put 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 is 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 – config 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 does not conflict with a run 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 given 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 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 |
Flags
--force with -add – overwrite an existing script with the same name.
--tagged="tag1;tag2" with -r – run by tags.
--ll / --localmode / --gm / --globalmode immediately after run – run in local/global mode, restoring 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 # shows current state (e.g., false)
This is convenient for projects: scripts stay in the repository and do not interfere with the global config.
Language support
run automatically generates Lua wrappers that call the original scripts with the passed arguments.
| Extension |
Language |
Note |
.py |
Python |
Looks for python3, then python |
.sh |
Bash |
Executes via bash |
.bat |
Batch |
Executes via cmd /c |
.lua |
Lua |
Executed 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 the concept of contracts (fixed configuration schemas).
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 automatically populated by the run CLI. After the first run, it looks like:
{
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 inside the wrapper.
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 does not conflict with run commands
run -tag deploy prod utils
run -r --tagged="prod" # runs all scripts with the tag prod
Local mode
cd ~/myproject
run -localmode true
run -add script.py build
# now the script will be saved in .run/
or
run --localmode add script.py build
Important: the --localmode flag must appear immediately after run to work correctly.
By Pt, 2026 – written using lc, tap, pack, tycl.