Skip to content

Commit 739048e

Browse files
authored
feat(blog): add post introducing rnr task runner (#38)
1 parent 0b3a06b commit 739048e

2 files changed

Lines changed: 195 additions & 0 deletions

File tree

284 KB
Loading
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
---
2+
title: "Introducing rnr - A Zero-Dependency Task Runner"
3+
date: "2026-01-12T12:00:00-05:00"
4+
categories: [rust, oss, cli]
5+
description: "Meet rnr (pronounced 'runner') - a cross-platform task runner that lives inside your repo. Contributors clone and run, zero friction."
6+
---
7+
8+
Have you ever cloned a repository, ready to contribute, only to discover you need to install Node.js, Python, Make, or some other global dependency just to run the build? I have. Many times. And honestly, it's frustrating.
9+
10+
I wanted something simpler. Something where contributors could clone a repo and immediately run tasks without any setup. No "first, install this runtime" steps. No version mismatches. Just clone and go.
11+
12+
So I built **rnr** (pronounced "runner").
13+
14+
## What is rnr?
15+
16+
rnr is a cross-platform task runner with one key differentiator: **the binaries live inside your repository**. When a contributor clones your project, they already have everything they need to run your build tasks. Zero friction.
17+
18+
It's written in Rust, compiles to native binaries for all major platforms, and uses a simple YAML configuration file to define your tasks.
19+
20+
## The Problem
21+
22+
Most task runners require contributors to have something installed globally:
23+
24+
- **npm scripts** require Node.js
25+
- **Makefiles** require Make (and good luck on Windows)
26+
- **Just** requires installing just
27+
- **Task** requires installing task
28+
29+
For maintainers, this is fine. But for contributors—especially those making quick documentation fixes or small improvements—asking them to install a runtime just to run a build is a barrier.
30+
31+
## The Solution
32+
33+
With rnr, you initialize once as a maintainer:
34+
35+
```bash
36+
# Linux
37+
curl -fsSL https://github.com/CodingWithCalvin/rnr.cli/releases/latest/download/rnr-linux-amd64 -o rnr
38+
chmod +x rnr
39+
./rnr init
40+
41+
# macOS (Apple Silicon)
42+
curl -fsSL https://github.com/CodingWithCalvin/rnr.cli/releases/latest/download/rnr-macos-arm64 -o rnr
43+
chmod +x rnr
44+
./rnr init
45+
46+
# Windows (PowerShell)
47+
Invoke-WebRequest -Uri "https://github.com/CodingWithCalvin/rnr.cli/releases/latest/download/rnr-windows-amd64.exe" -OutFile "rnr.exe"
48+
.\rnr.exe init
49+
```
50+
51+
The `init` command presents an interactive selector where you choose which platforms your contributors might use:
52+
53+
```
54+
Which platforms should this project support?
55+
56+
[x] linux-amd64 (760 KB)
57+
[ ] macos-amd64 (662 KB)
58+
[x] macos-arm64 (608 KB) <- current
59+
[x] windows-amd64 (584 KB)
60+
[ ] windows-arm64 (528 KB)
61+
62+
Selected: 1.95 MB total
63+
```
64+
65+
Once you confirm, rnr downloads the appropriate binaries and sets up wrapper scripts. Here's what gets created:
66+
67+
```
68+
your-repo/
69+
├── .rnr/
70+
│ ├── config.yaml # Tracks configured platforms
71+
│ └── bin/ # Platform binaries (only selected ones)
72+
├── rnr # Unix wrapper script (auto-detects platform)
73+
├── rnr.cmd # Windows wrapper script
74+
└── rnr.yaml # Your task definitions
75+
```
76+
77+
The wrapper scripts automatically detect the current platform and architecture, then run the correct binary from `.rnr/bin/`. Commit all of this to your repo.
78+
79+
After that, contributors simply run:
80+
81+
```bash
82+
./rnr build # Run your build task
83+
./rnr test # Run your tests
84+
./rnr --list # See all available tasks
85+
```
86+
87+
That's it. No installation required on their end.
88+
89+
## Defining Tasks
90+
91+
Tasks are defined in an `rnr.yaml` file at the root of your repository. The syntax is intentionally simple.
92+
93+
**Simple one-liners:**
94+
95+
```yaml
96+
build: cargo build --release
97+
test: cargo test
98+
lint: cargo clippy
99+
```
100+
101+
**Full task definitions** with descriptions, working directories, and environment variables:
102+
103+
```yaml
104+
build:
105+
description: Build for production
106+
dir: src/backend
107+
env:
108+
NODE_ENV: production
109+
cmd: npm run build
110+
```
111+
112+
**Sequential steps** that reference other tasks:
113+
114+
```yaml
115+
ci:
116+
description: Run CI pipeline
117+
steps:
118+
- task: lint
119+
- task: test
120+
- task: build
121+
```
122+
123+
**Parallel execution** for speeding up independent operations:
124+
125+
```yaml
126+
build-all:
127+
description: Build all services
128+
steps:
129+
- cmd: echo "Starting builds..."
130+
- parallel:
131+
- task: build-api
132+
- task: build-web
133+
- cmd: echo "All done!"
134+
```
135+
136+
**Nested task files** for monorepos—subdirectories can have their own `rnr.yaml`:
137+
138+
```yaml
139+
# Root rnr.yaml
140+
api:build:
141+
dir: services/api
142+
task: build # Runs 'build' from services/api/rnr.yaml
143+
```
144+
145+
## Built-in Commands
146+
147+
rnr ships with a few built-in commands:
148+
149+
- `rnr <task>` — Execute a task from your `rnr.yaml`
150+
- `rnr init` — Initialize rnr in the current directory
151+
- `rnr upgrade` — Update to the latest rnr binaries
152+
- `rnr --list` — View all available tasks
153+
- `rnr --version` — Display the current version
154+
- `rnr --help` — Show help information
155+
156+
## Why Rust?
157+
158+
I chose Rust for a few reasons:
159+
160+
1. **Single binary** — No runtime dependencies, just a native executable
161+
2. **Cross-platform** — Compiles cleanly to Windows, macOS, and Linux
162+
3. **Performance** — Fast startup, minimal overhead
163+
4. **I wanted to learn more Rust** — Let's be honest, this was a big motivator
164+
165+
## Get Started
166+
167+
If you maintain an open source project and want to reduce friction for contributors, give rnr a try:
168+
169+
1. Download the binary for your platform from the [releases page](https://github.com/CodingWithCalvin/rnr.cli/releases)
170+
2. Run `./rnr init` and select your target platforms
171+
3. Create your `rnr.yaml` with your tasks
172+
4. Commit the binaries and config to your repo
173+
174+
Your contributors will thank you.
175+
176+
I'm already using rnr on a couple of my own projects—[dtvem.cli](https://github.com/CodingWithCalvin/dtvem.cli) and [rnr.cli itself](https://github.com/CodingWithCalvin/rnr.cli). Yes, rnr builds rnr. Dogfooding at its finest.
177+
178+
## What's Next?
179+
180+
This is v0.1.0, so there's plenty more I want to add:
181+
182+
- Task dependencies (`depends: [build, test]`)
183+
- Conditional execution (`if: ${{ env.CI }}`)
184+
- Watch mode (`watch: [src/**/*.rs]`)
185+
- Variable interpolation (`${{ vars.version }}`)
186+
- Caching and incremental builds
187+
- Interactive task picker
188+
189+
If any of these would be useful for your workflow, let me know—or better yet, open an issue on GitHub.
190+
191+
## It's Open Source
192+
193+
rnr is MIT licensed and available on GitHub at [CodingWithCalvin/rnr.cli](https://github.com/CodingWithCalvin/rnr.cli). If you find bugs, have feature requests, or want to contribute, PRs are absolutely welcome.
194+
195+
I'd love to hear what you think. Let me know if you try it out!

0 commit comments

Comments
 (0)