DEV Community

Cover image for I built a GitHub Action that works with any stack — here's how
rexrun
rexrun

Posted on

I built a GitHub Action that works with any stack — here's how

The problem

Every time I clone a repo, I have to figure out how to run it.

  • Go project? go test ./... — unless it uses make test
  • Node project? npm test — unless it uses pnpm or yarn or bun
  • Rust? cargo test. Python? Could be pytest, python -m unittest, or poetry run pytest.

This is fine for my own projects. But when I'm reviewing a PR, onboarding a new teammate, or setting up CI for a polyglot team, it becomes noise.

What I built

rex is a single Go binary that detects your project's stack and runs the right command. No config file. No reading the README.

git clone https://github.com/someone/unknown-project
cd unknown-project
rex test   # it just works
Enter fullscreen mode Exit fullscreen mode

How it works under the hood

The detection logic is surprisingly simple — and that's the point.

Step 1: File scanning

rex walks your project root and looks for known files:

File Stack Package manager
go.mod Go go modules
package.json + pnpm-lock.yaml Node pnpm
Cargo.toml Rust cargo
pyproject.toml + uv.lock Python uv
pom.xml Java Maven
build.gradle Java Gradle
Gemfile Ruby bundler
composer.json PHP composer
mix.exs Elixir mix
build.zig Zig zig

This happens in <50ms because it's just os.Stat calls — no network, no parsing heavy files.

Step 2: Command mapping

Once the stack is known, rex maps standard verbs to the right tool:

// Go
test  -> "go test ./..."
run   -> "go run ./cmd/server"
build -> "go build ./..."

// Node (pnpm)
test  -> "pnpm test"
run   -> "pnpm run dev"
build -> "pnpm run build"
Enter fullscreen mode Exit fullscreen mode

Step 3: Priority chain (the smart part)

rex doesn't blindly guess. It respects what's already there:

1. Justfile / Makefile (task runner overrides everything)
2. package.json scripts / Cargo.toml / go.mod (ecosystem native)
3. Language heuristics (fallback)
Enter fullscreen mode Exit fullscreen mode

If a Makefile defines a test target, rex test runs make test — even in a Go project.

The GitHub Action

The most interesting part is how this became a GitHub Action.

Instead of requiring Go to be installed in the runner, the action downloads the correct binary directly from the release page:

- uses: rexrun-dev/rex@v0.4.0
  with:
    command: test
Enter fullscreen mode Exit fullscreen mode

This single step replaces 10+ lines of stack-specific YAML. Works for all 12 supported languages.

Why composite actions?

I used GitHub's composite action type instead of Docker. Why?

  • Faster: no container startup
  • Smaller: no image to pull
  • Portable: works on any runner (ubuntu, macOS, Windows)

The trade-off? The install script has to handle OS/arch detection:

OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
case "$ARCH" in
  x86_64) ARCH="amd64" ;;
  aarch64|arm64) ARCH="arm64" ;;
esac
URL="https://github.com/rexrun-dev/rex/releases/download/${VERSION}/rex_${VERSION#v}_${OS}_${ARCH}.tar.gz"
curl -sL "$URL" | tar xz -C /usr/local/bin rex
Enter fullscreen mode Exit fullscreen mode

Watch mode

A recent addition: rex watch polls the filesystem and re-runs your command on change.

rex watch test   # re-run tests when files change
rex watch build  # re-build on change
Enter fullscreen mode Exit fullscreen mode

It's not using inotify or fsnotify — just a lightweight polling loop with hash-based change detection. This makes it portable across all platforms without CGO or platform-specific dependencies.

CI generator

rex ci generates a GitHub Actions workflow file customized for your detected stack:

$ rex ci
✓ created .github/workflows/ci.yml (go project)
Enter fullscreen mode Exit fullscreen mode

The generated YAML uses the official setup actions for each language (setup-go, setup-node, setup-python, etc.) and runs the correct test command.

Numbers

  • Binary size: ~3.5 MB
  • Startup time: <50ms
  • Languages supported: 12
  • Lines of Go: ~2,000
  • Zero runtime dependencies

Try it

brew tap rexrun-dev/tap && brew install rex
# or
go install rexrun.dev/rex/cmd/rex@latest
Enter fullscreen mode Exit fullscreen mode

Or try the interactive playground at rexrun.dev — paste any GitHub repo URL and see what rex would detect.


GitHub: github.com/rexrun-dev/rex
Marketplace: github.com/marketplace/actions/rex-universal-project-runner

Top comments (0)