run – Script Manager

go install github.com/pt-main/run@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.
Why run?
| Problem |
run solves |
| Scripts scattered across projects |
Global storage at ~/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 |
| Safety |
TYCL config with a strict contract |
| Compactness |
Small binary, fully platform-independent |
run gives globality, simplicity, and control without unnecessary complexity.
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 is in your PATH
Via go install
go install github.com/pt-main/run@latest
On first launch run will create the following structure in ~/run/:
config.tycl – configuration (TYCL) with the list of scripts.
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 all 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 that have any of the given tags |
run r --tagged="deploy;test" |
r --tagged="..." --parallel |
Run tagged scripts in parallel |
run r --tagged="deploy;build" --parallel |
r --tagged="..." --args="" |
Pass arguments to the script (use when you need to avoid conflicts with run flags, or to explicitly pass no 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 for that single command, restoring the previously set mode afterwards.
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 # prints current state (e.g., false)
This is convenient for projects: scripts live in the repository and do not interfere with the global config.
Language support
run automatically generates Lua wrappers that invoke the original scripts with the passed arguments.
| Extension |
Language |
Notes |
.py |
Python |
Looks for python3, then python |
.sh |
Bash |
Executes via bash |
.bat |
Batch (Windows) |
Executes via cmd /c |
.lua |
Lua |
Executed directly (no wrapper) |
Adding a new language is easy – just add a template in templates.go.
Project structure
~/run/
├── config.tycl # TYCL config (strict contract)
├── scripts/ # Lua wrappers for execution
│ └── myscript.lua
└── base/ # Original scripts
└── myscript.py
TYCL config
Script configuration is built on Tycl – a typed language with the concept of contracts (fixed config formats).
The config contract is:
strict {
scripts: objects = strict {
name: string, // Script name (command)
script: string, // Wrapper file name (matches the Lua script name in run/scripts, without extension)
description: string, // Description
tags: strings, // Tags
source: string, // Source path of the original script
ext: string, // Extension (.py, .sh, .bat, .lua)
},
}
The config is filled automatically by the run CLI. After first launch it looks like this:
{
scripts: objects = [
{
name: string = "test",
script: string = "test",
description: string = "[?BBK]Simple script for functions test[?RT]",
source: string = "",
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.
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.
License
Apache 2.0 – see LICENSE for details.
By Pt, 2026 – built with tap, tycl and lc.