diff --git a/src/lib/lib.rs b/src/lib/lib.rs
index ab1ededfcf7c6693fd2b2f880ba8d07c9d15087f..045da92a627ebc97c1465de637e4336c34df6c1d 100644
--- a/src/lib/lib.rs
+++ b/src/lib/lib.rs
@@ -47,6 +47,8 @@ mod builtins;
 mod shell;
 mod ascii_helpers;
 
-pub use shell::{Binary, Capture, Fork, IonError, IonResult, Shell, ShellBuilder};
+pub use shell::binary::MAN_ION;
 pub use shell::flags;
 pub use shell::status;
+pub use shell::{Binary, Capture, Fork, IonError, IonResult, Shell, ShellBuilder};
+pub use shell::pipe_exec::job_control::JobControl;
diff --git a/src/lib/shell/binary/mod.rs b/src/lib/shell/binary/mod.rs
index 46132cb497f5be1d32ada11543b7e50ae44e5937..e7c5eaf5380c1a1abdd0d462bc15f71dd8a2d0b9 100644
--- a/src/lib/shell/binary/mod.rs
+++ b/src/lib/shell/binary/mod.rs
@@ -7,22 +7,18 @@ mod terminate;
 use self::prompt::{prompt, prompt_fn};
 use self::readln::readln;
 use self::terminate::{terminate_quotes, terminate_script_quotes};
-use super::{FlowLogic, JobControl, Shell, ShellHistory};
-use super::flags::*;
+use super::{FlowLogic, Shell, ShellHistory};
 use super::flow_control::Statement;
 use super::status::*;
 use liner::{Buffer, Context};
-use smallvec::SmallVec;
 use std::env;
-use std::error::Error;
 use std::fs::File;
-use std::io::{stdout, Write};
 use std::io::ErrorKind;
-use std::iter::{self, FromIterator};
+use std::iter;
 use std::path::Path;
 use std::process;
 
-const MAN_ION: &'static str = r#"NAME
+pub const MAN_ION: &'static str = r#"NAME
     ion - ion shell
 
 SYNOPSIS
@@ -44,9 +40,6 @@ OPTIONS
 "#;
 
 pub trait Binary {
-    /// Launches the shell, parses arguments, and then diverges into one of the `execution`
-    /// paths.
-    fn main(self);
     /// Parses and executes the arguments that were supplied to the shell.
     fn execute_arguments<A: Iterator<Item = String>>(&mut self, args: A);
     /// Creates an interactive session that reads from a prompt provided by
@@ -192,47 +185,6 @@ impl Binary for Shell {
         }
     }
 
-    fn main(mut self) {
-        let mut args = env::args().skip(1);
-        while let Some(path) = args.next() {
-            match path.as_str() {
-                "-n" | "--no-execute" => {
-                    self.flags |= NO_EXEC;
-                    continue;
-                }
-                "-c" => self.execute_arguments(args),
-                "-v" | "--version" => self.display_version(),
-                "-h" | "--help" => {
-                    let stdout = stdout();
-                    let mut stdout = stdout.lock();
-                    match stdout
-                        .write_all(MAN_ION.as_bytes())
-                        .and_then(|_| stdout.flush())
-                    {
-                        Ok(_) => return,
-                        Err(err) => panic!("{}", err.description().to_owned()),
-                    }
-                }
-                _ => {
-                    let mut array = SmallVec::from_iter(Some(path.clone().into()));
-                    for arg in args {
-                        array.push(arg.into());
-                    }
-                    self.variables.set_array("args", array);
-                    if let Err(err) = self.execute_script(&path) {
-                        eprintln!("ion: {}", err);
-                    }
-                }
-            }
-
-            self.wait_for_background();
-            let previous_status = self.previous_status;
-            self.exit(previous_status);
-        }
-
-        self.execute_interactive();
-    }
-
     fn display_version(&self) {
         println!("{}", include!(concat!(env!("OUT_DIR"), "/version_string")));
         process::exit(0);
diff --git a/src/lib/shell/mod.rs b/src/lib/shell/mod.rs
index 07a4087bec2854ce3c77b6d7ee1649d1c730fbb1..dfdf25cb31a5180931ccc7b4de9792c9dfb6fcd4 100644
--- a/src/lib/shell/mod.rs
+++ b/src/lib/shell/mod.rs
@@ -1,18 +1,18 @@
 mod assignments;
-mod binary;
 mod completer;
 mod flow;
 mod fork;
 mod history;
 mod job;
-mod pipe_exec;
 pub mod flags;
 pub mod fork_function;
 pub mod status;
 pub mod variables;
+pub(crate) mod binary;
 pub(crate) mod colors;
 pub(crate) mod directory_stack;
 pub(crate) mod flow_control;
+pub(crate) mod pipe_exec;
 pub(crate) mod plugins;
 pub(crate) mod signals;
 
@@ -71,7 +71,7 @@ pub struct Shell {
     /// Note that the context is only available in an interactive session.
     pub(crate) context: Option<Context>,
     /// Contains the aliases, strings, and array variable maps.
-    pub(crate) variables: Variables,
+    pub variables: Variables,
     /// Contains the current state of flow control parameters.
     flow_control: FlowControl,
     /// Contains the directory stack parameters.
@@ -203,7 +203,8 @@ impl<'a> Shell {
         }
     }
 
