diff --git a/.gitignore b/.gitignore
index c77774d..8e6827f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,6 @@
 
 # env
 .env
+
+# temp
+/tmp
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index 11ba1db..e770a80 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -19,9 +19,9 @@ checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
 
 [[package]]
 name = "async-trait"
-version = "0.1.85"
+version = "0.1.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056"
+checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -63,9 +63,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
 
 [[package]]
 name = "cc"
-version = "1.2.10"
+version = "1.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
+checksum = "e4730490333d58093109dc02c23174c3f4d490998c3fed3cc8e82d57afedb9cf"
 dependencies = [
  "shlex",
 ]
@@ -142,10 +142,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
-name = "forcebot-rs-v2"
+name = "forcebot_core"
 version = "0.1.0"
 dependencies = [
  "dotenv",
+ "lazy_static",
  "tokio",
  "twitch-irc",
 ]
@@ -199,13 +200,14 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.15"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi",
+ "wasi 0.13.3+wasi-0.2.2",
+ "windows-targets",
 ]
 
 [[package]]
@@ -214,6 +216,12 @@ version = "0.31.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
 
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
 [[package]]
 name = "libc"
 version = "0.2.169"
@@ -264,15 +272,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
 dependencies = [
  "libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
  "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "moderator_reactor"
+version = "0.1.0"
+dependencies = [
+ "dotenv",
+ "forcebot_core",
+ "lazy_static",
+ "tokio",
+ "twitch-irc",
+]
+
 [[package]]
 name = "native-tls"
-version = "0.2.12"
+version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
+checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c"
 dependencies = [
  "libc",
  "log",
@@ -285,6 +304,17 @@ dependencies = [
  "tempfile",
 ]
 
+[[package]]
+name = "new_empty_bot"
+version = "0.1.0"
+dependencies = [
+ "dotenv",
+ "forcebot_core",
+ "lazy_static",
+ "tokio",
+ "twitch-irc",
+]
+
 [[package]]
 name = "num-traits"
 version = "0.2.19"
@@ -311,9 +341,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
 
 [[package]]
 name = "openssl"
-version = "0.10.68"
+version = "0.10.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
+checksum = "f5e534d133a060a3c19daec1eb3e98ec6f4685978834f2dbadfe2ec215bab64e"
 dependencies = [
  "bitflags",
  "cfg-if",
@@ -337,9 +367,9 @@ dependencies = [
 
 [[package]]
 name = "openssl-probe"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
 
 [[package]]
 name = "openssl-sys"
@@ -429,9 +459,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "rustix"
-version = "0.38.43"
+version = "0.38.44"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
+checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
 dependencies = [
  "bitflags",
  "errno",
@@ -493,6 +523,39 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "simple_command_bot"
+version = "0.1.0"
+dependencies = [
+ "dotenv",
+ "forcebot_core",
+ "lazy_static",
+ "tokio",
+ "twitch-irc",
+]
+
+[[package]]
+name = "simple_debug_listener"
+version = "0.1.0"
+dependencies = [
+ "dotenv",
+ "forcebot_core",
+ "lazy_static",
+ "tokio",
+ "twitch-irc",
+]
+
+[[package]]
+name = "simple_module_example"
+version = "0.1.0"
+dependencies = [
+ "dotenv",
+ "forcebot_core",
+ "lazy_static",
+ "tokio",
+ "twitch-irc",
+]
+
 [[package]]
 name = "slab"
 version = "0.4.9"
@@ -520,9 +583,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.96"
+version = "2.0.98"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
+checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -531,9 +594,9 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.15.0"
+version = "3.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
+checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
 dependencies = [
  "cfg-if",
  "fastrand",
@@ -680,9 +743,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.14"
+version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
+checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
 
 [[package]]
 name = "vcpkg"
@@ -696,6 +759,15 @@ version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
+[[package]]
+name = "wasi"
+version = "0.13.3+wasi-0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
 [[package]]
 name = "windows-sys"
 version = "0.52.0"
@@ -777,3 +849,12 @@ name = "windows_x86_64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
+dependencies = [
+ "bitflags",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 53faa8d..7b027e7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,22 +1,7 @@
-[package]
-name = "forcebot-rs-v2"
-version = "0.1.0"
-edition = "2021"
-default-run = "forcebot-rs-v2"
-
-[dependencies]
-dotenv = "0.15.0"
-tokio = { version = "1.33.0", features = ["full"] }
-twitch-irc = "5.0.1"
-
-# [[bin]]
-# name = "simple_bot"
-# path = "src/simple_bot.rs"
-
-# [[bin]]
-# name = "simple_bot_listener"
-# path = "src/simple_bot_listener.rs"
-
-# [lib]
-# name = "botlib"
-# path = "src/lib.rs"
\ No newline at end of file
+[workspace]
+members = [
+    "forcebot_core",
+    "simple_module_example",
+    "new_empty_bot",
+    "simple_debug_listener", 
+    "moderator_reactor", "simple_command_bot"]
diff --git a/forcebot_core/Cargo.toml b/forcebot_core/Cargo.toml
new file mode 100644
index 0000000..70ac147
--- /dev/null
+++ b/forcebot_core/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "forcebot_core"
+version = "0.1.0"
+edition = "2021"
+default-run = "fun_bot"
+
+[dependencies]
+# async-recursion = "1.1.1" /* has issues when used */
+dotenv = "0.15.0"
+lazy_static = "1.5.0"
+tokio = { version = "1.33.0", features = ["full"] }
+twitch-irc = "5.0.1"
diff --git a/forcebot_core/src/bin/fun_bot.rs b/forcebot_core/src/bin/fun_bot.rs
new file mode 100644
index 0000000..b506faf
--- /dev/null
+++ b/forcebot_core/src/bin/fun_bot.rs
@@ -0,0 +1,87 @@
+//! WIP Fun forcebot with catered customizations #todo
+//!
+//! Custom modules that can be managed in chat through `disable` and `enable` commands
+//! - `besty` - uses a custom prefix tp trigger
+//! - `guests`
+//! - `pyramid`
+//! - `quiet`
+//!
+//!
+//! Be sure the followig is defined in `.env`
+//! - login_name
+//! - access_token
+//! - bot_channels
+//! - prefix
+//! - bot_admins
+//!
+//! Bot access tokens be generated here -
+//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
+//! - More Info - <https://dev.twitch.tv/docs/authentication>
+
+use forcebot_core::{
+    custom_mods::{debug, guest_badge, pyramid},
+    Bot,
+};
+
+#[tokio::main]
+pub async fn main() {
+    /* Create the bot using env */
+    let bot = Bot::new().await;
+
+    /* 1. Load the module into the bot */
+    bot.load_module(funbot_objs::create_module()).await;
+    bot.load_module(guest_badge::create_module()).await;
+    bot.load_module(pyramid::create_module()).await;
+    bot.load_module(debug::create_module()).await;
+
+    /* 3. Run the bot */
+    bot.run().await;
+}
+
+pub mod funbot_objs {
+    use std::sync::Arc;
+
+    use forcebot_core::{execution_async, Badge, Bot, Command, Module};
+    use twitch_irc::message::ServerMessage;
+
+    /// Create a Module with a loaded Command object
+    pub fn create_module() -> Module {
+        let mut custom_mod = Module::new(
+            vec!["besty".to_string()],
+            "Now Aware of besty xdd666 ".to_string(),
+        );
+
+        custom_mod.load_command(create_cmd_test());
+        // custom_mod.set_status_by_default(Status::Disabled);
+
+        custom_mod
+    }
+
+    /// Create a Command Object
+    fn create_cmd_test() -> Command {
+        let mut cmd = Command::new(
+            vec!["remind besty".to_string()],
+            "annytfYandere ".to_string(),
+        );
+
+        async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+            if let ServerMessage::Privmsg(msg) = message {
+                let _ = bot
+                    .chat
+                    .lock()
+                    .await
+                    .say_in_reply_to(&msg, "annytfYandere he's mine".to_string())
+                    .await;
+                return Result::Ok("Success".to_string());
+            }
+            Result::Err("Not Valid message type".to_string())
+        }
+
+        cmd.set_exec_fn(execution_async(execbody));
+
+        cmd.set_admin_only(false);
+        cmd.set_min_badge(Badge::Vip);
+
+        cmd
+    }
+}
diff --git a/src/bin/new_bot.rs b/forcebot_core/src/bin/new_bot.rs
similarity index 73%
rename from src/bin/new_bot.rs
rename to forcebot_core/src/bin/new_bot.rs
index cbe682b..856f6b1 100644
--- a/src/bin/new_bot.rs
+++ b/forcebot_core/src/bin/new_bot.rs
@@ -1,24 +1,22 @@
 //! Example simple Binary crate that creates & runs bot based on `.env`
-//! Be sure the followig is defined in `.env` 
+//! Be sure the followig is defined in `.env`
 //! - login_name
 //! - access_token
 //! - bot_channels
 //! - prefix
 //! - bot_admins
-//! 
-//! Bot access tokens be generated here - 
+//!
+//! Bot access tokens be generated here -
 //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
 //! - More Info - <https://dev.twitch.tv/docs/authentication>
 
-use forcebot_rs_v2::Bot;
+use forcebot_core::Bot;
 
 #[tokio::main]
 pub async fn main() {
-
     /* 1. Create the bot using env */
-    let bot = Bot::new();
+    let bot = Bot::new().await;
 
     /* 2. Run the bot */
     bot.run().await;
-
 }
diff --git a/src/bin/simple_module.rs b/forcebot_core/src/bin/simple_module.rs
similarity index 52%
rename from src/bin/simple_module.rs
rename to forcebot_core/src/bin/simple_module.rs
index 61d66e5..477da78 100644
--- a/src/bin/simple_module.rs
+++ b/forcebot_core/src/bin/simple_module.rs
@@ -1,76 +1,76 @@
 //! Simple Module with a Command
-//! 
-//! Adding objects through packages provides controls , 
+//!
+//! Adding objects through packages provides controls ,
 //! such as moderators, and brodcasters can disable or enable mods
-//! 
-//! Here, moderators or above can enable or disable the `test` 
+//!
+//! Here, moderators or above can enable or disable the `test`
 //! module with the command `<prefix> disable test`
-//! 
-//! Be sure the followig is defined in `.env` 
+//!
+//! Be sure the followig is defined in `.env`
 //! - login_name
 //! - access_token
 //! - bot_channels
 //! - prefix
 //! - bot_admins
-//! 
-//! Bot access tokens be generated here - 
+//!
+//! Bot access tokens be generated here -
 //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
 //! - More Info - <https://dev.twitch.tv/docs/authentication>
 
-use forcebot_rs_v2::Bot;
+use forcebot_core::Bot;
 
 #[tokio::main]
 pub async fn main() {
-
     /* Create the bot using env */
-    let mut bot = Bot::new();
+    let bot = Bot::new().await;
 
     /* load the Module */
-    bot.load_module(custom_mod::new());
+    bot.load_module(custom_mod::new()).await;
 
     /* Run the bot */
     bot.run().await;
-
 }
 
-
 pub mod custom_mod {
     use std::sync::Arc;
 
-    use forcebot_rs_v2::{asyncfn_box, Badge, Bot, Command, Module};
+    use forcebot_core::{execution_async, Badge, Bot, Command, Module};
     use twitch_irc::message::ServerMessage;
 
-
-    /// Module with a loaded command
+    /// Module definition with a loaded command
     pub fn new() -> Module {
         /* 1. Create a new module */
-        let mut custom_mod = Module::new("test".to_string(), "".to_string());
+        let mut custom_mod = Module::new(vec!["test".to_string()], "".to_string());
 
         /* 2. Load the cmd into a new module */
         custom_mod.load_command(cmd_test());
 
         custom_mod
-
     }
 
+    /// Command definition
     pub fn cmd_test() -> Command {
         /* 1. Create a new cmd */
-        let mut cmd = Command::new("test".to_string(),"".to_string());
+        let mut cmd = Command::new(vec!["test".to_string()], "".to_string());
 
         /* 2. Define exec callback  */
-        async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
+        async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
             if let ServerMessage::Privmsg(msg) = message {
-                let _= bot.client.say_in_reply_to(
-                    &msg, "test return".to_string()).await;
+                let _ = bot
+                    .chat
+                    .lock()
+                    .await
+                    .say_in_reply_to(&msg, "test return".to_string())
+                    .await;
             }
-            Result::Err("Not Valid message type".to_string()) 
+            Result::Err("Not Valid message type".to_string())
         }
 
         /* 3. Set Command flags */
-        cmd.set_exec_fn(asyncfn_box(execbody));
+        cmd.set_exec_fn(execution_async(execbody));
         cmd.set_admin_only(false);
         cmd.set_min_badge(Badge::Moderator);
 
         cmd
-        }
-}
\ No newline at end of file
+    }
+}
diff --git a/forcebot_core/src/botcore.rs b/forcebot_core/src/botcore.rs
new file mode 100644
index 0000000..a750843
--- /dev/null
+++ b/forcebot_core/src/botcore.rs
@@ -0,0 +1,5 @@
+pub mod bot;
+pub mod bot_objects;
+pub mod built_in_mods;
+pub mod chat;
+pub mod modules;
diff --git a/forcebot_core/src/botcore/bot.rs b/forcebot_core/src/botcore/bot.rs
new file mode 100644
index 0000000..f3774a1
--- /dev/null
+++ b/forcebot_core/src/botcore/bot.rs
@@ -0,0 +1,482 @@
+// use async_recursion::async_recursion;
+use dotenv::dotenv;
+use std::{
+    env,
+    sync::{Arc, RwLock},
+    time::{Duration, Instant},
+};
+use tokio::sync::{mpsc::UnboundedReceiver, Mutex};
+use twitch_irc::{
+    login::StaticLoginCredentials,
+    message::{PrivmsgMessage, ServerMessage},
+    SecureTCPTransport, TwitchIRCClient,
+};
+
+// use crate::{Badge, Command, Listener, Module};
+use super::{bot_objects::command::Command, built_in_mods, chat::Chat};
+
+use super::super::botcore::modules::Module;
+use crate::botcore::bot_objects::listener::Listener;
+use crate::botcore::{bot_objects::Badge, chat};
+// use super::
+
+use super::{
+    bot_objects::built_in_objects,
+    modules::{self, Status},
+};
+
+/// Twitch chat bot
+pub struct Bot {
+    /// Prefix for commands
+    prefix: String,
+    /// inbound chat msg stream
+    incoming_msgs: Mutex<UnboundedReceiver<ServerMessage>>,
+    /// outbound chat client msg stream
+    pub client: TwitchIRCClient<SecureTCPTransport, StaticLoginCredentials>,
+    /// *preferred* bot enforced outbound chat client msg stream
+    pub chat: Mutex<Chat>,
+    /// joined channels
+    botchannels: Vec<String>,
+    /// admin chatters
+    admins: Vec<String>,
+    /// listeners
+    listeners: Mutex<Vec<Listener>>,
+    /// commands
+    commands: Mutex<Vec<Command>>,
+    /// modules
+    modules: RwLock<Vec<Module>>,
+    /// channel module status
+    channel_module_status: RwLock<Vec<(String, String, modules::Status)>>,
+    /// chatter guest badges - chatter,channel,Badge,start_time,duration
+    chatter_guest_badges: Mutex<Vec<(String, String, Badge, Instant, Duration)>>,
+    /// Message cache
+    message_cache: Mutex<Vec<PrivmsgMessage>>,
+    // /// channel_quiet
+    // channel_quiet_yn: RwLock<Vec<(String,RwLock<bool>)>>,
+}
+
+impl Bot {
+    /// Creates a new `Bot` using env variables
+    ///
+    /// Be sure the following is defined in an `.env` file
+    /// - login_name
+    /// - access_token
+    /// - bot_channels
+    /// - prefix
+    /// - bot_admins
+    // #[async_recursion]
+    pub async fn new() -> Arc<Bot> {
+        dotenv().ok();
+        let bot_login_name = env::var("login_name").unwrap().to_owned();
+        let oauth_token = env::var("access_token").unwrap().to_owned();
+        let prefix = env::var("prefix").unwrap().to_owned();
+
+        let mut botchannels = Vec::new();
+
+        for chnl in env::var("bot_channels").unwrap().split(',') {
+            botchannels.push(chnl.to_owned());
+        }
+
+        Bot::new_from(bot_login_name, oauth_token, prefix, botchannels).await
+    }
+
+    /// Creates a new `Bot` using bot information
+    ///
+    /// Bot will join `botchannels` argument
+    pub async fn new_from(
+        bot_login_name: String,
+        oauth_token: String,
+        prefix: String,
+        botchannels: Vec<String>,
+    ) -> Arc<Bot> {
+        dotenv().ok();
+        let bot_login_name = bot_login_name;
+
+        let config = twitch_irc::ClientConfig::new_simple(StaticLoginCredentials::new(
+            bot_login_name.to_owned(),
+            Some(oauth_token.to_owned()),
+        ));
+
+        let (incoming_messages, client) =
+            TwitchIRCClient::<SecureTCPTransport, StaticLoginCredentials>::new(config);
+
+        let mut botchannels_all = Vec::new();
+        botchannels_all.extend(botchannels);
+
+        let mut admins = Vec::new();
+
+        if let Ok(value) = env::var("bot_admins") {
+            for admin in value.split(',') {
+                admins.push(String::from(admin))
+            }
+        }
+
+        let bot = Bot {
+            prefix,
+            incoming_msgs: Mutex::new(incoming_messages),
+            client: client.clone(),
+            chat: Mutex::new(Chat::new(client).await),
+            botchannels: botchannels_all,
+            listeners: Mutex::new(vec![]),
+            commands: Mutex::new(vec![]),
+            admins,
+            modules: RwLock::new(vec![]),
+            channel_module_status: RwLock::new(vec![]),
+            chatter_guest_badges: Mutex::new(vec![]),
+            message_cache: Mutex::new(vec![]),
+            //  channel_quiet_yn : RwLock::new(vec![]),
+        };
+
+        async fn load_modules(bot: Bot) -> Bot {
+            // let mut bot1 = bot;
+
+            // bot1.chat = Some(Chat::new(client, bot1));
+
+            for cmd in built_in_objects::create_commands() {
+                bot.load_command(cmd).await;
+            }
+            built_in_mods::load_built_in_mods(&bot).await;
+
+            bot
+        }
+
+        let bot = load_modules(bot).await;
+
+        let bot = Arc::new(bot);
+
+        // let lock = bot.chat.lock().await;
+
+        // *lock = Some(Chat::new(chat, bot.clone()));
+
+        // let cht = Chat::new(chat).await;
+
+        // bot.chat.lock()
+
+        // lock.set_parent_bot(bot.clone());
+
+        println!("Joined - {:?}", bot.botchannels);
+
+        bot.clone()
+    }
+
+    /// Runs the bot
+    pub async fn run(self: Arc<Self>) {
+        for chnl in &self.botchannels {
+            self.client.join(chnl.to_owned()).unwrap();
+        }
+
+        // let bot = Arc::new(self);
+        let bot = self;
+
+        let join_handle = tokio::spawn(async move {
+            let a = bot.clone();
+            let mut in_msgs_lock = a.incoming_msgs.lock().await;
+
+            while let Some(message) = in_msgs_lock.recv().await {
+                // dbg!(message.clone())  ;
+
+                let bot_listener_lock = bot.listeners.lock().await;
+                for listener in bot_listener_lock.iter() {
+                    let a = listener.clone();
+                    if a.cond_triggered(bot.clone(), message.clone()).await {
+                        let _ = listener.execute_fn(bot.clone(), message.clone()).await;
+                    }
+                }
+
+                if let ServerMessage::Privmsg(msg) = message.clone() {
+                    // let mut cache_lock = bot.message_cache.lock().await;
+                    let mut cache_lock = bot.message_cache.lock().await;
+                    cache_lock.push(msg.clone());
+                    // dbg!(cache_lock.clone());
+                    drop(cache_lock);
+
+                    let cmd_lock = bot.commands.lock().await;
+                    for cmd in cmd_lock.iter() {
+                        let a = cmd.clone();
+                        if a.command_triggered(bot.clone(), msg.clone()).await {
+                            let _ = cmd.execute_fn(bot.clone(), message.clone()).await;
+                        }
+                    }
+
+                    fn get_enabled_channel_modules(bot: Arc<Bot>, channel: String) -> Vec<Module> {
+                        let botmodules_lock = bot.modules.read().unwrap();
+                        let botmodules_cpy = botmodules_lock.clone();
+                        drop(botmodules_lock);
+
+                        let mut enabled_mods = Vec::new();
+
+                        'module_loop: for module in &*botmodules_cpy {
+                            // dbg!("try cms read");
+                            let cms_lock = bot.channel_module_status.read().unwrap();
+
+                            for channel_flags in cms_lock.iter() {
+                                if channel_flags.0 == channel {
+                                    if module.get_names().contains(&channel_flags.1)
+                                        && channel_flags.2 == Status::Disabled
+                                    {
+                                        continue 'module_loop;
+                                    }
+                                }
+                            }
+                            enabled_mods.push(module.clone());
+                        }
+
+                        enabled_mods
+                    }
+
+                    for module in
+                        get_enabled_channel_modules(bot.clone(), msg.clone().channel_login)
+                    {
+                        for listener in module.get_listeners() {
+                            let a = listener.clone();
+                            if a.cond_triggered(bot.clone(), message.clone()).await {
+                                let _ = listener.execute_fn(bot.clone(), message.clone()).await;
+                            }
+                        }
+                        for cmd in module.get_commands() {
+                            let a = cmd.clone();
+                            if a.command_triggered(bot.clone(), msg.clone()).await {
+                                let _ = cmd.execute_fn(bot.clone(), message.clone()).await;
+                            }
+                        }
+                    }
+                } else {
+                };
+            }
+            drop(in_msgs_lock);
+        });
+
+        join_handle.await.unwrap();
+    }
+
+    /// Loads a `Listener` into the bot
+    pub async fn load_listener(&self, l: Listener) {
+        let a = Arc::new(self);
+        let mut listlock = a.listeners.lock().await;
+        listlock.push(l);
+    }
+
+    /// Loads a `Command` into the bot
+    pub async fn load_command(&self, c: Command) {
+        let a = Arc::new(self);
+        let mut cmdlock = a.commands.lock().await;
+        cmdlock.push(c);
+    }
+
+    pub async fn get_module(&self, module: String) -> Option<Module> {
+        let modlock = self.modules.read().unwrap();
+        for modl in modlock.iter() {
+            if modl.get_names().contains(&module) {
+                return Some(modl.clone());
+            }
+        }
+        None
+    }
+
+    pub fn get_prefix(&self) -> String {
+        self.prefix.clone()
+    }
+
+    pub fn get_admins(&self) -> Vec<String> {
+        self.admins.clone()
+    }
+
+    /// loads a `Module` and its bot objects
+    pub async fn load_module(&self, m: Module) {
+        // dbg!("load module - start",m.get_names().first().unwrap());
+        let bot = Arc::new(self);
+        // let bot_lock = bot.lock().await;
+        // dbg!("bot arc");
+        if m.get_status_by_default() == Status::Disabled {
+            // dbg!("module fund disabled by default");
+            // dbg!("inner if");
+            for (_index, chnl) in bot.botchannels.iter().enumerate() {
+                // dbg!("iter - ",index);
+                bot.disable_module(chnl.clone(), m.get_names().first().unwrap().clone())
+                    .await
+            }
+        }
+        // dbg!("aftee disable check");
+        // dbg!(bot.modules);
+        let mut botmods = bot.modules.write().unwrap();
+        // dbg!(m);
+        // dbg!("loading module ",m.get_names());
+        botmods.push(m);
+    }
+
+    pub async fn get_channel_module_status(&self, channel: String, module: String) -> Status {
+        // dbg!("get channel module status");
+        let found_disabled: bool = {
+            // dbg!("try cms read");
+            let cms_lock = self.channel_module_status.read().unwrap();
+            // dbg!("cms read lock");
+            // dbg!(module.clone());
+            let mut found = false;
+
+            for channel_flags in cms_lock.iter() {
+                if channel_flags.0 == channel {
+                    if channel_flags.1 == module && channel_flags.2 == Status::Disabled {
+                        found = true;
+                    }
+                }
+            }
+            found
+        };
+
+        let module_loaded: bool = {
+            let mut loaded_yn = false;
+
+            for loaded_m in self.modules.read().unwrap().iter() {
+                if loaded_m.get_names().contains(&module) {
+                    loaded_yn = true;
+                }
+            }
+
+            loaded_yn
+        };
+
+        if found_disabled {
+            return Status::Disabled;
+        } else if !module_loaded {
+            return Status::NotLoaded;
+        } else {
+            return Status::Enabled;
+        };
+    }
+
+    pub async fn disable_module(&self, channel: String, module: String) {
+        // dbg!("disable module called",channel.clone(),module.clone());
+
+        let found_disabled: bool = {
+            // dbg!("finding disabled mod");
+            // dbg!("try cms read");
+            let cms_lock = self.channel_module_status.read().unwrap();
+            // dbg!("cms read lock");
+            // dbg!(module.clone());
+
+            let mut found = false;
+
+            for channel_flags in cms_lock.iter() {
+                if channel_flags.0 == channel {
+                    if channel_flags.1 == module && channel_flags.2 == Status::Disabled {
+                        found = true;
+                    }
+                }
+            }
+            drop(cms_lock);
+            found
+        };
+
+        if !found_disabled {
+            let mut cms_lock = self.channel_module_status.write().unwrap();
+
+            cms_lock.push((channel, module.clone(), Status::Disabled));
+
+            drop(cms_lock);
+        }
+    }
+
+    pub async fn enable_module(&self, channel: String, module: String) {
+        // dbg!("enable module called",channel.clone(),module.clone());
+        // dbg!("try cms write");
+        let mut lock = self.channel_module_status.write().unwrap();
+        // dbg!("cms write lock");
+        // dbg!(module.clone());
+        while lock.contains(&(channel.clone(), module.clone(), Status::Disabled)) {
+            let index = lock
+                .iter()
+                .position(|x| *x == (channel.clone(), module.clone(), Status::Disabled))
+                .unwrap();
+            lock.remove(index);
+        }
+        drop(lock);
+    }
+
+    pub async fn get_channel_guest_badges(
+        &self,
+        chatter: String,
+        channel: String,
+    ) -> Vec<(Badge, Instant, Duration)> {
+        let bot = Arc::new(self);
+        let guest_badges_lock = bot.chatter_guest_badges.lock().await;
+
+        let mut badges = vec![];
+        for temp_badge in guest_badges_lock.iter() {
+            if temp_badge.0 == chatter
+                && temp_badge.1 == channel
+                && temp_badge.3 + temp_badge.4 > Instant::now()
+            {
+                badges.push((temp_badge.2.clone(), temp_badge.3, temp_badge.4));
+            }
+        }
+
+        badges
+    }
+
+    pub async fn issue_new_guest_badge(
+        &self,
+        chatter: String,
+        channel: String,
+        badge: Badge,
+        start: Instant,
+        dur: Duration,
+    ) {
+        let bot = Arc::new(self);
+        let mut guest_badges_lock = bot.chatter_guest_badges.lock().await;
+
+        guest_badges_lock.push((chatter, channel, badge, start, dur));
+    }
+
+    pub fn get_message_cache(&self) -> &Mutex<Vec<PrivmsgMessage>> {
+        &self.message_cache
+    }
+
+    /// get message cache newest to oldest for a channel
+    pub async fn get_message_cache_per_channel(&self, channel: String) -> Vec<PrivmsgMessage> {
+        let cache = self.message_cache.lock().await;
+        let mut rslt = vec![];
+        for a in cache
+            .iter()
+            .rev()
+            .filter(|x| x.channel_login == channel)
+            .into_iter()
+        {
+            rslt.push(a.clone());
+        }
+        rslt
+    }
+
+    // /// Get the quiet status of a channel
+    // pub fn get_channel_quiet(&self,channel:String) -> bool {
+    //     for a in self.channel_quiet_yn.read().unwrap().iter() {
+    //         if a.0 == channel {
+    //             return a.1.read().unwrap().clone();
+    //         }
+    //     }
+    //     return false;
+    // }
+
+    // /// Get the quiet status of a channel
+    // pub fn set_channel_quiet(&self,channel:String,quiet_on:bool) {
+    //     let mut found = false;
+
+    //     let chnlquiet = self.channel_quiet_yn.read().unwrap();
+    //     for rec in chnlquiet.iter() {
+    //         if rec.0 == channel {
+    //             found = true;
+    //             let mut status = rec.1.write().unwrap();
+    //             *status = quiet_on;
+    //             drop(status);
+    //         }
+    //     }
+    //     drop(chnlquiet);
+
+    //     if !found {
+    //         // dbg!("set chn quiet > !found channel quiet status");
+    //         let mut chnlquiet = self.channel_quiet_yn.write().unwrap();
+    //         chnlquiet.push((channel,RwLock::new(quiet_on)));
+    //         drop(chnlquiet);
+    //     }
+
+    // }
+}
diff --git a/forcebot_core/src/botcore/bot_objects.rs b/forcebot_core/src/botcore/bot_objects.rs
new file mode 100644
index 0000000..77de39c
--- /dev/null
+++ b/forcebot_core/src/botcore/bot_objects.rs
@@ -0,0 +1,399 @@
+pub mod command;
+pub mod listener;
+
+use std::boxed::Box;
+use std::future::Future;
+use std::pin::Pin;
+use std::sync::Arc;
+
+use twitch_irc::message::{PrivmsgMessage, ServerMessage};
+
+use super::bot::Bot;
+
+/// chat badge
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub enum Badge {
+    Moderator,
+    Broadcaster,
+    Vip,
+}
+
+pub type ExecBody = Box<
+    dyn Fn(Arc<Bot>, ServerMessage) -> Pin<Box<dyn Future<Output = Result<String, String>> + Send>>
+        + Send
+        + Sync,
+>;
+
+/// used to store async execution functions. Primarily used for `Command`
+///
+/// call this to store execution functions in `Commands`
+///
+/// # example
+/// ```
+/// /* 2. Define exec callback  */
+///  async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
+///   /* do smth */
+///  }
+///
+/// /* 3. Set Command flags */
+///  cmd.set_exec_fn(execution_async(execbody));
+/// ```
+///
+pub fn execution_async<T>(f: fn(Arc<Bot>, ServerMessage) -> T) -> ExecBody
+where
+    T: Future<Output = Result<String, String>> + Send + 'static,
+{
+    Box::new(move |a, b| Box::pin(f(a, b)))
+}
+
+pub type CommandTrigger = Box<
+    dyn Fn(Arc<Bot>, PrivmsgMessage) -> Pin<Box<dyn Future<Output = bool> + Send>> + Send + Sync,
+>;
+
+/// used to store async trigger condition callback functions. Primarily used for `Command`
+///
+/// # example
+/// ```
+/// /* 2. Define condition callback  */
+/// async fn condition01(bot:Arc<Bot>,message:ServerMessage) -> bool {
+///   /* do smth */
+/// }
+///
+/// /* 3. Set Command flags */
+/// cmd.set_custom_cond_async(command_condition_async(condition01));
+/// ```
+///
+pub fn command_condition_async<T>(f: fn(Arc<Bot>, PrivmsgMessage) -> T) -> CommandTrigger
+where
+    T: Future<Output = bool> + Send + 'static,
+{
+    Box::new(move |a, b| Box::pin(f(a, b)))
+}
+
+pub type ListenerTrigger = Box<
+    dyn Fn(Arc<Bot>, ServerMessage) -> Pin<Box<dyn Future<Output = bool> + Send>> + Send + Sync,
+>;
+
+/// used to store async trigger condition callback functions. Primarily used for `Listener`
+///
+/// # example
+/// ```
+/// /* 2. Define condition callback  */
+/// async fn condition01(bot:Arc<Bot>,message:ServerMessage) -> bool {
+///   /* do smth */
+/// }
+///
+/// /* 3. Set Command flags */
+/// cmd.set_custom_cond_async(listener_condition_async(condition01));
+/// ```
+///
+pub fn listener_condition_async<T>(f: fn(Arc<Bot>, ServerMessage) -> T) -> ListenerTrigger
+where
+    T: Future<Output = bool> + Send + 'static,
+{
+    Box::new(move |a, b| Box::pin(f(a, b)))
+}
+
+/// collection of functions to create built in objects
+pub mod built_in_objects {
+    const TEMP_BADGE_DUR_MIN: u64 = 30;
+
+    use std::{
+        sync::Arc,
+        time::{Duration, Instant},
+    };
+
+    use twitch_irc::message::ServerMessage;
+
+    use super::{super::modules::Status, command::Command, execution_async, Badge, Bot};
+
+    /// create a vector of command build in objects
+    pub fn create_commands() -> Vec<Command> {
+        let mut cmds = vec![];
+
+        cmds.push(create_disable_cmd());
+        cmds.push(create_enable_cmd());
+        cmds.push(create_iam_role_cmd());
+
+        cmds
+    }
+
+    fn create_disable_cmd() -> Command {
+        /* 1. Create a new blank cmd */
+        let mut cmd = Command::new(vec!["disable".to_string()], "".to_string());
+
+        /* 2. Define an async fn callback execution */
+        async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+            if let ServerMessage::Privmsg(msg) = message {
+                let mut action_taken = false;
+                for (i, arg) in msg
+                    .message_text
+                    .replace("\u{e0000}", "")
+                    .trim()
+                    .split(" ")
+                    .enumerate()
+                {
+                    if i > 1 {
+                        if bot
+                            .get_channel_module_status(msg.channel_login.clone(), arg.to_string())
+                            .await
+                            == Status::Enabled
+                        {
+                            action_taken = true;
+                            bot.disable_module(msg.channel_login.clone(), arg.to_string())
+                                .await;
+                        }
+                    }
+                }
+                if action_taken {
+                    let _ = bot
+                        .chat
+                        .lock()
+                        .await
+                        .say_in_reply_to(&msg, String::from("Disabled!"))
+                        .await;
+                }
+            }
+            Result::Err("Not Valid message type".to_string())
+        }
+
+        /* 3. Set and Store the execution body using `execution_async()`  */
+        cmd.set_exec_fn(execution_async(execbody));
+
+        /* 4. optionally, remove admin only default flag */
+        cmd.set_admin_only(false);
+
+        /* 5. optionally, set min badge*/
+        cmd.set_min_badge(Badge::Moderator /* ::Moderator */);
+        cmd
+    }
+
+    fn create_enable_cmd() -> Command {
+        /* 1. Create a new blank cmd */
+        let mut cmd = Command::new(vec!["enable".to_string()], "".to_string());
+
+        /* 2. Define an async fn callback execution */
+        async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+            if let ServerMessage::Privmsg(msg) = message {
+                let mut bot_message = "".to_string();
+                let mut re_enabled = false;
+
+                for (i, arg) in msg
+                    .message_text
+                    .replace("\u{e0000}", "")
+                    .trim()
+                    .split(" ")
+                    .enumerate()
+                {
+                    if i > 1 {
+                        if Status::Disabled
+                            == bot
+                                .get_channel_module_status(
+                                    msg.channel_login.clone(),
+                                    arg.to_string(),
+                                )
+                                .await
+                        {
+                            bot.enable_module(msg.channel_login.clone(), arg.to_string())
+                                .await;
+
+                            //bot.get_modules()
+                            if let Some(found_mod) = bot.get_module(arg.to_string()).await {
+                                bot_message = bot_message.to_string()
+                                    + found_mod.get_bot_read_description().as_str();
+                            }
+                            re_enabled = true;
+                        }
+                    }
+                }
+
+                if re_enabled {
+                    if bot_message.len() > 250 {
+                        bot_message = bot_message[..250].to_string();
+                    }
+
+                    let _ = bot
+                        .chat
+                        .lock()
+                        .await
+                        .say_in_reply_to(&msg, format!("Enabled! {}", bot_message))
+                        .await;
+                }
+            }
+            Result::Err("Not Valid message type".to_string())
+        }
+
+        /* 3. Set and Store the execution body using `execution_async()`  */
+        cmd.set_exec_fn(execution_async(execbody));
+
+        /* 4. optionally, remove admin only default flag */
+        cmd.set_admin_only(false);
+
+        /* 5. optionally, set min badge*/
+        cmd.set_min_badge(Badge::Moderator);
+        cmd
+    }
+
+    /// adminonly command that grants a temporary role
+    fn create_iam_role_cmd() -> Command {
+        /* 1. Create a new blank cmd */
+        let mut cmd = Command::new(
+            vec!["I am ".to_string(), "I'm ".to_string(), "Im a ".to_string()],
+            "".to_string(),
+        );
+
+        /* 2. Define an async fn callback execution */
+        async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+            if let ServerMessage::Privmsg(msg) = message {
+                for (i, arg) in msg
+                    .message_text
+                    .replace("\u{e0000}", "")
+                    .trim()
+                    .split(" ")
+                    .enumerate()
+                {
+                    if i > 1 {
+                        // bot.disable_module(msg.channel_login.clone(), arg.to_string()).await;
+                        // #todo
+                        // if not dont have the badge or have a lower priviledge badge
+                        // and they dont have an active guest badge, ths admin can be
+                        // recognzed wth that badge
+
+                        if arg == "mod" || arg == "moderator" {
+                            let curr_temp_badges = bot
+                                .get_channel_guest_badges(
+                                    msg.sender.login.clone(),
+                                    msg.channel_login.clone(),
+                                )
+                                .await;
+                            let mut found = false;
+                            for temp_badge in curr_temp_badges {
+                                if temp_badge.0 == Badge::Moderator {
+                                    found = true;
+                                }
+                            }
+                            if found {
+                                /* do nothing */
+                            } else {
+                                bot.issue_new_guest_badge(
+                                    msg.sender.login.clone(),
+                                    msg.channel_login.clone(),
+                                    Badge::Moderator,
+                                    Instant::now(),
+                                    Duration::from_secs(60 * TEMP_BADGE_DUR_MIN),
+                                )
+                                .await;
+
+                                let _ = bot
+                                    .chat
+                                    .lock()
+                                    .await
+                                    .say_in_reply_to(
+                                        &msg,
+                                        format!(
+                                            "Temp {:?} issued for {:?} minutes",
+                                            Badge::Moderator,
+                                            TEMP_BADGE_DUR_MIN
+                                        ),
+                                    )
+                                    .await;
+                            }
+                        }
+                        if arg == "vip" {
+                            let curr_temp_badges = bot
+                                .get_channel_guest_badges(
+                                    msg.sender.login.clone(),
+                                    msg.channel_login.clone(),
+                                )
+                                .await;
+                            let mut found = false;
+                            for temp_badge in curr_temp_badges {
+                                if temp_badge.0 == Badge::Vip {
+                                    found = true;
+                                }
+                            }
+                            if found {
+                                /* do nothing */
+                            } else {
+                                bot.issue_new_guest_badge(
+                                    msg.sender.login.clone(),
+                                    msg.channel_login.clone(),
+                                    Badge::Vip,
+                                    Instant::now(),
+                                    Duration::from_secs(60 * TEMP_BADGE_DUR_MIN),
+                                )
+                                .await;
+
+                                let _ = bot
+                                    .chat
+                                    .lock()
+                                    .await
+                                    .say_in_reply_to(
+                                        &msg,
+                                        format!(
+                                            "Temp {:?} issued for {:?} minutes for the bot admin",
+                                            Badge::Vip,
+                                            TEMP_BADGE_DUR_MIN
+                                        ),
+                                    )
+                                    .await;
+                            }
+                        }
+                        if arg == "broadcaster" || arg == "strimmer" || arg == "streamer" {
+                            let curr_temp_badges = bot
+                                .get_channel_guest_badges(
+                                    msg.sender.login.clone(),
+                                    msg.channel_login.clone(),
+                                )
+                                .await;
+                            let mut found = false;
+                            for temp_badge in curr_temp_badges {
+                                if temp_badge.0 == Badge::Broadcaster {
+                                    found = true;
+                                }
+                            }
+                            if found {
+                                /* do nothing */
+                            } else {
+                                bot.issue_new_guest_badge(
+                                    msg.sender.login.clone(),
+                                    msg.channel_login.clone(),
+                                    Badge::Broadcaster,
+                                    Instant::now(),
+                                    Duration::from_secs(60 * TEMP_BADGE_DUR_MIN),
+                                )
+                                .await;
+
+                                let _ = bot
+                                    .chat
+                                    .lock()
+                                    .await
+                                    .say_in_reply_to(
+                                        &msg,
+                                        format!(
+                                            "Temp {:?} issued for {:?} minutes for the bot admin",
+                                            Badge::Broadcaster,
+                                            TEMP_BADGE_DUR_MIN
+                                        ),
+                                    )
+                                    .await;
+                            }
+                        }
+                    }
+                }
+                // let _ = bot.chat.lock().await.say_in_reply_to(&msg, String::from("Disabled!")).await ;
+            }
+            Result::Err("Not Valid message type".to_string())
+        }
+
+        /* 3. Set and Store the execution body using `execution_async()`  */
+        cmd.set_exec_fn(execution_async(execbody));
+
+        /* 4. optionally, remove admin only default flag */
+        cmd.set_admin_only(true);
+
+        // /* 5. optionally, set min badge*/
+        // cmd.set_min_badge(Badge::Moderator);
+        cmd
+    }
+}
diff --git a/forcebot_core/src/botcore/bot_objects/command.rs b/forcebot_core/src/botcore/bot_objects/command.rs
new file mode 100644
index 0000000..10a1e6b
--- /dev/null
+++ b/forcebot_core/src/botcore/bot_objects/command.rs
@@ -0,0 +1,226 @@
+use std::sync::Arc;
+
+use twitch_irc::message::{PrivmsgMessage, ServerMessage};
+
+use super::{command_condition_async, execution_async, Badge, Bot};
+
+use super::{CommandTrigger, ExecBody};
+
+/// Bot `Command` that stores trigger condition callback and a execution functon
+///
+/// A prefix character or phrase can be defined for the bot to evaluate a trigger condition
+///
+/// A command or command phrase defines the phrase after the prefix phrase
+///
+/// If no min badge role is provided, Broadcaster is defaulted. All commands require at least a vip role
+///
+/// AdminOnly commands can only be ran by admin
+///
+/// Use `execution_async()` on custom async execution bodies
+#[derive(Clone)]
+pub struct Command {
+    commands: Vec<String>,
+    exec_fn: Arc<ExecBody>,
+    min_badge: Badge,
+    /// only admins can run - default : `true`
+    admin_only: bool,
+    /// admin role overrides channel badge - default : `false`
+    admin_override: bool,
+    prefix: String,
+    custom_cond_fn: fn(Arc<Bot>, PrivmsgMessage) -> bool,
+    custom_cond_async: Arc<CommandTrigger>,
+}
+
+impl Command {
+    /// Creates a new empty `Command` using command `String` and prefix `String`
+    /// Pass an empty string prefix if the bot should use the bot default
+    ///    
+    /// Call `set_trigger_cond_fn()` and `set_exec_fn()` to trigger & execution function callbacks
+    /// if a blank prefix is given, the bot will look for the bot prefix instead
+    ///
+    /// By default, the new command is admin_only
+    pub fn new(commands: Vec<String>, prefix: String) -> Command {
+        async fn execbody(_: Arc<Bot>, _: ServerMessage) -> Result<String, String> {
+            Result::Ok("success".to_string())
+        }
+        async fn condition01(_: Arc<Bot>, _: PrivmsgMessage) -> bool {
+            true
+        }
+
+        Command {
+            commands,
+            prefix,
+            exec_fn: Arc::new(execution_async(execbody)),
+            min_badge: Badge::Vip,
+            admin_only: true,
+            admin_override: false,
+            custom_cond_fn: |_: Arc<Bot>, _: PrivmsgMessage| true,
+            custom_cond_async: Arc::new(command_condition_async(condition01)),
+        }
+    }
+
+    /// set a trigger condition callback that returns true if the command should trigger
+    pub fn set_custom_cond_fn(&mut self, cond_fn: fn(Arc<Bot>, PrivmsgMessage) -> bool) {
+        self.custom_cond_fn = cond_fn;
+    }
+
+    /// sets the async trigger condition for listener
+    ///
+    /// Same as `set_custom_cond_fn()` , but async define
+    ///
+    /// Use`execution_async()` on the async fn when storing
+    ///
+    /// Example -
+    /// ```rust
+    /// /* 1. Create a new blank Listener */
+    /// let mut cmd = Command::new();
+    ///
+    /// /* 2. define an async function */
+    /// async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true }
+    ///
+    /// /* 3. Set and Store the execution body using `execution_async()`  */
+    /// cmd.set_custom_cond_async(condition_async(condition01));
+    /// ```
+    ///
+    pub fn set_custom_cond_async(&mut self, condition: CommandTrigger) {
+        self.custom_cond_async = Arc::new(condition);
+    }
+
+    /// sets the execution body of the listener for when it triggers
+    ///
+    /// Use`execution_async()` on the async fn when storing
+    ///
+    ///
+    pub fn set_exec_fn(&mut self, exec_fn: ExecBody) {
+        self.exec_fn = Arc::new(exec_fn);
+    }
+
+    /// checks if the trigger condition is met
+    /// specifically if the message is a valid command and min badge roles provided
+    ///
+    pub async fn command_triggered(&self, bot: Arc<Bot>, msg: PrivmsgMessage) -> bool {
+        fn cmd_called(cmd: &Command, bot: Arc<Bot>, message: PrivmsgMessage) -> bool {
+            let mut prefixed_cmd = "".to_string();
+            if cmd.prefix == "" {
+                prefixed_cmd.push_str(&bot.get_prefix());
+            } else {
+                prefixed_cmd.push_str(&cmd.prefix);
+            }
+            for cmd_nm in &cmd.commands {
+                prefixed_cmd.push_str(cmd_nm);
+                if message.message_text.starts_with(prefixed_cmd.as_str()) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        async fn caller_badge_ok(cmd: &Command, bot: Arc<Bot>, message: PrivmsgMessage) -> bool {
+            // senders that are admins skip badge check if the command is adminonly
+            if cmd.admin_only && bot.get_admins().contains(&message.sender.login) {
+                return true;
+            };
+
+            // adminOnly commands will can only be ran by admins
+            if cmd.admin_only && bot.get_admins().contains(&message.sender.login) {
+                return false;
+            }
+
+            // admin role overrides badge check if enabled
+            if cmd.admin_override && bot.get_admins().contains(&message.sender.login) {
+                return true;
+            }
+
+            for badge in message.badges {
+                match cmd.min_badge {
+                    Badge::Broadcaster => {
+                        if badge.name == "broadcaster" {
+                            return true;
+                        } else {
+                            return false;
+                        }
+                    }
+                    Badge::Moderator => match badge.name.as_str() {
+                        "moderator" | "broadcaster" => return true,
+                        _ => (),
+                    },
+                    Badge::Vip => match badge.name.as_str() {
+                        "vip" | "moderator" | "broadcaster" => return true,
+                        _ => (),
+                    },
+                }
+            }
+
+            for temp_badge in bot
+                .get_channel_guest_badges(message.sender.login, message.channel_login)
+                .await
+            {
+                match (cmd.min_badge.clone(), temp_badge.0) {
+                    (Badge::Broadcaster, Badge::Broadcaster) => return true,
+                    (Badge::Moderator, Badge::Moderator)
+                    | (Badge::Moderator, Badge::Broadcaster) => return true,
+                    (Badge::Vip, Badge::Vip)
+                    | (Badge::Vip, Badge::Moderator)
+                    | (Badge::Vip, Badge::Broadcaster) => return true,
+                    _ => (),
+                }
+            }
+
+            return false;
+        }
+
+        /// determines if the command caller can run the command
+        /// based on admin_only flag
+        ///
+        /// callers who are admins can run admin_only commands
+        /// callers can run non-admin_only commands
+        fn admin_only_ok(cmd: &Command, bot: Arc<Bot>, message: PrivmsgMessage) -> bool {
+            if (cmd.admin_only && bot.get_admins().contains(&message.sender.login))
+                || !cmd.admin_only
+            {
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        async fn custom_cond_ok(cmd: &Command, bot: Arc<Bot>, message: PrivmsgMessage) -> bool {
+            (cmd.custom_cond_fn)(bot.clone(), message.clone())
+                && (cmd.custom_cond_async)(bot, message).await
+        }
+
+        // async fn quiet_off_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool {
+        //     !bot.chat.lock().await.get_channel_quiet(message.channel_login.clone())
+        //     || bot.chat.lock().await.get_channel_quiet(message.channel_login.clone()) && cmd.commands.contains(&("quiet off".to_string()))
+        // }
+
+        cmd_called(self, bot.clone(), msg.clone())
+            && caller_badge_ok(self, bot.clone(), msg.clone()).await
+            && admin_only_ok(self, bot.clone(), msg.clone())
+            && custom_cond_ok(self, bot.clone(), msg.clone()).await
+        //  &&
+        // quiet_off_ok(self, bot, msg).await
+    }
+
+    /// executes the listeners executon body
+    pub async fn execute_fn(&self, bot: Arc<Bot>, msg: ServerMessage) -> Result<String, String> {
+        (self.exec_fn)(bot, msg).await
+    }
+
+    /// sets min_badge to run the cmd
+    // pub fn set_min_badge(&mut self,min_badge:String) {
+    pub fn set_min_badge(&mut self, min_badge: Badge) {
+        self.min_badge = min_badge
+    }
+
+    /// sets admin_only
+    pub fn set_admin_only(&mut self, admin_only: bool) {
+        self.admin_only = admin_only
+    }
+
+    /// sets admin_override . This lets admins bypass
+    /// badge restrictions   
+    pub fn set_admin_override(&mut self, admin_override: bool) {
+        self.admin_override = admin_override
+    }
+}
diff --git a/forcebot_core/src/botcore/bot_objects/listener.rs b/forcebot_core/src/botcore/bot_objects/listener.rs
new file mode 100644
index 0000000..2633b3b
--- /dev/null
+++ b/forcebot_core/src/botcore/bot_objects/listener.rs
@@ -0,0 +1,147 @@
+use std::sync::Arc;
+
+use twitch_irc::message::ServerMessage;
+
+use crate::Module;
+
+use super::{execution_async, listener_condition_async, Bot};
+
+use super::{ExecBody, ListenerTrigger};
+
+/// Bot `Listener` that stores trigger condition callback and a execution functon
+///
+/// Use `Listener` functions to define the Trigger Condition & Execution callbacks.
+/// When the Trigger callback is `true`, the Execution callback runs in the bot loop
+///
+/// Create a new empty `Listener` with `new()`
+///
+/// Use the following on the empty listener before loading it into the bot to set the callbacks
+///
+/// - `set_trigger_cond_fn()` - to define the Trigger condition callback
+///
+/// - `set_exec_fn()` - to define the Execution Callback
+#[derive(Clone)]
+pub struct Listener {
+    /// trigger condition
+    trigger_cond_fn: fn(Arc<Bot>, ServerMessage) -> bool,
+    /// trigger condition for async
+    trigger_cond_async: Arc<ListenerTrigger>,
+    /// execution body
+    exec_fn: Arc<ExecBody>,
+    parent_module: Arc<Option<Module>>,
+}
+
+impl Listener {
+    /// Creates a new empty `Listener`
+    ///
+    /// Use `Listener` functions to define the Trigger Condition & Execution callbacks.
+    /// When the Trigger callback is `true`, the Execution callback runs in the bot loop
+    ///
+    /// Use the following on the empty listener before loading it into the bot to set the callbacks
+    ///
+    /// - `set_trigger_cond_fn()` - to define the Trigger condition callback
+    ///
+    /// - `set_exec_fn()` - to define the Execution Callback
+    pub fn new() -> Listener {
+        async fn execbody(_: Arc<Bot>, _: ServerMessage) -> Result<String, String> {
+            Result::Ok("success".to_string())
+        }
+        async fn condition01(_: Arc<Bot>, _: ServerMessage) -> bool {
+            true
+        }
+        Listener {
+            trigger_cond_fn: |_: Arc<Bot>, _: ServerMessage| true,
+            trigger_cond_async: Arc::new(listener_condition_async(condition01)),
+            exec_fn: Arc::new(execution_async(execbody)),
+            parent_module: Arc::new(None),
+        }
+    }
+
+    /// set a trigger conditin callback that returns true if the listener shoud trigger
+    pub fn set_trigger_cond_fn(&mut self, cond_fn: fn(Arc<Bot>, ServerMessage) -> bool) {
+        self.trigger_cond_fn = cond_fn;
+    }
+
+    /// sets the async trigger condition for listener
+    ///
+    /// Same as `set_trigger_cond_fn()` , but async define
+    ///
+    /// Use`condition_async()` on the async fn when storing
+    ///
+    /// Example -
+    /// ```rust
+    /// /* 1. Create a new blank Listener */
+    /// let mut listener = Listener::new();
+    ///
+    /// /* 2. define an async function */
+    /// async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true }
+    ///
+    /// /* 3. Set and Store the execution body using `execution_async()`  */
+    /// listener.set_trigger_cond_async(condition_async(condition01));
+    /// ```
+    ///
+    pub fn set_trigger_cond_async(&mut self, condition: ListenerTrigger) {
+        self.trigger_cond_async = Arc::new(condition);
+    }
+
+    /// sets the execution body of the listener for when it triggers
+    ///
+    /// Use`execution_async()` on the async fn when storing
+    ///
+    /// Example -
+    /// ```rust
+    /// /* 1. Create a new blank Listener */
+    /// let mut listener = Listener::new();
+    ///
+    /// /* 2. define an async function */
+    /// async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> {Result::Ok("success".to_string()) }
+    ///
+    /// /* 3. Set and Store the execution body using `execution_async()`  */
+    /// listener.set_exec_fn(execution_async(execbody));
+    /// ```
+    ///
+    pub fn set_exec_fn(&mut self, exec_fn: ExecBody) {
+        self.exec_fn = Arc::new(exec_fn);
+    }
+
+    /// checks if the trigger condition is met
+    pub async fn cond_triggered(&self, bot: Arc<Bot>, msg: ServerMessage) -> bool {
+        let list = Arc::new(self.clone());
+
+        async fn defined_conditions_ok(
+            list: Arc<Listener>,
+            bot: Arc<Bot>,
+            msg: ServerMessage,
+        ) -> bool {
+            // let list = Arc::new(self);
+            (list.trigger_cond_fn)(bot.clone(), msg.clone())
+                && (list.trigger_cond_async)(bot, msg).await
+        }
+
+        // async fn quiet_off_ok(list:Arc<Listener>,bot:Arc<Bot>,message:ServerMessage) -> bool {
+        //     if let ServerMessage::Privmsg(msg) = message {
+
+        //         if let Some(parent_mod) = &*list.parent_module {
+        //             return !bot.chat.lock().await.get_channel_quiet(msg.channel_login) || parent_mod.get_names().contains(&"debug".to_string());
+        //         }
+
+        //         return !bot.chat.lock().await.get_channel_quiet(msg.channel_login) ;
+        //     }
+        //     return true; /* quiet is off for non chat msgs */
+        // }
+
+        defined_conditions_ok(list.clone(), bot.clone(), msg.clone()).await
+        // &&
+        // quiet_off_ok(list, bot, msg).await
+    }
+
+    /// executes the listeners executon body
+    pub async fn execute_fn(&self, bot: Arc<Bot>, msg: ServerMessage) -> Result<String, String> {
+        (self.exec_fn)(bot, msg).await
+    }
+
+    /// sets parent module
+    pub fn set_parent_module(&mut self, module: Module) {
+        self.parent_module = Arc::new(Some(module));
+    }
+}
diff --git a/forcebot_core/src/botcore/built_in_mods.rs b/forcebot_core/src/botcore/built_in_mods.rs
new file mode 100644
index 0000000..03b8d28
--- /dev/null
+++ b/forcebot_core/src/botcore/built_in_mods.rs
@@ -0,0 +1,10 @@
+// use std::sync::Arc;
+
+use crate::Bot;
+
+pub mod quiet;
+
+/// used to internally load internal modules
+pub async fn load_built_in_mods(bot: &Bot) {
+    bot.load_module(quiet::create_module()).await;
+}
diff --git a/forcebot_core/src/botcore/built_in_mods/quiet.rs b/forcebot_core/src/botcore/built_in_mods/quiet.rs
new file mode 100644
index 0000000..7a12cc1
--- /dev/null
+++ b/forcebot_core/src/botcore/built_in_mods/quiet.rs
@@ -0,0 +1,90 @@
+use std::sync::Arc;
+
+use twitch_irc::message::ServerMessage;
+
+use crate::{execution_async, Badge, Bot, Command, Module};
+
+/// quiet the bot in a channel
+///
+/// use
+/// `quiet on`
+/// `quiet off`
+///
+///
+///
+
+/// Use this function when loading modules into the bot
+///
+/// For example
+/// ```rust
+/// bot.load_module(quiet::create_module());
+/// ```
+///
+pub fn create_module() -> Module {
+    /* 1. Create a new module */
+    let mut custom_mod = Module::new(vec!["quiet".to_string()], "".to_string());
+
+    /* 2. Load the cmd into a new module */
+    custom_mod.load_command(cmd_quiet_on());
+    custom_mod.load_command(cmd_quiet_off());
+    custom_mod
+}
+
+/// Command definition for quiet command
+fn cmd_quiet_on() -> Command {
+    /* 1. Create a new cmd */
+    let mut cmd = Command::new(vec!["quiet on".to_string()], "".to_string());
+
+    /* 2. Define exec callback  */
+    async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+        if let ServerMessage::Privmsg(msg) = message {
+            // dbg!("quiet on called");
+
+            let chatlock = bot.chat.lock().await;
+            let _ = chatlock.say_in_reply_to(&msg, "Shush ".to_string()).await;
+
+            chatlock.set_channel_quiet(msg.channel_login.clone(), true);
+            println!("channel {} set quiet true", msg.channel_login);
+
+            return Result::Ok("Success".to_string());
+        }
+        Result::Err("Not Valid message type".to_string())
+    }
+
+    /* 3. Set Command flags */
+    cmd.set_exec_fn(execution_async(execbody));
+    cmd.set_admin_only(false);
+    cmd.set_min_badge(Badge::Moderator);
+    cmd.set_admin_override(true);
+
+    cmd
+}
+
+/// Command definition for quiet command
+fn cmd_quiet_off() -> Command {
+    /* 1. Create a new cmd */
+    let mut cmd = Command::new(vec!["quiet off".to_string()], "".to_string());
+
+    /* 2. Define exec callback  */
+    async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+        if let ServerMessage::Privmsg(msg) = message {
+            let chatlock = bot.chat.lock().await;
+
+            chatlock.set_channel_quiet(msg.channel_login.clone(), false);
+            let _ = chatlock
+                .say_in_reply_to(&msg, "GoodGirl I'll be good for u chat rar ".to_string())
+                .await;
+
+            println!("channel {} set quiet false", msg.channel_login);
+        }
+        Result::Err("Not Valid message type".to_string())
+    }
+
+    /* 3. Set Command flags */
+    cmd.set_exec_fn(execution_async(execbody));
+    cmd.set_admin_only(false);
+    cmd.set_min_badge(Badge::Moderator);
+    cmd.set_admin_override(true);
+
+    cmd
+}
diff --git a/forcebot_core/src/botcore/chat.rs b/forcebot_core/src/botcore/chat.rs
new file mode 100644
index 0000000..42f1ec6
--- /dev/null
+++ b/forcebot_core/src/botcore/chat.rs
@@ -0,0 +1,140 @@
+use std::{
+    fmt::Error,
+    ops::Mul,
+    rc::Rc,
+    sync::{Arc, Mutex, RwLock},
+};
+
+use twitch_irc::{
+    login::StaticLoginCredentials, message::ReplyToMessage, SecureTCPTransport, TwitchIRCClient,
+};
+
+use crate::Bot;
+
+/// Bot API to send messages to send messages to chat
+///
+/// Uses TwitchIRCClient say_in_reply_to() but enforces controls like quiet
+///
+///
+
+pub struct Chat {
+    /// outbound chat client msg stream
+    pub client: TwitchIRCClient<SecureTCPTransport, StaticLoginCredentials>,
+    /// channel_quiet
+    channel_quiet_yn: RwLock<Vec<(String, RwLock<bool>)>>,
+}
+
+impl Chat {
+    pub async fn new(client: TwitchIRCClient<SecureTCPTransport, StaticLoginCredentials>) -> Chat {
+        Chat {
+            client,
+            // parent_bot : Mutex::new(Bot::new().await) ,
+            channel_quiet_yn: RwLock::new(vec![]),
+        }
+    }
+
+    // pub fn set_parent_bot(&self,parent_bot_in:Arc<Bot>)
+    // {
+    //     let mut lock = self.parent_bot.lock().unwrap();
+    //     *lock = parent_bot_in;
+    // }
+
+    /// helper
+    fn ok_to_send(&self, channel_login: String) -> bool {
+        fn not_quiet_ok(chat: &Chat, channel_login: String) -> bool {
+            // let lock = chat.parent_bot.lock().unwrap();
+            // let a = lock.as_ref();
+            // if let Some(bot) = &*lock {
+            return !chat.get_channel_quiet(channel_login);
+            // }
+            // true
+        }
+        not_quiet_ok(self, channel_login)
+    }
+
+    /// Get the quiet status of a channel
+    pub fn get_channel_quiet(&self, channel: String) -> bool {
+        for a in self.channel_quiet_yn.read().unwrap().iter() {
+            if a.0 == channel {
+                return a.1.read().unwrap().clone();
+            }
+        }
+        return false;
+    }
+
+    /// Get the quiet status of a channel
+    pub fn set_channel_quiet(&self, channel: String, quiet_on: bool) {
+        let mut found = false;
+
+        let chnlquiet = self.channel_quiet_yn.read().unwrap();
+        for rec in chnlquiet.iter() {
+            if rec.0 == channel {
+                found = true;
+                let mut status = rec.1.write().unwrap();
+                *status = quiet_on;
+                drop(status);
+            }
+        }
+        drop(chnlquiet);
+
+        if !found {
+            // dbg!("set chn quiet > !found channel quiet status");
+            let mut chnlquiet = self.channel_quiet_yn.write().unwrap();
+            chnlquiet.push((channel, RwLock::new(quiet_on)));
+            drop(chnlquiet);
+        }
+    }
+
+    pub async fn say_in_reply_to(
+        &self,
+        reply_to: &impl ReplyToMessage,
+        message: String,
+    ) -> Result<(), ()> {
+        // reply_to.channel_login()
+        if self.ok_to_send(reply_to.channel_login().to_string()) {
+            match self.client.say_in_reply_to(reply_to, message).await {
+                Ok(_) => return Ok(()),
+                Err(_) => return Err(()),
+            }
+        } else {
+            return Err(());
+        }
+    }
+
+    pub async fn say(&self, channel_login: String, message: String) -> Result<(), ()> {
+        if self.ok_to_send(channel_login.to_string()) {
+            match self.client.say(channel_login, message).await {
+                Ok(_) => return Ok(()),
+                Err(_) => return Err(()),
+            }
+        } else {
+            return Err(());
+        }
+    }
+
+    pub async fn me(&self, channel_login: String, message: String) -> Result<(), ()> {
+        if self.ok_to_send(channel_login.to_string()) {
+            match self.client.me(channel_login, message).await {
+                Ok(_) => return Ok(()),
+                Err(_) => return Err(()),
+            }
+        } else {
+            return Err(());
+        }
+    }
+
+    pub async fn me_in_reply_to(
+        &self,
+        reply_to: &impl ReplyToMessage,
+        message: String,
+    ) -> Result<(), ()> {
+        if self.ok_to_send(reply_to.channel_login().to_string()) {
+            match self.client.me_in_reply_to(reply_to, message).await {
+                Ok(_) => return Ok(()),
+                Err(_) => return Err(()),
+            }
+        } else {
+            return Err(());
+        }
+    }
+}
diff --git a/forcebot_core/src/botcore/modules.rs b/forcebot_core/src/botcore/modules.rs
new file mode 100644
index 0000000..dd9cc29
--- /dev/null
+++ b/forcebot_core/src/botcore/modules.rs
@@ -0,0 +1,74 @@
+// use std::sync::{Arc, Mutex};
+
+use super::bot_objects::command::Command;
+use super::bot_objects::listener::Listener;
+
+#[derive(PartialEq, Eq, Debug, Clone)]
+pub enum Status {
+    Disabled,
+    Enabled,
+    NotLoaded,
+}
+
+/// Bot `Module` that groups a set of `bot_objects`
+///
+/// Elevated chatters can disable modules by their name or chat alias
+#[derive(Clone)]
+pub struct Module {
+    name: Vec<String>,
+    // _alias: String,
+    bot_read_description: String,
+    listeners: Vec<Listener>,
+    commands: Vec<Command>,
+    // disable module at load for bot channels
+    default_status_per_channel: Status,
+}
+
+impl Module {
+    /// create a new module
+    pub fn new(name: Vec<String>, bot_read_description: String) -> Module {
+        Module {
+            name,
+            // _alias: alias,
+            bot_read_description,
+            listeners: vec![],
+            commands: vec![],
+            default_status_per_channel: Status::Enabled,
+        }
+    }
+
+    /// Loads a `Listener` into the module
+    pub fn load_listener(&mut self, mut l: Listener) {
+        l.set_parent_module(self.clone());
+        self.listeners.push(l);
+    }
+
+    /// Loads a `Command` into the module
+    pub fn load_command(&mut self, c: Command) {
+        self.commands.push(c);
+    }
+
+    pub fn get_listeners(&self) -> Vec<Listener> {
+        self.listeners.clone()
+    }
+
+    pub fn get_commands(&self) -> Vec<Command> {
+        self.commands.clone()
+    }
+
+    pub fn get_names(&self) -> Vec<String> {
+        self.name.clone()
+    }
+
+    pub fn get_bot_read_description(&self) -> String {
+        self.bot_read_description.clone()
+    }
+
+    pub fn set_status_by_default(&mut self, status: Status) {
+        self.default_status_per_channel = status;
+    }
+
+    pub fn get_status_by_default(&self) -> Status {
+        self.default_status_per_channel.clone()
+    }
+}
diff --git a/forcebot_core/src/custom_mods.rs b/forcebot_core/src/custom_mods.rs
new file mode 100644
index 0000000..fdbd664
--- /dev/null
+++ b/forcebot_core/src/custom_mods.rs
@@ -0,0 +1,4 @@
+pub mod debug;
+pub mod guest_badge;
+pub mod pyramid;
+// pub mod quiet;
diff --git a/forcebot_core/src/custom_mods/debug.rs b/forcebot_core/src/custom_mods/debug.rs
new file mode 100644
index 0000000..0457e54
--- /dev/null
+++ b/forcebot_core/src/custom_mods/debug.rs
@@ -0,0 +1,138 @@
+use std::sync::Arc;
+
+use crate::{execution_async, modules::Status, Bot, Command, Listener, Module};
+use twitch_irc::message::ServerMessage;
+
+/// debug module
+///
+/// Commands to enable debugging messages in chat
+///
+/// `debug on` to start
+///
+/// `debug off` to stop
+///
+///
+
+/// Use this function when loading modules into the bot
+///
+/// For example
+/// ```rust
+/// bot.load_module(debug::create_module());
+/// ```
+///
+pub fn create_module() -> Module {
+    /* 1. Create a new module */
+    let mut custom_mod = Module::new(vec!["debug".to_string()], "".to_string());
+
+    /* 2. Load the cmd into a new module */
+    custom_mod.load_command(cmd_debug_on());
+    custom_mod.load_command(cmd_debug_off());
+    custom_mod
+}
+
+/// Command definition for debug command
+fn cmd_debug_on() -> Command {
+    /* 1. Create a new cmd */
+    let mut cmd = Command::new(vec!["debug on".to_string()], "".to_string());
+
+    /* 2. Define exec callback  */
+    async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+        if let ServerMessage::Privmsg(msg) = message {
+            // dbg!("debug cmd on executed");
+
+            let modulename = "debug listener".to_string();
+
+            if let Status::NotLoaded = bot
+                .get_channel_module_status(msg.channel_login.clone(), modulename.clone())
+                .await
+            {
+                let module = create_listener_module(modulename.clone());
+                bot.load_module(module.clone()).await;
+            }
+            let modl = bot.get_module(modulename).await.unwrap();
+            bot.enable_module(
+                msg.channel_login.clone(),
+                modl.get_names().first().unwrap().clone(),
+            )
+            .await;
+            println!("Debug enabled for channel {}", msg.channel_login);
+        }
+        Result::Err("Not Valid message type".to_string())
+    }
+
+    /* 3. Set Command flags */
+    cmd.set_exec_fn(execution_async(execbody));
+    cmd.set_admin_only(true);
+    // cmd.set_min_badge(Badge::Moderator);
+    cmd.set_admin_override(true);
+
+    cmd
+}
+
+/// Command definition for debug off command
+fn cmd_debug_off() -> Command {
+    /* 1. Create a new cmd */
+    let mut cmd = Command::new(vec!["debug off".to_string()], "".to_string());
+
+    /* 2. Define exec callback  */
+    async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+        if let ServerMessage::Privmsg(msg) = message {
+            // dbg!("debug cmd on executed");
+
+            let modulename = "debug listener".to_string();
+
+            // if let Status::NotLoaded = bot.get_channel_module_status(msg.channel_login.clone(), modulename.clone()).await  {
+            //     let module = create_listener_module(modulename.clone());
+            //     bot.load_module(module.clone()).await;
+            // }
+            let modl = bot.get_module(modulename).await.unwrap();
+            bot.disable_module(
+                msg.channel_login.clone(),
+                modl.get_names().first().unwrap().clone(),
+            )
+            .await;
+            println!("Debug disabled for channel {}", msg.channel_login);
+        }
+        Result::Err("Not Valid message type".to_string())
+    }
+
+    /* 3. Set Command flags */
+    cmd.set_exec_fn(execution_async(execbody));
+    cmd.set_admin_only(true);
+    // cmd.set_min_badge(Badge::Moderator);
+    cmd.set_admin_override(true);
+
+    cmd
+}
+
+fn create_listener_module(name: String) -> Module {
+    let mut custom_mod = Module::new(vec![name], "".to_string());
+    // dbg!("debug listener module created");
+    custom_mod.load_listener(cmd_debug_listener());
+    custom_mod.set_status_by_default(Status::Disabled);
+
+    custom_mod
+}
+
+/// Listener for debug
+fn cmd_debug_listener() -> Listener {
+    // dbg!("Creating debug listener");
+    /* 2a. Create a new blank Listener */
+    let mut listener = Listener::new();
+
+    /* 2b. Set a trigger condition function for listener */
+    listener.set_trigger_cond_fn(|_: Arc<Bot>, _: ServerMessage| true);
+
+    /* 2c. Define an async fn callback execution */
+    async fn execbody(_: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+        if let ServerMessage::Privmsg(msg) = message {
+            dbg!(msg); /* outputs message to debug */
+        }
+        Result::Err("Not Valid message type".to_string())
+    }
+
+    /* 2d. Set and Store the execution body using `execution_async()`  */
+    listener.set_exec_fn(execution_async(execbody));
+
+    listener
+}
diff --git a/forcebot_core/src/custom_mods/guest_badge.rs b/forcebot_core/src/custom_mods/guest_badge.rs
new file mode 100644
index 0000000..2cf4ae7
--- /dev/null
+++ b/forcebot_core/src/custom_mods/guest_badge.rs
@@ -0,0 +1,175 @@
+use std::{
+    sync::Arc,
+    time::{Duration, Instant},
+};
+
+use twitch_irc::message::ServerMessage;
+
+use crate::{execution_async, Badge, Bot, Command, Module};
+
+/// guest_badge / guest module
+///
+/// Temporary badges can be issued to chatters. The bot then opens functionality
+/// to that chatter based on the recognized role
+///  
+/// Chatters with real badge roles will be able to share guest
+/// badges based on their role
+///
+///
+///
+
+const VIP_GIVEN_DUR_MIN: u64 = 15;
+const MOD_GIVEN_DUR_MIN: u64 = 30;
+
+/// Use this function when loading modules into the bot
+///
+/// For example
+/// ```rust
+/// bot.load_module(guest_badge::create_module());
+/// ```
+///
+pub fn create_module() -> Module {
+    let mut custom_mod = Module::new(
+        vec!["guests".to_string()],
+        "Temp Guest badges can be given by chatters with badges. ".to_string(),
+    );
+
+    custom_mod.load_command(create_cmd_mod());
+    custom_mod.load_command(create_cmd_vip());
+
+    custom_mod
+}
+
+fn create_cmd_vip() -> Command {
+    let mut cmd = Command::new(vec!["vip".to_string()], "".to_string());
+
+    async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+        if let ServerMessage::Privmsg(msg) = message {
+            let guest_dur_min = {
+                let mut result = VIP_GIVEN_DUR_MIN;
+                for badge in msg.clone().badges {
+                    if badge.name == "vip" {
+                        result = VIP_GIVEN_DUR_MIN;
+                    }
+                    if badge.name == "moderator" {
+                        result = MOD_GIVEN_DUR_MIN;
+                    }
+                }
+                result
+            };
+
+            let mut badges_issued = false;
+            for (i, arg) in msg
+                .message_text
+                .replace("\u{e0000}", "")
+                .trim()
+                .split(" ")
+                .enumerate()
+            {
+                if i > 1 {
+                    let mut already_vip = false;
+
+                    for guest_badge in bot
+                        .get_channel_guest_badges(arg.trim().to_string(), msg.channel_login.clone())
+                        .await
+                    {
+                        if guest_badge.0 == Badge::Vip {
+                            already_vip = true
+                        }
+                    }
+                    if !already_vip {
+                        badges_issued = true;
+                        bot.issue_new_guest_badge(
+                            arg.trim().to_string(),
+                            msg.channel_login.clone(),
+                            Badge::Vip,
+                            Instant::now(),
+                            Duration::from_secs(60 * guest_dur_min),
+                        )
+                        .await;
+                    }
+                }
+            }
+            if badges_issued {
+                let _ = bot
+                    .chat
+                    .lock()
+                    .await
+                    .say_in_reply_to(
+                        &msg.clone(),
+                        format!("Guest badges issued for {} min", guest_dur_min),
+                    )
+                    .await;
+                return Result::Ok("Success".to_string());
+            }
+        }
+        Result::Err("Not Valid message type".to_string())
+    }
+
+    cmd.set_exec_fn(execution_async(execbody));
+
+    cmd.set_admin_only(false);
+    cmd.set_admin_override(true);
+    cmd.set_min_badge(Badge::Vip);
+    cmd
+}
+
+fn create_cmd_mod() -> Command {
+    let mut cmd = Command::new(vec!["mod".to_string()], "".to_string());
+
+    async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+        if let ServerMessage::Privmsg(msg) = message {
+            let mut badges_issued = false;
+            for (i, arg) in msg
+                .message_text
+                .replace("\u{e0000}", "")
+                .trim()
+                .split(" ")
+                .enumerate()
+            {
+                if i > 1 {
+                    let mut already_mod = false;
+                    for guest_badge in bot
+                        .get_channel_guest_badges(arg.trim().to_string(), msg.channel_login.clone())
+                        .await
+                    {
+                        if guest_badge.0 == Badge::Moderator {
+                            already_mod = true
+                        }
+                    }
+                    if !already_mod {
+                        badges_issued = true;
+                        bot.issue_new_guest_badge(
+                            arg.trim().to_string(),
+                            msg.channel_login.clone(),
+                            Badge::Moderator,
+                            Instant::now(),
+                            Duration::from_secs(60 * MOD_GIVEN_DUR_MIN),
+                        )
+                        .await;
+                    }
+                }
+            }
+            if badges_issued {
+                let _ = bot
+                    .chat
+                    .lock()
+                    .await
+                    .say_in_reply_to(
+                        &msg,
+                        format!("Guest badges issued for {} min", MOD_GIVEN_DUR_MIN),
+                    )
+                    .await;
+                return Result::Ok("Success".to_string());
+            }
+        }
+        Result::Err("Not Valid message type".to_string())
+    }
+
+    cmd.set_exec_fn(execution_async(execbody));
+
+    cmd.set_admin_only(false);
+    cmd.set_admin_override(true);
+    cmd.set_min_badge(Badge::Moderator);
+    cmd
+}
diff --git a/forcebot_core/src/custom_mods/pyramid.rs b/forcebot_core/src/custom_mods/pyramid.rs
new file mode 100644
index 0000000..99deb25
--- /dev/null
+++ b/forcebot_core/src/custom_mods/pyramid.rs
@@ -0,0 +1,485 @@
+use std::sync::{Arc, Mutex};
+
+use twitch_irc::message::{PrivmsgMessage, ServerMessage};
+
+// use crate::{execution_async, listener_condition_async, Badge, Bot, Command, Listener, Module};
+use super::super::botcore::bot::Bot;
+use super::super::botcore::bot_objects::command::Command;
+use super::super::botcore::bot_objects::execution_async;
+use super::super::botcore::bot_objects::listener::Listener;
+use super::super::botcore::bot_objects::listener_condition_async;
+use super::super::botcore::bot_objects::Badge;
+use super::super::botcore::modules::Module;
+
+/// pyramid module
+///
+/// for detecting & handling pyramids
+///
+/// - listener - detects pyramid
+/// - cmd & listener - interrupts some chatters temporarily
+///
+///
+use lazy_static::lazy_static;
+
+/// Use this function when loading modules into the bot
+///
+/// For example
+/// ```rust
+/// bot.load_module(pyramid::create_module());
+/// ```
+///
+pub fn create_module() -> Module {
+    let mut custom_mod = Module::new(
+        vec!["pyramid".to_string(), "pyramids".to_string()],
+        "o7 I can handle pyramids".to_string(),
+    );
+    custom_mod.load_listener(create_pyramid_detector());
+
+    custom_mod
+}
+
+fn create_pyramid_detector() -> Listener {
+    /* 1. Create a new blank Listener */
+    let mut listener = Listener::new();
+
+    /* 2. Define an async trigger condition callback */
+    async fn condition01(bot: Arc<Bot>, message: ServerMessage) -> bool {
+        if let ServerMessage::Privmsg(msg) = message {
+            if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await
+                && get_pyramid_size(msg.channel_login) > 3
+            {
+                return true;
+            }
+        }
+        false
+    }
+
+    /* 3. Set a trigger condition function for listener */
+    listener.set_trigger_cond_async(listener_condition_async(condition01));
+
+    /* 4. Define an async fn callback execution */
+    async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+        if let ServerMessage::Privmsg(msg) = message {
+            dbg!("enter pyramid listener execution - after pyramid complete");
+            // if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await {
+
+            // let _ = bot.chat.lock().await.
+            dbg!("> get start pattern");
+            let pattern = get_start_pattern(msg.channel_login.clone());
+            let mut outmsg;
+
+            /* Prefer emote before pattern in case pattern is command */
+            if pattern.len() < 50 {
+                outmsg = format!("Clap {}", pattern);
+            } else {
+                outmsg = "Clap".to_string();
+            }
+
+            dbg!(get_pyramid_size(msg.channel_login.clone()));
+            if get_pyramid_size(msg.channel_login.clone()) < 4 {
+                outmsg = format!("{} annytfMagniGlass", outmsg);
+            }
+
+            dbg!("> start pattern :", pattern);
+
+            dbg!("> say_in_reply_to completed :", outmsg.clone());
+            let _ = bot.chat.lock().await.say_in_reply_to(&msg, outmsg).await;
+
+            dbg!("> set pyramid started - false");
+            set_pyramid_started(msg.channel_login.clone(), false);
+
+            return Result::Ok("Success".to_string());
+            // }
+        }
+        Result::Err("Not Valid message type".to_string())
+    }
+
+    /* 5. Set and Store the execution body using `execution_async()`  */
+    listener.set_exec_fn(Box::new(move |a, b| Box::pin(execbody(a, b))));
+
+    listener
+}
+
+/// detect pyramid based on latest message and channel
+///
+///
+async fn detect_pyramid_complete_ok(_bot: Arc<Bot>, msg: PrivmsgMessage) -> bool {
+    dbg!("enter detect_pyramid_complete()");
+
+    let msgtext = msg
+        .message_text
+        .replace("ó €€", "")
+        .replace("\u{e0000}", "")
+        .trim()
+        .to_string();
+    let msgchannel = msg.channel_login;
+    let msgchatter = msg.sender.login;
+
+    // 1. Check if Pyramid started in chat > and recognize pyramid started
+    if !is_pyramid_started(msgchannel.clone())
+        & check_start_pyramid(msgchannel.clone(), msgtext.clone())
+    {
+        dbg!("> set pyramid started - true");
+        set_pyramid_started(msgchannel.clone(), true);
+        push_to_compare(
+            msgchannel.clone(),
+            msgchatter.clone(),
+            get_start_pattern(msgchannel.clone()),
+        );
+    }
+
+    if is_pyramid_started(msgchannel.clone()) {
+        push_to_compare(msgchannel.clone(), msgchatter.clone(), msgtext.clone());
+    }
+
+    // 2a. If Pyramid Not Started, Assume message is a potential start pattern
+    if !is_pyramid_started(msgchannel.clone()) {
+        set_start_pattern(msgchannel.clone(), msgtext.clone());
+    }
+
+    // 2b. If Pyramid is Started, and the latest message is the pattern, check for
+    // symmetry to determine pyramid
+
+    if is_pyramid_started(msgchannel.clone())
+        && msgtext.clone() == get_start_pattern(msgchannel.clone())
+    {
+        if symmetry_ok(msgchannel.clone()) {
+            return true;
+        } else {
+            dbg!("> set pyramid started - false");
+            set_pyramid_started(msgchannel, false);
+
+            return false;
+        }
+    }
+
+    // 2c. if Pyramid is strted but latest message does not ontain pattern
+    if is_pyramid_started(msgchannel.clone())
+        && !msgtext
+            .clone()
+            .contains(get_start_pattern(msgchannel.clone()).as_str())
+    {
+        dbg!("> set pyramid started - false");
+        set_pyramid_started(msgchannel, false);
+
+        return false;
+    } else {
+        return false;
+    };
+}
+
+lazy_static! {
+    /// Message Compare stack per channel (channel:String,msgstack:Vec<(chatter:String,message:String)>)
+    pub static ref COMPARE_MSG_STACK_PER_CHNL: Mutex<Vec<(String,Mutex<Vec<(String,String)>>)>>  = Mutex::new(vec![]);
+    #[derive(Debug)]
+    /// Pyramid Started per channel (channel:String,started:bool)
+    pub static ref PYRAMID_STARTED_PER_CHNL:  Mutex<Vec<(String,Mutex<bool>)>> = Mutex::new(vec![]);
+    /// Start patterns per channel (channel:String,pattern:String)
+    pub static ref START_PATTERNS_PER_CHNL: Mutex<Vec<(String,Mutex<String>)>> = Mutex::new(vec![]);
+    /// Pyramid sze per channel (channel:String,started:bool)
+    pub static ref PYRAMID_SIZE_PER_CHNL:  Mutex<Vec<(String,Mutex<i32>)>> = Mutex::new(vec![]);
+    /// temp message stack checker
+    pub static ref TEMP_MSG_STACK: Mutex<Vec<String>> = Mutex::new(vec![]);
+
+    /// interruptor targets - (channel:String,chatters:Vec<String>>)
+    pub static ref INTERRUPT_TRG_PER_CHNL: Mutex<Vec<(String,Mutex<Vec<String>>)>>  = Mutex::new(vec![]);
+
+}
+
+fn read_top_of_compare(channel: String) -> Option<(String, String)> {
+    let comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap();
+
+    for rec in comp_perchnl.iter() {
+        if rec.0 == channel {
+            let msg_stack = rec.1.lock().unwrap();
+
+            return msg_stack.last().cloned();
+        }
+    }
+    None
+}
+
+fn pop_top_of_compare(channel: String) -> Option<(String, String)> {
+    let comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap();
+
+    for rec in comp_perchnl.iter() {
+        if rec.0 == channel {
+            let mut msg_stack = rec.1.lock().unwrap();
+
+            let popped = msg_stack.pop();
+            return popped;
+        }
+    }
+    None
+}
+
+fn set_pyramid_started(channel: String, started: bool) {
+    let mut start_perchnl = PYRAMID_STARTED_PER_CHNL.lock().unwrap();
+    let mut found = false;
+    for rec in start_perchnl.iter() {
+        if rec.0 == channel {
+            found = true;
+            let mut rec_started = rec.1.lock().unwrap();
+            *rec_started = started;
+        }
+    }
+    if !found {
+        start_perchnl.push((channel, Mutex::new(started)));
+    }
+}
+
+fn is_pyramid_started(channel: String) -> bool {
+    let start_perchnl = PYRAMID_STARTED_PER_CHNL.lock().unwrap();
+    for rec in start_perchnl.iter() {
+        if rec.0 == channel {
+            let rec_started = rec.1.lock().unwrap();
+            return *rec_started;
+        }
+    }
+    false
+}
+
+fn set_start_pattern(channel: String, pattern: String) {
+    let mut start_patterns = START_PATTERNS_PER_CHNL.lock().unwrap();
+
+    let mut found = false;
+    for rec in start_patterns.iter() {
+        if rec.0 == channel {
+            found = true;
+            let mut patternlock = rec.1.lock().unwrap();
+            *patternlock = pattern.clone();
+        }
+    }
+    if !found {
+        start_patterns.push((channel.clone(), Mutex::new(pattern.clone())));
+    }
+}
+
+fn get_start_pattern(channel: String) -> String {
+    let start_patterns = START_PATTERNS_PER_CHNL.lock().unwrap();
+
+    for rec in start_patterns.iter() {
+        if rec.0 == channel {
+            let patternlock = rec.1.lock().unwrap();
+            return patternlock.clone();
+        }
+    }
+
+    return "".to_string();
+}
+
+/// pushes message to compare stack
+fn push_to_compare(channel: String, chatter: String, message: String) {
+    let mut comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap();
+
+    let mut found = false;
+    for rec in comp_perchnl.iter() {
+        if rec.0 == channel {
+            found = true;
+            let mut msg_stack = rec.1.lock().unwrap();
+            msg_stack.push((chatter.clone(), message.clone()));
+            // dbg!("Push message to cmp stack ; result last cmp_pchnl - ",comp_perchnl.last());
+        }
+    }
+    if !found {
+        comp_perchnl.push((channel, Mutex::new(vec![(chatter, message)])));
+    }
+}
+
+/// checks latest and next latest messages for potential start
+fn check_start_pyramid(channel: String, msgtext: String) -> bool {
+    msgtext
+        == format!(
+            "{} {}",
+            get_start_pattern(channel.clone()),
+            get_start_pattern(channel.clone())
+        )
+    // msgtext == format!("{} {} {}",
+    //     get_start_pattern(channel.clone()),
+    //     get_start_pattern(channel.clone()),
+    //     get_start_pattern(channel.clone())
+    // )
+}
+
+/// pops the compare stack to determine symmetry
+fn symmetry_ok(channel: String) -> bool {
+    let mut temp_stack = TEMP_MSG_STACK.lock().unwrap();
+    let mut checking_started = false;
+    if !(read_top_of_compare(channel.clone())
+        .unwrap_or(("".to_string(), "".to_string()))
+        .1
+        == get_start_pattern(channel.clone()))
+    {
+        return false;
+    }
+
+    let mut pyramid_size = 0;
+    loop {
+        if !checking_started
+            && read_top_of_compare(channel.clone())
+                .unwrap_or(("".to_string(), "".to_string()))
+                .1
+                == get_start_pattern(channel.clone())
+        {
+            checking_started = true;
+        }
+
+        if temp_stack.last().is_none()
+            || read_top_of_compare(channel.clone())
+                .unwrap_or(("".to_string(), "".to_string()))
+                .1
+                .len()
+                > temp_stack.last().unwrap_or(&"".to_string()).len()
+        {
+            temp_stack.push(
+                pop_top_of_compare(channel.clone())
+                    .unwrap_or(("".to_string(), "".to_string()))
+                    .1,
+            );
+            pyramid_size += 1;
+        } else if temp_stack.last().is_some()
+            && read_top_of_compare(channel.clone())
+                .unwrap_or(("".to_string(), "".to_string()))
+                .1
+                .len()
+                < temp_stack.last().unwrap_or(&"".to_string()).len()
+        {
+            temp_stack.pop();
+            if temp_stack.last().unwrap_or(&"".to_string()).clone()
+                == read_top_of_compare(channel.clone())
+                    .unwrap_or(("".to_string(), "".to_string()))
+                    .1
+            {
+                temp_stack.pop();
+
+                continue;
+            } else {
+                set_pyramid_size(channel.clone(), 0);
+                temp_stack.clear();
+                return false;
+            }
+        } else {
+            set_pyramid_size(channel.clone(), 0);
+            return false;
+        }
+
+        if checking_started
+            && read_top_of_compare(channel.clone()).unwrap().1 == get_start_pattern(channel.clone())
+        {
+            /* leave pyramid size set for exection */
+            set_pyramid_size(channel.clone(), pyramid_size * 2 - 1);
+            temp_stack.clear();
+            return true;
+        }
+    }
+}
+
+fn set_pyramid_size(channel: String, size: i32) {
+    let mut size_perchnl = PYRAMID_SIZE_PER_CHNL.lock().unwrap();
+    let mut found = false;
+    for rec in size_perchnl.iter() {
+        if rec.0 == channel {
+            found = true;
+            let mut rec_started = rec.1.lock().unwrap();
+            *rec_started = size;
+        }
+    }
+    if !found {
+        size_perchnl.push((channel, Mutex::new(size)));
+    }
+}
+
+fn get_pyramid_size(channel: String) -> i32 {
+    let size_perchnl = PYRAMID_SIZE_PER_CHNL.lock().unwrap();
+    for rec in size_perchnl.iter() {
+        if rec.0 == channel {
+            let rec_started = rec.1.lock().unwrap();
+            return *rec_started;
+        }
+    }
+    0
+}
+
+/// #todo
+///
+/// pyramid interruptor
+///
+/// pick chatters that will be interrupted if they solo build
+///
+/// takes in arguments as chatters
+///
+/// chatters are then interrupted for a random duration under 15m
+///
+/// if a duration is given, take that duration eg 15m , 25m
+///
+///
+fn _create_interruptor_cmd() -> Command {
+    let mut cmd = Command::new(
+        vec!["no pyramid".to_string(), "no pyramids".to_string()],
+        "".to_string(),
+    );
+
+    /* 2. Define an async fn callback execution */
+    async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+        if let ServerMessage::Privmsg(msg) = message {
+            let _ = bot
+                .chat
+                .lock()
+                .await
+                .say_in_reply_to(&msg, String::from("test success"))
+                .await;
+            return Result::Ok("Success".to_string());
+        }
+        Result::Err("Not Valid message type".to_string())
+    }
+
+    /* 3. Set and Store the execution body using `execution_async()`  */
+    cmd.set_exec_fn(Box::new(move |a, b| Box::pin(execbody(a, b))));
+
+    /* 4. optionally, remove admin only default flag */
+    cmd.set_admin_only(false);
+
+    /* 5. optionally, set min badge*/
+    cmd.set_min_badge(Badge::Moderator);
+
+    cmd
+}
+
+/// #todo
+fn _create_interruptor_module(channel: String) -> Module {
+    /* 1. Create a new module */
+    let modname = format!("interruptor {}", channel);
+    let mut custom_mod = Module::new(vec![modname], "".to_string());
+
+    /* 2. Load the cmd into a new module */
+    custom_mod.load_listener(_create_interruptor_listener());
+
+    custom_mod
+}
+
+/// #todo
+fn _create_interruptor_listener() -> Listener {
+    /* 2a. Create a new blank Listener */
+    let mut listener = Listener::new();
+
+    /* 2b. Set a trigger condition function for listener */
+    listener.set_trigger_cond_fn(|_: Arc<Bot>, _: ServerMessage| true);
+
+    /* 2c. Define an async fn callback execution */
+    async fn execbody(_: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+        dbg!(message); /* outputs message to debug */
+        Result::Ok("Success".to_string())
+    }
+
+    /* 2d. Set and Store the execution body using `execution_async()`  */
+    listener.set_exec_fn(execution_async(execbody));
+
+    listener
+}
+
+/// #todo
+///
+/// Returns Some(chatter) if the pyramid in progress is being built by a solo
+fn _solo_building(_channel: String) -> Option<String> {
+    None
+}
diff --git a/forcebot_core/src/lib.rs b/forcebot_core/src/lib.rs
new file mode 100644
index 0000000..6d3f317
--- /dev/null
+++ b/forcebot_core/src/lib.rs
@@ -0,0 +1,234 @@
+//! `forcebot_core` library for `forcebot-rs-v2` Twitch chat bot
+//!
+//! Customize by adding additional bot objects
+//!
+//! # New Bot
+//!
+//! Uses Env defined variables to create and run the bot
+//!
+//! ```rust
+//! use forcebot_core::Bot;
+//!
+//! #[tokio::main]
+//! pub async fn main() {
+//!
+//!     /* 1. Create the bot using env */
+//!     let bot = Bot::new();
+//!
+//!     /* 2. Run the bot */
+//!     bot.run().await;
+//!
+//! }
+//!
+//! ```
+//!
+//!
+//! # Customize with Modules
+//!
+//! A `Module` is a group of bot objects (eg `Command`) that elevated users can manage through built in `disable` and `enable` commands
+//!
+//! Custom `Modules` can be loaded into a new bot with minimum coding : just load the modules and run the bot
+//!    
+//! ```rust
+//! use forcebot_core::{custom_mods::{guest_badge, pyramid}, Bot};
+//!    
+//! #[tokio::main]
+//! pub async fn main() {
+//!    
+//!    /* 1. Create the bot using env */
+//!    let mut bot = Bot::new();
+//!    
+//!    /* 2. Load Custom Modules */
+//!    bot.load_module(guest_badge::create_module()).await;
+//!    bot.load_module(pyramid::create_module()).await;
+//!       
+//!    /* 3. Run the bot */
+//!    bot.run().await;
+//!    
+//! }
+//!    ```
+//!    
+//!
+//! # Create your own Custom Modules
+//!
+//! Create a custom `Module` by :
+//!
+//! 1. Defining Functions that create the Custom Bot Objects (eg `Command`)
+//!
+//! 2. Define a function that creates a `Module` with the Custom Bot Objects loaded
+//!
+//!
+//! ```rust
+//! use forcebot_core::Bot;
+//!    
+//!    #[tokio::main]
+//!    pub async fn main() {
+//!    
+//!        /* Create the bot using env */
+//!        let mut bot = Bot::new();
+//!    
+//!        /* load the Module */
+//!        bot.load_module(custom_mod::new());
+//!    
+//!        /* Run the bot */
+//!        bot.run().await;
+//!    
+//!    }
+//!    
+//!    pub mod custom_mod {
+//!        use std::sync::Arc;
+//!    
+//!        use forcebot_core::{execution_async, Badge, Bot, Command, Module};
+//!        use twitch_irc::message::ServerMessage;
+//!    
+//!    
+//!        /// Module definition with a loaded command
+//!        pub fn new() -> Module {
+//!            /* 1. Create a new module */
+//!            let mut custom_mod = Module::new(
+//!                vec!["test".to_string()],
+//!                "".to_string());
+//!    
+//!            /* 2. Load the cmd into a new module */
+//!            custom_mod.load_command(cmd_test());
+//!    
+//!            custom_mod
+//!    
+//!        }
+//!    
+//!        /// Command definition
+//!        pub fn cmd_test() -> Command {
+//!            /* 1. Create a new cmd */
+//!            let mut cmd = Command::new(vec!["test".to_string()],"".to_string());
+//!    
+//!            /* 2. Define exec callback  */
+//!            async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
+//!                if let ServerMessage::Privmsg(msg) = message {
+//!                    let _= bot.client.say_in_reply_to(
+//!                        &msg, "test return".to_string()).await;
+//!                }
+//!                Result::Err("Not Valid message type".to_string())
+//!            }
+//!    
+//!            /* 3. Set Command flags */
+//!            cmd.set_exec_fn(execution_async(execbody));
+//!            cmd.set_admin_only(false);
+//!            cmd.set_min_badge(Badge::Moderator);
+//!    
+//!            cmd
+//!        }
+//!    }
+//!    
+//!
+//! ```
+//!
+//! # Simple Debug Listener
+//! Bot with a simple listener that listens for all messages and prints in output
+//!
+//! ```rust
+//! use std::sync::Arc;
+//!
+//! use forcebot_core::{execution_async, Bot, Listener};
+//! use twitch_irc::message::ServerMessage;
+//!
+//! #[tokio::main]
+//! pub async fn main() {
+//!
+//!     /* 1. Create the bot using env */
+//!     let mut bot = Bot::new();
+//!
+//!     /* 2a. Create a new blank Listener */
+//!     let mut listener = Listener::new();
+//!
+//!     /* 2b. Set a trigger condition function for listener */
+//!     listener.set_trigger_cond_fn(
+//!         |_:Arc<Bot>,_:ServerMessage| true
+//!     );
+//!
+//!     /* 2c. Define an async fn callback execution */
+//!     async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
+//!         dbg!(message); /* outputs message to debug */
+//!         Result::Ok("Success".to_string())
+//!     }
+//!
+//!     /* 2d. Set and Store the execution body using `execution_async()`  */
+//!     listener.set_exec_fn(execution_async(execbody));
+//!
+//!     /* 3. Load the listener into the bot */
+//!     bot.load_listener(listener);
+//!
+//!     /* 4. Run the bot */
+//!     bot.run().await;
+//!
+//! }
+//!
+//! ```
+//!
+//! # Moderator Reactor
+//!
+//! ```
+//!
+//! use std::sync::Arc;
+//!
+//! use forcebot_core::Bot;
+//! use forcebot_core::execution_async;
+//! use forcebot_core::Listener;
+//! use twitch_irc::message::ServerMessage;
+//!
+//!
+//! #[tokio::main]
+//! pub async fn main() {
+//!
+//!     /* Create the bot using env */
+//!     let mut bot = Bot::new();
+//!
+//!     /* 1. Create a new blank Listener */
+//!     let mut listener = Listener::new();
+//!
+//!     /* 2. Set a trigger condition function for listener */
+//!
+//!     listener.set_trigger_cond_fn(
+//!         |_:Arc<Bot>,message:ServerMessage|
+//!            if let ServerMessage::Privmsg(msg) = message {
+//!                 for badge in msg.badges {
+//!                     if matches!(badge, x if x.name == "moderator") {
+//!                         // dbg!("moderator found");
+//!                         return true;
+//!                     }
+//!                 }
+//!                 false
+//!             } else { false }
+//!     );
+//!
+//!     /* 3. Define an async fn callback execution */
+//!     async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
+//!         if let ServerMessage::Privmsg(msg) = message {
+//!             let _ = bot.client.say_in_reply_to(&msg, "pepeKneel".to_string()).await ;
+//!             return Result::Ok("Success".to_string()) ;
+//!         }
+//!         Result::Err("Not Valid message type".to_string())
+//!     }
+//!
+//!     /* 4. Set and Store the execution body using `execution_async()`  */
+//!     listener.set_exec_fn(execution_async(execbody));
+//!
+//!     /* 5. Load the listener into the bot */
+//!     bot.load_listener(listener);
+//!
+//!    /* Run the bot */
+//!    bot.run().await;
+//!
+//! }
+
+pub mod botcore;
+pub mod custom_mods;
+pub use botcore::bot::Bot;
+pub use botcore::bot_objects::command_condition_async;
+pub use botcore::bot_objects::execution_async;
+pub use botcore::bot_objects::listener::Listener;
+pub use botcore::bot_objects::listener_condition_async;
+// pub use crate::botcore::bot_objects::command::Command;
+pub use botcore::bot_objects::command::Command;
+pub use botcore::bot_objects::Badge;
+pub use botcore::modules;
+pub use botcore::modules::Module;
diff --git a/moderator_reactor/Cargo.toml b/moderator_reactor/Cargo.toml
new file mode 100644
index 0000000..f3431e6
--- /dev/null
+++ b/moderator_reactor/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "moderator_reactor"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+forcebot_core = {path = "../forcebot_core"}
+dotenv = "0.15.0"
+lazy_static = "1.5.0"
+tokio = { version = "1.33.0", features = ["full"] }
+twitch-irc = "5.0.1"
diff --git a/moderator_reactor/src/main.rs b/moderator_reactor/src/main.rs
new file mode 100644
index 0000000..284dd0a
--- /dev/null
+++ b/moderator_reactor/src/main.rs
@@ -0,0 +1,67 @@
+//! Simple bot with a custom listeners that listens for moderators and respond to the moderator
+//!
+//! Be sure the followig is defined in `.env`
+//! - login_name
+//! - access_token
+//! - bot_channels
+//! - prefix
+//! - bot_admins
+//!
+//! Bot access tokens be generated here -
+//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
+//! - More Info - <https://dev.twitch.tv/docs/authentication>
+
+use std::sync::Arc;
+
+use forcebot_core::execution_async;
+use forcebot_core::Bot;
+use forcebot_core::Listener;
+use twitch_irc::message::ServerMessage;
+
+#[tokio::main]
+pub async fn main() {
+    /* Create the bot using env */
+    let bot = Bot::new().await;
+
+    /* 1. Create a new blank Listener */
+    let mut listener = Listener::new();
+
+    /* 2. Set a trigger condition function for listener */
+
+    listener.set_trigger_cond_fn(|_: Arc<Bot>, message: ServerMessage| {
+        if let ServerMessage::Privmsg(msg) = message {
+            for badge in msg.badges {
+                if matches!(badge, x if x.name == "moderator") {
+                    // dbg!("moderator found");
+                    return true;
+                }
+            }
+            false
+        } else {
+            false
+        }
+    });
+
+    /* 3. Define an async fn callback execution */
+    async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+        if let ServerMessage::Privmsg(msg) = message {
+            let _ = bot
+                .chat
+                .lock()
+                .await
+                .say_in_reply_to(&msg, "pepeKneel".to_string())
+                .await;
+            return Result::Ok("Success".to_string());
+        }
+        Result::Err("Not Valid message type".to_string())
+    }
+
+    /* 4. Set and Store the execution body using `execution_async()`  */
+    listener.set_exec_fn(execution_async(execbody));
+
+    /* 5. Load the listener into the bot */
+    bot.load_listener(listener).await;
+
+    /* Run the bot */
+    bot.run().await;
+}
diff --git a/new_empty_bot/Cargo.toml b/new_empty_bot/Cargo.toml
new file mode 100644
index 0000000..96d5d3f
--- /dev/null
+++ b/new_empty_bot/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "new_empty_bot"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+forcebot_core = {path = "../forcebot_core"}
+dotenv = "0.15.0"
+lazy_static = "1.5.0"
+tokio = { version = "1.33.0", features = ["full"] }
+twitch-irc = "5.0.1"
diff --git a/src/main.rs b/new_empty_bot/src/main.rs
similarity index 71%
rename from src/main.rs
rename to new_empty_bot/src/main.rs
index ebbe171..856f6b1 100644
--- a/src/main.rs
+++ b/new_empty_bot/src/main.rs
@@ -1,25 +1,22 @@
 //! Example simple Binary crate that creates & runs bot based on `.env`
