In the DevOps world, internal tooling is not a luxury—it's a necessity. Whether you're deploying to Kubernetes, releasing software, or bootstrapping new services, custom scripts often bridge the gap between teams, tools, and infrastructure.

But let's face it: internal scripts tend to start as quick-and-dirty Bash hacks, and over time, they become unreadable, unmaintainable, and fragile. Sound familiar?

What if we could treat Bash like a real programming language, with structure, modules, versioning, and installable tools?

That’s where Mush comes in.


The State of Internal Tooling in DevOps

Almost every DevOps team builds their own tools. Here are some real-world examples:

Tool Name What It Does
deploy.sh Deploy a service with custom settings
release.sh Create a new release and update changelogs
check-env Verify if the developer machine has the required dependencies
onboard.sh Set up a new repo with templates and CI/CD
kube-wrapper Simplify Kubernetes commands across namespaces and clusters
git-policies Enforce Git commit rules and tag naming

These tools often grow from a one-liner in a README to a critical script used by the entire team—yet we rarely invest in making them maintainable.


Why Bash Scripts Get Ugly

  • No module system (copy-paste culture)
  • Zero discoverability (--help? What help?)
  • Hard to test
  • Impossible to version cleanly
  • No proper CLI structure or autocompletion
  • Unclear dependencies

What if we could fix all of that—without leaving Bash?


Meet Mush: Modular Shell Scripting

Mush is a lightweight ecosystem that gives your Bash scripts:

  • A clear project structure (src/, tests/, mush.yaml)
  • Modular architecture (module primitive to load other scripts)
  • Built-in CLI command dispatching
  • Automatic --help generation
  • Dependency management via Git
  • Easy install and distribution (mush build, mush install)

Think of it like Cargo for Shell.


A Real Example: Hello, Bash Tool

Let’s build a simple CLI tool using Mush.

mush new hello-bash
cd hello-bash

Create your main file:

# src/main.sh
main() {
  echo "Hello, Bash World!"
}

Your config file:

# Manifest.toml
name: hello
version: 0.1.0

Build and run:

mush build --release
./bin/hello

Result:

$ ./bin/hello
Hello, Bash World!

You now have a real executable, with structure, dispatch, and versioning—using only Bash.


Internal DevOps Tooling with Mush

Let’s imagine some real DevOps use cases:

1. A CLI to Standardize Deployments

# src/deploy.sh
module utils

devops::deploy() {
  env="$1"
  utils::banner "Deploying to $env..."
  kubectl apply -f k8s/$env.yaml
}
./devops deploy staging

Now you have devops deploy, devops help, devops version... all for free.


2. Kubernetes Wrapper Tool

kubetool logs app-name --env prod
kubetool switch-context dev
kubetool apply-all teamX

Under the hood: one script per command in src/, loaded with module and structured like a Go or Rust CLI.


3. Project Onboarding Tool

onboard new-service
  • Clones a template repo
  • Sets up CI/CD
  • Creates GitHub repo
  • Registers service in monitoring

Organized as:

src/
├── main.sh
├── git.sh
├── ci.sh
├── register.sh

Reused across teams. Versioned. Maintained. Documented.


Why Mush Matters

For DevOps teams, Mush is a game changer:

  • No more spaghetti Bash
  • Encourages structure and reuse
  • Teams can collaborate on shared modules
  • Tools can be versioned, installed, and reused
  • Easy to write, even easier to maintain

Mush brings modern software development practices to one of the most widely used languages in infrastructure—Bash.


Final Thoughts

Every time you write a script like deploy.sh, you’re building a tool.

Why not treat it like one?

Mush lets you build real, structured, maintainable tools—with zero dependencies and 100% Bash.

So next time your team needs a CLI helper, skip the Python and Go boilerplate. Use Mush, and make your scripts proud.


Try it out

Happy scripting!