diff --git a/xtask/src/clippy.rs b/xtask/src/clippy.rs
new file mode 100644
index 0000000..e873fac
--- /dev/null
+++ b/xtask/src/clippy.rs
@@ -0,0 +1,37 @@
+use clap::Parser;
+use std::{path::PathBuf, process::Command};
+
+#[derive(Debug, Parser)]
+pub struct Options {
+    /// Clippy will fix as much as it can
+    #[clap(long)]
+    pub fix: bool,
+    /// Clippy will ignore if the directory has uncommitted changes
+    #[clap(long)]
+    pub allow_dirty: bool,
+    /// Clippy will fix staged files
+    #[clap(long)]
+    pub allow_staged: bool,
+}
+
+/// Run Clippy on the project
+pub fn run_clippy(opts: Options) -> Result<(), anyhow::Error> {
+    let mut args = vec!["clippy"];
+
+    if opts.fix {
+        args.push("--fix")
+    }
+    if opts.allow_dirty {
+        args.push("--allow-dirty")
+    }
+    if opts.allow_staged {
+        args.push("--allow-staged")
+    }
+    let status = Command::new("cargo")
+        .current_dir(PathBuf::from("{{project-name}}-ebpf"))
+        .args(&args)
+        .status()
+        .expect("failed to build userspace");
+    assert!(status.success());
+    Ok(())
+}
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 5079458..d838751 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -1,5 +1,6 @@
-mod build_ebpf;
 mod build;
+mod build_ebpf;
+mod clippy;
 mod run;
 
 use std::process::exit;
@@ -17,6 +18,7 @@ enum Command {
     BuildEbpf(build_ebpf::Options),
     Build(build::Options),
     Run(run::Options),
+    Clippy(clippy::Options),
 }
 
 fn main() {
@@ -27,6 +29,7 @@ fn main() {
         BuildEbpf(opts) => build_ebpf::build_ebpf(opts),
         Run(opts) => run::run(opts),
         Build(opts) => build::build(opts),
+        Clippy(opts) => clippy::run_clippy(opts),
     };
 
     if let Err(e) = ret {