-//! Be sure the followig is defined in `.env` 
+//! Be sure the followig is defined in `.env`
 //! - login_name
 //! - access_token
 //! - bot_channels
 //! - prefix
 //! - bot_admins
-//! 
-//! Bot access tokens be generated here - 
+//!
+//! Bot access tokens be generated here -
 //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
 //! - More Info - <https://dev.twitch.tv/docs/authentication>
 
-use forcebot_rs_v2::botcore::bot::Bot;
-
+use forcebot_core::Bot;
 
 #[tokio::main]
 pub async fn main() {
-
     /* 1. Create the bot using env */
-    let bot = Bot::new();
+    let bot = Bot::new().await;
 
     /* 2. Run the bot */
     bot.run().await;
-
 }
diff --git a/readme.md b/readme.md
index d192a1b..aa9355c 100644
--- a/readme.md
+++ b/readme.md
@@ -1,4 +1,4 @@
-Twitch chat bot written in rust
+Customizable Twitch chat bot written in rust
 
 # Quick Start 
 
@@ -22,28 +22,66 @@ bot_admins=ADMIN
 3. Build & run
 
 ```
-cargo run
+cargo run -p forcebot_core 
 ```
 
+# Features
+
+## Built In Chat Commands
+
+- `quiet on` / `quiet off` - Moderators & Broadcasters can quiet the bot
+
+- `enable $module$` / `disable $module$` - Moderators & Broadcasters can enable or disable `Modules` of bot functionality through chat `Commands`
+
+
+## Custom Modules can be coded to load additional functionality 
+
+Developers an create Modules that add more bot functionality
+
+The main `forcebot_core` Binary crate includes the following Custom `Modules`  
+   
+- `debug` - outputs to console messages from the channel where it was enabled. Toggle debug with the Commands `debug on` or `debug off`
+- `guest_badge` - Temporary badges can be issued to chatters
+- `besty` - Tomfoolery
+- `pyramid` - for detecting & handling pyramids
+
+
+## `forcebot_core` Bot Library
+
+- `forcebot_core` library API provides Custom package developers a way to add functionality by adding `Modules` that contain Bot Objects like `Commands` and `Listeners`
+- `Listeners` and `Commands` listen for a defined callback trigger condition and run an defined execution callback 
+- `Commands` are similar to `Listeners` with refined trigger conditions including using bot `prefix` with the `Command` , triggers based on `Badge` , and more
+- Workspace for package developers to independently code their own `Modules`
+
+## Workspaces
+
+
+Workspace comes with binary crates with working or example bots that use `forcebot_core` library 
+- `moderator_reactor` - bot kneels to all moderator messages
+- `simple_module_example` - bot has a `test` `Module` with a `test` `Command` . Moderators & Broadcasters can manage the `Module` in chat with `enable` / `disable` `Commands`
+- `new_empty_bot` - while empty, has `disable` and `enable` chat `Commands` . This is an example of the bot without any loaded modules
+- `simple_command_bot` - bot responds to a `test` `Command`. As the command was not loaded through a `Module`, `disable` & `enable` commands don't work on the `test` command. This could be a Global `Command`  
+- `simple_debug_listener` - bot outputs all twitch `ServerMessages` received to terminal
+    
+
+
 # Example Bots
 
