diff --git a/build.rs b/build.rs
index 502b1b1..8cb0b9d 100644
--- a/build.rs
+++ b/build.rs
@@ -1,38 +1,39 @@
 use chrono::Datelike;
 use std::{env, process::Command};
 
 fn main() {
     #[cfg(windows)]
     {
         println!("cargo:warning=This project is not supported on Windows.");
         std::process::exit(1);
     }
 
     /* version attributes */
     let date = chrono::Utc::now();
     let profile = env::var("PROFILE").unwrap();
     let output = Command::new("git").args(&["rev-parse", "--short=10", "HEAD"]).output().unwrap();
     let output_full = Command::new("git").args(&["rev-parse", "HEAD"]).output().unwrap();
 
     println!("cargo:rustc-env=TARGET={}", env::var("TARGET").unwrap());
     println!("cargo:rustc-env=GIT_HASH={}", String::from_utf8(output.stdout).unwrap());
     println!("cargo:rustc-env=GIT_HASH_FULL={}", String::from_utf8(output_full.stdout).unwrap());
     println!("cargo:rustc-env=BUILD_DATE={}-{}-{}", date.year(), date.month(), date.day());
 
     /* profile matching */
     match profile.as_str() {
         "debug" => println!("cargo:rustc-env=PROFILE=debug"),
         "release" => println!("cargo:rustc-env=PROFILE=release"),
         _ => println!("cargo:rustc-env=PROFILE=none"),
     }
 
     /* cc linking */
     cxx_build::bridge("src/main.rs")
         .file("src/cc/bridge.cc")
         .file("src/cc/process.cc")
-        .flag_if_supported("-std=c++14")
+        .file("src/cc/fork.cc")
+        .flag_if_supported("-std=c++17")
         .compile("bridge");
 
-    let watched = vec!["main.rs", "cc/bridge.cc", "cc/process.cc", "include/process.h"];
+    let watched = vec!["main.rs", "cc/bridge.cc", "cc/process.cc", "cc/fork.cc", "include/bridge.h", "include/process.h", "include/fork.h"];
     watched.iter().for_each(|file| println!("cargo:rerun-if-changed=src/{}", file));
 }
diff --git a/src/cc/bridge.cc b/src/cc/bridge.cc
index e1786a0..57d337d 100644
--- a/src/cc/bridge.cc
+++ b/src/cc/bridge.cc
@@ -1,13 +1,17 @@
 #include "../include/bridge.h"
-#include "process.cc"
+#include "../include/process.h"
+
 #include <signal.h>
+#include <iostream>
+#include <string>
+using namespace std;
 
 int64_t stop(int64_t pid) {
   return kill(pid, SIGTERM);
 }
 
