diff --git a/Cargo.lock b/Cargo.lock
index 171caddb779aead920384a7efd531a5b26ad5bf3..fef3be67c3b6f545559c356a6cc18791da386fd0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1467,9 +1467,12 @@ dependencies = [
 
 [[package]]
 name = "macros-rs"
-version = "0.5.2"
+version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb1feaac5c34086868f3f439dabbd71baf6a785f256aacdde7c66c95b56b12d6"
+checksum = "9cfca1250b52a785fbe49de29612471f59592b6b659159dcfcb976af08c803b4"
+dependencies = [
+ "termcolor",
+]
 
 [[package]]
 name = "maid"
diff --git a/Cargo.toml b/Cargo.toml
index d0a1963740a8cfb1f7f0f6be8bdd432c95c6a791..49a246a9d820ebbbdb9c6289269ad72610220aa6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -77,7 +77,7 @@ flate2 = "1.0.35"
 anyhow = "1.0.93"
 tracing = "0.1.40"
 termcolor = "1.4.1"
-macros-rs = "0.5.2"
+macros-rs = "1.4.1"
 indicatif = "0.17.9"
 serde_json = "1.0.133"
 text_placeholder = "0.5.1"
diff --git a/maid/client/cli/dispatch.rs b/maid/client/cli/dispatch.rs
index b908b31c9e70a7b70a591ba00b288105d138b6b2..ece144cb680778992d36bb8d0b2cf870d30e1f67 100644
--- a/maid/client/cli/dispatch.rs
+++ b/maid/client/cli/dispatch.rs
@@ -1,8 +1,7 @@
-use crate::helpers;
 use maid::log::prelude::*;
 
 use inquire::Text;
-use macros_rs::string;
+use macros_rs::fs::file_exists;
 use notify::RecursiveMode;
 use notify_debouncer_mini::new_debouncer;
 use std::{fs::File, io::Write, path::Path, time::Duration};
@@ -41,7 +40,7 @@ pub(crate) fn init() {
     let path = "maidfile";
     let example_maidfile = "[tasks.example]\ninfo = \"this is a comment\"\nscript = \"echo 'hello world'\"";
 
-    if !helpers::Exists::file(path.to_owned()).unwrap() {
+    if !file_exists!(path) {
         println!("This utility will walk you through creating a maidfile.\n");
 
         let mut file = File::create(&path).unwrap();
@@ -62,7 +61,7 @@ pub(crate) fn init() {
 
         writeln!(&mut file, "\n{example_maidfile}").unwrap();
         println!("{}", "\n✨ success, saved maidfile".yellow());
-        if helpers::Exists::file(string!(".git")).unwrap() {
+        if file_exists!(".git") {
             println!("{}", "dont forget to add '.maid' to your .gitignore".white());
         }
     } else {
diff --git a/maid/client/cli/mod.rs b/maid/client/cli/mod.rs
index 3fea7553b75ef67bb29d0891813bff278a4935fe..fb24243155626d75f7441912de2d048f32e709ca 100644
--- a/maid/client/cli/mod.rs
+++ b/maid/client/cli/mod.rs
@@ -2,20 +2,24 @@ pub(crate) mod dispatch;
 pub(crate) mod run;
 pub(crate) mod tasks;
 
-use crate::helpers;
 use crate::parse;
 use crate::server;
-use crate::structs::{Cache, CacheConfig, Task};
 use crate::task;
 
-use maid::log::prelude::*;
+use maid::models::client::{Cache, CacheConfig, Task};
+use maid::{helpers, log::prelude::*};
 
 use fs_extra::dir::get_size;
 use global_placeholders::global;
 use human_bytes::human_bytes;
-use macros_rs::{crashln, fmtstr, string, ternary};
 use std::{env, path::Path, time::Instant};
 
+use macros_rs::{
+    exp::ternary,
+    fmt::{fmtstr, string},
+    fs::{file_exists, folder_exists},
+};
+
 pub fn get_version(short: bool) -> String {
     return match short {
         true => format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")),
@@ -24,7 +28,7 @@ pub fn get_version(short: bool) -> String {
 }
 
 pub fn info(path: &String) {
-    let values = helpers::maidfile::merge(path);
+    let values = parse::merge(path);
     let project_root = parse::file::find_maidfile_root(path);
 
     let name = match &values.project {
@@ -62,22 +66,22 @@ pub fn exec(task: &str, args: &Vec<String>, path: &String, silent: bool, is_dep:
             tasks::List::all(path, silent, log_level, force);
         }
     } else {
-        let values = helpers::maidfile::merge(path);
+        let values = parse::merge(path);
         let project_root = parse::file::find_maidfile_root(path);
         let cwd = &helpers::file::get_current_working_dir();
 
         if values.tasks.get(task).is_none() {
-            crashln!("Maid could not find the task '{task}'. Does it exist?");
+            error!("Could not find the task '{task}'. Does it exist?");
         }
 
         if is_remote && values.tasks.get(task).unwrap().remote.is_none() {
-            crashln!("Maid could not find the remote task '{task}'. Does it exist?");
+            error!("Could not find the remote task '{task}'. Does it exist?");
         }
 
         match values.tasks.get(task).unwrap().remote.as_ref() {
             Some(val) => {
                 if val.exclusive && !is_remote {
-                    crashln!("Task '{task}' is remote only.");
+                    error!("Task '{task}' is remote only.");
                 }
             }
             None => {}
@@ -125,7 +129,7 @@ pub fn exec(task: &str, args: &Vec<String>, path: &String, silent: bool, is_dep:
         .to_string();
 
         if !cache.path.trim().is_empty() && !cache.target.is_empty() && !is_remote {
-            if !helpers::Exists::folder(global!("maid.cache_dir", task)).unwrap() {
+            if !folder_exists!(&global!("maid.cache_dir", task)) {
                 std::fs::create_dir_all(global!("maid.cache_dir", task)).unwrap();
                 debug!("created maid cache dir");
             }
@@ -133,7 +137,7 @@ pub fn exec(task: &str, args: &Vec<String>, path: &String, silent: bool, is_dep:
             let hash = task::cache::create_hash(&cache.path);
             let config_path = format!(".maid/cache/{task}/{}.toml", task);
 
-            if !helpers::Exists::file(config_path.clone()).unwrap() {
+            if !file_exists!(&config_path) {
                 match std::fs::write(
                     config_path.clone(),
                     toml::to_string(&CacheConfig {
@@ -142,19 +146,19 @@ pub fn exec(task: &str, args: &Vec<String>, path: &String, silent: bool, is_dep:
                     })
                     .unwrap(),
                 ) {
-                    Ok(_) => debug!("created {task} cache config"),
-                    Err(err) => crashln!("error {err} creating cache config"),
+                    Ok(_) => debug!("Created {task} cache config"),
+                    Err(err) => error!(%err, "Cannot create cache config"),
                 };
             }
 
             let contents = match std::fs::read_to_string(config_path.clone()) {
                 Ok(content) => content,
-                Err(err) => crashln!("Cannot read cache config: {err}"),
+                Err(err) => error!(%err, "Cannot read cache config"),
             };
 
             let json = match toml::from_str::<CacheConfig>(&contents) {
                 Ok(contents) => contents,
-                Err(err) => crashln!("Cannot read cache config: {err}"),
+                Err(err) => error!(%err, "Cannot read cache config"),
             };
 
             if json.hash == hash && !is_dep && !force {
diff --git a/maid/client/cli/run.rs b/maid/client/cli/run.rs
index 59ded4eb331225195f202e06258a03186df51b2e..b0ff970f9a9ede716ab5dfb5f318fad14fc602dc 100644
--- a/maid/client/cli/run.rs
+++ b/maid/client/cli/run.rs
@@ -1,14 +1,12 @@
-use maid::log::prelude::*;
+use maid::models::client::{Cache, Runner};
+use maid::{helpers, log::prelude::*, table};
 
 use crate::cli;
-use crate::helpers;
 use crate::shell::IntoArgs;
-use crate::structs::{Cache, Runner};
-use crate::table;
 
 use fs_extra::dir::get_size;
 use human_bytes::human_bytes;
-use macros_rs::{crashln, string};
+
 use std::env;
 use std::io::Error;
 use std::path::Path;
@@ -71,7 +69,7 @@ fn run_script(runner: Runner) {
 
     let cache = match &runner.maidfile.tasks[runner.name].cache {
         Some(cache) => cache.clone(),
-        None => Cache { path: string!(""), target: vec![] },
+        None => Cache { path: "".to_string(), target: vec![] },
     };
 
     let exit_code = helpers::status::code(status);
@@ -128,18 +126,18 @@ pub fn task(task: cli::Task) {
     if task.script.is_str() {
         match task.script.as_str() {
             Some(cmd) => script.push(cmd),
-            None => crashln!("Unable to parse maidfile. Missing string value."),
+            None => error!("Unable to parse Maidfile. Missing string value."),
         };
     } else if task.script.is_array() {
         match IntoIterator::into_iter(match task.script.as_array() {
             Some(iter) => iter,
-            None => crashln!("Unable to parse maidfile. Missing array value."),
+            None => error!("Unable to parse Maidfile. Missing array value."),
         }) {
             mut iter => loop {
                 match Iterator::next(&mut iter) {
                     Some(val) => match val.as_str() {
                         Some(cmd) => script.push(cmd),
-                        None => crashln!("Unable to parse maidfile. Missing string value."),
+                        None => error!("Unable to parse Maidfile. Missing string value."),
                     },
                     None => break,
                 };
diff --git a/maid/client/cli/tasks.rs b/maid/client/cli/tasks.rs
index 49d64ac4a2986593f348542979024aad91790388..ac7a2265c949596c753520a088b36ab6ad85d37d 100644
--- a/maid/client/cli/tasks.rs
+++ b/maid/client/cli/tasks.rs
@@ -1,16 +1,14 @@
 use crate::cli;
-use crate::helpers;
 use crate::parse;
-use crate::structs;
-use crate::table;
 
 use inquire::Select;
-use macros_rs::{string, ternary};
+use macros_rs::{exp::ternary, fmt::string};
 use maid::log::prelude::*;
+use maid::{models::client::DisplayTask, table};
 use text_placeholder::Template;
 
 pub fn json(path: &String, args: &Vec<String>, hydrate: bool) {
-    let values = helpers::maidfile::merge(path);
+    let values = parse::merge(path);
     let project_root = parse::file::find_maidfile_root(path);
     let json = values.clone().to_json();
     let table = table::create(values.clone(), args, project_root);
@@ -22,7 +20,7 @@ pub fn json(path: &String, args: &Vec<String>, hydrate: bool) {
 pub struct List;
 impl List {
     pub fn all(path: &String, silent: bool, log_level: Option<tracing::Level>, force: bool) {
-        let values = helpers::maidfile::merge(path);
+        let values = parse::merge(path);
         let mut options: Vec<_> = values
             .tasks
             .iter()
@@ -51,7 +49,7 @@ impl List {
                     },
                 };
 
-                return structs::DisplayTask {
+                return DisplayTask {
                     name: key.clone(),
                     formatted: format!("{} {} {}", format!("{key}").bright_yellow(), info, verbose.bright_blue()),
                     hidden: hidden.clone(),
@@ -71,7 +69,7 @@ impl List {
     }
 
     pub fn remote(path: &String, silent: bool, log_level: Option<tracing::Level>) {
-        let values = helpers::maidfile::merge(path);
+        let values = parse::merge(path);
         let mut options: Vec<_> = values
             .tasks
             .iter()
@@ -94,7 +92,7 @@ impl List {
                     None => true,
                 };
 
-                return structs::DisplayTask {
+                return DisplayTask {
                     name: key.clone(),
                     formatted: format!("{} {} {}", format!("{key}").bright_yellow(), info, verbose.bright_blue()),
                     hidden: hidden.clone(),
diff --git a/maid/client/helpers/maidfile.rs b/maid/client/helpers/maidfile.rs
deleted file mode 100644
index 6c7aad8f7c9a5ecbab7ec934986ce7fa4ce9f190..0000000000000000000000000000000000000000
--- a/maid/client/helpers/maidfile.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-use crate::parse;
-use crate::structs::{DisplayTask, Maidfile};
-use maid::log::prelude::*;
-
-pub fn merge(path: &String) -> Maidfile {
-    let mut values = parse::file::read_maidfile(path);
-    let imported_values = parse::import::push(values.import.clone());
-
-    for import in imported_values.iter() {
-        values = match merge_struct::merge(&values, &import) {
-            Ok(merge) => merge,
-            Err(err) => error!(%err, "Unable to import tasks"),
-        };
-    }
-
-    return values;
-}
-
-impl Maidfile {
-    pub fn to_json(&self) -> String {
-        match serde_json::to_string(&self) {
-            Ok(contents) => contents,
-            Err(err) => error!(%err, "Cannot read Maidfile"),
-        }
-    }
-}
-
-impl std::fmt::Display for DisplayTask {
-    #[inline]
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.formatted, f) }
-}
diff --git a/maid/client/helpers/mod.rs b/maid/client/helpers/mod.rs
index 19ab9a6c15fa3652f8eb9886ff294c98bafcd926..cbcf28ec0ba73e0a6c15886b5a4dbd6a86233139 100644
--- a/maid/client/helpers/mod.rs
+++ b/maid/client/helpers/mod.rs
@@ -1,15 +1 @@
-use anyhow::Error;
-use macros_rs::str;
-use std::path::Path;
-
-pub struct Exists;
-impl Exists {
-    pub fn folder(dir_name: String) -> Result<bool, Error> { Ok(Path::new(str!(dir_name)).is_dir()) }
-    pub fn file(file_name: String) -> Result<bool, Error> { Ok(Path::new(str!(file_name)).exists()) }
-}
-
-pub mod file;
-pub mod logger;
-pub mod maidfile;
-pub mod status;
-pub mod string;
+pub(crate) mod logger;
diff --git a/maid/client/main.rs b/maid/client/main.rs
index 588217d50c5d5840c25ac70a4d723086ae8147a2..f493e1a33466419cdcedae84e94c6b2fba604c8b 100644
--- a/maid/client/main.rs
+++ b/maid/client/main.rs
@@ -4,8 +4,6 @@ mod helpers;
 mod parse;
 mod server;
 mod shell;
-mod structs;
-mod table;
 mod task;
 
 use maid::log::{
@@ -14,7 +12,7 @@ use maid::log::{
 };
 
 use clap::{Parser, ValueEnum};
-use macros_rs::str;
+use macros_rs::fmt::str;
 use std::path::Path;
 
 macro_rules! dispatch {
diff --git a/maid/client/parse/file.rs b/maid/client/parse/file.rs
index 49380a220df4728ef4f831f58d7914289f49c342..75875090b8d866a9559a5dfb192d3442639478ab 100644
--- a/maid/client/parse/file.rs
+++ b/maid/client/parse/file.rs
@@ -1,7 +1,7 @@
-use crate::structs::Maidfile;
 use maid::log::prelude::*;
+use maid::models::client::Maidfile;
 
-use macros_rs::{crashln, string, then};
+use macros_rs::{exp::then, fmt::string};
 use std::{env, fs, io::Result, path::Path, path::PathBuf};
 
 macro_rules! create_path {
@@ -22,9 +22,7 @@ struct Filesystem {
 fn working_dir() -> PathBuf {
     match env::current_dir() {
         Ok(path) => path,
-        Err(_) => {
-            crashln!("Unable to find current working dir");
-        }
+        Err(_) => error!("Unable to find current working dir"),
     }
 }
 
@@ -80,10 +78,7 @@ fn find_file(starting_directory: &Path, file_name: &String) -> Option<PathBuf> {
 fn read_file(path: PathBuf, kind: &str) -> Maidfile {
     let contents = match fs::read_to_string(&path) {
         Ok(contents) => contents,
-        Err(err) => {
-            warn!("{}", err);
-            crashln!("Cannot find maidfile. Does it exist?");
-        }
+        Err(_) => error!("Cannot find Maidfile. Does it exist?"),
     };
 
     let result = match kind {
diff --git a/maid/client/parse/import.rs b/maid/client/parse/import.rs
index 69c6ea8bd1ccc50723ea7127cb3d7f0d8a6fb85e..0b0f789d256b1241ffe8564359c0b84131fba05d 100644
--- a/maid/client/parse/import.rs
+++ b/maid/client/parse/import.rs
@@ -1,6 +1,6 @@
 use crate::parse;
-use crate::structs::Maidfile;
-use macros_rs::fmtstr;
+use macros_rs::fmt::fmtstr;
+use maid::models::client::Maidfile;
 
 pub fn push(path_list: Option<Vec<String>>) -> Vec<Maidfile> {
     let mut values: Vec<Maidfile> = vec![];
diff --git a/maid/client/parse/mod.rs b/maid/client/parse/mod.rs
index 27d98a3270795f0898a516ca6ba574e60b31e588..5cc7f0fba8ad6d6d983f5437a5690906ad5e51c9 100644
--- a/maid/client/parse/mod.rs
+++ b/maid/client/parse/mod.rs
@@ -1,2 +1,19 @@
 pub mod file;
 pub mod import;
+
+use maid::log::prelude::*;
+use maid::models::client::Maidfile;
+
+pub(crate) fn merge(path: &String) -> Maidfile {
+    let mut values = file::read_maidfile(path);
+    let imported_values = import::push(values.import.clone());
+
+    for import in imported_values.iter() {
+        values = match merge_struct::merge(&values, &import) {
+            Ok(merge) => merge,
+            Err(err) => error!(%err, "Unable to import tasks"),
+        };
+    }
+
+    return values;
+}
diff --git a/maid/client/server/cli.rs b/maid/client/server/cli.rs
index 4f4f6aa3722d3ca0ce48ea29bc4ebfe8b0d3a451..c98c5b8ec0eabd73dfc8ecb2faca9abfec159621 100644
--- a/maid/client/server/cli.rs
+++ b/maid/client/server/cli.rs
@@ -1,9 +1,10 @@
-use crate::helpers;
+use crate::parse;
 use crate::server;
-use crate::structs::{ConnectionData, ConnectionInfo, Kind, Level, Maidfile, Task, Websocket};
 
-use macros_rs::{crashln, fmtstr};
-use maid::log::prelude::*;
+use maid::models::client::{ConnectionData, ConnectionInfo, Kind, Level, Maidfile, Task, Websocket};
+use maid::{helpers, log::prelude::*};
+
+use macros_rs::fmt::fmtstr;
 use reqwest::blocking::Client;
 use tungstenite::protocol::frame::{coding::CloseCode::Normal, CloseFrame};
 use tungstenite::{client::connect_with_config, client::IntoClientRequest, protocol::WebSocketConfig, Message};
@@ -26,7 +27,7 @@ fn health(client: Client, values: Maidfile) -> server::api::health::Route {
 }
 
 pub fn connect(path: &String) {
-    let values = helpers::maidfile::merge(path);
+    let values = parse::merge(path);
     let client = Client::new();
     let body = health(client, values);
 
@@ -53,18 +54,18 @@ pub fn remote(task: Task) {
     if task.script.is_str() {
         match task.script.as_str() {
             Some(cmd) => script.push(cmd),
-            None => crashln!("Unable to parse maidfile. Missing string value."),
+            None => error!("Unable to parse Maidfile. Missing string value."),
         };
     } else if task.script.is_array() {
         match IntoIterator::into_iter(match task.script.as_array() {
             Some(iter) => iter,
-            None => crashln!("Unable to parse maidfile. Missing array value."),
+            None => error!("Unable to parse Maidfile. Missing array value."),
         }) {
             mut iter => loop {
                 match Iterator::next(&mut iter) {
                     Some(val) => match val.as_str() {
                         Some(cmd) => script.push(cmd),
-                        None => crashln!("Unable to parse maidfile. Missing string value."),
+                        None => error!("Unable to parse Maidfile. Missing string value."),
                     },
                     None => break,
                 };
@@ -109,9 +110,7 @@ pub fn remote(task: Task) {
 
     let file_name = match server::file::write_tar(&task.remote.unwrap().push) {
         Ok(name) => name,
-        Err(err) => {
-            crashln!("Unable to create archive.\nError: {err}")
-        }
+        Err(err) => error!(%err, "Unable to create archive"),
     };
 
     debug!("sending information");
@@ -131,13 +130,11 @@ pub fn remote(task: Task) {
             Ok(Message::Binary(archive)) => {
                 let archive_name = match server::file::read_tar(&archive) {
                     Ok(name) => name,
-                    Err(err) => {
-                        crashln!("Unable to read archive.\nError: {err}")
-                    }
+                    Err(err) => error!(%err, "Unable to read archive"),
                 };
 
                 if let Err(err) = server::file::unpack_tar(&archive_name) {
-                    crashln!("Unable to create archive.\nError: {err}")
+                    error!(%err, "Unable to create archive")
                 }
 
                 server::file::remove_tar(&archive_name);
@@ -160,6 +157,6 @@ pub fn remote(task: Task) {
         // run.rs:96 implement that later
         reason: std::borrow::Cow::Borrowed("finished task successfully"),
     })) {
-        crashln!("Unable to close socket.\nError: {err}")
+        error!(%err, "Unable to close socket")
     };
 }
diff --git a/maid/client/server/file.rs b/maid/client/server/file.rs
index 0e864a9ae78473aad465c131d081470b67bf771f..72ea0d7806e571e9b45ad4d771ff281ffb458666 100644
--- a/maid/client/server/file.rs
+++ b/maid/client/server/file.rs
@@ -1,8 +1,6 @@
-use crate::helpers;
-
 use flate2::{read::GzDecoder, write::GzEncoder, Compression};
 use global_placeholders::global;
-use macros_rs::crashln;
+use macros_rs::fs::folder_exists;
 use maid::log::prelude::*;
 use std::{fs::write, fs::File, path::PathBuf};
 use tar::{Archive, Builder};
@@ -21,12 +19,12 @@ fn append_to_tar(builder: &mut Builder<GzEncoder<File>>, path: &String) -> Resul
 
 pub fn remove_tar(file: &String) {
     if let Err(_) = std::fs::remove_file(file) {
-        crashln!("Unable to remove temporary archive. does it exist?");
+        error!("Unable to remove temporary archive. does it exist?");
     }
 }
 
 pub fn read_tar(archive: &Vec<u8>) -> Result<String, std::io::Error> {
-    if !helpers::Exists::folder(global!("maid.temp_dir")).unwrap() {
+    if !folder_exists!(&global!("maid.temp_dir")) {
         std::fs::create_dir_all(global!("maid.temp_dir")).unwrap();
         debug!("created maid temp dir");
     }
@@ -46,7 +44,7 @@ pub fn unpack_tar(path: &String) -> std::io::Result<()> {
 }
 
 pub fn write_tar(files: &Vec<String>) -> Result<String, std::io::Error> {
-    if !helpers::Exists::folder(global!("maid.temp_dir")).unwrap() {
+    if !folder_exists!(&global!("maid.temp_dir")) {
         std::fs::create_dir_all(global!("maid.temp_dir")).unwrap();
         debug!("created maid temp dir");
     }
diff --git a/maid/client/server/parse.rs b/maid/client/server/parse.rs
index 0701cae032c0e00a69ef3f9883a761854f70289d..80b2e6bb49d8c5eaf9f99f120d1c3e41245da459 100644
--- a/maid/client/server/parse.rs
+++ b/maid/client/server/parse.rs
@@ -1,5 +1,5 @@
-use crate::structs::Maidfile;
-use macros_rs::{string, ternary};
+use macros_rs::{exp::ternary, fmt::string};
+use maid::models::client::Maidfile;
 
 pub fn address(values: &Maidfile) -> String {
     match &values.project {
diff --git a/maid/client/task/progress.rs b/maid/client/task/progress.rs
index 8ac4f0a50d0db92f845a83bebe525e88d320a96c..94847f86f7f71951bd683fd1acb5874fd3bf1037 100644
--- a/maid/client/task/progress.rs
+++ b/maid/client/task/progress.rs
@@ -1,5 +1,5 @@
 use indicatif::{ProgressBar, ProgressStyle};
-use macros_rs::fmtstr;
+use macros_rs::fmt::fmtstr;
 
 pub fn init(ticks: Vec<&str>, template: &str, tick: u64) -> ProgressBar {
     let pb = ProgressBar::new_spinner();
diff --git a/maid/server/docker/run.rs b/maid/server/docker/run.rs
index 91f858c79d607a30bbad7f341a9ddc5203ee6e22..feb8421b349ce4f35f2ead6e7fef88cd4d1c471f 100644
--- a/maid/server/docker/run.rs
+++ b/maid/server/docker/run.rs
@@ -16,11 +16,15 @@ use bytes::Bytes;
 use flate2::{write::GzEncoder, Compression};
 use futures_core::Stream;
 use futures_util::{stream::TryStreamExt, SinkExt, StreamExt};
-use macros_rs::{fmtstr, str, string, then};
 use rocket_ws::{stream::DuplexStream, Message};
 use std::{default::Default, io::Write, path::PathBuf};
 use text_placeholder::Template;
 
+use macros_rs::{
+    exp::then,
+    fmt::{fmtstr, str, string},
+};
+
 use bollard::{
     container::{Config, DownloadFromContainerOptions, RemoveContainerOptions, UploadToContainerOptions},
     errors::Error,
diff --git a/maid/server/helpers/file.rs b/maid/server/helpers/file.rs
deleted file mode 100644
index 4c1eb7250eaa8329572a441016a4821274bb1ac6..0000000000000000000000000000000000000000
--- a/maid/server/helpers/file.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use crate::helpers;
-use maid::log::prelude::*;
-
-use flate2::{read::GzDecoder, write::GzEncoder, Compression};
-use global_placeholders::global;
-use macros_rs::crashln;
-use std::{fs::write, fs::File, path::PathBuf};
-use tar::{Archive, Builder};
-use uuid::Uuid;
-
-fn append_to_tar(builder: &mut Builder<GzEncoder<File>>, path: &String) -> Result<(), std::io::Error> {
-    let pathbuf = PathBuf::from(path);
-
-    if pathbuf.is_file() {
-        builder.append_path(&pathbuf)?;
-    } else if pathbuf.is_dir() {
-        builder.append_dir_all(&pathbuf, &pathbuf)?;
-    }
-    Ok(())
-}
-
-pub fn remove_tar(file: &String) {
-    if let Err(_) = std::fs::remove_file(file) {
-        crashln!("Unable to remove temporary archive. does it exist?");
-    }
-}
-
-pub fn read_tar(archive: &Vec<u8>) -> Result<String, std::io::Error> {
-    if !helpers::Exists::folder(global!("maid.temp_dir")).unwrap() {
-        std::fs::create_dir_all(global!("maid.temp_dir")).unwrap();
-        info!("created maid temp dir");
-    }
-
-    let file_name = format!("{}/{}.tgz", global!("maid.temp_dir"), Uuid::new_v4());
-    write(&file_name, archive)?;
-
-    Ok(file_name)
-}
-
-pub fn unpack_tar(path: &String) -> std::io::Result<()> {
-    let archive = File::open(&path)?;
-    let tar = GzDecoder::new(archive);
-    let mut archive = Archive::new(tar);
-
-    archive.unpack(".")
-}
-
-pub fn write_tar(files: &Vec<String>) -> Result<String, std::io::Error> {
-    if !helpers::Exists::folder(global!("maid.temp_dir")).unwrap() {
-        std::fs::create_dir_all(global!("maid.temp_dir")).unwrap();
-        info!("created maid temp dir");
-    }
-
-    let file_name = format!("{}/{}.tgz", global!("maid.temp_dir"), Uuid::new_v4());
-    let archive = File::create(&file_name)?;
-    let enc = GzEncoder::new(archive, Compression::default());
-    let mut tar = Builder::new(enc);
-
-    info!("compressing to {}", &file_name);
-    for path in files {
-        append_to_tar(&mut tar, path)?;
-        info!("{} {:?}", helpers::string::add_icon(), path);
-    }
-
-    Ok(file_name)
-}
diff --git a/maid/server/helpers/mod.rs b/maid/server/helpers/mod.rs
index 34eaa3eb76937338f15e0eb66b130b3139a20b5f..fb8c6f9ded9de353855f9a5d18a6c879a4e2beb1 100644
--- a/maid/server/helpers/mod.rs
+++ b/maid/server/helpers/mod.rs
@@ -1,15 +1,3 @@
-use anyhow::Error;
-use macros_rs::str;
-use std::path::Path;
-
-pub struct Exists;
-impl Exists {
-    pub fn folder(dir_name: String) -> Result<bool, Error> { Ok(Path::new(str!(dir_name)).is_dir()) }
-    pub fn file(file_name: String) -> Result<bool, Error> { Ok(Path::new(str!(file_name)).exists()) }
-}
-
-pub mod os;
-pub mod file;
 pub mod format;
-pub mod string;
-pub mod logger;
\ No newline at end of file
+pub mod logger;
+pub mod os;
diff --git a/maid/server/helpers/string.rs b/maid/server/helpers/string.rs
deleted file mode 100644
index b02f4afb4da9fe3e764da902e51d503728b2bd3e..0000000000000000000000000000000000000000
--- a/maid/server/helpers/string.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-use colored::{ColoredString, Colorize};
-use std::path::Path;
-
-pub fn seperator() -> ColoredString { ":".white() }
-pub fn arrow_icon() -> ColoredString { "»".white() }
-pub fn add_icon() -> ColoredString { "+".green() }
-pub fn cross_icon() -> ColoredString { "✖".red() }
-pub fn check_icon() -> ColoredString { "✔".green() }
-
-pub fn path_to_str(path: &Path) -> &'static str { Box::leak(String::from(path.to_string_lossy()).into_boxed_str()) }
-
-pub fn trim_start_end(value: &str) -> &str {
-    let mut chars = value.chars();
-    chars.next();
-    chars.next_back();
-    chars.as_str()
-}
diff --git a/maid/server/main.rs b/maid/server/main.rs
index 95621965b377bf9a694df3e168b44963d1fa6e0e..44d2744e18cb651f6562ce662e7cd8249f0870de 100644
--- a/maid/server/main.rs
+++ b/maid/server/main.rs
@@ -6,7 +6,7 @@ mod table;
 
 use bollard::{Docker, API_DEFAULT_VERSION};
 use docker::container;
-use macros_rs::{fmtstr, ternary};
+use macros_rs::{exp::ternary, fmt::fmtstr};
 use maid::log::prelude::*;
 use rocket::futures::SinkExt;
 use rocket::{get, http::Status, launch, outcome::Outcome, routes, State};
@@ -64,7 +64,7 @@ impl From<Response> for Message {
 }
 
 #[derive(Debug)]
-struct Token(String);
+struct Token;
 
 #[rocket::async_trait]
 impl<'r> rocket::request::FromRequest<'r> for Token {
@@ -76,8 +76,7 @@ impl<'r> rocket::request::FromRequest<'r> for Token {
 
         if let Some(header_value) = authorization_header {
             if header_value == fmtstr!("Bearer {token}") {
-                let token = header_value.trim_start_matches("Bearer ").to_owned();
-                return Outcome::Success(Token(token));
+                return Outcome::Success(Token);
             }
         }
 
diff --git a/maid/server/table.rs b/maid/server/table.rs
index 10f21939072608fd35d9b752b5b771bf263ae525..30f1e7ebb513f359b9a53846df43c553ada9e7ec 100644
--- a/maid/server/table.rs
+++ b/maid/server/table.rs
@@ -1,8 +1,7 @@
-use crate::helpers;
 use crate::structs::Maidfile;
-use maid::log::prelude::*;
+use maid::{helpers, log::prelude::*};
 
-use macros_rs::{str, ternary};
+use macros_rs::{exp::ternary, fmt::str};
 use serde_json::Value;
 use std::path::PathBuf;
 use std::{collections::BTreeMap, collections::HashMap, env};
diff --git a/maid/client/helpers/file.rs b/maid/shared/helpers/file.rs
similarity index 59%
rename from maid/client/helpers/file.rs
rename to maid/shared/helpers/file.rs
index 3b4b7ed469f0b78ec571e17f875ac751abf66293..d5dc9feac5daffe7ca054de2c7043d8b8206a5a2 100644
--- a/maid/client/helpers/file.rs
+++ b/maid/shared/helpers/file.rs
@@ -1,11 +1,9 @@
-use macros_rs::crashln;
+use crate::log::prelude::*;
 use std::env;
 
 pub fn get_current_working_dir() -> String {
     match env::current_dir() {
         Ok(path) => path.into_os_string().into_string().unwrap(),
-        Err(_) => {
-            crashln!("Unable to find current working dir");
-        }
+        Err(err) => error!(%err, "Unable to find current working dir"),
     }
 }
diff --git a/maid/shared/helpers/maidfile.rs b/maid/shared/helpers/maidfile.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f06e7c49a0f3787dcaa024c0af7bedc8bad82983
--- /dev/null
+++ b/maid/shared/helpers/maidfile.rs
@@ -0,0 +1,16 @@
+use crate::log::prelude::*;
+use crate::models::client::{DisplayTask, Maidfile};
+
+impl Maidfile {
+    pub fn to_json(&self) -> String {
+        match serde_json::to_string(&self) {
+            Ok(contents) => contents,
+            Err(err) => error!(%err, "Cannot read Maidfile"),
+        }
+    }
+}
+
+impl std::fmt::Display for DisplayTask {
+    #[inline]
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.formatted, f) }
+}
diff --git a/maid/shared/helpers/mod.rs b/maid/shared/helpers/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..655613b429042b93ac6dd8bd4bbaa7444b4edda2
--- /dev/null
+++ b/maid/shared/helpers/mod.rs
@@ -0,0 +1,4 @@
+pub mod file;
+pub mod maidfile;
+pub mod status;
+pub mod string;
diff --git a/maid/client/helpers/status.rs b/maid/shared/helpers/status.rs
similarity index 95%
rename from maid/client/helpers/status.rs
rename to maid/shared/helpers/status.rs
index 12bdb71d0a0640f67eeb85406854f486b1375942..8fba557a154d634152c61893bae85adbd164a925 100644
--- a/maid/client/helpers/status.rs
+++ b/maid/shared/helpers/status.rs
@@ -1,4 +1,4 @@
-use maid::log::prelude::*;
+use crate::log::prelude::*;
 use std::{io::Error, process::ExitStatus};
 
 pub fn error(debug_err: &str) {
diff --git a/maid/client/helpers/string.rs b/maid/shared/helpers/string.rs
similarity index 75%
rename from maid/client/helpers/string.rs
rename to maid/shared/helpers/string.rs
index 0a05c959a2b3bf642994a969dd059f5c347060a3..a185af6c96f07bdc0b69c57c3725a0c8581bba0b 100644
--- a/maid/client/helpers/string.rs
+++ b/maid/shared/helpers/string.rs
@@ -1,12 +1,9 @@
-use std::path::Path;
-
-// cache
-use std::collections::HashMap;
 use std::sync::{LazyLock, Mutex};
+use std::{collections::HashMap, path::Path};
 
 static STRING_CACHE: LazyLock<Mutex<HashMap<String, &'static str>>> = LazyLock::new(|| Mutex::new(HashMap::new()));
 
-pub(crate) fn path_to_str(path: &Path) -> &'static str {
+pub fn path_to_str(path: &Path) -> &'static str {
     let string = path.to_string_lossy().into_owned();
     if let Some(cached) = STRING_CACHE.lock().unwrap().get(&string) {
         return cached;
@@ -17,7 +14,7 @@ pub(crate) fn path_to_str(path: &Path) -> &'static str {
     leaked
 }
 
-pub(crate) fn trim_start_end(value: &str) -> &str {
+pub fn trim_start_end(value: &str) -> &str {
     let mut chars = value.chars();
     chars.next();
     chars.next_back();
diff --git a/maid/shared/lib.rs b/maid/shared/lib.rs
index 7746688323b6f61592b1756f309a21cbedd4a960..e452e21a2930656fbafe9a3bcbd7071f2a60a38a 100644
--- a/maid/shared/lib.rs
+++ b/maid/shared/lib.rs
@@ -1,2 +1,5 @@
 pub mod colors;
+pub mod helpers;
 pub mod log;
+pub mod models;
+pub mod table;
diff --git a/maid/client/structs.rs b/maid/shared/models/client.rs
similarity index 96%
rename from maid/client/structs.rs
rename to maid/shared/models/client.rs
index 5b14cbbcc1139772d69bbdbdc00767dddbb9a8ae..1cabfef2ce69b45f5bf8a686543e4baa3821fbd3 100644
--- a/maid/client/structs.rs
+++ b/maid/shared/models/client.rs
@@ -1,14 +1,14 @@
 use serde::{Deserialize, Serialize};
 use std::collections::BTreeMap;
 use std::path::PathBuf;
-use toml::Value as TomlValue;
+use toml::Value;
 
 #[derive(Clone, Debug, Deserialize, Serialize)]
 pub struct Maidfile {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub import: Option<Vec<String>>,
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub env: Option<BTreeMap<String, TomlValue>>,
+    pub env: Option<BTreeMap<String, Value>>,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub project: Option<Project>,
     pub tasks: BTreeMap<String, Tasks>,
@@ -39,7 +39,7 @@ pub struct Address {
 
 #[derive(Clone, Debug, Deserialize, Serialize)]
 pub struct Tasks {
-    pub script: TomlValue,
+    pub script: Value,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub hide: Option<bool>,
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -83,7 +83,7 @@ pub struct Task {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub remote: Option<Remote>,
     pub project: PathBuf,
-    pub script: TomlValue,
+    pub script: Value,
     pub path: String,
     pub args: Vec<String>,
     pub silent: bool,
diff --git a/maid/shared/models/mod.rs b/maid/shared/models/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..17f582a527ab3aad9aeacfc2a6f1d931ad49f1bc
--- /dev/null
+++ b/maid/shared/models/mod.rs
@@ -0,0 +1,3 @@
+pub mod client;
+pub mod server;
+pub mod shared;
diff --git a/maid/shared/models/server.rs b/maid/shared/models/server.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ddb7b023ff6eeac39244fe358dc84ab4758d4501
--- /dev/null
+++ b/maid/shared/models/server.rs
@@ -0,0 +1,90 @@
+use serde::{Deserialize, Serialize};
+use serde_json::Value;
+use std::collections::BTreeMap;
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct ConnectionInfo {
+    pub name: String,
+    pub args: Vec<String>,
+    pub remote: Remote,
+    pub script: Vec<String>,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct ConnectionData {
+    pub info: ConnectionInfo,
+    pub maidfile: Maidfile,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Maidfile {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub import: Option<Vec<String>>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub env: Option<BTreeMap<String, Value>>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub project: Option<Project>,
+    pub tasks: BTreeMap<String, Tasks>,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Project {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub name: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub version: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub server: Option<Server>, // wip
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Server {
+    pub address: Address, // wip
+    pub token: String,    // wip
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Address {
+    pub host: String,
+    pub port: i64,
+    pub ssl: bool,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Tasks {
+    pub script: Value,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub hide: Option<bool>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub path: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub info: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub cache: Option<Cache>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub remote: Option<Remote>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub depends: Option<Vec<String>>,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Cache {
+    pub path: String,
+    pub target: Vec<String>,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct CacheConfig {
+    pub target: Vec<String>,
+    pub hash: String,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Remote {
+    pub push: Vec<String>,
+    pub pull: String,
+    pub image: String,
+    pub shell: String,
+    pub silent: bool,
+    pub exclusive: bool,
+}
diff --git a/maid/shared/models/shared.rs b/maid/shared/models/shared.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/maid/client/table.rs b/maid/shared/table.rs
similarity index 95%
rename from maid/client/table.rs
rename to maid/shared/table.rs
index bc5e705e055eff5ec5f4c05914bc8da5993cd0be..b3db9da3ed89890d078c179c151b3e77a19acba1 100644
--- a/maid/client/table.rs
+++ b/maid/shared/table.rs
@@ -1,8 +1,8 @@
 use crate::helpers;
-use crate::structs::Maidfile;
-use maid::log::prelude::*;
+use crate::log::prelude::*;
+use crate::models::client::Maidfile;
 
-use macros_rs::{str, ternary};
+use macros_rs::{exp::ternary, fmt::str};
 use std::path::PathBuf;
 use std::{collections::BTreeMap, collections::HashMap, env};
 use text_placeholder::Template;