-Use the following commands to build and run built-in bots. No coding required!
+Use the following to build and run built-in bots. No coding required!
 
-## New Bot
+## New Empty Bot
 Run an empty simple bot that logs into chat and has minimum built in functions 
 
 ```
-cargo run --bin new_bot
+cargo run -p new_empty_bot
 ```
 
-## WIP Customized Fun Bot
+## Full Featured Forcebot
 
 Run a forcebot with fun catered customizations
 
-*ongoing work in progress*
-
 ```
-cargo run --bin fun_bot
+cargo run -p forcebot_core 
 ```
 
 
@@ -51,28 +89,69 @@ cargo run --bin fun_bot
 Run a bot that listens to all messages and output to console
 
 ```
-cargo run --bin simple_debug_listener
+cargo run -p simple_debug_listener
 ```
 
 ## Simple Command Bot
 Run a bot that uses the `test` chat `Command` . `Commands` are prefixed and must be ran by a chatter with a `vip` badge or above 
 
 ```
-cargo run --bin simple_command_bot
+cargo run -p simple_command_bot
 ```
 
 ## Moderator Reactor
 Run a bot that listens for messages with the `moderator` badge, and replies to that mod with an emote
 
 ```
-cargo run --bin moderator_reactor
+cargo run -p moderator_reactor
 ```
 
 ## Module loaded Bot
 Run a bot that has a `test` chat `Command`. As the command was loaded through a module, moderators or broadcastors can `enable` or `disable` the module through chat commands
 
 ```
-cargo run --bin simple_module
+cargo run -p simple_module_example
+```
+
+# Workspace packages 
+
+Source is a workspace of packages . In particular, `forcebot_core` is the main library crate to use
+
+*TIP* : if you want to start customizing you own bot, create a binary package in the workspace for your bot's binary crate
+
+More info about workspaces - https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html
+
+
+## Creating a new package
+
+To create a new package 
+
+1. Create a new package
+
+For example, to create a new binary crate in the workspace
+
+```
+cargo new my_new_bot
+```
+
+2. In the newly created directory for your package, adjust the `Cargo.toml` to the following 
+
+```
+[dependencies]
+forcebot_core = {path = "../forcebot_core"}
+dotenv = "0.15.0"
+lazy_static = "1.5.0"
+tokio = { version = "1.33.0", features = ["full"] }
+twitch-irc = "5.0.1"
+```
+
+3. Copy `main.rs` from the `new_empty_bot` package into your package
+
+4. Optionally, customize your `main()` to load modules before starting the bot
+
+5. Build and run your package
+```
+cargo run -p my_new_bot
 ```
 
 
