diff --git a/Cargo.lock b/Cargo.lock
index ff31e6d6b970b17bc0c32a6ac9b1b4ae3a615f23..7cbeacf84634f85cca65a8c06247bbe7d19634fc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -369,6 +369,18 @@ dependencies = [
  "powerfmt",
 ]
 
+[[package]]
+name = "dot"
+version = "0.1.0"
+dependencies = [
+ "async-std",
+ "clap",
+ "hercules_rt",
+ "juno_build",
+ "rand",
+ "with_builtin_macros",
+]
+
 [[package]]
 name = "either"
 version = "1.13.0"
@@ -682,6 +694,7 @@ dependencies = [
 name = "juno_build"
 version = "0.1.0"
 dependencies = [
+ "hercules_ir",
  "hercules_rt",
  "juno_frontend",
  "with_builtin_macros",
@@ -835,6 +848,18 @@ dependencies = [
  "vob",
 ]
 
+[[package]]
+name = "matmul"
+version = "0.1.0"
+dependencies = [
+ "async-std",
+ "clap",
+ "hercules_rt",
+ "juno_build",
+ "rand",
+ "with_builtin_macros",
+]
+
 [[package]]
 name = "memchr"
 version = "2.7.4"
diff --git a/Cargo.toml b/Cargo.toml
index d618b9b5c210fbdd636b9b4ed42b7434cdc98fb7..63579146428581973a4c93e987160ad415ea0418 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,8 +12,8 @@ members = [
 	#"hercules_test/hercules_interpreter",
 	#"hercules_test/hercules_tests",
 
-	#"hercules_samples/dot",
-	#"hercules_samples/matmul",
+	"hercules_samples/dot",
+	"hercules_samples/matmul",
 	#"hercules_samples/fac",
 
 	"juno_frontend",
@@ -22,4 +22,4 @@ members = [
 
 	#"juno_samples/matmul",
 	"juno_samples/simple3",
-]
\ No newline at end of file
+]
diff --git a/hercules_samples/dot/Cargo.toml b/hercules_samples/dot/Cargo.toml
index ab10aedaeb3c680c1c26f3bc425178f34c6485c9..69cd39e388661b3f7f6dca53cf9210ab7050902c 100644
--- a/hercules_samples/dot/Cargo.toml
+++ b/hercules_samples/dot/Cargo.toml
@@ -4,8 +4,13 @@ version = "0.1.0"
 authors = ["Russel Arbore <rarbore2@illinois.edu>"]
 edition = "2021"
 
+[build-dependencies]
+juno_build = { path = "../../juno_build" }
+
 [dependencies]
 clap = { version = "*", features = ["derive"] }
+juno_build = { path = "../../juno_build" }
 hercules_rt = { path = "../../hercules_rt" }
 rand = "*"
 async-std = "*"
+with_builtin_macros = "0.1.0"
diff --git a/hercules_samples/dot/build.rs b/hercules_samples/dot/build.rs
index 47fb55e82fc0266b03c6a7ba94717738038b489c..cfa03fd3b989748fe530071f289fb31f036283b4 100644
--- a/hercules_samples/dot/build.rs
+++ b/hercules_samples/dot/build.rs
@@ -1,12 +1,10 @@
-use std::env::current_dir;
+extern crate juno_build;
+use juno_build::JunoCompiler;
 
 fn main() {
-    println!(
-        "cargo::rustc-link-search=native={}",
-        current_dir().unwrap().display()
-    );
-    println!("cargo::rustc-link-lib=static=dot");
-
-    println!("cargo::rerun-if-changed=dot.hman");
-    println!("cargo::rerun-if-changed=libdot.a");
+    JunoCompiler::new()
+        .ir_in_src("dot.hir")
+        .unwrap()
+        .build()
+        .unwrap();
 }
diff --git a/hercules_samples/dot/dot.hir b/hercules_samples/dot/src/dot.hir
similarity index 100%
rename from hercules_samples/dot/dot.hir
rename to hercules_samples/dot/src/dot.hir
diff --git a/hercules_samples/dot/src/main.rs b/hercules_samples/dot/src/main.rs
index dbf18713465c10f7fafc7de0e180a6d43f0003a6..3d282ae2568a778edd70fc8cb077ac509f29536e 100644
--- a/hercules_samples/dot/src/main.rs
+++ b/hercules_samples/dot/src/main.rs
@@ -1,12 +1,8 @@
 extern crate async_std;
 extern crate clap;
-extern crate hercules_rt;
+extern crate juno_build;
 
-// To compile currently, run from the Hercules project root directory:
-// cargo run --bin hercules_driver hercules_samples/dot/dot.hir "Codegen(\"hercules_samples/dot\",\"dot\")"
-// Then, you can execute this example with:
-// cargo run --bin dot
-hercules_rt::use_hman!("hercules_samples/dot/dot.hman");
+juno_build::juno!("dot");
 
 fn main() {
     async_std::task::block_on(async {
diff --git a/hercules_samples/fac/Cargo.toml b/hercules_samples/fac/Cargo.toml
index bef11a91f027edf84f1e719538168e4ce8fd21e7..9082a4fc4194ac3fa9c694a5a5973f605772a384 100644
--- a/hercules_samples/fac/Cargo.toml
+++ b/hercules_samples/fac/Cargo.toml
@@ -4,8 +4,13 @@ version = "0.1.0"
 authors = ["Russel Arbore <rarbore2@illinois.edu>"]
 edition = "2021"
 
+[build-dependencies]
+juno_build = { path = "../../juno_build" }
+
 [dependencies]
 clap = { version = "*", features = ["derive"] }
+juno_build = { path = "../../juno_build" }
 hercules_rt = { path = "../../hercules_rt" }
 rand = "*"
 async-std = "*"
+with_builtin_macros = "0.1.0"
diff --git a/hercules_samples/fac/build.rs b/hercules_samples/fac/build.rs
index f43f9fbd956813de7f530d93c3afbb94a29995c6..49a6024828516f994522e66bf1de1d714f63e75b 100644
--- a/hercules_samples/fac/build.rs
+++ b/hercules_samples/fac/build.rs
@@ -1,12 +1,10 @@
-use std::env::current_dir;
+extern crate juno_build;
+use juno_build::JunoCompiler;
 
 fn main() {
-    println!(
-        "cargo::rustc-link-search=native={}",
-        current_dir().unwrap().display()
-    );
-    println!("cargo::rustc-link-lib=static=fac");
-
-    println!("cargo::rerun-if-changed=fac.hman");
-    println!("cargo::rerun-if-changed=libfac.a");
+    JunoCompiler::new()
+        .ir_in_src("fac.hir")
+        .unwrap()
+        .build()
+        .unwrap();
 }
diff --git a/hercules_samples/fac/fac.hir b/hercules_samples/fac/src/fac.hir
similarity index 100%
rename from hercules_samples/fac/fac.hir
rename to hercules_samples/fac/src/fac.hir
diff --git a/hercules_samples/fac/src/main.rs b/hercules_samples/fac/src/main.rs
index 5e5b4ddefb73835c45b399009e9709b06e056217..e29860ee6942b8cbea3d084d4de0310f7fb6cf2a 100644
--- a/hercules_samples/fac/src/main.rs
+++ b/hercules_samples/fac/src/main.rs
@@ -1,12 +1,8 @@
 extern crate async_std;
 extern crate clap;
-extern crate hercules_rt;
+extern crate juno_build;
 
-// To compile currently, run from the Hercules project root directory:
-// cargo run --bin hercules_driver hercules_samples/fac/fac.hir "Codegen(\"hercules_samples/fac\",\"fac\")"
-// Then, you can execute this example with:
-// cargo run --bin fac
-hercules_rt::use_hman!("hercules_samples/fac/fac.hman");
+juno_build::juno!("fac");
 
 fn main() {
     async_std::task::block_on(async {
diff --git a/hercules_samples/matmul/Cargo.toml b/hercules_samples/matmul/Cargo.toml
index 744b3f596a1007d0e22f55e2975b0357f70c663e..9066c1535e2c40400bdb3b5ca20a3e38237ef597 100644
--- a/hercules_samples/matmul/Cargo.toml
+++ b/hercules_samples/matmul/Cargo.toml
@@ -4,8 +4,13 @@ version = "0.1.0"
 authors = ["Russel Arbore <rarbore2@illinois.edu>"]
 edition = "2021"
 
+[build-dependencies]
+juno_build = { path = "../../juno_build" }
+
 [dependencies]
 clap = { version = "*", features = ["derive"] }
+juno_build = { path = "../../juno_build" }
 hercules_rt = { path = "../../hercules_rt" }
 rand = "*"
 async-std = "*"
+with_builtin_macros = "0.1.0"
diff --git a/hercules_samples/matmul/build.rs b/hercules_samples/matmul/build.rs
index aa4cd97f33d5f06754a3306f2d824e0cf38eb4ea..ec6eb892326c5d6eb341c89239b0465de0cf4a49 100644
--- a/hercules_samples/matmul/build.rs
+++ b/hercules_samples/matmul/build.rs
@@ -1,12 +1,10 @@
-use std::env::current_dir;
+extern crate juno_build;
+use juno_build::JunoCompiler;
 
 fn main() {
-    println!(
-        "cargo::rustc-link-search=native={}",
-        current_dir().unwrap().display()
-    );
-    println!("cargo::rustc-link-lib=static=matmul");
-
-    println!("cargo::rerun-if-changed=matmul.hman");
-    println!("cargo::rerun-if-changed=libmatmul.a");
+    JunoCompiler::new()
+        .ir_in_src("matmul.hir")
+        .unwrap()
+        .build()
+        .unwrap();
 }
diff --git a/hercules_samples/matmul/src/main.rs b/hercules_samples/matmul/src/main.rs
index ac5e96b26e65aa16adc266a784a9a727ce5d76e0..26168d4b55c270b50957b0dc5a8792dbff65c5dc 100644
--- a/hercules_samples/matmul/src/main.rs
+++ b/hercules_samples/matmul/src/main.rs
@@ -2,13 +2,9 @@
 
 extern crate async_std;
 extern crate clap;
-extern crate hercules_rt;
+extern crate juno_build;
 
-// To compile currently, run from the Hercules project root directory:
-// cargo run --bin hercules_driver hercules_samples/matmul/matmul.hir "Codegen(\"hercules_samples/matmul\",\"matmul\")"
-// Then, you can execute this example with:
-// cargo run --bin matmul
-hercules_rt::use_hman!("hercules_samples/matmul/matmul.hman");
+juno_build::juno!("matmul");
 
 fn main() {
     async_std::task::block_on(async {
diff --git a/hercules_samples/matmul/matmul.hir b/hercules_samples/matmul/src/matmul.hir
similarity index 100%
rename from hercules_samples/matmul/matmul.hir
rename to hercules_samples/matmul/src/matmul.hir
diff --git a/juno_build/Cargo.toml b/juno_build/Cargo.toml
index 2e35059ef535fc32780d0fbd41bbc6de96771932..4f6234988f7e30ade972933dcec56b29412369ba 100644
--- a/juno_build/Cargo.toml
+++ b/juno_build/Cargo.toml
@@ -7,4 +7,5 @@ edition = "2021"
 [dependencies]
 juno_frontend = { path = "../juno_frontend" }
 hercules_rt = { path = "../hercules_rt" }
+hercules_ir = { path = "../hercules_ir" }
 with_builtin_macros = "0.1.0"
diff --git a/juno_build/src/lib.rs b/juno_build/src/lib.rs
index c40d8de1b255190dcfda5508188eaf577b1c8047..e01a518722d8e074905593f04e14391e0d905a9e 100644
--- a/juno_build/src/lib.rs
+++ b/juno_build/src/lib.rs
@@ -1,16 +1,21 @@
+extern crate hercules_ir;
 extern crate hercules_rt;
+
 use juno_compiler::*;
 
 use std::env::{current_dir, var};
 use std::fmt::Write;
-use std::fs::create_dir_all;
+use std::fs::{create_dir_all, read_to_string};
 use std::path::{Path, PathBuf};
 
 use with_builtin_macros::with_builtin;
 
 // JunoCompiler is used to compile juno files into a library and manifest file appropriately to
 // import the definitions into a rust project via the juno! macro defined below
+// You can also specify a Hercules IR file instead of a Juno file and this will compile that IR
+// file (though in that case a schedule is not supported)
 pub struct JunoCompiler {
+    ir_src_path: Option<PathBuf>,
     src_path: Option<PathBuf>,
     out_path: Option<PathBuf>,
     verify: JunoVerify,
@@ -21,6 +26,7 @@ pub struct JunoCompiler {
 impl JunoCompiler {
     pub fn new() -> Self {
         JunoCompiler {
+            ir_src_path: None,
             src_path: None,
             out_path: None,
             verify: JunoVerify::None,
@@ -32,6 +38,33 @@ impl JunoCompiler {
     // Sets the name of the Juno file, this file should be contained in the src/
     // file of the package that the JunoCompiler is used in the build script of
     pub fn file_in_src<P>(mut self, file: P) -> Result<Self, String>
+    where
+        P: AsRef<Path>,
+    {
+        self.src_path = Some(Self::make_src_path(&file)?);
+        self.ir_src_path = None;
+        self.out_path = Some(Self::get_out_path(&file)?);
+        Self::print_cargo_info(file);
+
+        Ok(self)
+    }
+
+    // Sets the name of the input Hercules IR file which is contained in the src/ directory of the
+    // package that the JunoCompiler is used in the build script of
+    pub fn ir_in_src<P>(mut self, file: P) -> Result<Self, String>
+    where
+        P: AsRef<Path>,
+    {
+        self.ir_src_path = Some(Self::make_src_path(&file)?);
+        self.src_path = None;
+        self.out_path = Some(Self::get_out_path(&file)?);
+        Self::print_cargo_info(file);
+
+        Ok(self)
+    }
+
+    // Construct the path to a file in the source directory
+    fn make_src_path<P>(file: P) -> Result<PathBuf, String>
     where
         P: AsRef<Path>,
     {
@@ -48,34 +81,45 @@ impl JunoCompiler {
         };
         path.push("src");
         path.push(file.as_ref());
-        self.src_path = Some(path);
 
-        // We also set the output file in this process, under the OUT_DIR cargo provides
+        Ok(path)
+    }
+
+    // Construct the path to the output directory, under the OUT_DIR cargo provides
+    fn get_out_path<P>(file: P) -> Result<PathBuf, String>
+    where
+        P: AsRef<Path>,
+    {
         let mut out = PathBuf::new();
         out.push(var("OUT_DIR").unwrap());
         out.push(file.as_ref().parent().unwrap().to_str().unwrap());
         let Ok(()) = create_dir_all(&out) else {
             return Err("Failed to create output directory.".to_string());
         };
-        self.out_path = Some(out);
+        Ok(out)
+    }
 
-        // Tell cargo to rerun if the Juno file changes
+    // Prints information to tell cargo the following
+    // - Rerun if the source file changes
+    // - Add the output directory to its linker search
+    // - Link the compiled library file
+    // Tell cargo to rerun if the Juno file changes
+    fn print_cargo_info<P>(src_file: P)
+    where
+        P: AsRef<Path>,
+    {
         println!(
             "cargo::rerun-if-changed=src/{}",
-            file.as_ref().to_str().unwrap()
+            src_file.as_ref().to_str().unwrap()
         );
-        // Tell cargo to include the output directory in its linker search
-        // (and to link the resulting library)
         println!(
             "cargo::rustc-link-search=native={}",
             var("OUT_DIR").unwrap()
         );
         println!(
             "cargo::rustc-link-lib=static={}",
-            file.as_ref().file_stem().unwrap().to_str().unwrap()
+            src_file.as_ref().file_stem().unwrap().to_str().unwrap()
         );
-
-        Ok(self)
     }
 
     pub fn verify(mut self, enabled: bool) -> Self {
@@ -139,7 +183,8 @@ impl JunoCompiler {
     // Builds the juno file into a libary and a manifest file.
     pub fn build(self) -> Result<(), String> {
         let JunoCompiler {
-            src_path: Some(src_path),
+            ir_src_path: ir_src_path,
+            src_path: src_path,
             out_path: Some(out_path),
             verify,
             x_dot,
@@ -149,12 +194,35 @@ impl JunoCompiler {
             return Err("No source file specified.".to_string());
         };
 
-        let src_file = src_path.to_str().unwrap().to_string();
         let out_dir = out_path.to_str().unwrap().to_string();
 
-        match compile(src_file, verify, x_dot, schedule, out_dir) {
-            Ok(()) => Ok(()),
-            Err(errs) => Err(format!("{}", errs)),
+        if let Some(src_path) = src_path {
+            let src_file = src_path.to_str().unwrap().to_string();
+
+            match compile(src_file, verify, x_dot, schedule, out_dir) {
+                Ok(()) => Ok(()),
+                Err(errs) => Err(format!("{}", errs)),
+            }
+        } else {
+            let Some(ir_src_path) = ir_src_path else {
+                return Err("No source file specified.".to_string());
+            };
+
+            let ir_src_file = ir_src_path.to_str().unwrap().to_string();
+            let ir_src_path = Path::new(&ir_src_file);
+            let module_name = String::from(ir_src_path.file_stem().unwrap().to_str().unwrap());
+
+            let Ok(contents) = read_to_string(&ir_src_path) else {
+                return Err("Unable to open and read input file.".to_string());
+            };
+            let Ok(ir_mod) = hercules_ir::parse::parse(&contents) else {
+                return Err("Unable to parse Hercules IR file.".to_string());
+            };
+
+            match compile_ir(ir_mod, None, verify, x_dot, schedule, out_dir, module_name) {
+                Ok(()) => Ok(()),
+                Err(errs) => Err(format!("{}", errs)),
+            }
         }
     }
 }
diff --git a/juno_frontend/src/lib.rs b/juno_frontend/src/lib.rs
index 1ac61fe519f3a3eb85a09cae26d53e78cbe0230c..96fefb7f0e9d374a48ddc4691545aa9910edaf69 100644
--- a/juno_frontend/src/lib.rs
+++ b/juno_frontend/src/lib.rs
@@ -14,6 +14,8 @@ extern crate hercules_ir;
 use std::fmt;
 use std::path::Path;
 
+use juno_scheduler::FunctionMap;
+
 pub enum JunoVerify {
     None,
     JunoOpts,
@@ -96,6 +98,26 @@ pub fn compile(
     };
     let (module, func_info) = codegen::codegen_program(prg);
 
+    compile_ir(
+        module,
+        Some(func_info),
+        verify,
+        x_dot,
+        schedule,
+        output_dir,
+        module_name,
+    )
+}
+
+pub fn compile_ir(
+    module: hercules_ir::ir::Module,
+    func_info: Option<FunctionMap>,
+    verify: JunoVerify,
+    x_dot: bool,
+    schedule: JunoSchedule,
+    output_dir: String,
+    module_name: String,
+) -> Result<(), ErrorMessage> {
     let mut pm = match schedule {
         JunoSchedule::None => hercules_opt::pass::PassManager::new(module),
         JunoSchedule::DefaultSchedule => {
@@ -103,16 +125,24 @@ pub fn compile(
             pm.make_plans();
             pm
         }
-        JunoSchedule::Schedule(file) => match juno_scheduler::schedule(&module, func_info, file) {
-            Ok(plans) => {
-                let mut pm = hercules_opt::pass::PassManager::new(module);
-                pm.set_plans(plans);
-                pm
-            }
-            Err(msg) => {
-                return Err(ErrorMessage::SchedulingError(msg));
+        JunoSchedule::Schedule(file) => {
+            let Some(func_info) = func_info else {
+                return Err(ErrorMessage::SchedulingError(
+                    "Cannot schedule, no function information provided".to_string(),
+                ));
+            };
+
+            match juno_scheduler::schedule(&module, func_info, file) {
+                Ok(plans) => {
+                    let mut pm = hercules_opt::pass::PassManager::new(module);
+                    pm.set_plans(plans);
+                    pm
+                }
+                Err(msg) => {
+                    return Err(ErrorMessage::SchedulingError(msg));
+                }
             }
-        },
+        }
     };
     if verify.verify() || verify.verify_all() {
         pm.add_pass(hercules_opt::pass::Pass::Verify);