Built in Rust for developers who live in multiple runtimes.
run
gives you a consistent CLI, persistent REPLs, and batteries-included examples for your favorite languages.
Table of contents
- Website and Docs
- Overview
- Highlights
- Quickstart
- Installation
- How it works
- Supported languages
- Command Variations - Flexible Syntax
- Command-Line Flags Reference
- ⚠️ When to Use --lang (Important!)
- Main Function Flexibility
- Examples
- REPL
- Stdin Piping Examples
- Language-Specific Notes
Website and Docs
The official website and full documentation are available here:
- Website: https://run.esubalew.et/
- Docs Overview: https://run.esubalew.et/docs/overview
Use these links to explore features, language guides, and detailed examples.
Overview - Universal Multi-Language Runner
A powerful command-line tool for executing code in 25 programming languages
What is run?
run is a universal multi-language runner and smart REPL (Read-Eval-Print Loop) written in Rust. It provides a unified interface for executing code across 25 programming languages without the hassle of managing multiple compilers, interpreters, or build tools.
Whether you're a beginner learning your first programming language or an experienced polyglot developer, run streamlines your workflow by providing consistent commands and behavior across all supported languages.
Who is this for?
• Beginners: Learn programming without worrying about complex setup procedures. Just install run and start coding in any language.
• Students: Quickly test code snippets and experiment with different programming paradigms across multiple languages.
• Developers: Prototype ideas rapidly, test algorithms, and switch between languages seamlessly without context switching.
• DevOps Engineers: Write and test automation scripts in various languages from a single tool.
• Educators: Teach programming concepts across multiple languages with a consistent interface.
Why was run created?
Traditional development workflows require installing and configuring separate tools for each programming language. This creates several problems:
• Time-consuming setup: Installing compilers, interpreters, package managers, and configuring environments for each language.
• Inconsistent interfaces: Each language has different commands and flags for compilation and execution.
• Cognitive overhead: Remembering different commands and workflows for each language.
• Barrier to entry: Beginners struggle with setup before writing their first line of code.
run solves these problems by providing a single, unified interface that handles all the complexity behind the scenes. You focus on writing code, and run takes care of the rest.
Why Rust?
run is built with Rust for several compelling reasons:
• Performance: Rust's zero-cost abstractions and efficient memory management ensure run starts instantly and executes with minimal overhead.
• Reliability: Rust's strong type system and ownership model prevent common bugs like null pointer dereferences and data races, making run stable and crash-resistant.
• Cross-platform: Rust compiles to native code for Windows, macOS, and Linux, providing consistent behavior across all platforms.
• Memory safety: No garbage collector means predictable performance without unexpected pauses.
• Modern tooling: Cargo (Rust's package manager) makes building and distributing run straightforward.
• Future-proof: Rust's growing ecosystem and industry adoption ensure long-term maintainability.
Quickstart
# Show build metadata for the current binary
run --version
# Execute a snippet explicitly
run --lang python --code "print('hello, polyglot world!')"
# Let run detect language from the file extension
run examples/go/hello/main.go
# Drop into the interactive REPL (type :help inside)
run
# Pipe stdin (here: JSON) into Node.js
echo '{"name":"Ada"}' | run js --code "const data = JSON.parse(require('fs').readFileSync(0, 'utf8')); console.log(`hi ${data.name}`)"
# Pipe stdin into Python
echo "Hello from stdin" | run python --code "import sys; print(sys.stdin.read().strip().upper())"
# Pipe stdin into Go
echo "world" | run go --code 'import "fmt"; import "bufio"; import "os"; scanner := bufio.NewScanner(os.Stdin); scanner.Scan(); fmt.Printf("Hello, %s!\n", scanner.Text())'
Installation
All release assets are published on the GitHub Releases page, including macOS builds for both Apple Silicon (arm64) and Intel (x86_64). Pick the method that fits your platform:
Installing run is straightforward. Choose the method that works best for your system:
Cargo (Rust)
cargo install run-kit
> Installs the run
binary from the run-kit
crate. Updating? Run cargo install run-kit --force
.
# Or build from source
git clone https://github.com/Esubaalew/run.git
cd run
cargo install --path .
> This builds the run binary using your active Rust toolchain. The project targets Rust 1.70 or newer.
Homebrew (macOS)
brew install --formula https://github.com/Esubaalew/run/releases/latest/download/homebrew-run.rb
> This formula is published as a standalone file on each release; it isn’t part of the default Homebrew taps. Installing by name (brew install homebrew-run
) will fail—always point Homebrew to the release URL above (or download the file and run brew install ./homebrew-run.rb
).
Once the latest release artifacts are published, Homebrew automatically selects the correct macOS binary for your CPU (Intel or Apple Silicon) based on this formula.
Debian / Ubuntu
ARCH=${ARCH:-amd64}
DEB_FILE=$(curl -s https://api.github.com/repos/Esubaalew/run/releases/latest \
| grep -oE "run_[0-9.]+_${ARCH}\\.deb" | head -n 1)
curl -LO "https://github.com/Esubaalew/run/releases/latest/download/${DEB_FILE}"
curl -LO "https://github.com/Esubaalew/run/releases/latest/download/${DEB_FILE}.sha256"
sha256sum --check "${DEB_FILE}.sha256"
sudo apt install "./${DEB_FILE}"
> Tip: If you prefer to select the files manually, open the latest release page, note the .deb
and matching .sha256
asset names for your architecture (e.g., amd64
, arm64
), and substitute them for ${DEB_FILE}
above.
Windows (Scoop)
scoop install https://github.com/Esubaalew/run/releases/latest/download/run-scoop.json
Install script (macOS / Linux)
curl -fsSLO https://raw.githubusercontent.com/Esubaalew/run/master/scripts/install.sh
chmod +x install.sh
./install.sh --add-path # optional: append ~/.local/bin to PATH
Pass --version v0.2.0
, --prefix /usr/local/bin
, or --repo yourname/run
to customize the install.
Download the archive directly
- Grab the
tar.gz
(macOS/Linux) orzip
(Windows) from the latest release. - Extract it and copy
run
/run.exe
onto yourPATH
. - Optionally execute the bundled
install.sh
to handle the copy for you.
Build from source
cargo install run-kit
The project targets Rust 1.70+. Installing from crates.io gives you the same run
binary that CI publishes; use --force
when upgrading to a newer release.
Verify installation:
# Verify installation
run --version
Output:
run 0.2.0
How it works
run
shells out to real toolchains under the hood. Each LanguageEngine
implements a small trait that knows how to:
- Detect whether the toolchain is available (e.g.
python3
,go
,rustc
). - Prepare a temporary workspace (compilation for compiled languages, transient scripts for interpreters).
- Execute snippets, files, or stdin streams and surface stdout/stderr consistently.
- Manage session state for the interactive REPL (persistent modules, stateful scripts, or regenerated translation units).
This architecture keeps the core lightweight while making it easy to add new runtimes or swap implementations.
Supported languages
run
supports 25+ languages:
run supports 25 programming languages out of the box, covering a wide range of paradigms and use cases:
# Scripting Languages
Python, JavaScript, Ruby, Bash, Lua, Perl, PHP
# Compiled Languages
Rust, Go, C, C++, Java, C#, Swift, Kotlin, Crystal, Zig, Nim
# Typed & Functional Languages
TypeScript, Haskell, Elixir, Julia
# Specialized Languages
R (Statistical computing)
Dart (Mobile development)
Category | Languages & aliases | Toolchain expectations |
---|---|---|
Scripting & shells | Bash (bash ), Python (py , python ), Ruby (rb , ruby ), PHP (php ), Perl (perl ), Groovy (groovy , grv ), Lua (lua ), R (r ), Elixir (ex , elixir ) |
Matching interpreter on PATH
|
Web & typed scripting | JavaScript (js , node ), TypeScript (ts , deno ), Dart (dart ), Kotlin (kt , kotlin ) |
node , deno , dart , kotlinc + JRE |
Systems & compiled | C (c ), C++ (cpp , cxx ), Rust (rs , rust ), Go (go ), Swift (swift ), Zig (zig ), Nim (nim ), Haskell (hs , haskell ), Crystal (cr , crystal ), C# (cs , csharp ), Java (java ), Julia (jl , julia ) |
Respective compiler / toolchain |
Categorization notes
The categories above are usage-based to match how you’ll likely run code with run
rather than strict language taxonomies. Examples:
- Kotlin can target the JVM, Native, or JavaScript. If you’re using Kotlin/JS, it behaves closer to the “Web & typed scripting” workflow, while Kotlin/JVM fits “Systems & compiled” (with a JRE).
- Swift is listed under “Systems & compiled” because
swiftc
produces native binaries; however, you can still use it interactively viarun
for scripting-like workflows. - TypeScript typically runs via Node or Deno at runtime (transpiled), which is why it appears under “Web & typed scripting.”
These groupings optimize for how commands are invoked and which toolchains run
detects and orchestrates.
Complete Language Aliases Reference
Every language in run
has multiple aliases for convenience. Use whichever feels most natural:
Alias | Description |
---|---|
python, py, py3, python3 |
Python programming language |
javascript, js, node, nodejs |
JavaScript (Node.js runtime) |
typescript, ts, ts-node, deno |
TypeScript with type checking |
rust, rs |
Rust systems programming language |
go, golang |
Go programming language |
c, gcc, clang |
C programming language |
cpp, c++, g++ |
C++ programming language |
java |
Java programming language |
csharp, cs, dotnet |
C# (.NET) |
ruby, rb, irb |
Ruby programming language |
bash, sh, shell, zsh |
Bash shell scripting |
lua, luajit |
Lua scripting language |
perl, pl |
Perl programming language |
groovy, grv, groovysh |
Groovy on the JVM |
php, php-cli |
PHP scripting language |
haskell, hs, ghci |
Haskell functional language |
elixir, ex, exs, iex |
Elixir functional language |
julia, jl |
Julia scientific computing |
dart, dartlang, flutter |
Dart language (Flutter) |
swift, swiftlang |
Swift programming language |
kotlin, kt, kts |
Kotlin (JVM/Native) |
r, rscript, cran |
R statistical computing |
crystal, cr, crystal-lang |
Crystal language |
zig, ziglang |
Zig systems language |
nim, nimlang |
Nim programming language |
Command Variations - Flexible Syntax
run supports multiple command formats to fit your workflow. You can be explicit with --lang or let run auto-detect the language:
- Full syntax with --lang and --code
run --lang rust --code "fn main() { println!(\"hello from rust\"); }"
Output:
hello from rust
- Shorthand flags (-l for --lang, -c for --code)
run -l rust -c "fn main() { println!(\"hello from rust\"); }"
- Omit --code flag (auto-detected)
run --code "fn main() { println!(\"hello from rust\"); }"
Output:
hello from rust
- Shorthand - just the code
run "fn main() { println!(\"hello from rust\"); }"
Output:
hello from rust
- Language first, then code
run rust "fn main() { println!(\"hello from rust\"); }"
Output:
hello from rust
Command-Line Flags Reference
run provides both long-form and short-form flags for convenience:
# Language specification
--lang, -l Specify the programming language
run --lang python "print('hello')"
run -l python "print('hello')"
# Code input
--code, -c Provide code as a string
run --code "print('hello')"
run -c "print('hello')"
# Combined usage
run -l python -c "print('hello')"
run --lang python --code "print('hello')"
⚠️ When to Use --lang (Important!)
While run can auto-detect languages, ambiguous syntax can cause confusion. For example, print('hello') looks similar in Python, Ruby, Lua, and other languages. Always use --lang for correctness when the syntax is ambiguous or when you need deterministic behavior.
# ❌ Ambiguous - may choose wrong language
run "print('hello')"
Output:
hello # But which language was used?
# ✅ Explicit - always correct
run --lang python "print('hello')"
Output:
hello # Guaranteed to use Python
RECOMMENDATION: Always use --lang for correctness when:
• The syntax is ambiguous across multiple languages
• You want to ensure the exact language is used
• You're writing scripts or automation that must be deterministic
Main Function Flexibility
For compiled languages (Rust, Go, C, C++, Java, etc.), run is smart about main functions:
• Write complete programs with main functions
• Write code without main functions (run wraps it automatically)
• Both approaches work in REPL mode and inline execution
Go Example - With main function
$ run go
run universal REPL. Type :help for commands.
go>>> package main
import "fmt"
func main() {
fmt.Println("Hello, world!")
}
Hello, world!
Go Example - Without main function
go>>> fmt.Println("Hello, world!")
Hello, world!
Examples
Real programs live under the examples/
tree—each language has a hello
and a progress
scenario. The headers document expected output so you can diff your toolchain.
run examples/rust/hello.rs
run examples/typescript/progress.ts
run examples/python/counter.py
REPL
Being inside REPL we can use the ff commands
The REPL supports several built-in commands for managing your session:
Command | Purpose |
---|---|
:help |
List available meta commands |
:languages |
Show detected engines and status |
:lang <id> or :<alias>
|
Switch the active language (:py , :go , …) |
:detect on/off/toggle |
Control snippet language auto-detection |
:load path/to/file |
Execute a file inside the current session |
:reset |
Clear the accumulated session state |
:exit / :quit
|
Leave the REPL |
Alias | Description |
---|---|
:help |
Show available REPL commands |
:quit or :q |
Exit the REPL |
:clear or :c |
Clear the screen |
:reset |
Reset the session (clear all variables) |
:lang <language> |
Switch to a different language |
:py, :js, :go, etc. |
Quick language switch shortcuts |
Interactive REPL - Line by Line or Paste All
The REPL mode is incredibly flexible. You can:
• Type code line by line interactively
• Paste entire programs at once
• Mix both approaches in the same session
This works for ALL supported languages!
Python Example - Paste entire program
$ run python
python>>> def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
for i in range(10):
print(f"F({i}) = {fibonacci(i)}")
F(0) = 0
F(1) = 1
F(2) = 1
F(3) = 2
F(4) = 3
F(5) = 5
F(6) = 8
F(7) = 13
F(8) = 21
F(9) = 34
Python Example - Line by line
python>>> x = 10
python>>> y = 20
python>>> print(x + y)
30
Tip: The exact file names follow the pattern
run_<version>_<arch>.deb
. If you prefer to choose manually, visit the latest release page, note the.deb
and matching.sha256
asset names for your architecture (e.g.amd64
,arm64
), and substitute them for${DEB_FILE}
above.
In REPL mode, variables persist across commands within the same language session. You can also switch languages on the fly using :lang commands.
When you switch languages, variables from the previous language do NOT carry over (each language has its own isolated session).
Variable Persistence Example
$ run go
go>>> x := 10
go>>> x
10
go>>> :c
switched to c
c>>> int x = 10;
c>>> x
10
c>>> 10 + 10
20
c>>> :py
switched to python
python>>> y = 10
python>>> y
10
python>>> print(y)
10
python>>> z = 4
python>>> z is y
False
python>>> z == y
False
DEB*FILE=$(curl -s https://api.github.com/repos/Esubaalew/run/releases/latest \
| grep -oE 'run*[0-9.]+_amd64.deb' | head -n 1)
curl -LO "https://github.com/Esubaalew/run/releases/latest/download/${DEB_FILE}"
curl -LO "https://github.com/Esubaalew/run/releases/latest/download/${DEB_FILE}.sha256"
sha256sum --check "${DEB_FILE}.sha256"
sudo apt install "./${DEB_FILE}"
Built-in REPL Commands
:help → Show help and available commands
:languages → List all supported languages
:clear → Clear the screen
:exit or :quit → Exit the REPL
:lang <language> → Switch to a different language
Ctrl+D → Exit the REPL
Stdin Piping Examples
run
supports piping input from stdin to your code snippets across all languages. Here are more examples for different languages:
Node.js (JSON Processing)
echo '{"name":"Ada"}' | run js --code "const data = JSON.parse(require('fs').readFileSync(0, 'utf8')); console.log(`hi ${data.name}`)"
Output:
hi Ada
Python (Uppercase Conversion)
echo "Hello from stdin" | run python --code "import sys; print(sys.stdin.read().strip().upper())"
Output:
HELLO FROM STDIN
Go (Greeting)
echo "world" | run go --code 'import "fmt"; import "bufio"; import "os"; scanner := bufio.NewScanner(os.Stdin); scanner.Scan(); fmt.Printf("Hello, %s!\n", scanner.Text())'
Output:
Hello, world!
Ruby (Line Counting)
echo -e "line1\nline2\nline3" | run ruby --code "puts gets(nil).lines.count"
Output:
3
Bash (Echo with Prefix)
echo "input text" | run bash --code 'read line; echo "Processed: $line"'
Output:
Processed: input text
Language-Specific Notes
For detailed usage, quirks, and best practices for each language, visit the dedicated documentation:
- Python: Tips for scripting, data processing, and REPL persistence.
- JavaScript/Node.js: Async code, modules, and stdin handling.
- Rust: Compilation flags, error handling, and workspace management.
- Go: Package imports, build optimizations, and concurrency examples.
- C/C++: Compiler selection, linking, and multi-file support.
-
C++: Remember to include the standard headers your snippet depends on—
std::cout
and friends require#include <iostream>
. When in doubt, wrap the snippet in a minimalmain
for portability:
cat <<'EOF' | run cpp
#include <iostream>
int square(int x) { return x * x; }
int main() {
std::cout << square(7) << std::endl;
return 0;
}
EOF
Skipping the include or main
will lead to compiler errors such as use of undeclared identifier 'std'
.
-
C: Avoid piping code through the shell’s
printf
—it expands%d
,\n
, and friends beforerun
sees the source. Use quoted here-docs instead so the compiler gets the exact text you typed:
cat <<'EOF' | run c
#include <stdio.h>
int main() {
int value = 10;
printf("%d\n", value);
return 0;
}
EOF
- Java: Classpath management, JVM args, and enterprise patterns.
- TypeScript: Type checking, Deno vs Node, and transpilation.
-
Groovy: When piping code via here-docs, quote the delimiter (
<<'EOF'
) so the shell doesn’t expand$variables
before Groovy sees them. Example:
cat <<'EOF' | run groovy
def name = "Esubalew"
println "Hello, $name!"
EOF
Without quoting, shells like Bash erase the interpolation and Groovy prints Hello, !
.
-
TypeScript (Deno):
run
uses Deno for TypeScript execution. Deno requires explicit module specifiers and does not accept bare Node builtin names likefs
— use thenode:
prefix for Node builtins (for exampleimport fs from "node:fs"
). Also prefer a quoted here-doc for multi-line snippets to avoid shell interpolation/globbing issues. Example:
# here-doc (recommended)
cat <<'EOF' | run typescript
import fs from "node:fs";
console.log('[TypeScript] hello');
EOF
Safe inline (zsh):
run --lang typescript --code $'import fs from "node:fs";\nconsole.log("[TypeScript] hello");\n'
-
Dart: Inline
--code
snippets are written to a temporary.dart
file and executed withdart run
. However, shell quoting still matters — single quotes or unescaped characters will cause zsh to attempt globbing or parameter expansion. Use a quoted here-doc to avoid that problem. Example:
# here-doc (recommended)
cat <<'EOF' | run dart
void main() {
print('[Dart] hello');
}
EOF
Safe inline (zsh):
run --lang dart --code $'void main() { print("[Dart] hello"); }\n'
Top comments (0)