diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 15af260b6b731d128f00abb1811edcf04e9da76c..a3326b97d9a0ab1bb4045ade71e0cfe0069f7ce7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -17,8 +17,12 @@ jobs:
         uses: actions-rs/toolchain@v1
         with:
           toolchain: stable
+      - name: Install dependencies
+        run: |
+          cargo install cargo-script
       - name: Run fmt check
-        run: make fmt-check
+        run: |
+          ./make.rs fmt --check
 
   test:
     runs-on: ubuntu-latest
@@ -31,8 +35,12 @@ jobs:
           sudo apt update --yes
           sudo apt upgrade --yes
           sudo apt install protobuf-compiler --yes
+          cargo install cargo-script
       - name: Show configuration
-        run: make show
+        run: |
+          ./make.rs version
       - name: Run tests
         run: |
-          make check clippy test
+          ./make.rs check
+          ./make.rs clippy
+          ./make.rs test
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a1720e8ab1ef72320bdbbe20c7629b1af6456b03..d44462d5e90e9ab805ca2a8f12d319e4bcf3b1c4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -16,9 +16,10 @@ workflow:
 
 fmt:
   stage: fmt
-
+  before_script:
+    - cargo install cargo-script
   script:
-    - make fmt-check
+    - ./make.rs fmt --check
 
 test:
   stage: test
@@ -28,7 +29,10 @@ test:
     - apt update --yes
     - apt upgrade --yes
     - apt install protobuf-compiler --yes
-    - make show
+    - cargo install cargo-script
+    - ./make.rs version
 
   script:
-    - make check clippy test
+    - ./make.rs check
+    - ./make.rs clippy
+    - ./make.rs test
diff --git a/Makefile b/Makefile
deleted file mode 100644
index c9913f0524fcb969ec26ab2240e693c5a232715d..0000000000000000000000000000000000000000
--- a/Makefile
+++ /dev/null
@@ -1,44 +0,0 @@
-DEFAULT_GOAL: fmt-check check clippy test
-
-.PHONY: fmt-check
-fmt-check:
-	cargo fmt --all -- --check
-
-.PHONY: fmt
-fmt:
-	cargo fmt --all
-
-.PHONY: check
-check:
-	cargo check --workspace --all-targets
-	cargo check --workspace --all-targets --features kzg
-	cargo check --workspace --all-targets --features aplonk
-	cargo check --workspace --all-targets --all-features
-
-.PHONY: clippy
-clippy:
-	cargo clippy --workspace --all-targets --all-features -- -D warnings
-
-.PHONY: test
-test:
-	cargo test --workspace --verbose --all-features
-	cargo test --examples --verbose
-
-.PHONY: show
-show:
-	@rustup --version 2> /dev/null
-	@rustup show active-toolchain
-	@rustc --version
-	@cargo --version
-	@cargo clippy --version
-
-.PHONY: doc
-doc:
-	RUSTDOCFLAGS="--html-in-header katex.html" cargo doc --no-deps --open
-
-.PHONY: build-examples
-build-examples:
-	cargo build --examples --release
-
-print-%:
-	@echo $($*)
diff --git a/README.md b/README.md
index f309ec76b27e1cbb3155b454681deda482dfbc26..2f9badd5b57ca7396d96ab17bb2a40bc5c195b3f 100644
--- a/README.md
+++ b/README.md
@@ -11,11 +11,9 @@ see `cargo doc` or [the library itself](src/)
 
 ## the tests
 ```shell
-make
-```
-or
-```shell
-make check clippy test
+./make.rs check
+./make.rs clippy
+./make.rs test
 ```
 
 Other examples that showcase the Komodo API are available in [`examples/`](examples/).