@@ -83,25 +162,55 @@ cargo run --bin simple_module
 Uses Env defined variables to create and run the bot
 
 ```rust
-use forcebot_rs_v2::Bot;
+use forcebot_core::Bot;
 
 #[tokio::main]
 pub async fn main() {
 
     /* 1. Create the bot using env */
-    let bot = Bot::new();
+    let bot = Bot::new().await;
 
     /* 2. Run the bot */
     bot.run().await;
 
 }
-
 ```
 
-## Customize with Modules
+## Customize by Loading Custom Modules 
 
 A `Module` is a group of bot objects (eg `Command`) that elevated users can manage through built in `disable` and `enable` commands
 
+Custom `Modules` can be loaded into a new bot with minimum coding : just load the modules and run the bot
+
+```rust
+use forcebot_core::{custom_mods::{debug, guest_badge, pyramid}, Bot};
+
+
+
+#[tokio::main]
+pub async fn main() {
+
+    /* Create the bot using env */
+    let bot = Bot::new().await;
+
+    /* 1. Load the module into the bot */
+    bot.load_module(funbot_objs::create_module()).await;
+
+    /* 2. Load Custom Modules */
+    bot.load_module(guest_badge::create_module()).await;
+    bot.load_module(pyramid::create_module()).await;
+    bot.load_module(debug::create_module()).await;
+    
+    
+    /* 3. Run the bot */
+    bot.run().await;
+
+}
+```
+
+
+## Create your own Custom Modules
+
 Create a custom `Module` by :
 
 1. Defining Functions that create the Custom Bot Objects (eg `Command`)