-int64_t run(Str name, Str log_path, Str command) {
-  process::Runner runner;
-  runner.New(std::string(name), std::string(log_path));
-  return runner.Run(std::string(command));
+int64_t run(ProcessMetadata metadata) {  
+  process::Runner runner;  
+  runner.New(std::string(metadata.name), std::string(metadata.log_path));
+  return runner.Run(std::string(metadata.command), std::string(metadata.shell), metadata.args);
 }
\ No newline at end of file
diff --git a/src/cc/fork.cc b/src/cc/fork.cc
new file mode 100644
index 0000000..322ad5e
--- /dev/null
+++ b/src/cc/fork.cc
@@ -0,0 +1,82 @@
+#include "../include/fork.h"
+#include <cstring>
+#include <stdexcept>
+#include <cstdlib>
+#include <iostream>
+#include <unistd.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <pwd.h>
+#include <unistd.h>
+#endif
+
+std::string home() {
+    #ifdef _WIN32
+    const char* userProfile = std::getenv("USERPROFILE");
+    if (userProfile) {
+        return std::string(userProfile);
+    } else {
+        return "";
+    }
+    #else
+    struct passwd* pw = getpwuid(getuid());
+    if (pw && pw->pw_dir) {
+        return std::string(pw->pw_dir);
+    } else {
+        return "";
+    }
+    #endif
+}
+
+
+Fork fork_process() {
+    pid_t res = ::fork();
+    if (res == -1) {
+        throw std::runtime_error("fork() failed");
+    } else if (res == 0) {
+        return Fork::Child;
+    } else {
+        return Fork::Parent;
+    }
+}
+
+pid_t set_sid() {
+    pid_t res = ::setsid();
+    if (res == -1) {
+        throw std::runtime_error("setsid() failed");
+    }
+    return res;
+}
+
+void close_fd() {
+    if (::close(0) == -1 || ::close(1) == -1 || ::close(2) == -1) {
+        throw std::runtime_error("close() failed");
+    }
+}
+
+int32_t try_fork(bool nochdir, bool noclose, Callback callback) {
+    try {
+        Fork forkResult = fork_process();
+        if (forkResult == Fork::Parent) {
+            exit(0);
+        } else if (forkResult == Fork::Child) {
+            set_sid();
+            if (!nochdir) {
+                std::string home_dir = home() + ".pmc";
+                chdir(home_dir.c_str());
+            }
+            if (!noclose) {
+                close_fd();
+            }
+            forkResult = fork_process();
+        }
+        return static_cast<int32_t>(forkResult);
+    } catch (const std::exception& e) {
+        std::cerr << "[PMC] (cc) Error setting up daemon handler\n";
+    }
+    
+    callback();
+    return -1;
+}
\ No newline at end of file
diff --git a/src/cc/process.cc b/src/cc/process.cc
index bd52079..a92024c 100644
--- a/src/cc/process.cc
+++ b/src/cc/process.cc
@@ -1,73 +1,84 @@
 #include "../include/process.h"
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/wait.h>
 #include <signal.h>
 #include <iostream>
+using namespace std;
 
 namespace process {
 volatile sig_atomic_t childExitStatus = 0;
 
+pair<std::string, std::string> split(const std::string& str) {
+    size_t length = str.length();
+    size_t midpoint = length / 2;
+
+    std::string firstHalf = str.substr(0, midpoint);
+    std::string secondHalf = str.substr(midpoint);
+
+    return make_pair(firstHalf, secondHalf);
+}
+
 void sigchld_handler(int signo) {
   (void)signo;
   int status;
   while (waitpid(-1, &status, WNOHANG) > 0) {
     childExitStatus = status;
   }
 }
 
 void Runner::New(const std::string &name, const std::string &logPath) {
   std::string stdoutFileName = logPath + "/" + name + "-out.log";
   std::string stderrFileName = logPath + "/" + name + "-error.log";
   
   stdout_fd = open(stdoutFileName.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0644);
   stderr_fd = open(stderrFileName.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0644);
 
   struct sigaction sa;
   sa.sa_handler = sigchld_handler;
   sigemptyset(&sa.sa_mask);
   sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
   if (sigaction(SIGCHLD, &sa, NULL) == -1) {
     std::cerr << "[PMC] (cc) Error setting up SIGCHLD handler\n";
   }
 }
 
 Runner::~Runner() {
   if (stdout_fd != -1) {
     close(stdout_fd);
   }
 
   if (stderr_fd != -1) {
     close(stderr_fd);
   }
 }
 
-int64_t Runner::Run(const std::string &command) {
+int64_t Runner::Run(const std::string &command, const std::string &shell, Vec<String> args) {
   pid_t pid = fork();
 
   if (pid == -1) {
     std::cerr << "[PMC] (cc) Unable to fork\n";
     return -1;
   } else if (pid == 0) {
     setsid();
 
     close(STDIN_FILENO);
     close(STDOUT_FILENO);
     close(STDERR_FILENO);
 
     dup2(stdout_fd, STDOUT_FILENO);
     dup2(stderr_fd, STDERR_FILENO);
 
-    if (execl("/bin/bash", "bash", "-c", command.c_str(), (char *)nullptr) == -1) {
+    if (execl(shell.c_str(), args[0].c_str(), args[1].c_str(), command.c_str(), (char *)nullptr) == -1) {
       std::cerr << "[PMC] (cc) Unable to execute the command\n";
       exit(EXIT_FAILURE);
     }
   } else {
     close(stdout_fd);
     close(stderr_fd);
 
     return pid;
   }
   
   return -1;
 }} 
diff --git a/src/cli.rs b/src/cli.rs
index 237efc7..4bfe10c 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -1,289 +1,289 @@
 use crate::file;
 use crate::helpers::{self, ColoredString};
 use crate::process::Runner;
 use crate::structs::Args;
 
 use colored::Colorize;
 use global_placeholders::global;
 use macros_rs::{crashln, string, ternary};
 use psutil::process::{MemoryInfo, Process};
 use serde::Serialize;
 use serde_json::json;
 use std::env;
 
 use tabled::{
     settings::{
         object::{Columns, Rows},
         style::{BorderColor, Style},
         themes::Colorization,
         Color, Rotate,
     },
     Table, Tabled,
 };
 
 pub fn get_version(short: bool) -> String {
     return match short {
         true => format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")),
         false => format!("{} ({} {}) [{}]", env!("CARGO_PKG_VERSION"), env!("GIT_HASH"), env!("BUILD_DATE"), env!("PROFILE")),
     };
 }
 
 pub fn start(name: &Option<String>, args: &Option<Args>) {
     let mut runner = Runner::new();
 
     match args {
         Some(Args::Id(id)) => {
             println!("{} Applying action restartProcess on ({id})", *helpers::SUCCESS);
             runner.restart(*id, name);
 
             println!("{} restarted ({id}) ✓", *helpers::SUCCESS);
-            list(&string!(""));
+            list(&string!("default"));
         }
         Some(Args::Script(script)) => {
             let name = match name {
                 Some(name) => string!(name),
                 None => string!(script.split_whitespace().next().unwrap_or_default()),
             };
 
             println!("{} Creating process with ({name})", *helpers::SUCCESS);
-            runner.start(name.clone(), script);
+            runner.start(&name, script);
 
             println!("{} created ({name}) ✓", *helpers::SUCCESS);
-            list(&string!(""));
+            list(&string!("default"));
         }
         None => {}
     }
 }
 
 pub fn stop(id: &usize) {
     println!("{} Applying action stopProcess on ({id})", *helpers::SUCCESS);
     let mut runner = Runner::new();
     runner.stop(*id);
     println!("{} stopped ({id}) ✓", *helpers::SUCCESS);
-    list(&string!(""));
+    list(&string!("default"));
 }
 
 pub fn remove(id: &usize) {
     println!("{} Applying action removeProcess on ({id})", *helpers::SUCCESS);
     let mut runner = Runner::new();
     runner.remove(*id);
     println!("{} removed ({id}) ✓", *helpers::SUCCESS);
 }
 
 pub fn info(id: &usize, format: &String) {
     let runner = Runner::new();
 
     #[derive(Clone, Debug, Tabled)]
     struct Info {
         #[tabled(rename = "error log path ")]
         log_error: String,
         #[tabled(rename = "out log path")]
         log_out: String,
         #[tabled(rename = "cpu percent")]
         cpu_percent: String,
         #[tabled(rename = "memory usage")]
         memory_usage: String,
         #[tabled(rename = "script command ")]
         command: String,
         #[tabled(rename = "exec cwd")]
         path: String,
         #[tabled(rename = "script id")]
         id: String,
         uptime: String,
         pid: String,
         name: String,
         status: ColoredString,
     }
 
     impl Serialize for Info {
         fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
             let trimmed_json = json!({
                 "id": &self.id.trim(),
                 "name": &self.name.trim(),
                 "pid": &self.pid.trim(),
                 "uptime": &self.uptime.trim(),
                 "status": &self.status.0.trim(),
                 "log_error": &self.log_error.trim(),
                 "log_out": &self.log_out.trim(),
                 "cpu": &self.cpu_percent.trim(),
                 "mem": &self.memory_usage.trim(),
                 "command": &self.command.trim(),
                 "path": &self.path.trim(),
             });
 
             trimmed_json.serialize(serializer)
         }
     }
 
     if let Some(home) = home::home_dir() {
         if let Some(item) = runner.info(*id) {
             let mut memory_usage: Option<MemoryInfo> = None;
             let mut cpu_percent: Option<f32> = None;
 
             if let Ok(mut process) = Process::new(item.pid as u32) {
                 memory_usage = process.memory_info().ok();
                 cpu_percent = process.cpu_percent().ok();
             }
 
             let cpu_percent = match cpu_percent {
                 Some(percent) => format!("{:.2}%", percent),
                 None => string!("0%"),
             };
 
             let memory_usage = match memory_usage {
                 Some(usage) => helpers::format_memory(usage.rss()),
                 None => string!("0b"),
             };
 
             let path = file::make_relative(&item.path, &home)
                 .map(|relative_path| relative_path.to_string_lossy().into_owned())
                 .unwrap_or_else(|| crashln!("{} Unable to get your current directory", *helpers::FAIL));
 
             let data = vec![Info {
                 cpu_percent,
                 memory_usage,
                 id: string!(id),
                 name: item.name.clone(),
                 command: format!("/bin/bash -c '{}'", item.script.clone()),
                 path: format!("{} ", path),
                 log_out: global!("pmc.logs.out", item.name.as_str()),
                 log_error: global!("pmc.logs.error", item.name.as_str()),
                 pid: ternary!(item.running, format!("{}", item.pid), string!("n/a")),
                 status: ColoredString(ternary!(item.running, "online".green().bold(), "stopped".red().bold())),
                 uptime: ternary!(item.running, format!("{}", helpers::format_duration(item.started)), string!("none")),
             }];
 
             let table = Table::new(data.clone())
                 .with(Rotate::Left)
                 .with(Style::rounded().remove_horizontals())
                 .with(Colorization::exact([Color::FG_CYAN], Columns::first()))
                 .with(BorderColor::filled(Color::FG_BRIGHT_BLACK))
                 .to_string();
 
             if let Ok(json) = serde_json::to_string(&data[0]) {
                 match format.as_str() {
                     "raw" => println!("{:?}", data[0]),
                     "json" => println!("{json}"),
                     _ => {
                         println!("{}\n{table}\n", format!("Describing process with id ({id})").on_bright_white().black());
                         println!(" {}", format!("Use `pmc logs {id} [--lines <num>]` to display logs").white());
                         println!(" {}", format!("Use `pmc env {id}`  to display environment variables").white());
                     }
                 };
             };
         } else {
             crashln!("{} Process ({id}) not found", *helpers::FAIL);
         }
     } else {
         crashln!("{} Impossible to get your home directory", *helpers::FAIL);
     }
 }
 
 pub fn logs(id: &usize, lines: &usize) {
     let runner = Runner::new();
 
     if let Some(item) = runner.info(*id) {
         println!("{}", format!("Showing last {lines} lines for process [{id}] (change the value with --lines option)").yellow());
 
         let log_error = global!("pmc.logs.error", item.name.as_str());
         let log_out = global!("pmc.logs.out", item.name.as_str());
 
         file::logs(*lines, &log_error, *id, "error", &item.name);
         file::logs(*lines, &log_out, *id, "out", &item.name);
     } else {
         crashln!("{} Process ({id}) not found", *helpers::FAIL);
     }
 }
 
 #[cfg(target_os = "macos")]
 pub fn env(id: &usize) {
     let runner = Runner::new();
 
     if let Some(item) = runner.info(*id) {
         for (key, value) in item.env.iter() {
             println!("{}: {}", key, value.green());
         }
     } else {
         crashln!("{} Process ({id}) not found", *helpers::FAIL);
     }
 }
 
 pub fn list(format: &String) {
     let runner = Runner::new();
     let mut processes: Vec<ProcessItem> = Vec::new();
 
     #[derive(Tabled, Debug)]
     struct ProcessItem {
         id: ColoredString,
         name: String,
         pid: String,
         uptime: String,
         status: ColoredString,
         cpu: String,
         mem: String,
     }
 
     impl serde::Serialize for ProcessItem {
         fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
             let trimmed_json = json!({
                 "id": &self.id.0.trim(),
                 "name": &self.name.trim(),
                 "pid": &self.pid.trim(),
                 "uptime": &self.uptime.trim(),
                 "status": &self.status.0.trim(),
                 "cpu": &self.cpu.trim(),
                 "mem": &self.mem.trim(),
             });
             trimmed_json.serialize(serializer)
         }
     }
 
     if runner.list().is_empty() {
         println!("{} Process table empty", *helpers::SUCCESS);
     } else {
         for (id, item) in runner.list() {
             let mut memory_usage: Option<MemoryInfo> = None;
             let mut cpu_percent: Option<f32> = None;
 
             if let Ok(mut process) = Process::new(item.pid as u32) {
                 memory_usage = process.memory_info().ok();
                 cpu_percent = process.cpu_percent().ok();
             }
 
             let cpu_percent = match cpu_percent {
                 Some(percent) => format!("{:.0}%", percent),
                 None => string!("0%"),
             };
 
             let memory_usage = match memory_usage {
                 Some(usage) => helpers::format_memory(usage.rss()),
                 None => string!("0b"),
             };
 
             processes.push(ProcessItem {
                 id: ColoredString(id.cyan().bold()),
                 pid: ternary!(item.running, format!("{}  ", item.pid), string!("n/a  ")),
                 cpu: format!("{cpu_percent}   "),
                 mem: format!("{memory_usage}   "),
                 name: format!("{}   ", item.name.clone()),
                 status: ColoredString(ternary!(item.running, "online   ".green().bold(), "stopped   ".red().bold())),
                 uptime: ternary!(item.running, format!("{}  ", helpers::format_duration(item.started)), string!("none  ")),
             });
         }
 
         let table = Table::new(&processes)
             .with(Style::rounded().remove_verticals())
             .with(BorderColor::filled(Color::FG_BRIGHT_BLACK))
             .with(Colorization::exact([Color::FG_BRIGHT_CYAN], Rows::first()))
             .to_string();
 
         if let Ok(json) = serde_json::to_string(&processes) {
             match format.as_str() {
                 "raw" => println!("{:?}", processes),
                 "json" => println!("{json}"),
                 "default" => println!("{table}"),
                 _ => {}
             };
         };
     }
 }
diff --git a/src/config/mod.rs b/src/config/mod.rs
new file mode 100644
index 0000000..10cc14b
--- /dev/null
+++ b/src/config/mod.rs
@@ -0,0 +1,45 @@
+pub mod structs;
+
+use crate::file::{self, Exists};
+use crate::helpers;
+
+use colored::Colorize;
+use macros_rs::{crashln, string};
+use std::fs;
+use structs::{Config, Daemon, Runner};
+
+pub fn read() -> Config {
+    match home::home_dir() {
+        Some(path) => {
+            let path = path.display();
+            let config_path = format!("{path}/.pmc/config.toml");
+
+            if !Exists::file(config_path.clone()).unwrap() {
+                let config = Config {
+                    runner: Runner {
+                        shell: string!("/bin/bash"),
+                        args: vec![string!("bash"), string!("-c")],
+                        log_path: format!("{path}/.pmc/logs"),
+                    },
+                    daemon: Daemon {
+                        interval: 1000,
+                        kind: string!("default"),
+                    },
+                };
+
+                let contents = match toml::to_string(&config) {
+                    Ok(contents) => contents,
+                    Err(err) => crashln!("{} Cannot parse config.\n{}", *helpers::FAIL, string!(err).white()),
+                };
+
+                if let Err(err) = fs::write(&config_path, contents) {
+                    crashln!("{} Error writing config.\n{}", *helpers::FAIL, string!(err).white())
+                }
+                log::info!("created config file");
+            }
+
+            file::read(config_path)
+        }
+        None => crashln!("{} Impossible to get your home directory", *helpers::FAIL),
+    }
+}
diff --git a/src/config/structs.rs b/src/config/structs.rs
new file mode 100644
index 0000000..a3d8a0e
--- /dev/null
+++ b/src/config/structs.rs
@@ -0,0 +1,20 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct Config {
+    pub runner: Runner,
+    pub daemon: Daemon,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct Runner {
+    pub shell: String,
+    pub args: Vec<String>,
+    pub log_path: String,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct Daemon {
+    pub interval: u64,
+    pub kind: String,
+}
diff --git a/src/daemon/mod.rs b/src/daemon/mod.rs
index 74a7aa8..2f49271 100644
--- a/src/daemon/mod.rs
+++ b/src/daemon/mod.rs
@@ -1,199 +1,217 @@
 pub mod fork;
 pub mod pid;
 
+use crate::config;
 use crate::helpers::{self, ColoredString};
 use crate::process::Runner;
 use crate::service;
 
 use chrono::{DateTime, Utc};
 use colored::Colorize;
 use fork::{daemon, Fork};
 use global_placeholders::global;
 use macros_rs::{crashln, string, ternary, then};
 use psutil::process::{MemoryInfo, Process};
 use serde::Serialize;
 use serde_json::json;
 use std::{process, thread::sleep, time::Duration};
 
 use tabled::{
     settings::{
         object::Columns,
         style::{BorderColor, Style},
         themes::Colorization,
         Color, Rotate,
     },
     Table, Tabled,
 };
 
 extern "C" fn handle_termination_signal(_: libc::c_int) {
     pid::remove();
     unsafe { libc::_exit(0) }
 }
 
 fn restart_process(runner: Runner) {
     let items = runner.list().iter().filter_map(|(id, item)| Some((id.trim().parse::<usize>().ok()?, item)));
     for (id, item) in items {
         then!(!item.running || pid::running(item.pid as i32), continue);
         let name = &Some(item.name.clone());
         let mut runner_instance = Runner::new();
         runner_instance.restart(id, name);
     }
 }
 
 pub fn health(format: &String) {
     let runner = Runner::new();
     let mut pid: Option<i32> = None;
     let mut cpu_percent: Option<f32> = None;
     let mut uptime: Option<DateTime<Utc>> = None;
     let mut memory_usage: Option<MemoryInfo> = None;
 
     #[derive(Clone, Debug, Tabled)]
     struct Info {
         #[tabled(rename = "pid file")]
         pid_file: String,
         #[tabled(rename = "fork path")]
         path: String,
         #[tabled(rename = "cpu percent")]
         cpu_percent: String,
         #[tabled(rename = "memory usage")]
         memory_usage: String,
+        #[tabled(rename = "daemon type")]
+        external: String,
         #[tabled(rename = "process count")]
         process_count: usize,
         uptime: String,
         pid: String,
         status: ColoredString,
     }
 
     impl Serialize for Info {
         fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
             let trimmed_json = json!({
              "pid_file": &self.pid_file.trim(),
              "path": &self.path.trim(),
              "cpu": &self.cpu_percent.trim(),
              "mem": &self.memory_usage.trim(),
              "process_count": &self.process_count.to_string(),
              "uptime": &self.uptime.trim(),
              "pid": &self.pid.trim(),
              "status": &self.status.0.trim(),
             });
 
             trimmed_json.serialize(serializer)
         }
     }
 
     if pid::exists() {
         if let Ok(process_id) = pid::read() {
             if let Ok(mut process) = Process::new(process_id as u32) {
                 pid = Some(process_id);
                 uptime = Some(pid::uptime().unwrap());
                 memory_usage = process.memory_info().ok();
                 cpu_percent = process.cpu_percent().ok();
             }
         }
     }
 
     let cpu_percent = match cpu_percent {
         Some(percent) => format!("{:.2}%", percent),
         None => string!("0%"),
     };
 
     let memory_usage = match memory_usage {
         Some(usage) => helpers::format_memory(usage.rss()),
         None => string!("0b"),
     };
 
     let uptime = match uptime {
         Some(uptime) => helpers::format_duration(uptime),
         None => string!("none"),
     };
 
     let pid = match pid {
         Some(pid) => string!(pid),
         None => string!("n/a"),
     };
 
     let data = vec![Info {
         pid: pid,
         cpu_percent,
         memory_usage,
         uptime: uptime,
         path: global!("pmc.base"),
-        pid_file: format!("{}  ", global!("pmc.pid")),
+        external: global!("pmc.daemon.kind"),
         process_count: runner.list().keys().len(),
+        pid_file: format!("{}  ", global!("pmc.pid")),
         status: ColoredString(ternary!(pid::exists(), "online".green().bold(), "stopped".red().bold())),
     }];
 
     let table = Table::new(data.clone())
         .with(Rotate::Left)
         .with(Style::rounded().remove_horizontals())
         .with(Colorization::exact([Color::FG_CYAN], Columns::first()))
         .with(BorderColor::filled(Color::FG_BRIGHT_BLACK))
         .to_string();
 
     if let Ok(json) = serde_json::to_string(&data[0]) {
         match format.as_str() {
             "raw" => println!("{:?}", data[0]),
             "json" => println!("{json}"),
             "default" => {
                 println!("{}\n{table}\n", format!("PMC daemon information").on_bright_white().black());
                 println!(" {}", format!("Use `pmc daemon restart` to restart the daemon").white());
                 println!(" {}", format!("Use `pmc daemon reset` to clean process id values").white());
             }
             _ => {}
         };
     };
 }
 
 pub fn stop() {
     if pid::exists() {
         println!("{} Stopping PMC daemon", *helpers::SUCCESS);
 
         match pid::read() {
             Ok(pid) => {
                 service::stop(pid as i64);
                 pid::remove();
                 println!("{} PMC daemon stopped", *helpers::SUCCESS);
             }
             Err(err) => crashln!("{} Failed to read PID file: {}", *helpers::FAIL, err),
         }
     } else {
         crashln!("{} The daemon is not running", *helpers::FAIL)
     }
 }
 
 pub fn start() {
+    let external = match global!("pmc.daemon.kind").as_str() {
+        "external" => true,
+        "default" => false,
+        "rust" => false,
+        "cc" => true,
+        _ => false,
+    };
+
     pid::name("PMC Restart Handler Daemon");
-    println!("{} Spawning PMC daemon with pmc_home={}", *helpers::SUCCESS, global!("pmc.base"));
+    println!("{} Spawning PMC daemon (pmc_base={})", *helpers::SUCCESS, global!("pmc.base"));
 
     if pid::exists() {
         match pid::read() {
             Ok(pid) => then!(!pid::running(pid), pid::remove()),
             Err(_) => crashln!("{} The daemon is already running", *helpers::FAIL),
         }
     }
 
-    println!("{} PMC Successfully daemonized", *helpers::SUCCESS);
-    match daemon(false, false) {
-        Ok(Fork::Parent(_)) => {}
-        Ok(Fork::Child) => {
-            unsafe { libc::signal(libc::SIGTERM, handle_termination_signal as usize) };
-            pid::write(process::id());
-
-            loop {
-                let runner = Runner::new();
-                then!(!runner.list().is_empty(), restart_process(runner));
-                sleep(Duration::from_secs(1));
-            }
+    extern "C" fn init() {
+        let config = config::read();
+        unsafe { libc::signal(libc::SIGTERM, handle_termination_signal as usize) };
+        pid::write(process::id());
+
+        loop {
+            let runner = Runner::new();
+            then!(!runner.list().is_empty(), restart_process(runner));
+            sleep(Duration::from_millis(config.daemon.interval));
         }
-        Err(err) => {
-            crashln!("{} Daemon creation failed with code {err}", *helpers::FAIL)
+    }
+
+    println!("{} PMC Successfully daemonized (type={})", *helpers::SUCCESS, global!("pmc.daemon.kind"));
+    if external {
+        let callback = crate::Callback(init);
+        crate::service::try_fork(false, false, callback);
+    } else {
+        match daemon(false, false) {
+            Ok(Fork::Parent(_)) => {}
+            Ok(Fork::Child) => init(),
+            Err(err) => crashln!("{} Daemon creation failed with code {err}", *helpers::FAIL),
         }
     }
 }
 
 pub fn restart() {
     if pid::exists() {
         stop();
     }
     start();
 }
diff --git a/src/file.rs b/src/file.rs
index 46ae189..ab525aa 100644
--- a/src/file.rs
+++ b/src/file.rs
@@ -1,45 +1,84 @@
 use crate::helpers;
 use anyhow::Error;
 use colored::Colorize;
-use macros_rs::{crashln, str, ternary};
+use macros_rs::{crashln, str, string, ternary};
 
 use std::{
     env,
-    fs::File,
+    fs::{self, File},
     io::{self, BufRead, BufReader},
     path::{Path, PathBuf, StripPrefixError},
+    thread::sleep,
+    time::Duration,
 };
 
 pub fn logs(lines_to_tail: usize, log_file: &str, id: usize, log_type: &str, item_name: &str) {
     let file = File::open(log_file).unwrap();
     let reader = BufReader::new(file);
     let lines: Vec<String> = reader.lines().collect::<io::Result<_>>().unwrap();
     let color = ternary!(log_type == "out", "green", "red");
 
     println!("{}", format!("\n{log_file} last {lines_to_tail} lines:").bright_black());
 
     let start_index = if lines.len() > lines_to_tail { lines.len() - lines_to_tail } else { 0 };
     for (_, line) in lines.iter().skip(start_index).enumerate() {
         println!("{} {}", format!("{}|{} |", id, item_name).color(color), line);
     }
 }
 
 pub fn cwd() -> PathBuf {
     match env::current_dir() {
         Ok(path) => path,
         Err(_) => crashln!("{} Unable to find current working directory", *helpers::FAIL),
     }
 }
 
 pub fn make_relative(current: &Path, home: &Path) -> Option<std::path::PathBuf> {
     match current.strip_prefix(home) {
         Ok(relative_path) => Some(Path::new("~").join(relative_path)),
         Err(StripPrefixError { .. }) => None,
     }
 }
 
 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 fn read<T: serde::de::DeserializeOwned>(path: String) -> T {
+    let mut retry_count = 0;
+    let max_retries = 5;
+
+    let contents = loop {
+        match fs::read_to_string(&path) {
+            Ok(contents) => break contents,
+            Err(err) => {
+                retry_count += 1;
+                if retry_count >= max_retries {
+                    crashln!("{} Cannot find dumpfile.\n{}", *helpers::FAIL, string!(err).white());
+                } else {
+                    println!("{} Error reading dumpfile. Retrying... (Attempt {}/{})", *helpers::FAIL, retry_count, max_retries);
+                }
+            }
+        }
+        sleep(Duration::from_secs(1));
+    };
+
+    retry_count = 0;
+
+    loop {
+        match toml::from_str(&contents).map_err(|err| string!(err)) {
+            Ok(parsed) => break parsed,
+            Err(err) => {
+                retry_count += 1;
+                if retry_count >= max_retries {
+                    crashln!("{} Cannot parse dumpfile.\n{}", *helpers::FAIL, err.white());
+                } else {
+                    println!("{} Error parsing dumpfile. Retrying... (Attempt {}/{})", *helpers::FAIL, retry_count, max_retries);
+                }
+            }
+        }
+        sleep(Duration::from_secs(1));
+    }
+}
diff --git a/src/globals.rs b/src/globals.rs
index 60c7bbf..6d497c0 100644
--- a/src/globals.rs
+++ b/src/globals.rs
@@ -1,26 +1,43 @@
+use crate::config;
+use crate::file::Exists;
 use crate::helpers;
+
 use global_placeholders::init;
 use macros_rs::crashln;
+use std::fs;
 
 pub fn init() {
     match home::home_dir() {
         Some(path) => {
-            let base = format!("{}/.pmc/", path.display());
-            let logs = format!("{}/.pmc/logs/", path.display());
-            let pid = format!("{}/.pmc/daemon.pid", path.display());
-            let dump = format!("{}/.pmc/dump.toml", path.display());
-
-            init!("pmc.pid", pid);
-            init!("pmc.base", base);
-            init!("pmc.logs", logs);
-            init!("pmc.dump", dump);
-
-            let out = format!("{logs}{{}}-out.log");
-            let error = format!("{logs}{{}}-error.log");
+            let path = path.display();
+            if !Exists::folder(format!("{path}/.pmc/")).unwrap() {
+                fs::create_dir_all(format!("{path}/.pmc/")).unwrap();
+                log::info!("created pmc base dir");
+            }
+
+            let config = config::read();
+            if !Exists::folder(config.runner.log_path.clone()).unwrap() {
+                fs::create_dir_all(&config.runner.log_path).unwrap();
+                log::info!("created pmc log dir");
+            }
+
+            init!("pmc.base", format!("{path}/.pmc/"));
+            init!("pmc.pid", format!("{path}/.pmc/daemon.pid"));
+            init!("pmc.dump", format!("{path}/.pmc/process.dump"));
+
+            init!("pmc.config.shell", config.runner.shell);
+            init!("pmc.config.log_path", config.runner.log_path);
+
+            init!("pmc.daemon.kind", config.daemon.kind);
+            init!("pmc.daemon.interval", config.daemon.interval);
+            init!("pmc.daemon.logs", format!("{path}/.pmc/daemon.log"));
+
+            let out = format!("{}/{{}}-out.log", config.runner.log_path);
+            let error = format!("{}/{{}}-error.log", config.runner.log_path);
 
             init!("pmc.logs.out", out);
             init!("pmc.logs.error", error);
         }
         None => crashln!("{} Impossible to get your home directory", *helpers::FAIL),
     }
 }
diff --git a/src/include/bridge.h b/src/include/bridge.h
index b0b769c..7041631 100644
--- a/src/include/bridge.h
+++ b/src/include/bridge.h
@@ -1,10 +1,21 @@
-#ifndef bridge
-#define bridge
+#ifndef BRIDGE_H
+#define BRIDGE_H
 
 #include "rust.h"
 using namespace rust;
 
-int64_t stop(int64_t pid);
-int64_t run(Str name, Str log_path, Str command);
+#ifndef CXXBRIDGE1_STRUCT_ProcessMetadata
+#define CXXBRIDGE1_STRUCT_ProcessMetadata
+struct ProcessMetadata final {
+  String name;
+  String shell;
+  String command;
+  String log_path;
+  Vec<String> args;
+  using IsRelocatable = std::true_type;
+};
+#endif
 
-#endif
\ No newline at end of file
+extern "C" int64_t stop(int64_t pid);
+extern "C" int64_t run(ProcessMetadata metadata);
+#endif
diff --git a/src/include/fork.h b/src/include/fork.h
new file mode 100644
index 0000000..825405d
--- /dev/null
+++ b/src/include/fork.h
@@ -0,0 +1,19 @@
+#ifndef FORK_H
+#define FORK_H
+#include <string>
+
+#ifndef CXXBRIDGE1_ENUM_Fork
+#define CXXBRIDGE1_ENUM_Fork
+enum class Fork: uint8_t {
+    Parent,
+    Child
+};
+#endif
+
+using Callback = void(*)();
+extern "C" pid_t set_sid();
+extern "C" void close_fd();
+extern "C" Fork fork_process();
+extern "C" int chdir(const char* dir);
+extern "C" int32_t try_fork(bool nochdir, bool noclose, Callback callback);
+#endif
diff --git a/src/include/process.h b/src/include/process.h
index b7a168c..3947a37 100644
--- a/src/include/process.h
+++ b/src/include/process.h
@@ -1,20 +1,20 @@
-#ifndef process
-#define process
+#ifndef PROCESS_H
+#define PROCESS_H
 
 #include "rust.h"
 using namespace rust;
 
 namespace process {
   class Runner {
   public:
     void New(const std::string &name, const std::string &logPath);
-    int64_t Run(const std::string &command);
+    int64_t Run(const std::string &command, const std::string &shell, Vec<String> args);
     ~Runner();
 
   private:
     int stdout_fd;
     int stderr_fd;
   };
 }
 
 #endif
diff --git a/src/main.rs b/src/main.rs
index 2f0cd56..3ffc003 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,153 +1,173 @@
 mod cli;
+mod config;
 mod daemon;
 mod file;
 mod globals;
 mod helpers;
 mod process;
 mod structs;
 
-use crate::file::Exists;
 use crate::structs::Args;
-
 use clap::{Parser, Subcommand};
 use clap_verbosity_flag::Verbosity;
-use global_placeholders::global;
+use cxx::{type_id, ExternType};
 use macros_rs::{str, string, then};
 
 fn validate_id_script(s: &str) -> Result<Args, String> {
     if let Ok(id) = s.parse::<usize>() {
         Ok(Args::Id(id))
     } else {
         Ok(Args::Script(s.to_owned()))
     }
 }
 
 #[derive(Parser)]
 #[command(version = str!(cli::get_version(false)))]
 struct Cli {
     #[command(subcommand)]
     command: Commands,
     #[clap(flatten)]
     verbose: Verbosity,
 }
 
 #[derive(Subcommand)]
 enum Daemon {
     /// Reset process index
     #[command(alias = "clean")]
     Reset,
     /// Stop daemon
     #[command(alias = "kill")]
     Stop,
     /// Restart daemon
     #[command(alias = "restart", alias = "start")]
     Restore,
     /// Check daemon
     #[command(alias = "info")]
     Health {
         /// Format output
         #[arg(long, default_value_t = string!("default"))]
         format: String,
     },
 }
 
 // add pmc restore command
 #[derive(Subcommand)]
 enum Commands {
     /// Start/Restart a process
     #[command(alias = "restart")]
     Start {
         #[arg(long, help = "process name")]
         name: Option<String>,
         #[clap(value_parser = validate_id_script)]
         args: Option<Args>,
     },
 
     /// Stop/Kill a process
     #[command(alias = "kill")]
     Stop { id: usize },
 
     /// Stop then remove a process
     #[command(alias = "rm")]
     Remove { id: usize },
 
     /// Get env of a process
     #[command(alias = "cmdline")]
     Env { id: usize },
 
     /// Get information of a process
     #[command(alias = "info")]
     Details {
         id: usize,
         /// Format output
         #[arg(long, default_value_t = string!("default"))]
         format: String,
     },
 
     /// List all processes
     #[command(alias = "ls")]
     List {
         /// Format output
         #[arg(long, default_value_t = string!("default"))]
         format: String,
     },
 
     /// Get logs from a process
     Logs {
         id: usize,
         #[arg(long, default_value_t = 15, help = "")]
         lines: usize,
     },
 
     /// Daemon management
     Daemon {
         #[command(subcommand)]
         command: Daemon,
     },
 }
 
 fn main() {
     globals::init();
 
     let cli = Cli::parse();
     let mut env = env_logger::Builder::new();
     env.filter_level(cli.verbose.log_level_filter()).init();
 
-    if !Exists::folder(global!("pmc.logs")).unwrap() {
-        std::fs::create_dir_all(global!("pmc.logs")).unwrap();
-        log::info!("Created PMC log directory");
-    }
-
     match &cli.command {
         // add --watch
         Commands::Start { name, args } => cli::start(name, args),
         Commands::Stop { id } => cli::stop(id),
         Commands::Remove { id } => cli::remove(id),
         Commands::Env { id } => cli::env(id),
         Commands::Details { id, format } => cli::info(id, format),
         Commands::List { format } => cli::list(format),
         Commands::Logs { id, lines } => cli::logs(id, lines),
 
         Commands::Daemon { command } => match command {
             Daemon::Reset => {}
             Daemon::Stop => daemon::stop(),
             Daemon::Restore => daemon::restart(),
             Daemon::Health { format } => daemon::health(format),
         },
     };
 
     if !matches!(&cli.command, Commands::Daemon { .. }) {
         then!(!daemon::pid::exists(), daemon::start());
     }
 }
 
+#[repr(transparent)]
+pub struct Callback(pub extern "C" fn());
+
+unsafe impl ExternType for Callback {
+    type Id = type_id!("Callback");
+    type Kind = cxx::kind::Trivial;
+}
+
 #[cxx::bridge]
 pub mod service {
+
+    #[repr(u8)]
+    enum Fork {
+        Parent,
+        Child,
+    }
+
+    pub struct ProcessMetadata {
+        pub name: String,
+        pub shell: String,
+        pub command: String,
+        pub log_path: String,
+        pub args: Vec<String>,
+    }
+
     unsafe extern "C++" {
         include!("pmc/src/include/process.h");
         include!("pmc/src/include/bridge.h");
+        include!("pmc/src/include/fork.h");
+        type Callback = crate::Callback;
 
         pub fn stop(pid: i64) -> i64;
-        pub fn run(name: &str, log_path: &str, command: &str) -> i64;
+        pub fn run(metadata: ProcessMetadata) -> i64;
+        pub fn try_fork(nochdir: bool, noclose: bool, callback: Callback) -> i32;
     }
 }
diff --git a/src/process/dump.rs b/src/process/dump.rs
index 904a56a..017489a 100644
--- a/src/process/dump.rs
+++ b/src/process/dump.rs
@@ -1,77 +1,33 @@
-use crate::file::Exists;
+use crate::file::{self, Exists};
 use crate::helpers::{self, Id};
 use crate::process::Runner;
 
 use colored::Colorize;
 use global_placeholders::global;
 use macros_rs::{crashln, string};
-use std::{collections::BTreeMap, fs, thread::sleep, time::Duration};
+use std::{collections::BTreeMap, fs};
 
 pub fn read() -> Runner {
-    if !Exists::folder(global!("pmc.base")).unwrap() {
-        fs::create_dir_all(global!("pmc.base")).unwrap();
-        log::info!("created pmc base dir");
-    }
-
     if !Exists::file(global!("pmc.dump")).unwrap() {
         let runner = Runner {
             id: Id::new(0),
-            log_path: global!("pmc.logs"),
             process_list: BTreeMap::new(),
         };
 
         write(&runner);
         log::info!("created dump file");
     }
 
-    let mut retry_count = 0;
-    let max_retries = 5;
-
-    let contents = loop {
-        match fs::read_to_string(global!("pmc.dump")) {
-            Ok(contents) => break contents,
-            Err(err) => {
-                retry_count += 1;
-                if retry_count >= max_retries {
-                    crashln!("{} Cannot find dumpfile.\n{}", *helpers::FAIL, string!(err).white());
-                } else {
-                    println!("{} Error reading dumpfile. Retrying... (Attempt {}/{})", *helpers::FAIL, retry_count, max_retries);
-                }
-            }
-        }
-        sleep(Duration::from_secs(1));
-    };
-
-    retry_count = 0;
-
-    loop {
-        match toml::from_str(&contents).map_err(|err| string!(err)) {
-            Ok(parsed) => break parsed,
-            Err(err) => {
-                retry_count += 1;
-                if retry_count >= max_retries {
-                    crashln!("{} Cannot parse dumpfile.\n{}", *helpers::FAIL, err.white());
-                } else {
-                    println!("{} Error parsing dumpfile. Retrying... (Attempt {}/{})", *helpers::FAIL, retry_count, max_retries);
-                }
-            }
-        }
-        sleep(Duration::from_secs(1));
-    }
+    file::read(global!("pmc.dump"))
 }
 
 pub fn write(dump: &Runner) {
-    if !Exists::folder(global!("pmc.base")).unwrap() {
-        fs::create_dir_all(global!("pmc.base")).unwrap();
-        log::info!("created pmc base dir");
-    }
-
     let contents = match toml::to_string(dump) {
         Ok(contents) => contents,
         Err(err) => crashln!("{} Cannot parse dump.\n{}", *helpers::FAIL, string!(err).white()),
     };
 
     if let Err(err) = fs::write(global!("pmc.dump"), contents) {
         crashln!("{} Error writing dumpfile.\n{}", *helpers::FAIL, string!(err).white())
     }
 }
diff --git a/src/process/mod.rs b/src/process/mod.rs
index 4ae86d3..767e30d 100644
--- a/src/process/mod.rs
+++ b/src/process/mod.rs
@@ -1,119 +1,134 @@
 mod dump;
 
+use crate::config;
 use crate::file;
 use crate::helpers::{self, Id};
-use crate::service::{run, stop};
+use crate::service::{run, stop, ProcessMetadata};
 
 use chrono::serde::ts_milliseconds;
 use chrono::{DateTime, Utc};
 use macros_rs::{crashln, string};
 use serde::{Deserialize, Serialize};
 use std::collections::{BTreeMap, HashMap};
 use std::env;
 use std::path::PathBuf;
 
 #[derive(Debug, Deserialize, Serialize)]
 pub struct Process {
     pub pid: i64,
     pub name: String,
     pub path: PathBuf,
     pub script: String,
     pub env: HashMap<String, String>,
     #[serde(with = "ts_milliseconds")]
     pub started: DateTime<Utc>,
     pub running: bool,
 }
 
 #[derive(Debug, Deserialize, Serialize)]
 pub struct Runner {
     id: Id,
-    log_path: String,
     process_list: BTreeMap<String, Process>,
 }
 
 impl Runner {
     pub fn new() -> Self {
         let dump = dump::read();
 
         let runner = Runner {
             id: dump.id,
-            log_path: dump.log_path,
             process_list: dump.process_list,
         };
 
         dump::write(&runner);
         return runner;
     }
 
-    pub fn start(&mut self, name: String, command: &String) {
-        let pid = run(&name, &self.log_path, &command);
+    pub fn start(&mut self, name: &String, command: &String) {
+        let config = config::read().runner;
+        let pid = run(ProcessMetadata {
+            name: name.clone(),
+            log_path: config.log_path,
+            command: command.clone(),
+            shell: config.shell,
+            args: config.args,
+        });
+
         self.process_list.insert(
             string!(self.id.next()),
             Process {
                 pid,
-                name,
-                env: env::vars().collect(),
+                running: true,
                 path: file::cwd(),
+                name: name.clone(),
                 started: Utc::now(),
-                script: string!(command),
-                running: true,
+                script: command.clone(),
+                env: env::vars().collect(),
             },
         );
         dump::write(&self);
     }
 
     pub fn stop(&mut self, id: usize) {
         if let Some(item) = self.process_list.get_mut(&string!(id)) {
             stop(item.pid);
             item.running = false;
             dump::write(&self);
         } else {
             crashln!("{} Process ({id}) not found", *helpers::FAIL);
         }
     }
 
     pub fn restart(&mut self, id: usize, name: &Option<String>) {
         if let Some(item) = self.info(id) {
             let script = item.script.clone();
             let path = item.path.clone();
             let env = item.env.clone();
 
             let name = match name {
                 Some(name) => string!(name.trim()),
                 None => string!(item.name.clone()),
             };
 
             if let Err(err) = std::env::set_current_dir(&path) {
                 crashln!("{} Failed to set working directory {:?}\nError: {:#?}", *helpers::FAIL, path, err);
             };
 
             self.stop(id);
-            let pid = run(&name, &self.log_path, &script);
+
+            let config = config::read().runner;
+            let pid = run(ProcessMetadata {
+                name: name.clone(),
+                log_path: config.log_path,
+                command: script.clone(),
+                shell: config.shell,
+                args: config.args,
+            });
 
             self.process_list.insert(
                 string!(id),
                 Process {
                     pid,
+                    env,
                     name,
                     path,
-                    env,
                     script,
-                    started: Utc::now(),
                     running: true,
+                    started: Utc::now(),
                 },
             );
             dump::write(&self);
         } else {
             crashln!("{} Failed to restart process ({})", *helpers::FAIL, id);
         }
     }
 
     pub fn remove(&mut self, id: usize) {
         self.stop(id);
         self.process_list.remove(&string!(id));
         dump::write(&self);
     }
 
     pub fn info(&self, id: usize) -> Option<&Process> { self.process_list.get(&string!(id)) }
     pub fn list(&self) -> &BTreeMap<String, Process> { &self.process_list }
 }