diff --git a/make.rs b/make.rs
new file mode 100755
index 0000000000000000000000000000000000000000..6fa31a677015bd806a691f7161bee307d338a59d
--- /dev/null
+++ b/make.rs
@@ -0,0 +1,123 @@
+#!/usr/bin/env run-cargo-script
+//! ```cargo
+//! [package]
+//! name = "komodo-make"
+//! version = "1.0.0"
+//! edition = "2021"
+//!
+//! [dependencies]
+//! nob = { git = "https://gitlab.isae-supaero.fr/a.stevan/nob.rs", rev = "e4b03cdd4f1ba9daf3095930911b12fb28b6a248" }
+//! clap = { version = "4.5.17", features = ["derive"] }
+//! ```
+extern crate clap;
+
+use clap::{Parser, Subcommand};
+
+#[derive(Parser)]
+#[command(version, about, long_about = None)]
+struct Cli {
+    #[command(subcommand)]
+    command: Option<Commands>,
+}
+
+#[derive(Subcommand)]
+enum Commands {
+    /// Formats the code.
+    Fmt {
+        /// Only checks instead of really formatting.
+        #[arg(short, long)]
+        check: bool,
+    },
+    /// Checks the code.
+    Check,
+    /// Runs Clippy.
+    Clippy,
+    /// Runs the tests.
+    Test {
+        /// Be extra verbose with the output of the tests.
+        #[arg(short, long)]
+        verbose: bool,
+        /// Run the examples instead of regular tests.
+        #[arg(short, long)]
+        examples: bool,
+    },
+    /// Shows the version of all the tools used,
+    Version,
+    /// Builds the documentation
+    Doc {
+        /// Open the documentation in the browser.
+        #[arg(short, long)]
+        open: bool,
+        /// Document private items.
+        #[arg(short, long)]
+        private: bool,
+        /// Document all features.
+        #[arg(short, long)]
+        features: bool,
+    },
+}
+
+#[rustfmt::skip]
+fn main() {
+    let cli = Cli::parse();
+
+    match &cli.command {
+        Some(Commands::Fmt { check }) => {
+            if *check {
+                nob::run_cmd_and_fail!("cargo", "fmt", "--all", "--", "--check");
+            } else {
+                nob::run_cmd_and_fail!("cargo", "fmt", "--all");
+            }
+        }
+        Some(Commands::Check) => {
+            nob::run_cmd_and_fail!("cargo", "check", "--workspace", "--all-targets");
+            nob::run_cmd_and_fail!("cargo", "check", "--workspace", "--all-targets", "--features", "kzg");
+            nob::run_cmd_and_fail!("cargo", "check", "--workspace", "--all-targets", "--features", "aplonk");
+            nob::run_cmd_and_fail!("cargo", "check", "--workspace", "--all-targets", "--all-features");
+        }
+        Some(Commands::Clippy) => {
+            nob::run_cmd_and_fail!(
+                "cargo",
+                "clippy",
+                "--workspace",
+                "--all-targets",
+                "--all-features",
+                "--",
+                "-D",
+                "warnings"
+            )
+        }
+        Some(Commands::Test { verbose, examples }) => {
+            let mut cmd = vec!["cargo", "test"];
+
+            if *verbose { cmd.push("--verbose") }
+            if *examples {
+                cmd.push("--examples");
+            } else {
+                cmd.push("--workspace");
+                cmd.push("--all-features");
+            }
+
+            nob::run_cmd_as_vec_and_fail!(cmd);
+        }
+        Some(Commands::Version) => {
+            nob::run_cmd_and_fail!(@"rustup", "--version", "2>", "/dev/null");
+            nob::run_cmd_and_fail!(@"rustup", "show", "active-toolchain");
+            nob::run_cmd_and_fail!(@"rustc", "--version");
+            nob::run_cmd_and_fail!(@"cargo", "--version");
+            nob::run_cmd_and_fail!(@"cargo", "clippy", "--version");
+        }
+        Some(Commands::Doc {
+            open,
+            private,
+            features,
+        }) => {
+            let mut cmd = vec!["cargo", "doc", "--no-deps"];
+            if *open { cmd.push("--open") }
+            if *private { cmd.push("--document-private-items") }
+            if *features { cmd.push("--all-features") }
+            nob::run_cmd_as_vec_and_fail!(cmd ; "RUSTDOCFLAGS" => "--html-in-header katex.html");
+        },
+        None => {}
+    }
+}