@@ -110,16 +219,17 @@ Create a custom `Module` by :
 
 
 ```rust
-use forcebot_rs_v2::Bot;
+
+use forcebot_core::Bot;
 
 #[tokio::main]
 pub async fn main() {
 
     /* Create the bot using env */
-    let mut bot = Bot::new();
+    let bot = Bot::new().await;
 
     /* load the Module */
-    bot.load_module(custom_mod::new());
+    bot.load_module(custom_mod::new()).await;
 
     /* Run the bot */
     bot.run().await;
@@ -130,14 +240,16 @@ pub async fn main() {
 pub mod custom_mod {
     use std::sync::Arc;
 
-    use forcebot_rs_v2::{asyncfn_box, Badge, Bot, Command, Module};
+    use forcebot_core::{execution_async, Badge, Bot, Command, Module};
     use twitch_irc::message::ServerMessage;
 
 
-    /// Module with a loaded command
+    /// Module definition with a loaded command
     pub fn new() -> Module {
         /* 1. Create a new module */
-        let mut custom_mod = Module::new("test".to_string(), "".to_string());
+        let mut custom_mod = Module::new(
+            vec!["test".to_string()], 
+            "".to_string());
 
         /* 2. Load the cmd into a new module */
         custom_mod.load_command(cmd_test());
@@ -146,44 +258,45 @@ pub mod custom_mod {
 
     }
 
+    /// Command definition 
     pub fn cmd_test() -> Command {
         /* 1. Create a new cmd */
-        let mut cmd = Command::new("test".to_string(),"".to_string());
+        let mut cmd = Command::new(vec!["test".to_string()],"".to_string());
 
         /* 2. Define exec callback  */
         async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
             if let ServerMessage::Privmsg(msg) = message {
-                let _= bot.client.say_in_reply_to(
+                let _= bot.chat.lock().await.say_in_reply_to(
                     &msg, "test return".to_string()).await;
             }
             Result::Err("Not Valid message type".to_string()) 
         }
 
         /* 3. Set Command flags */
-        cmd.set_exec_fn(asyncfn_box(execbody));
+        cmd.set_exec_fn(execution_async(execbody));
         cmd.set_admin_only(false);
-        cmd.set_min_badge(Badge::Moderator);
+        cmd.set_min_badge(Badge::Vip);
 
         cmd
-        }
+    }
 }
-
 ```
 
 ## Simple Debug Listener
 Bot with a simple listener that listens for all messages and prints in output
 
 ```rust
+
 use std::sync::Arc;
 
-use forcebot_rs_v2::{asyncfn_box, Bot, Listener};
+use forcebot_core::{execution_async, Bot, Listener};
 use twitch_irc::message::ServerMessage;
 
 #[tokio::main]
 pub async fn main() {
 
     /* 1. Create the bot using env */
-    let mut bot = Bot::new();
+    let bot = Bot::new().await;
 
     /* 2a. Create a new blank Listener */
     let mut listener = Listener::new();
@@ -195,15 +308,15 @@ pub async fn main() {
 
     /* 2c. Define an async fn callback execution */
     async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
-        dbg!(message);
+        dbg!(message); /* outputs message to debug */
         Result::Ok("Success".to_string()) 
     }
 
-    /* 2d. Set and Store the execution body using `async_box()`  */
-    listener.set_exec_fn(asyncfn_box(execbody));
+    /* 2d. Set and Store the execution body using `execution_async()`  */
+    listener.set_exec_fn(execution_async(execbody));
 
     /* 3. Load the listener into the bot */
-    bot.load_listener(listener);
+    bot.load_listener(listener).await;
 
     /* 4. Run the bot */
     bot.run().await;
@@ -217,11 +330,12 @@ pub async fn main() {
 Example listener listens for a moderator badge and reply in chat 
 
 ```rust