-    pub(crate) fn exit(&mut self, status: i32) -> ! {
+    /// Cleanly exit ion
+    pub fn exit(&mut self, status: i32) -> ! {
         self.prep_for_exit();
         process::exit(status);
     }
diff --git a/src/lib/shell/pipe_exec/job_control.rs b/src/lib/shell/pipe_exec/job_control.rs
index 5fcd3d086b3c2cf433b78d7985e0aee2926e7079..b2d26a3f895eac03ac51dff2103971777d8e5630 100644
--- a/src/lib/shell/pipe_exec/job_control.rs
+++ b/src/lib/shell/pipe_exec/job_control.rs
@@ -20,7 +20,7 @@ pub(crate) fn set_foreground_as(pid: u32) {
     signals::unblock();
 }
 
-pub(crate) trait JobControl {
+pub trait JobControl {
     /// Waits for background jobs to finish before returning.
     fn wait_for_background(&mut self);
     /// Takes a background tasks's PID and whether or not it needs to be continued; resumes the
diff --git a/src/main.rs b/src/main.rs
index e5cd2d1d228672ac69e05df4c6c890aa604f361f..ad618c3c28e8a50a18fc629a7f14e04c56762c86 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,14 +1,59 @@
 extern crate ion_shell;
+extern crate smallvec;
 
+use ion_shell::JobControl;
+use ion_shell::MAN_ION;
+use ion_shell::flags::NO_EXEC;
 use ion_shell::{Binary, ShellBuilder};
+use smallvec::SmallVec;
+use std::env;
+use std::error::Error;
+use std::io::{stdout, Write};
+use std::iter::FromIterator;
 
 fn main() {
-    ShellBuilder::new()
+    let mut shell = ShellBuilder::new()
         .install_signal_handler()
         .block_signals()
         .set_unique_pid()
-        .as_binary()
-        .main();
-}
+        .as_binary();
+
+    let mut args = env::args().skip(1);
+    while let Some(path) = args.next() {
+        match path.as_str() {
+            "-n" | "--no-execute" => {
+                shell.flags |= NO_EXEC;
+                continue;
+            }
+            "-c" => shell.execute_arguments(args),
+            "-v" | "--version" => shell.display_version(),
+            "-h" | "--help" => {
+                let stdout = stdout();
+                let mut stdout = stdout.lock();
+                match stdout
+                    .write_all(MAN_ION.as_bytes())
+                    .and_then(|_| stdout.flush())
+                {
+                    Ok(_) => return,
+                    Err(err) => panic!("{}", err.description().to_owned()),
+                }
+            }
+            _ => {
+                let mut array = SmallVec::from_iter(Some(path.clone().into()));
+                for arg in args {
+                    array.push(arg.into());
+                }
+                shell.variables.set_array("args", array);
+                if let Err(err) = shell.execute_script(&path) {
+                    eprintln!("ion: {}", err);
+                }
+            }
+        }
 
-// TODO: The `Binary` / `main()` logic should be implemented here, and not within the library.
\ No newline at end of file
+        shell.wait_for_background();
+        let previous_status = shell.previous_status;
+        shell.exit(previous_status);
+    }
+
+    shell.execute_interactive();
+}