+
 use std::sync::Arc;
 
-use forcebot_rs_v2::Bot;
-use forcebot_rs_v2::asyncfn_box;
-use forcebot_rs_v2::Listener;
+use forcebot_core::Bot;
+use forcebot_core::execution_async;
+use forcebot_core::Listener;
 use twitch_irc::message::ServerMessage;
 
 
@@ -229,16 +343,16 @@ use twitch_irc::message::ServerMessage;
 pub async fn main() {
 
     /* Create the bot using env */
-    let mut bot = Bot::new();
+    let bot = Bot::new().await;
 
     /* 1. Create a new blank Listener */
     let mut listener = Listener::new();
 
     /* 2. Set a trigger condition function for listener */
+
     listener.set_trigger_cond_fn(
         |_:Arc<Bot>,message:ServerMessage| 
             if let ServerMessage::Privmsg(msg) = message {
-                
                 for badge in msg.badges {
                     if matches!(badge, x if x.name == "moderator") {
                         // dbg!("moderator found");
@@ -252,24 +366,23 @@ pub async fn main() {
     /* 3. Define an async fn callback execution */
     async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
         if let ServerMessage::Privmsg(msg) = message {
-            let _ = bot.client.say_in_reply_to(&msg, "pepeKneel".to_string()).await ;
+            let _ = bot.chat.lock().await.say_in_reply_to(&msg, "pepeKneel".to_string()).await ;
             return Result::Ok("Success".to_string()) ;
         }
         Result::Err("Not Valid message type".to_string()) 
     }
 
-    /* 4. Set and Store the execution body using `async_box()`  */
-    listener.set_exec_fn(asyncfn_box(execbody));
+    /* 4. Set and Store the execution body using `execution_async()`  */
+    listener.set_exec_fn(execution_async(execbody));
 
     /* 5. Load the listener into the bot */
-    bot.load_listener(listener);
+    bot.load_listener(listener).await;
 
     /* Run the bot */
     bot.run().await;
 
 }
 
-
 ```
 
 ## Simple Test Command
@@ -277,9 +390,10 @@ pub async fn main() {
 ```rust
 use std::sync::Arc;
 
-use forcebot_rs_v2::Bot;
-use forcebot_rs_v2::asyncfn_box;
-use forcebot_rs_v2::Command;
+use forcebot_core::Badge;
+use forcebot_core::Bot;
+use forcebot_core::execution_async;
+use forcebot_core::Command;
 use twitch_irc::message::ServerMessage;
 
 
@@ -287,31 +401,31 @@ use twitch_irc::message::ServerMessage;
 pub async fn main() {
 
     /* Create the bot using env */
-    let mut bot = Bot::new();
+    let bot = Bot::new().await;
 
     /* 1. Create a new blank cmd */
-    let mut cmd = Command::new("test".to_string(),"".to_string());
+    let mut cmd = Command::new(vec!["test".to_string()],"".to_string());
 
     /* 2. Define an async fn callback execution */
     async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
         if let ServerMessage::Privmsg(msg) = message {
-            let _ = bot.client.say_in_reply_to(&msg, String::from("test success")).await;
+            let _ = bot.chat.lock().await.say_in_reply_to(&msg, String::from("test success")).await;
             return Result::Ok("Success".to_string()) ;
         }
         Result::Err("Not Valid message type".to_string()) 
     }
 
-    /* 3. Set and Store the execution body using `async_box()`  */
-    cmd.set_exec_fn(asyncfn_box(execbody));
+    /* 3. Set and Store the execution body using `execution_async()`  */
+    cmd.set_exec_fn(execution_async(execbody));
 
     /* 4. optionally, remove admin only default flag */
     cmd.set_admin_only(false);
 
     /* 5. optionally, set min badge*/
-    cmd.set_min_badge("broadcaster".to_string());
-// 
+    cmd.set_min_badge(Badge::Moderator);
+
     /* 6. Load the cmd into the bot */
-    bot.load_command(cmd);
+    bot.load_command(cmd).await;
 
     /* Run the bot */
     bot.run().await;
@@ -320,16 +434,13 @@ pub async fn main() {
 
 ```
 
-# Crate Rust Documentation 
+# Crate Rust API Documentation 
 
-Create Crate documentation
+Create `forcebot_rs_v2` Rust Crate documentation
 
-Clean Build Documentation 
+Documentation - Clean Build & Open in Default Browser  
 ```
-cargo clean && cargo doc
+cargo clean && cargo doc --open
 ```
 
-Open Crate Doc
-```
-cargo doc --open
-```
+
diff --git a/simple_command_bot/Cargo.toml b/simple_command_bot/Cargo.toml
new file mode 100644
index 0000000..25f2f0f
--- /dev/null
+++ b/simple_command_bot/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "simple_command_bot"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+forcebot_core = {path = "../forcebot_core"}
+dotenv = "0.15.0"
+lazy_static = "1.5.0"
+tokio = { version = "1.33.0", features = ["full"] }
+twitch-irc = "5.0.1"
diff --git a/src/bin/simple_command_bot.rs b/simple_command_bot/src/main.rs
similarity index 51%
rename from src/bin/simple_command_bot.rs
rename to simple_command_bot/src/main.rs
index a6ec70e..c49e55c 100644
--- a/src/bin/simple_command_bot.rs
+++ b/simple_command_bot/src/main.rs
@@ -1,47 +1,50 @@
 //! Bot with custom example commands that responds to caller if allowed
-//! 
+//!
 //! Commands that are passed a blank prefix will use the bot prefix
-//! 
-//! Be sure the followig is defined in `.env` 
+//!
+//! Be sure the followig is defined in `.env`
 //! - login_name
 //! - access_token
 //! - bot_channels
 //! - prefix
 //! - bot_admins
-//! 
-//! Bot access tokens be generated here - 
+//!
+//! Bot access tokens be generated here -
 //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
 //! - More Info - <https://dev.twitch.tv/docs/authentication>
 
 use std::sync::Arc;
 
-use forcebot_rs_v2::Badge;
-use forcebot_rs_v2::Bot;
-use forcebot_rs_v2::asyncfn_box;
-use forcebot_rs_v2::Command;
+use forcebot_core::execution_async;
+use forcebot_core::Badge;
+use forcebot_core::Bot;
+use forcebot_core::Command;
 use twitch_irc::message::ServerMessage;
 
-
 #[tokio::main]
 pub async fn main() {
-
     /* Create the bot using env */
-    let mut bot = Bot::new();
+    let bot = Bot::new().await;
 
     /* 1. Create a new blank cmd */
-    let mut cmd = Command::new("test".to_string(),"".to_string());
+    let mut cmd = Command::new(vec!["test".to_string()], "".to_string());
 
     /* 2. Define an async fn callback execution */
-    async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
+    async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
         if let ServerMessage::Privmsg(msg) = message {
-            let _ = bot.client.say_in_reply_to(&msg, String::from("test success")).await;
-            return Result::Ok("Success".to_string()) ;
+            let _ = bot
+                .chat
+                .lock()
+                .await
+                .say_in_reply_to(&msg, String::from("test success"))
+                .await;
+            return Result::Ok("Success".to_string());
         }
-        Result::Err("Not Valid message type".to_string()) 
+        Result::Err("Not Valid message type".to_string())
     }
 
-    /* 3. Set and Store the execution body using `async_box()`  */
-    cmd.set_exec_fn(asyncfn_box(execbody));
+    /* 3. Set and Store the execution body using `execution_async()`  */
+    cmd.set_exec_fn(execution_async(execbody));
 
     /* 4. optionally, remove admin only default flag */
     cmd.set_admin_only(false);
@@ -50,9 +53,8 @@ pub async fn main() {
     cmd.set_min_badge(Badge::Moderator);
 
     /* 6. Load the cmd into the bot */
-    bot.load_command(cmd);
+    bot.load_command(cmd).await;
 
     /* Run the bot */
     bot.run().await;
-
 }
diff --git a/simple_debug_listener/Cargo.toml b/simple_debug_listener/Cargo.toml
new file mode 100644
index 0000000..fceb717
--- /dev/null
+++ b/simple_debug_listener/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "simple_debug_listener"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+forcebot_core = {path = "../forcebot_core"}
+dotenv = "0.15.0"
+lazy_static = "1.5.0"
+tokio = { version = "1.33.0", features = ["full"] }
+twitch-irc = "5.0.1"
diff --git a/src/bin/simple_debug_listener.rs b/simple_debug_listener/src/main.rs
similarity index 54%
rename from src/bin/simple_debug_listener.rs
rename to simple_debug_listener/src/main.rs
index ee129bd..b6dc626 100644
--- a/src/bin/simple_debug_listener.rs
+++ b/simple_debug_listener/src/main.rs
@@ -1,47 +1,43 @@
 //! Example simple Binary crate that creates & runs bot based on `.env`
-//! Be sure the followig is defined in `.env` 
+//! Be sure the followig is defined in `.env`
 //! - login_name
 //! - access_token
 //! - bot_channels
 //! - prefix
 //! - bot_admins
-//! 
-//! Bot access tokens be generated here - 
+//!
+//! Bot access tokens be generated here -
 //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
 //! - More Info - <https://dev.twitch.tv/docs/authentication>
 
 use std::sync::Arc;
 
-use forcebot_rs_v2::{asyncfn_box, Bot, Listener};
+use forcebot_core::{execution_async, Bot, Listener};
 use twitch_irc::message::ServerMessage;
 
 #[tokio::main]
 pub async fn main() {
-
     /* 1. Create the bot using env */
-    let mut bot = Bot::new();
+    let bot = Bot::new().await;
 
     /* 2a. Create a new blank Listener */
     let mut listener = Listener::new();
 
     /* 2b. Set a trigger condition function for listener */
-    listener.set_trigger_cond_fn(
-        |_:Arc<Bot>,_:ServerMessage| true
-    );
+    listener.set_trigger_cond_fn(|_: Arc<Bot>, _: ServerMessage| true);
 
     /* 2c. Define an async fn callback execution */
-    async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
-        dbg!(message);
-        Result::Ok("Success".to_string()) 
+    async fn execbody(_: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+        dbg!(message); /* outputs message to debug */
+        Result::Ok("Success".to_string())
     }
 
-    /* 2d. Set and Store the execution body using `async_box()`  */
-    listener.set_exec_fn(asyncfn_box(execbody));
+    /* 2d. Set and Store the execution body using `execution_async()`  */
+    listener.set_exec_fn(execution_async(execbody));
 
     /* 3. Load the listener into the bot */
-    bot.load_listener(listener);
+    bot.load_listener(listener).await;
 
     /* 4. Run the bot */
     bot.run().await;
-
 }
diff --git a/simple_module_example/Cargo.toml b/simple_module_example/Cargo.toml
new file mode 100644
index 0000000..b00ba0b
--- /dev/null
+++ b/simple_module_example/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "simple_module_example"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+forcebot_core = {path = "../forcebot_core"}
+dotenv = "0.15.0"
+lazy_static = "1.5.0"
+tokio = { version = "1.33.0", features = ["full"] }
+twitch-irc = "5.0.1"
diff --git a/simple_module_example/src/main.rs b/simple_module_example/src/main.rs
new file mode 100644
index 0000000..0c07084
--- /dev/null
+++ b/simple_module_example/src/main.rs
@@ -0,0 +1,76 @@
+//! Simple Module with a Command
+//!
+//! Adding objects through packages provides controls ,
+//! such as moderators, and brodcasters can disable or enable mods
+//!
+//! Here, moderators or above can enable or disable the `test`
+//! module with the command `<prefix> disable test`
+//!
+//! Be sure the followig is defined in `.env`
+//! - login_name
+//! - access_token
+//! - bot_channels
+//! - prefix
+//! - bot_admins
+//!
+//! Bot access tokens be generated here -
+//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
+//! - More Info - <https://dev.twitch.tv/docs/authentication>
+
+use forcebot_core::Bot;
+
+#[tokio::main]
+pub async fn main() {
+    /* Create the bot using env */
+    let bot = Bot::new().await;
+
+    /* load the Module */
+    bot.load_module(custom_mod::new()).await;
+
+    /* Run the bot */
+    bot.run().await;
+}
+
+pub mod custom_mod {
+    use std::sync::Arc;
+
+    use forcebot_core::{execution_async, Badge, Bot, Command, Module};
+    use twitch_irc::message::ServerMessage;
+
+    /// Module definition with a loaded command
+    pub fn new() -> Module {
+        /* 1. Create a new module */
+        let mut custom_mod = Module::new(vec!["test".to_string()], "".to_string());
+
+        /* 2. Load the cmd into a new module */
+        custom_mod.load_command(cmd_test());
+
+        custom_mod
+    }
+
+    /// Command definition
+    pub fn cmd_test() -> Command {
+        /* 1. Create a new cmd */
+        let mut cmd = Command::new(vec!["test".to_string()], "".to_string());
+
+        /* 2. Define exec callback  */
+        async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
+            if let ServerMessage::Privmsg(msg) = message {
+                let _ = bot
+                    .chat
+                    .lock()
+                    .await
+                    .say_in_reply_to(&msg, "test return".to_string())
+                    .await;
+            }
+            Result::Err("Not Valid message type".to_string())
+        }
+
+        /* 3. Set Command flags */
+        cmd.set_exec_fn(execution_async(execbody));
+        cmd.set_admin_only(false);
+        cmd.set_min_badge(Badge::Vip);
+
+        cmd
+    }
+}
diff --git a/src/bin/fun_bot.rs b/src/bin/fun_bot.rs
deleted file mode 100644
index de67fda..0000000
--- a/src/bin/fun_bot.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-//! WIP Fun forcebot with catered customizations #todo
-//! 
-//! Custom modules that can be managed in chat through `disable` and `enable` commands
-//! - funbot 
-//! 
-//! Be sure the followig is defined in `.env` 
-//! - login_name
-//! - access_token
-//! - bot_channels
-//! - prefix
-//! - bot_admins
-//! 
-//! Bot access tokens be generated here - 
-//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
-//! - More Info - <https://dev.twitch.tv/docs/authentication>
-
-use forcebot_rs_v2::Bot;
-
-#[tokio::main]
-pub async fn main() {
-
-    /* Create the bot using env */
-    let mut bot = Bot::new();
-
-    /* 1. Load the module into the bot */
-    bot.load_module(funbot_objs::create_module());
-    
-    /* 2. Run the bot */
-    bot.run().await;
-
-}
-
-
-pub mod funbot_objs {
-    use std::sync::Arc;
-
-    use forcebot_rs_v2::{asyncfn_box, Badge, Bot, Command, Module};
-    use twitch_irc::message::ServerMessage;
-
-    /// Create a Module with a loaded Command object
-    pub fn create_module() -> Module {
-        let mut custom_mod = Module::new("funbot".to_string(), "".to_string());
-
-        custom_mod.load_command(create_cmd_test());
-
-        custom_mod
-    }
-
-    /// Create a Command Object
-    fn create_cmd_test() -> Command {
-    
-        let mut cmd = Command::new("remind besty".to_string(),"annytfYandere ".to_string());
-
-        async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
-            if let ServerMessage::Privmsg(msg) = message {
-                let _= bot.client.say_in_reply_to(
-                    &msg, "annytfYandere he's mine".to_string()).await;
-                    return Result::Ok("Success".to_string());
-            }
-            Result::Err("Not Valid message type".to_string()) 
-        }
-
-        cmd.set_exec_fn(asyncfn_box(execbody));
-
-        cmd.set_admin_only(false);
-        cmd.set_min_badge(Badge::Vip);
-        cmd
-
-    }
-}
\ No newline at end of file
diff --git a/src/bin/moderator_reactor.rs b/src/bin/moderator_reactor.rs
deleted file mode 100644
index a7bb62c..0000000
--- a/src/bin/moderator_reactor.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-//! Simple bot with a custom listeners that listens for moderators and respond to the moderator
-//! 
-//! Be sure the followig is defined in `.env` 
-//! - login_name
-//! - access_token
-//! - bot_channels
-//! - prefix
-//! - bot_admins
-//! 
-//! Bot access tokens be generated here - 
-//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
-//! - More Info - <https://dev.twitch.tv/docs/authentication>
-
-use std::sync::Arc;
-
-use forcebot_rs_v2::Bot;
-use forcebot_rs_v2::asyncfn_box;
-use forcebot_rs_v2::Listener;
-use twitch_irc::message::ServerMessage;
-
-
-#[tokio::main]
-pub async fn main() {
-
-    /* Create the bot using env */
-    let mut bot = Bot::new();
-
-    /* 1. Create a new blank Listener */
-    let mut listener = Listener::new();
-
-    /* 2. Set a trigger condition function for listener */
-
-    listener.set_trigger_cond_fn(
-        |_:Arc<Bot>,message:ServerMessage| 
-            if let ServerMessage::Privmsg(msg) = message {
-                // dbg!(msg.clone());
-                for badge in msg.badges {
-                    if matches!(badge, x if x.name == "moderator") {
-                        // dbg!("moderator found");
-                        return true;
-                    }
-                } 
-                false
-            } else { false }
-    );
-
-    /* 3. Define an async fn callback execution */
-    async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
-        if let ServerMessage::Privmsg(msg) = message {
-            let _ = bot.client.say_in_reply_to(&msg, "pepeKneel".to_string()).await ;
-            return Result::Ok("Success".to_string()) ;
-        }
-        Result::Err("Not Valid message type".to_string()) 
-    }
-
-    /* 4. Set and Store the execution body using `async_box()`  */
-    listener.set_exec_fn(asyncfn_box(execbody));
-
-    /* 5. Load the listener into the bot */
-    bot.load_listener(listener);
-
-    /* Run the bot */
-    bot.run().await;
-
-}
diff --git a/src/botcore.rs b/src/botcore.rs
deleted file mode 100644
index 678d9a9..0000000
--- a/src/botcore.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-pub mod bot;
-pub mod bot_objects;
-pub mod modules;
\ No newline at end of file
diff --git a/src/botcore/bot.rs b/src/botcore/bot.rs
deleted file mode 100644
index 89598af..0000000
--- a/src/botcore/bot.rs
+++ /dev/null
@@ -1,238 +0,0 @@
-
-
-use tokio::sync::{mpsc::UnboundedReceiver, Mutex};
-use twitch_irc::{login::StaticLoginCredentials, message::ServerMessage, SecureTCPTransport, TwitchIRCClient};
-use dotenv::dotenv;
-use std::{env, sync::Arc};
-
-use crate::{Command, Listener, Module};
-
-use super::bot_objects::built_in_objects;
-
-
-/// Twitch chat bot
-pub struct Bot 
-{
-    /// Prefix for commands
-    prefix: String,
-    /// inbound chat msg stream
-    incoming_msgs: Mutex<UnboundedReceiver<ServerMessage>>,
-    /// outbound chat client msg stream
-    pub client: TwitchIRCClient<SecureTCPTransport,StaticLoginCredentials>,
-    /// joined channels
-    botchannels: Vec<String>,
-    /// admin chatters
-    admins : Vec<String>,
-    /// listeners
-    listeners: Vec<Listener>,
-    /// commands
-    commands: Vec<Command>,
-    /// modules
-    modules: Vec<Module>,
-    /// channel module status
-    channel_module_status: Mutex<Vec<(String,String,String)>>
-}
-
-
-impl Bot
-{
-    /// Creates a new `Bot` using env variables
-    /// 
-    /// Be sure the following is defined in an `.env` file
-    /// - login_name
-    /// - access_token
-    /// - bot_channels
-    /// - prefix
-    /// - bot_admins
-    pub fn new() -> Bot {
-
-        dotenv().ok();
-        let bot_login_name = env::var("login_name").unwrap().to_owned();
-        let oauth_token = env::var("access_token").unwrap().to_owned();
-        let prefix = env::var("prefix")
-            .unwrap()
-            .to_owned();
-
-        let mut botchannels = Vec::new();
-
-        for chnl in env::var("bot_channels").unwrap().split(',') {
-                botchannels.push(chnl.to_owned());
-        }
-
-        Bot::new_from(bot_login_name, oauth_token, prefix, botchannels)
-       
-
-    }
-
-    /// Creates a new `Bot` using bot information
-    /// 
-    /// Bot joined channels will include channels from `.env` and `botchannels` argument
-    pub fn new_from(bot_login_name:String,oauth_token:String,prefix:String,botchannels:Vec<String>) -> Bot {
-
-        dotenv().ok();
-        let bot_login_name = bot_login_name;
-
-        let config = twitch_irc::ClientConfig::new_simple(StaticLoginCredentials::new(
-            bot_login_name.to_owned(),
-            Some(oauth_token.to_owned()),
-        ));
-
-        let (incoming_messages, client) =
-            TwitchIRCClient::<SecureTCPTransport, StaticLoginCredentials>::new(config);
-
-        let mut botchannels_all = Vec::new();
-        botchannels_all.extend(botchannels);
-
-        for chnl in env::var("bot_channels").unwrap().split(',') {
-            botchannels_all.push(chnl.to_owned());
-        }
-
-
-        let mut admins = Vec::new();
-
-        if let Ok(value) = env::var("bot_admins") {
-            for admin in value.split(',') {
-                admins.push(String::from(admin))        
-            }
-        }
-
-
-        let mut bot = Bot {
-             prefix,
-             incoming_msgs : Mutex::new(incoming_messages),
-             client,
-             botchannels : botchannels_all,
-             listeners : vec![],
-             commands : vec![],
-             admins,
-             modules:   vec![],
-             channel_module_status: Mutex::new(vec![]),
-        };
-
-        for cmd in built_in_objects::create_commands() {
-            bot.load_command(cmd);
-        }
-
-        bot
-    }
-
-    /// Runs the bot 
-    pub async fn run(self) {
-
-        for chnl in &self.botchannels {
-            self.client.join(chnl.to_owned()).unwrap();
-        }
-
-        let bot = Arc::new(self);
-
-        let join_handle = tokio::spawn(async move {
-            
-            let a = bot.clone();
-            let mut in_msgs_lock = a.incoming_msgs.lock().await;
-            
-            while let Some(message) = in_msgs_lock.recv().await {                
-                for listener in &(*bot).listeners {
-                    
-                    let a = listener.clone();
-                    if a.cond_triggered(bot.clone(),message.clone()) {
-                        
-                        let _ = listener.execute_fn(bot.clone(),message.clone()).await;
-                    }
-                }
-
-                if let ServerMessage::Privmsg(msg) = message.clone() {
-
-                    for cmd in &(*bot).commands {
-                    
-                        let a = cmd.clone();
-                        if a.command_triggered(bot.clone(),msg.clone()) {
-                             
-                            let _ = cmd.execute_fn(bot.clone(),message.clone()).await;
-                        }
-                    }
-
-
-                    for module in &(*bot).modules {
-                        
-                        let cms_lock = bot.channel_module_status.lock().await;
-                        if cms_lock.contains(&(msg.channel_login.clone(),module.get_name(),"disabled".to_string())) 
-                        { continue; }
-
-                        for listener in module.get_listeners() {
-                        
-                            let a = listener.clone();
-                            if a.cond_triggered(bot.clone(),message.clone()) {
-                                
-                                let _ = listener.execute_fn(bot.clone(),message.clone()).await;
-                            }
-                        }
-                        for cmd in module.get_commands() {
-                            
-                            let a = cmd.clone();
-                            if a.command_triggered(bot.clone(),msg.clone()) {
-                                
-                                let _ = cmd.execute_fn(bot.clone(),message.clone()).await;
-                            }
-                        }  
-                        
-                    }
-                    
-                } else {} ;
-                
-
-            }
-            drop(in_msgs_lock);
-        });
-        
-        join_handle.await.unwrap();
-    }
-
-    /// Loads a `Listener` into the bot
-    pub fn load_listener(&mut self,l : Listener) {
-        self.listeners.push(l);
-    }
-
-    /// Loads a `Command` into the bot
-    pub fn load_command(&mut self,c : Command) {
-        self.commands.push(c);
-    }
-    
-
-
-    pub fn get_prefix(&self) -> String {
-        self.prefix.clone()
-    }
-
-    pub fn get_admins(&self) -> Vec<String> {
-        self.admins.clone()
-    }
-    
-    /// loads a `Module` and its bot objects
-    pub fn load_module(&mut self,m: Module) {
-        self.modules.push(m)
-    }
-
-    pub async fn disable_module(&self,channel:String,module:String){
-        let mut lock = self.channel_module_status.lock().await;
-        if !lock.contains(&(channel.clone(),module.clone(),"disabled".to_string())) {
-            lock.push((channel,module,"disabled".to_string()));
-        }
-    }
-
-    pub async fn enable_module(&self,channel:String,module:String){
-        let mut lock = self.channel_module_status.lock().await;
-        if lock.contains(&(channel.clone(),module.clone(),"disabled".to_string())) {
-            
-            let index = lock
-                .iter()
-                .position(|x| *x == 
-                    (channel.clone(),module.clone(),"disabled".to_string()))
-                .unwrap();
-            lock.remove(index);
-        }
-    }
-
-
-}
-
-
diff --git a/src/botcore/bot_objects.rs b/src/botcore/bot_objects.rs
deleted file mode 100644
index 9fb6985..0000000
--- a/src/botcore/bot_objects.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-pub mod listener;
-pub mod command;
-
-
-use std::boxed::Box;
-use std::future::Future;
-use std::pin::Pin;
-use std::sync::Arc;
-
-use twitch_irc::message::ServerMessage;
-
-use super::bot::Bot;
-
-
-/// chat badge
-#[derive(Clone)]
-pub enum Badge {
-    Moderator,
-    Broadcaster,
-    Vip
-}
-
-
-pub type ExecBody = Box<
-    dyn Fn(Arc<Bot>,ServerMessage) -> Pin<Box<dyn Future<Output = Result<String,String>> + Send>> + Send + Sync,
->;
-
-pub fn asyncfn_box<T>(f: fn(Arc<Bot>,ServerMessage) -> T) -> ExecBody
-where
-    T: Future<Output = Result<String,String>> + Send + 'static,
-{
-    Box::new(move |a,b| Box::pin(f(a,b)))
-}
-
-
-
-/// collection of functions to create built in objects
-pub mod built_in_objects {
-    
-
-    use std::sync::Arc;
-
-    use twitch_irc::message::ServerMessage;
-
-    use crate::{asyncfn_box, Badge, Bot, Command};
-
-
-    /// create a vector of command build in objects
-    pub fn create_commands() -> Vec<Command> 
-    {
-        let mut cmds = vec![];
-
-        cmds.push(create_disable_cmd());
-        cmds.push(create_enable_cmd());
-
-        cmds
-
-    }
-
-    fn create_disable_cmd() -> Command {
-        /* 1. Create a new blank cmd */
-        let mut cmd = Command::new("disable".to_string(),"".to_string());
-
-        /* 2. Define an async fn callback execution */
-        async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
-            if let ServerMessage::Privmsg(msg) = message {
-                for (i,arg) in msg.message_text.split(" ").enumerate() {
-                    if i > 1 {
-                        bot.disable_module(msg.channel_login.clone(), arg.to_string()).await;
-                    }
-                }
-                let _ = bot.client.say_in_reply_to(&msg, String::from("Disabled!")).await ;
-            }
-            Result::Err("Not Valid message type".to_string()) 
-        }
-
-        /* 3. Set and Store the execution body using `async_box()`  */
-        cmd.set_exec_fn(asyncfn_box(execbody));
-
-        /* 4. optionally, remove admin only default flag */
-        cmd.set_admin_only(false);
-
-        /* 5. optionally, set min badge*/
-        cmd.set_min_badge(Badge::Moderator);
-        cmd
-        
-    } 
-
-    fn create_enable_cmd() -> Command {
-        /* 1. Create a new blank cmd */
-        let mut cmd = Command::new("enable".to_string(),"".to_string());
-
-        /* 2. Define an async fn callback execution */
-        async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
-            if let ServerMessage::Privmsg(msg) = message {
-                for (i,arg) in msg.message_text.split(" ").enumerate() {
-                    if i > 1 {
-                        bot.enable_module(msg.channel_login.clone(), arg.to_string()).await;
-                    }
-                }
-                
-                let _ = bot.client.say_in_reply_to(&msg, String::from("Enabled!")).await ;
-         }
-            Result::Err("Not Valid message type".to_string()) 
-        }
-
-        /* 3. Set and Store the execution body using `async_box()`  */
-        cmd.set_exec_fn(asyncfn_box(execbody));
-
-        /* 4. optionally, remove admin only default flag */
-        cmd.set_admin_only(false);
-
-        /* 5. optionally, set min badge*/
-        cmd.set_min_badge(Badge::Moderator);
-        cmd
-    }
-
-
-}
\ No newline at end of file
diff --git a/src/botcore/bot_objects/command.rs b/src/botcore/bot_objects/command.rs
deleted file mode 100644
index 574a22e..0000000
--- a/src/botcore/bot_objects/command.rs
+++ /dev/null
@@ -1,162 +0,0 @@
-use std::sync::Arc;
-
-use twitch_irc::message::{PrivmsgMessage, ServerMessage};
-
-use crate::{asyncfn_box, botcore::bot::Bot, Badge};
-
-use super::ExecBody;
-
-/// Bot `Command` that stores trigger condition callback and a execution functon
-/// 
-/// A prefix character or phrase can be defined for the bot to evaluate a trigger condition
-/// 
-/// A command or command phrase defines the phrase after the prefix phrase
-/// 
-/// If no min badge role is provided, Broadcaster is defaulted. All commands require at least a vip role
-/// 
-/// AdminOnly commands can only be ran by admin 
-/// 
-/// Use `asyncfn_box()` on custom async execution bodies
-#[derive(Clone)]
-pub struct Command
-{
-    command : String,
-    exec_fn : Arc<ExecBody>,
-    min_badge : Badge,
-    admin_only : bool,
-    prefix : String,
-    custom_cond_fn : fn(Arc<Bot>,PrivmsgMessage) -> bool,
-}
-
-impl Command
-{
-
-    /// Creates a new empty `Command` using command `String` and prefix `String`
-    /// Pass an empty string prefix if the bot should use the bot default
-    ///    
-    /// Call `set_trigger_cond_fn()` and `set_exec_fn()` to trigger & execution function callbacks
-    /// if a blank prefix is given, the bot will look for the bot prefix instead
-    /// 
-    /// By default, the new command is admin_only
-    pub fn new(command:String,prefix:String) -> Command {
-
-        async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> 
-        { Result::Ok("success".to_string()) }
-
-        Command {
-            command ,
-            prefix ,
-            exec_fn : Arc::new(asyncfn_box(execbody)),
-            min_badge : Badge::Vip,
-            admin_only : true,
-            custom_cond_fn : |_:Arc<Bot>,_:PrivmsgMessage| true,
-        }
-    }
-
-    /// set a trigger conditin callback that returns true if the listener shoud trigger
-    pub fn set_custom_cond_fn(&mut self,cond_fn: fn(Arc<Bot>,PrivmsgMessage) -> bool) {
-        self.custom_cond_fn = cond_fn;
-    }
-
-    /// sets the execution body of the listener for when it triggers
-    /// 
-    /// Use`asyncfn_box()` on the async fn when storing
-    /// 
-    /// 
-    pub fn set_exec_fn(&mut self,exec_fn:ExecBody ) {
-        self.exec_fn = Arc::new(exec_fn);
-    }
-
-    /// checks if the trigger condition is met
-    /// specifically if the message is a valid command and min badge roles provided
-    /// 
-    pub fn command_triggered(&self,bot:Arc<Bot>,msg:PrivmsgMessage) -> bool {
-
-        fn cmd_called(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool {
-                let mut prefixed_cmd = "".to_string();
-                if cmd.prefix == "" {
-                    prefixed_cmd.push_str(&bot.get_prefix());
-                } else { 
-                    prefixed_cmd.push_str(&cmd.prefix); 
-                }
-                prefixed_cmd.push_str(&cmd.command);
-                return message.message_text.starts_with(prefixed_cmd.as_str())
-        }
-
-        
-        fn caller_badge_ok(cmd:&Command,_bot:Arc<Bot>,message:PrivmsgMessage) -> bool {
-            for badge in message.badges {
-                
-                match cmd.min_badge {
-                    Badge::Broadcaster => {
-                        if badge.name == "broadcaster" { return true }
-                        else { return false } 
-                    },
-                    Badge::Moderator => {
-                        match badge.name.as_str() {
-                            "moderator" | "broadcaster" => return true,
-                            _ => (),
-                        }
-                    },
-                    Badge::Vip => {
-                        match badge.name.as_str() {
-                            "vip" | "moderator" | "broadcaster" => return true,
-                            _ => (),
-                        }
-                    },
-                }
-            }
-
-            return false;
-        }
-
-        
-        /// determines if the command caller can run the command 
-        /// based on admin_only flag
-        /// 
-        /// callers who are admins can run admin_only commands
-        /// callers can run non-admin_only commands
-        fn admin_only_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool {
-            if (cmd.admin_only && bot.get_admins().contains(&message.sender.login)) || !cmd.admin_only {
-                return true;
-            } else {
-                return false;
-            }
-        }
-
-        fn custom_cond_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool {
-            (cmd.custom_cond_fn)(bot,message)
-        }
-
-        // dbg!(msg.clone());
-
-        // dbg!(caller_badge_ok(self, bot.clone(), msg.clone()));
-        // dbg!(cmd_called(self, bot.clone(), msg.clone()) && 
-        // caller_badge_ok(self, bot.clone(), msg.clone()) &&
-        // admin_only_ok(self, bot.clone(), msg.clone()) &&
-        // custom_cond_ok(self, bot.clone(), msg.clone()));
-
-        cmd_called(self, bot.clone(), msg.clone()) && 
-        caller_badge_ok(self, bot.clone(), msg.clone()) &&
-        admin_only_ok(self, bot.clone(), msg.clone()) &&
-        custom_cond_ok(self, bot, msg)
-
-    }
-
-    /// executes the listeners executon body
-    pub async fn execute_fn(&self,bot:Arc<Bot>,msg:ServerMessage) -> Result<String, String> {
-        (self.exec_fn)(bot,msg).await
-    }
-
-
-    /// sets min_badge to run the cmd
-    // pub fn set_min_badge(&mut self,min_badge:String) {
-    pub fn set_min_badge(&mut self,min_badge:Badge) {
-        self.min_badge = min_badge
-    }
-
-    /// sets admin_only
-    pub fn set_admin_only(&mut self,admin_only:bool) {
-        self.admin_only = admin_only
-    }
-}
diff --git a/src/botcore/bot_objects/listener.rs b/src/botcore/bot_objects/listener.rs
deleted file mode 100644
index 2bebb8e..0000000
--- a/src/botcore/bot_objects/listener.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-use std::sync::Arc;
-
-use twitch_irc::message::ServerMessage;
-
-use crate::{asyncfn_box, Bot};
-
-use super::ExecBody;
-
-/// Bot `Listener`` that stores trigger condition callback and a execution functon
-/// 
-/// Use `asyncfn_box()` on custom async execution bodies
-#[derive(Clone)]
-pub struct Listener
-{
-    /// trigger condition
-    trigger_cond_fn : fn(Arc<Bot>,ServerMessage) -> bool,
-    /// execution body
-    exec_fn : Arc<ExecBody>,
-}
-
-impl Listener
-{
-
-    /// Creates a new empty `Listener` . 
-    /// Call `set_trigger_cond_fn()` and `set_exec_fn()` to trigger & execution function callbacks
-    pub fn new() -> Listener {
-
-        async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> {Result::Ok("success".to_string()) }
-
-        Listener {
-            trigger_cond_fn : |_:Arc<Bot>,_:ServerMessage| false,
-            exec_fn : Arc::new(asyncfn_box(execbody))
-        }
-    }
-
-    /// set a trigger conditin callback that returns true if the listener shoud trigger
-    pub fn set_trigger_cond_fn(&mut self,cond_fn: fn(Arc<Bot>,ServerMessage) -> bool) {
-        self.trigger_cond_fn = cond_fn;
-    }
-
-    /// sets the execution body of the listener for when it triggers
-    /// 
-    /// Use`asyncfn_box()` on the async fn when storing
-    /// 
-    /// Example - 
-    /// ```rust
-    /// /* 1. Create a new blank Listener */
-    /// let mut listener = Listener::new();
-    ///
-    /// /* 2. define an async function */
-    /// async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> {Result::Ok("success".to_string()) }
-    /// 
-    /// /* 3. Set and Store the execution body using `async_box()`  */
-    /// listener.set_exec_fn(asyncfn_box(execbody));
-    /// ```
-    /// 
-    pub fn set_exec_fn(&mut self,exec_fn:ExecBody ) {
-        self.exec_fn = Arc::new(exec_fn);
-    }
-
-    /// checks if the trigger condition is met
-    pub fn cond_triggered(&self,bot:Arc<Bot>,msg:ServerMessage) -> bool {
-        (self.trigger_cond_fn)(bot,msg)
-    }
-
-    /// executes the listeners executon body
-    pub async fn execute_fn(&self,bot:Arc<Bot>,msg:ServerMessage) -> Result<String, String> {
-        // (self.exec_fn)(bot,msg)
-        (self.exec_fn)(bot,msg).await
-    }
-}
-
diff --git a/src/botcore/modules.rs b/src/botcore/modules.rs
deleted file mode 100644
index e57ecc2..0000000
--- a/src/botcore/modules.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-use crate::{Command, Listener};
-
-
-/// Bot `Module` that groups a set of `bot_objects`
-/// 
-/// Elevated chatters can disable modules by their name or chat alias
-pub struct Module
-{
-    name: String,
-    _alias: String,
-    listeners: Vec<Listener>,
-    commands: Vec<Command>,
-}
-
-impl Module 
-{
-    /// create a new module
-    pub fn new(name:String,alias:String) -> Module {
-        Module {
-            name,
-            _alias: alias,
-            listeners: vec![],
-            commands: vec![]
-        }
-    }
-
-    /// Loads a `Listener` into the module
-    pub fn load_listener(&mut self,l : Listener) {
-        self.listeners.push(l);
-    }
-
-    /// Loads a `Command` into the module
-    pub fn load_command(&mut self,c : Command) {
-        self.commands.push(c);
-    }
-
-    pub fn get_listeners(&self) -> Vec<Listener> {
-        self.listeners.clone()
-    }
- 
-    pub fn get_commands(&self) -> Vec<Command> {
-        self.commands.clone()
-    }
-
-    pub fn get_name(&self) -> String {
-        self.name.clone()
-    }
-
-}
\ No newline at end of file
diff --git a/src/custom_mods.rs b/src/custom_mods.rs
deleted file mode 100644
index e69de29..0000000
diff --git a/src/lib.rs b/src/lib.rs
deleted file mode 100644
index 9ecb36f..0000000
--- a/src/lib.rs
+++ /dev/null
@@ -1,206 +0,0 @@
-//! `forcebot-rs-v2` : Twitch chat bot written in rust.
-//! 
-//! Customize by adding additional bot objects
-//! 
-//! ## New Bot
-//! 
-//! Uses Env defined variables to create and run the bot
-//! 
-//! ```rust
-//! use forcebot_rs_v2::Bot;
-//! 
-//! #[tokio::main]
-//! pub async fn main() {
-//! 
-//!     /* 1. Create the bot using env */
-//!     let bot = Bot::new();
-//! 
-//!     /* 2. Run the bot */
-//!     bot.run().await;
-//! 
-//! }
-//! 
-//! ```
-//! 
-//! 
-//! ## Customize with Modules
-//! 
-//! A `Module` is a group of bot objects (eg `Command`) that elevated users can manage through built in `disable` and `enable` commands
-//! 
-//! Create a custom `Module` by :
-//! 
-//! 1. Defining Functions that create the Custom Bot Objects (eg `Command`)
-//! 
-//! 2. Define a function that creates a `Module` with the Custom Bot Objects loaded
-//! 
-//! 
-//! ```rust
-//! use forcebot_rs_v2::Bot;
-//! 
-//! #[tokio::main]
-//! pub async fn main() {
-//! 
-//!     /* Create the bot using env */
-//!     let mut bot = Bot::new();
-//! 
-//!     /* load the Module */
-//!     bot.load_module(custom_mod::new());
-//! 
-//!     /* Run the bot */
-//!     bot.run().await;
-//! 
-//! }
-//! 
-//! 
-//! pub mod custom_mod {
-//!     use std::sync::Arc;
-//! 
-//!     use forcebot_rs_v2::{asyncfn_box, Badge, Bot, Command, Module};
-//!     use twitch_irc::message::ServerMessage;
-//! 
-//! 
-//!     /// Module with a loaded command
-//!     pub fn new() -> Module {
-//!         /* 1. Create a new module */
-//!         let mut custom_mod = Module::new("test".to_string(), "".to_string());
-//! 
-//!         /* 2. Load the cmd into a new module */
-//!         custom_mod.load_command(cmd_test());
-//! 
-//!         custom_mod
-//! 
-//!     }
-//! 
-//!     pub fn cmd_test() -> Command {
-//!         /* 1. Create a new cmd */
-//!         let mut cmd = Command::new("test".to_string(),"".to_string());
-//! 
-//!         /* 2. Define exec callback  */
-//!         async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
-//!             if let ServerMessage::Privmsg(msg) = message {
-//!                 let _= bot.client.say_in_reply_to(
-//!                     &msg, "test return".to_string()).await;
-//!             }
-//!             Result::Err("Not Valid message type".to_string()) 
-//!         }
-//! 
-//!         /* 3. Set Command flags */
-//!         cmd.set_exec_fn(asyncfn_box(execbody));
-//!         cmd.set_admin_only(false);
-//!         cmd.set_min_badge(Badge::Moderator);
-//! 
-//!         cmd
-//!         }
-//! }
-//! 
-//! ```
-//! 
-//! ## Simple Debug Listener
-//! Bot with a simple listener that listens for all messages and prints in output
-//! 
-//! ```rust
-//! use std::sync::Arc;
-//! 
-//! use forcebot_rs_v2::{asyncfn_box, Bot, Listener};
-//! use twitch_irc::message::ServerMessage;
-//! 
-//! #[tokio::main]
-//! pub async fn main() {
-//! 
-//!     /* 1. Create the bot using env */
-//!     let mut bot = Bot::new();
-//! 
-//!     /* 2a. Create a new blank Listener */
-//!     let mut listener = Listener::new();
-//! 
-//!     /* 2b. Set a trigger condition function for listener */
-//!     listener.set_trigger_cond_fn(
-//!         |_:Arc<Bot>,_:ServerMessage| true
-//!     );
-//! 
-//!     /* 2c. Define an async fn callback execution */
-//!     async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
-//!         dbg!(message);
-//!         Result::Ok("Success".to_string()) 
-//!     }
-//! 
-//!     /* 2d. Set and Store the execution body using `async_box()`  */
-//!     listener.set_exec_fn(asyncfn_box(execbody));
-//! 
-//!     /* 3. Load the listener into the bot */
-//!     bot.load_listener(listener);
-//! 
-//!     /* 4. Run the bot */
-//!     bot.run().await;
-//! 
-//! }
-//! 
-//! ```
-//! 
-//! ## Modertor Reactor
-//! 
-//! ```
-//! 
-//! use std::sync::Arc;
-//! 
-//! use forcebot_rs_v2::Bot;
-//! use forcebot_rs_v2::asyncfn_box;
-//! use forcebot_rs_v2::Listener;
-//! use twitch_irc::message::ServerMessage;
-//! 
-//! 
-//! #[tokio::main]
-//! pub async fn main() {
-//! 
-//!     /* Create the bot using env */
-//!     let mut bot = Bot::new();
-//! 
-//!     /* 1. Create a new blank Listener */
-//!     let mut listener = Listener::new();
-//! 
-//!     /* 2. Set a trigger condition function for listener */
-//! 
-//!     listener.set_trigger_cond_fn(
-//!         |_:Arc<Bot>,message:ServerMessage| 
-//!            if let ServerMessage::Privmsg(msg) = message {
-//!                // dbg!(msg.clone());
-//!                 for badge in msg.badges {
-//!                     if matches!(badge, x if x.name == "moderator") {
-//!                         // dbg!("moderator found");
-//!                         return true;
-//!                     }
-//!                 } 
-//!                 false
-//!             } else { false }
-//!     );
-//! 
-//!     /* 3. Define an async fn callback execution */
-//!     async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
-//!         if let ServerMessage::Privmsg(msg) = message {
-//!             let _ = bot.client.say_in_reply_to(&msg, "pepeKneel".to_string()).await ;
-//!             return Result::Ok("Success".to_string()) ;
-//!         }
-//!         Result::Err("Not Valid message type".to_string()) 
-//!     }
-//! 
-//!     /* 4. Set and Store the execution body using `async_box()`  */
-//!     listener.set_exec_fn(asyncfn_box(execbody));
-//! 
-//!     /* 5. Load the listener into the bot */
-//!     bot.load_listener(listener);
-//!
-//!    /* Run the bot */
-//!    bot.run().await;
-//!
-//! }
-
-
-
-pub mod botcore;
-pub use crate::botcore::bot::Bot;
-pub use crate::botcore::bot_objects::asyncfn_box;
-pub use crate::botcore::bot_objects::listener::Listener;
-pub use crate::botcore::bot_objects::command::Command;
-pub use crate::botcore::modules::Module;
-pub use crate::botcore::bot_objects::Badge;
-