diff --git a/src/cli/internal.rs b/src/cli/internal.rs
new file mode 100644
index 0000000..1fc9b74
--- /dev/null
+++ b/src/cli/internal.rs
@@ -0,0 +1,131 @@
+use macros_rs::{crashln, string};
+use pmc::{config, file, helpers, log, process::Runner};
+use regex::Regex;
+
+pub struct Internal<'i> {
+    pub id: usize,
+    pub runner: Runner,
+    pub kind: String,
+    pub server_name: &'i String,
+}
+
+impl<'i> Internal<'i> {
+    pub fn create(mut self, script: &String, name: &Option<String>, watch: &Option<String>) {
+        let config = config::read();
+        let name = match name {
+            Some(name) => string!(name),
+            None => string!(script.split_whitespace().next().unwrap_or_default()),
+        };
+
+        if matches!(&**self.server_name, "internal" | "local") {
+            let pattern = Regex::new(r"(?m)^[a-zA-Z0-9]+(/[a-zA-Z0-9]+)*(\.js|\.ts)?$").unwrap();
+
+            if pattern.is_match(script) {
+                let script = format!("{} {script}", config.runner.node);
+                self.runner.start(&name, &script, file::cwd(), watch).save();
+            } else {
+                self.runner.start(&name, script, file::cwd(), watch).save();
+            }
+        } else {
+            let Some(servers) = config::servers().servers else {
+                crashln!("{} Failed to read servers", *helpers::FAIL)
+            };
+
+            if let Some(server) = servers.get(self.server_name) {
+                match Runner::connect(self.server_name.clone(), server.get(), false) {
+                    Some(mut remote) => remote.start(&name, script, file::cwd(), watch),
+                    None => crashln!("{} Failed to connect (name={}, address={})", *helpers::FAIL, self.server_name, server.address),
+                };
+            } else {
+                crashln!("{} Server '{}' does not exist", *helpers::FAIL, self.server_name,)
+            };
+        }
+
+        println!("{} Creating {}process with ({name})", *helpers::SUCCESS, self.kind);
+        println!("{} {}created ({name}) ✓", *helpers::SUCCESS, self.kind);
+    }
+
+    pub fn restart(self, name: &Option<String>, watch: &Option<String>) {
+        println!("{} Applying {}action restartProcess on ({})", *helpers::SUCCESS, self.kind, self.id);
+
+        if matches!(&**self.server_name, "internal" | "local") {
+            let mut item = self.runner.get(self.id);
+
+            match watch {
+                Some(path) => item.watch(path),
+                None => item.disable_watch(),
+            }
+
+            name.as_ref().map(|n| item.rename(n.trim().replace("\n", "")));
+            item.restart();
+
+            log!("process started (id={})", self.id);
+        } else {
+            let Some(servers) = config::servers().servers else {
+                crashln!("{} Failed to read servers", *helpers::FAIL)
+            };
+
+            if let Some(server) = servers.get(self.server_name) {
+                match Runner::connect(self.server_name.clone(), server.get(), false) {
+                    Some(remote) => {
+                        let mut item = remote.get(self.id);
+
+                        name.as_ref().map(|n| item.rename(n.trim().replace("\n", "")));
+                        item.restart();
+                    }
+                    None => crashln!("{} Failed to connect (name={}, address={})", *helpers::FAIL, self.server_name, server.address),
+                }
+            } else {
+                crashln!("{} Server '{}' does not exist", *helpers::FAIL, self.server_name)
+            };
+        }
+
+        println!("{} restarted {}({}) ✓", *helpers::SUCCESS, self.kind, self.id);
+    }
+
+    pub fn stop(mut self) {
+        println!("{} Applying {}action stopProcess on ({})", *helpers::SUCCESS, self.kind, self.id);
+
+        if !matches!(&**self.server_name, "internal" | "local") {
+            let Some(servers) = config::servers().servers else {
+                crashln!("{} Failed to read servers", *helpers::FAIL)
+            };
+
+            if let Some(server) = servers.get(self.server_name) {
+                self.runner = match Runner::connect(self.server_name.clone(), server.get(), false) {
+                    Some(remote) => remote,
+                    None => crashln!("{} Failed to connect (name={}, address={})", *helpers::FAIL, self.server_name, server.address),
+                };
+            } else {
+                crashln!("{} Server '{}' does not exist", *helpers::FAIL, self.server_name)
+            };
+        }
+
+        self.runner.get(self.id).stop();
+        println!("{} stopped {}({}) ✓", *helpers::SUCCESS, self.kind, self.id);
+        log!("process stopped {}(id={})", self.kind, self.id);
+    }
+
+    pub fn remove(mut self) {
+        println!("{} Applying {}action removeProcess on ({})", *helpers::SUCCESS, self.kind, self.id);
+
+        if !matches!(&**self.server_name, "internal" | "local") {
+            let Some(servers) = config::servers().servers else {
+                crashln!("{} Failed to read servers", *helpers::FAIL)
+            };
+
+            if let Some(server) = servers.get(self.server_name) {
+                self.runner = match Runner::connect(self.server_name.clone(), server.get(), false) {
+                    Some(remote) => remote,
+                    None => crashln!("{} Failed to remove (name={}, address={})", *helpers::FAIL, self.server_name, server.address),
+                };
+            } else {
+                crashln!("{} Server '{}' does not exist", *helpers::FAIL, self.server_name)
+            };
+        }
+
+        self.runner.remove(self.id);
+        println!("{} removed {}({}) ✓", *helpers::SUCCESS, self.kind, self.id);
+        log!("process removed (id={})", self.id);
+    }
+}
diff --git a/src/cli/mod.rs b/src/cli/mod.rs
index 5232fb3..fa6b59e 100644
--- a/src/cli/mod.rs
+++ b/src/cli/mod.rs
@@ -1,607 +1,520 @@
+pub(crate) mod internal;
 pub(crate) mod server;
 
 use colored::Colorize;
+use internal::Internal;
 use macros_rs::{crashln, string, ternary};
 use psutil::process::{MemoryInfo, Process};
-use regex::Regex;
 use serde::Serialize;
 use serde_json::json;
 use std::env;
 
 use pmc::{
     config, file,
     helpers::{self, ColoredString},
     log,
     process::{http, ItemSingle, Runner},
 };
 
 use tabled::{
     settings::{
         object::{Columns, Rows},
         style::{BorderColor, Style},
         themes::Colorization,
         Color, Modify, Rotate, Width,
     },
     Table, Tabled,
 };
 
 #[derive(Clone, Debug)]
 pub enum Args {
     Id(usize),
     Script(String),
 }
 
+#[derive(Clone, Debug)]
+pub enum Item {
+    Id(usize),
+    Name(String),
+}
+
 fn format(server_name: &String) -> (String, String) {
     let kind = ternary!(matches!(&**server_name, "internal" | "local"), "", "remote ").to_string();
     return (kind, server_name.to_string());
 }
 
 pub fn get_version(short: bool) -> String {
     return match short {
         true => format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")),
         false => match env!("GIT_HASH") {
             "" => format!("{} ({}) [{}]", env!("CARGO_PKG_VERSION"), env!("BUILD_DATE"), env!("PROFILE")),
             hash => format!("{} ({} {hash}) [{}]", env!("CARGO_PKG_VERSION"), env!("BUILD_DATE"), env!("PROFILE")),
         },
     };
 }
 
-pub fn start(name: &Option<String>, args: &Option<Args>, watch: &Option<String>, server_name: &String) {
-    let mut runner = Runner::new();
-    let config = config::read();
+pub fn start(name: &Option<String>, args: &Args, watch: &Option<String>, server_name: &String) {
+    let runner = Runner::new();
     let (kind, list_name) = format(server_name);
 
     match args {
-        Some(Args::Id(id)) => {
-            let runner: Runner = Runner::new();
-            println!("{} Applying {kind}action restartProcess on ({id})", *helpers::SUCCESS);
-
-            if matches!(&**server_name, "internal" | "local") {
-                let mut item = runner.get(*id);
-
-                match watch {
-                    Some(path) => item.watch(path),
-                    None => item.disable_watch(),
-                }
-
-                name.as_ref().map(|n| item.rename(n.trim().replace("\n", "")));
-                item.restart();
-
-                log!("process started (id={id})");
-            } else {
-                let Some(servers) = config::servers().servers else {
-                    crashln!("{} Failed to read servers", *helpers::FAIL)
-                };
-
-                if let Some(server) = servers.get(server_name) {
-                    match Runner::connect(server_name.clone(), server.get(), false) {
-                        Some(remote) => {
-                            let mut item = remote.get(*id);
-
-                            name.as_ref().map(|n| item.rename(n.trim().replace("\n", "")));
-                            item.restart();
-                        }
-                        None => crashln!("{} Failed to connect (name={server_name}, address={})", *helpers::FAIL, server.address),
-                    }
-                } else {
-                    crashln!("{} Server '{server_name}' does not exist", *helpers::FAIL)
-                };
-            }
-
-            println!("{} restarted {kind}({id}) ✓", *helpers::SUCCESS);
-            list(&string!("default"), &list_name);
-        }
-        Some(Args::Script(script)) => {
-            let name = match name {
-                Some(name) => string!(name),
-                None => string!(script.split_whitespace().next().unwrap_or_default()),
-            };
-            if matches!(&**server_name, "internal" | "local") {
-                let pattern = Regex::new(r"(?m)^[a-zA-Z0-9]+(/[a-zA-Z0-9]+)*(\.js|\.ts)?$").unwrap();
-
-                if pattern.is_match(script) {
-                    let script = format!("{} {script}", config.runner.node);
-                    runner.start(&name, &script, file::cwd(), watch).save();
-                } else {
-                    runner.start(&name, script, file::cwd(), watch).save();
-                }
-
-                log!("process created (name={name})");
-            } else {
-                let Some(servers) = config::servers().servers else {
-                    crashln!("{} Failed to read servers", *helpers::FAIL)
-                };
-
-                if let Some(server) = servers.get(server_name) {
-                    match Runner::connect(server_name.clone(), server.get(), false) {
-                        Some(mut remote) => remote.start(&name, script, file::cwd(), watch),
-                        None => crashln!("{} Failed to connect (name={server_name}, address={})", *helpers::FAIL, server.address),
-                    };
-                } else {
-                    crashln!("{} Server '{server_name}' does not exist", *helpers::FAIL)
-                };
-            }
-
-            println!("{} Creating {kind}process with ({name})", *helpers::SUCCESS);
-
-            println!("{} {kind}created ({name}) ✓", *helpers::SUCCESS);
-            list(&string!("default"), &list_name);
-        }
-        None => {}
+        Args::Id(id) => Internal { id: *id, runner, server_name, kind }.restart(name, watch),
+        Args::Script(script) => match runner.find(&script) {
+            Some(id) => Internal { id, runner, server_name, kind }.restart(name, watch),
+            None => Internal { id: 0, runner, server_name, kind }.create(script, name, watch),
+        },
     }
+
+    list(&string!("default"), &list_name);
 }
 
-pub fn stop(id: &usize, server_name: &String) {
-    let mut runner: Runner = Runner::new();
+pub fn stop(item: &Item, server_name: &String) {
+    let runner: Runner = Runner::new();
     let (kind, list_name) = format(server_name);
-    println!("{} Applying {kind}action stopProcess on ({id})", *helpers::SUCCESS);
-
-    if !matches!(&**server_name, "internal" | "local") {
-        let Some(servers) = config::servers().servers else {
-            crashln!("{} Failed to read servers", *helpers::FAIL)
-        };
 
-        if let Some(server) = servers.get(server_name) {
-            runner = match Runner::connect(server_name.clone(), server.get(), false) {
-                Some(remote) => remote,
-                None => crashln!("{} Failed to connect (name={server_name}, address={})", *helpers::FAIL, server.address),
-            };
-        } else {
-            crashln!("{} Server '{server_name}' does not exist", *helpers::FAIL)
-        };
+    match item {
+        Item::Id(id) => Internal { id: *id, runner, server_name, kind }.stop(),
+        Item::Name(name) => match runner.find(&name) {
+            Some(id) => Internal { id, runner, server_name, kind }.stop(),
+            None => crashln!("{} Process ({name}) not found", *helpers::FAIL),
+        },
     }
 
-    runner.get(*id).stop();
-    println!("{} stopped {kind}({id}) ✓", *helpers::SUCCESS);
-    log!("process stopped {kind}(id={id})");
-
     list(&string!("default"), &list_name);
 }
 
-pub fn remove(id: &usize, server_name: &String) {
-    let mut runner: Runner = Runner::new();
+pub fn remove(item: &Item, server_name: &String) {
+    let runner: Runner = Runner::new();
     let (kind, _) = format(server_name);
-    println!("{} Applying {kind}action removeProcess on ({id})", *helpers::SUCCESS);
 
-    if !matches!(&**server_name, "internal" | "local") {
-        let Some(servers) = config::servers().servers else {
-            crashln!("{} Failed to read servers", *helpers::FAIL)
-        };
-
-        if let Some(server) = servers.get(server_name) {
-            runner = match Runner::connect(server_name.clone(), server.get(), false) {
-                Some(remote) => remote,
-                None => crashln!("{} Failed to remove (name={server_name}, address={})", *helpers::FAIL, server.address),
-            };
-        } else {
-            crashln!("{} Server '{server_name}' does not exist", *helpers::FAIL)
-        };
+    match item {
+        Item::Id(id) => Internal { id: *id, runner, server_name, kind }.remove(),
+        Item::Name(name) => match runner.find(&name) {
+            Some(id) => Internal { id, runner, server_name, kind }.remove(),
+            None => crashln!("{} Process ({name}) not found", *helpers::FAIL),
+        },
     }
-
-    runner.remove(*id);
-    println!("{} removed {kind}({id}) ✓", *helpers::SUCCESS);
-    log!("process removed (id={id})");
 }
 
 pub fn info(id: &usize, format: &String, server_name: &String) {
     #[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 = "path hash")]
         hash: String,
         #[tabled(rename = "watching")]
         watch: String,
         children: String,
         #[tabled(rename = "exec cwd")]
         path: String,
         #[tabled(rename = "script command ")]
         command: String,
         #[tabled(rename = "script id")]
         id: String,
         restarts: u64,
         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(),
                 "pid": &self.pid.trim(),
                 "name": &self.name.trim(),
                 "path": &self.path.trim(),
                 "restarts": &self.restarts,
                 "hash": &self.hash.trim(),
                 "watch": &self.watch.trim(),
                 "children": &self.children,
                 "uptime": &self.uptime.trim(),
                 "status": &self.status.0.trim(),
                 "log_out": &self.log_out.trim(),
                 "cpu": &self.cpu_percent.trim(),
                 "command": &self.command.trim(),
                 "mem": &self.memory_usage.trim(),
                 "log_error": &self.log_error.trim(),
             });
 
             trimmed_json.serialize(serializer)
         }
     }
 
     let render_info = |data: Vec<Info>| {
         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());
                 }
             };
         };
     };
 
     if matches!(&**server_name, "internal" | "local") {
         if let Some(home) = home::home_dir() {
             let config = config::read().runner;
             let mut runner = Runner::new();
             let item = runner.process(*id);
 
             let mut memory_usage: Option<MemoryInfo> = None;
             let mut cpu_percent: Option<f32> = None;
 
             let path = file::make_relative(&item.path, &home).to_string_lossy().into_owned();
             let children = if item.children.is_empty() { "none".to_string() } else { format!("{:?}", item.children) };
 
             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 status = if item.running {
                 "online   ".green().bold()
             } else {
                 match item.crash.crashed {
                     true => "crashed   ",
                     false => "stopped   ",
                 }
                 .red()
                 .bold()
             };
 
             let data = vec![Info {
                 children,
                 cpu_percent,
                 memory_usage,
                 id: string!(id),
                 restarts: item.restarts,
                 name: item.name.clone(),
                 log_out: item.logs().out,
                 path: format!("{} ", path),
                 log_error: item.logs().error,
                 status: ColoredString(status),
                 pid: ternary!(item.running, format!("{}", item.pid), string!("n/a")),
                 command: format!("{} {} '{}'", config.shell, config.args.join(" "), item.script),
                 hash: ternary!(item.watch.enabled, format!("{}  ", item.watch.hash), string!("none  ")),
                 watch: ternary!(item.watch.enabled, format!("{path}/{}  ", item.watch.path), string!("disabled  ")),
                 uptime: ternary!(item.running, format!("{}", helpers::format_duration(item.started)), string!("none")),
             }];
 
             render_info(data)
         } else {
             crashln!("{} Impossible to get your home directory", *helpers::FAIL);
         }
     } else {
         let data: (pmc::process::Process, Runner);
         let Some(servers) = config::servers().servers else {
             crashln!("{} Failed to read servers", *helpers::FAIL)
         };
 
         if let Some(server) = servers.get(server_name) {
             data = match Runner::connect(server_name.clone(), server.get(), false) {
                 Some(mut remote) => (remote.process(*id).clone(), remote),
                 None => crashln!("{} Failed to connect (name={server_name}, address={})", *helpers::FAIL, server.address),
             };
         } else {
             crashln!("{} Server '{server_name}' does not exist", *helpers::FAIL)
         };
 
         let (item, remote) = data;
         let remote = remote.remote.unwrap();
         let info = http::info(&remote, *id);
         let path = item.path.to_string_lossy().into_owned();
 
         let status = if item.running {
             "online   ".green().bold()
         } else {
             match item.crash.crashed {
                 true => "crashed   ",
                 false => "stopped   ",
             }
             .red()
             .bold()
         };
 
         if let Ok(info) = info {
             let stats = info.json::<ItemSingle>().unwrap().stats;
             let children = if item.children.is_empty() { "none".to_string() } else { format!("{:?}", item.children) };
 
             let cpu_percent = match stats.cpu_percent {
                 Some(percent) => format!("{percent:.2}%"),
                 None => string!("0%"),
             };
 
             let memory_usage = match stats.memory_usage {
                 Some(usage) => helpers::format_memory(usage.rss),
                 None => string!("0b"),
             };
 
             let data = vec![Info {
                 children,
                 cpu_percent,
                 memory_usage,
                 id: string!(id),
                 path: path.clone(),
                 status: status.into(),
                 restarts: item.restarts,
                 name: item.name.clone(),
                 pid: ternary!(item.running, format!("{pid}", pid = item.pid), string!("n/a")),
                 log_out: format!("{}/{}-out.log", remote.config.log_path, item.name),
                 log_error: format!("{}/{}-error.log", remote.config.log_path, item.name),
                 hash: ternary!(item.watch.enabled, format!("{}  ", item.watch.hash), string!("none  ")),
                 command: format!("{} {} '{}'", remote.config.shell, remote.config.args.join(" "), item.script),
                 watch: ternary!(item.watch.enabled, format!("{path}/{}  ", item.watch.path), string!("disabled  ")),
                 uptime: ternary!(item.running, format!("{}", helpers::format_duration(item.started)), string!("none")),
             }];
 
             render_info(data)
         }
     }
 }
 
 pub fn logs(id: &usize, lines: &usize, server_name: &String) {
     let mut runner: Runner = Runner::new();
 
     if !matches!(&**server_name, "internal" | "local") {
         let Some(servers) = config::servers().servers else {
             crashln!("{} Failed to read servers", *helpers::FAIL)
         };
 
         if let Some(server) = servers.get(server_name) {
             runner = match Runner::connect(server_name.clone(), server.get(), false) {
                 Some(remote) => remote,
                 None => crashln!("{} Failed to connect (name={server_name}, address={})", *helpers::FAIL, server.address),
             };
         } else {
             crashln!("{} Server '{server_name}' does not exist", *helpers::FAIL)
         };
 
         let item = runner.info(*id).unwrap_or_else(|| crashln!("{} Process ({id}) not found", *helpers::FAIL));
         println!("{}", format!("Showing last {lines} lines for process [{id}] (change the value with --lines option)").yellow());
 
         for kind in vec!["error", "out"] {
             let logs = http::logs(&runner.remote.as_ref().unwrap(), *id, kind);
 
             if let Ok(log) = logs {
                 if log.lines.is_empty() {
                     println!("{} No logs found for {}/{kind}", *helpers::FAIL, item.name);
                     continue;
                 }
 
                 file::logs_internal(log.lines, *lines, log.path, *id, kind, &item.name)
             }
         }
     } else {
         let item = runner.info(*id).unwrap_or_else(|| crashln!("{} Process ({id}) not found", *helpers::FAIL));
         println!("{}", format!("Showing last {lines} lines for process [{id}] (change the value with --lines option)").yellow());
 
         file::logs(item, *lines, "error");
         file::logs(item, *lines, "out");
     }
 }
 
 pub fn env(id: &usize, server_name: &String) {
     let mut runner: Runner = Runner::new();
 
     if !matches!(&**server_name, "internal" | "local") {
         let Some(servers) = config::servers().servers else {
             crashln!("{} Failed to read servers", *helpers::FAIL)
         };
 
         if let Some(server) = servers.get(server_name) {
             runner = match Runner::connect(server_name.clone(), server.get(), false) {
                 Some(remote) => remote,
                 None => crashln!("{} Failed to connect (name={server_name}, address={})", *helpers::FAIL, server.address),
             };
         } else {
             crashln!("{} Server '{server_name}' does not exist", *helpers::FAIL)
         };
     }
 
     let item = runner.process(*id);
     item.env.iter().for_each(|(key, value)| println!("{}: {}", key, value.green()));
 }
 
 pub fn list(format: &String, server_name: &String) {
     let render_list = |runner: &mut Runner, internal: bool| {
         let mut processes: Vec<ProcessItem> = Vec::new();
 
         #[derive(Tabled, Debug)]
         struct ProcessItem {
             id: ColoredString,
             name: String,
             pid: String,
             uptime: String,
             #[tabled(rename = "↺")]
             restarts: String,
             status: ColoredString,
             cpu: String,
             mem: String,
             #[tabled(rename = "watching")]
             watch: String,
         }
 
         impl serde::Serialize for ProcessItem {
             fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
                 let trimmed_json = json!({
                     "cpu": &self.cpu.trim(),
                     "mem": &self.mem.trim(),
                     "id": &self.id.0.trim(),
                     "pid": &self.pid.trim(),
                     "name": &self.name.trim(),
                     "watch": &self.watch.trim(),
                     "uptime": &self.uptime.trim(),
                     "status": &self.status.0.trim(),
                     "restarts": &self.restarts.trim(),
                 });
                 trimmed_json.serialize(serializer)
             }
         }
 
         if runner.is_empty() {
             println!("{} Process table empty", *helpers::SUCCESS);
         } else {
             for (id, item) in runner.items() {
                 let mut cpu_percent: String = string!("0%");
                 let mut memory_usage: String = string!("0b");
 
                 if internal {
                     let mut usage_internals: (Option<f32>, Option<MemoryInfo>) = (None, None);
 
                     if let Ok(mut process) = Process::new(item.pid as u32) {
                         usage_internals = (process.cpu_percent().ok(), process.memory_info().ok());
                     }
 
                     cpu_percent = match usage_internals.0 {
                         Some(percent) => format!("{:.0}%", percent),
                         None => string!("0%"),
                     };
 
                     memory_usage = match usage_internals.1 {
                         Some(usage) => helpers::format_memory(usage.rss()),
                         None => string!("0b"),
                     };
                 } else {
                     let info = http::info(&runner.remote.as_ref().unwrap(), id);
 
                     if let Ok(info) = info {
                         let stats = info.json::<ItemSingle>().unwrap().stats;
 
                         cpu_percent = match stats.cpu_percent {
                             Some(percent) => format!("{:.2}%", percent),
                             None => string!("0%"),
                         };
 
                         memory_usage = match stats.memory_usage {
                             Some(usage) => helpers::format_memory(usage.rss),
                             None => string!("0b"),
                         };
                     }
                 }
 
                 let status = if item.running {
                     "online   ".green().bold()
                 } else {
                     match item.crash.crashed {
                         true => "crashed   ",
                         false => "stopped   ",
                     }
                     .red()
                     .bold()
                 };
 
                 processes.push(ProcessItem {
                     status: status.into(),
                     cpu: format!("{cpu_percent}   "),
                     mem: format!("{memory_usage}   "),
                     id: id.to_string().cyan().bold().into(),
                     restarts: format!("{}  ", item.restarts),
                     name: format!("{}   ", item.name.clone()),
                     pid: ternary!(item.running, format!("{}  ", item.pid), string!("n/a  ")),
                     watch: ternary!(item.watch.enabled, format!("{}  ", item.watch.path), string!("disabled  ")),
                     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()))
                 .with(Modify::new(Columns::single(1)).with(Width::truncate(35).suffix("...  ")))
                 .to_string();
 
             if let Ok(json) = serde_json::to_string(&processes) {
                 match format.as_str() {
                     "raw" => println!("{:?}", processes),
                     "json" => println!("{json}"),
                     "default" => println!("{table}"),
                     _ => {}
                 };
             };
         }
     };
 
     if let Some(servers) = config::servers().servers {
         let mut failed: Vec<(String, String)> = vec![];
 
         if let Some(server) = servers.get(server_name) {
             match Runner::connect(server_name.clone(), server.get(), true) {
                 Some(mut remote) => render_list(&mut remote, false),
                 None => println!("{} Failed to fetch (name={server_name}, address={})", *helpers::FAIL, server.address),
             }
         } else {
             if matches!(&**server_name, "internal" | "all" | "global" | "local") {
                 if *server_name == "all" || *server_name == "global" {
                     println!("{} Internal daemon", *helpers::SUCCESS);
                 }
                 render_list(&mut Runner::new(), true);
             } else {
                 crashln!("{} Server '{server_name}' does not exist", *helpers::FAIL);
             }
         }
 
         if *server_name == "all" || *server_name == "global" {
             for (name, server) in servers {
                 match Runner::connect(name.clone(), server.get(), true) {
                     Some(mut remote) => render_list(&mut remote, false),
                     None => failed.push((name, server.address)),
                 }
             }
         }
 
         if !failed.is_empty() {
             println!("{} Failed servers:", *helpers::FAIL);
             failed
                 .iter()
                 .for_each(|server| println!(" {} {} {}", "-".yellow(), format!("{}", server.0), format!("[{}]", server.1).white()));
         }
     } else {
         render_list(&mut Runner::new(), true);
     }
 }
diff --git a/src/main.rs b/src/main.rs
index f7d2ef2..b48f573 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,222 +1,238 @@
 mod cli;
 mod daemon;
 mod globals;
 mod webui;
 
-use crate::{cli::Args, globals::defaults};
 use clap::{Parser, Subcommand};
 use clap_verbosity_flag::{LogLevel, Verbosity};
 use macros_rs::{str, string, then};
 use update_informer::{registry, Check};
 
+use crate::{
+    cli::{Args, Item},
+    globals::defaults,
+};
+
+// migrate to helpers
 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()))
     }
 }
 
+// migrate to helpers
+fn validate_item(s: &str) -> Result<Item, String> {
+    if let Ok(id) = s.parse::<usize>() {
+        Ok(Item::Id(id))
+    } else {
+        Ok(Item::Name(s.to_owned()))
+    }
+}
+
 #[derive(Copy, Clone, Debug, Default)]
 struct NoneLevel;
 impl LogLevel for NoneLevel {
     fn default() -> Option<log::Level> { None }
 }
 
 #[derive(Parser)]
 #[command(version = str!(cli::get_version(false)))]
 struct Cli {
     #[command(subcommand)]
     command: Commands,
     #[clap(flatten)]
     verbose: Verbosity<NoneLevel>,
 }
 
 #[derive(Subcommand)]
 enum Daemon {
     /// Reset process index
     #[command(visible_alias = "clean")]
     Reset,
     /// Stop daemon
     #[command(visible_alias = "kill")]
     Stop,
     /// Restart daemon
     #[command(visible_alias = "restart", visible_alias = "start")]
     Restore {
         /// Daemon api
         #[arg(long)]
         api: bool,
         /// WebUI using api
         #[arg(long)]
         webui: bool,
     },
     /// Check daemon
     #[command(visible_alias = "info", visible_alias = "status")]
     Health {
         /// Format output
         #[arg(long, default_value_t = string!("default"))]
         format: String,
     },
 }
 
 #[derive(Subcommand)]
 enum Server {
     /// Add new server
     #[command(visible_alias = "add")]
     New,
     /// List servers
     #[command(visible_alias = "ls")]
     List {
         /// Format output
         #[arg(long, default_value_t = string!("default"))]
         format: String,
     },
     /// Remove server
     #[command(visible_alias = "rm")]
     Remove {
         /// Server name
         name: String,
     },
     /// Set default server
     #[command(visible_alias = "set")]
     Default {
         /// Server name
         name: Option<String>,
     },
 }
 
 // add pmc restore command
 #[derive(Subcommand)]
 enum Commands {
     /// Start/Restart a process
     #[command(visible_alias = "restart")]
     Start {
         /// Process name
         #[arg(long)]
         name: Option<String>,
         #[clap(value_parser = validate_id_script)]
-        args: Option<Args>,
+        args: Args,
         /// Watch to reload path
         #[arg(long)]
         watch: Option<String>,
         /// Server
         #[arg(short, long)]
         server: Option<String>,
     },
 
     /// Stop/Kill a process
     #[command(visible_alias = "kill")]
     Stop {
-        id: usize,
+        #[clap(value_parser = validate_item)]
+        item: Item,
         /// Server
         #[arg(short, long)]
         server: Option<String>,
     },
 
     /// Stop then remove a process
     #[command(visible_alias = "rm")]
     Remove {
-        id: usize,
+        #[clap(value_parser = validate_item)]
+        item: Item,
         /// Server
         #[arg(short, long)]
         server: Option<String>,
     },
 
     /// Get env of a process
     #[command(visible_alias = "cmdline")]
     Env {
         id: usize,
         /// Server
         #[arg(short, long)]
         server: Option<String>,
     },
 
     /// Get information of a process
     #[command(visible_alias = "info")]
     Details {
         id: usize,
         /// Format output
         #[arg(long, default_value_t = string!("default"))]
         format: String,
         /// Server
         #[arg(short, long)]
         server: Option<String>,
     },
 
     /// List all processes
     #[command(visible_alias = "ls")]
     List {
         /// Format output
         #[arg(long, default_value_t = string!("default"))]
         format: String,
         /// Server
         #[arg(short, long)]
         server: Option<String>,
     },
 
     /// Get logs from a process
     Logs {
         id: usize,
         #[arg(long, default_value_t = 15, help = "")]
         lines: usize,
         /// Server
         #[arg(short, long)]
         server: Option<String>,
     },
 
     /// Daemon management
     #[command(visible_alias = "agent", visible_alias = "bgd")]
     Daemon {
         #[command(subcommand)]
         command: Daemon,
     },
 
     /// Server management
     #[command(visible_alias = "remote", visible_alias = "srv")]
     Server {
         #[command(subcommand)]
         command: Server,
     },
 }
 
 fn main() {
     let cli = Cli::parse();
     let mut env = env_logger::Builder::new();
     let level = cli.verbose.log_level_filter();
     let informer = update_informer::new(registry::Crates, "pmc", env!("CARGO_PKG_VERSION"));
 
     if let Some(version) = informer.check_version().ok().flatten() {
         println!("{} New version is available: {version}", *pmc::helpers::WARN);
     }
 
     globals::init();
     env.filter_level(level).init();
 
     match &cli.command {
         Commands::Start { name, args, watch, server } => cli::start(name, args, watch, &defaults(server)),
-        Commands::Stop { id, server } => cli::stop(id, &defaults(server)),
-        Commands::Remove { id, server } => cli::remove(id, &defaults(server)),
+        Commands::Stop { item, server } => cli::stop(item, &defaults(server)),
+        Commands::Remove { item, server } => cli::remove(item, &defaults(server)),
         Commands::Env { id, server } => cli::env(id, &defaults(server)),
         Commands::Details { id, format, server } => cli::info(id, format, &defaults(server)),
         Commands::List { format, server } => cli::list(format, &defaults(server)),
         Commands::Logs { id, lines, server } => cli::logs(id, lines, &defaults(server)),
 
         Commands::Daemon { command } => match command {
             Daemon::Stop => daemon::stop(),
             Daemon::Reset => daemon::reset(),
             Daemon::Health { format } => daemon::health(format),
             Daemon::Restore { api, webui } => daemon::restart(api, webui, level.as_str() != "OFF"),
         },
 
         Commands::Server { command } => match command {
             Server::New => cli::server::new(),
             Server::Remove { name } => cli::server::remove(name),
             Server::Default { name } => cli::server::default(name),
             Server::List { format } => cli::server::list(format, cli.verbose.log_level()),
         },
     };
 
     if !matches!(&cli.command, Commands::Daemon { .. }) && !matches!(&cli.command, Commands::Server { .. }) {
         then!(!daemon::pid::exists(), daemon::restart(&false, &false, false));
     }
 }
diff --git a/src/process/mod.rs b/src/process/mod.rs
index f6fe68a..7743222 100644
--- a/src/process/mod.rs
+++ b/src/process/mod.rs
@@ -1,570 +1,576 @@
 mod unix;
 
 use crate::{
     config,
     config::structs::Server,
     file, helpers,
     service::{run, stop, ProcessMetadata},
 };
 
 use std::{
     env,
     path::PathBuf,
     sync::{Arc, Mutex},
 };
 
 use nix::{
     sys::signal::{kill, Signal},
     unistd::Pid,
 };
 
 use chrono::serde::ts_milliseconds;
 use chrono::{DateTime, Utc};
 use global_placeholders::global;
 use macros_rs::{crashln, string, ternary, then};
 use psutil::process;
 use serde::{Deserialize, Serialize};
 use std::collections::BTreeMap;
 use utoipa::ToSchema;
 
 #[derive(Serialize, Deserialize, ToSchema)]
 pub struct ItemSingle {
     pub info: Info,
     pub stats: Stats,
     pub watch: Watch,
     pub log: Log,
     pub raw: Raw,
 }
 
 #[derive(Serialize, Deserialize, ToSchema)]
 pub struct Info {
     pub id: usize,
     pub pid: i64,
     pub name: String,
     pub status: String,
     #[schema(value_type = String, example = "/path")]
     pub path: PathBuf,
     pub uptime: String,
     pub command: String,
     pub children: Vec<i64>,
 }
 
 #[derive(Serialize, Deserialize, ToSchema)]
 pub struct Stats {
     pub restarts: u64,
     pub start_time: i64,
     pub cpu_percent: Option<f32>,
     pub memory_usage: Option<MemoryInfo>,
 }
 
 #[derive(Serialize, Deserialize, ToSchema)]
 pub struct MemoryInfo {
     pub rss: u64,
     pub vms: u64,
 }
 
 #[derive(Serialize, Deserialize, ToSchema)]
 pub struct Log {
     pub out: String,
     pub error: String,
 }
 
 #[derive(Serialize, Deserialize, ToSchema)]
 pub struct Raw {
     pub running: bool,
     pub crashed: bool,
     pub crashes: u64,
 }
 
 #[derive(Clone)]
 pub struct LogInfo {
     pub out: String,
     pub error: String,
 }
 
 #[derive(Serialize, Deserialize, ToSchema)]
 pub struct ProcessItem {
     pid: i64,
     id: usize,
     cpu: String,
     mem: String,
     name: String,
     restarts: u64,
     status: String,
     uptime: String,
     #[schema(example = "/path")]
     watch_path: String,
     #[schema(value_type = String, example = "2000-01-01T01:00:00.000Z")]
     start_time: DateTime<Utc>,
 }
 
 #[derive(Clone)]
 pub struct ProcessWrapper {
     pub id: usize,
     pub runner: Arc<Mutex<Runner>>,
 }
 
 type Env = BTreeMap<String, String>;
 
 #[derive(Clone, Debug, Deserialize, Serialize)]
 pub struct Process {
     pub id: usize,
     pub pid: i64,
     pub env: Env,
     pub name: String,
     pub path: PathBuf,
     pub script: String,
     pub restarts: u64,
     pub running: bool,
     pub crash: Crash,
     pub watch: Watch,
     pub children: Vec<i64>,
     #[serde(with = "ts_milliseconds")]
     pub started: DateTime<Utc>,
 }
 
 #[derive(Clone, Debug, Deserialize, Serialize)]
 pub struct Crash {
     pub crashed: bool,
     pub value: u64,
 }
 
 #[derive(Clone, Debug, Deserialize, Serialize, ToSchema)]
 pub struct Watch {
     pub enabled: bool,
     #[schema(example = "/path")]
     pub path: String,
     pub hash: String,
 }
 
 #[derive(Clone, Debug, Deserialize, Serialize)]
 pub struct Runner {
     pub id: id::Id,
     #[serde(skip)]
     pub remote: Option<Remote>,
     pub list: BTreeMap<usize, Process>,
 }
 
 #[derive(Clone, Debug)]
 pub struct Remote {
     address: String,
     token: Option<String>,
     pub config: RemoteConfig,
 }
 
 #[derive(Clone, Debug, Deserialize)]
 pub struct RemoteConfig {
     pub shell: String,
     pub args: Vec<String>,
     pub log_path: String,
 }
 
 pub enum Status {
     Offline,
     Running,
 }
 
 impl Status {
     pub fn to_bool(&self) -> bool {
         match self {
             Status::Offline => false,
             Status::Running => true,
         }
     }
 }
 
 macro_rules! lock {
     ($runner:expr) => {{
         match $runner.lock() {
             Ok(runner) => runner,
             Err(err) => crashln!("Unable to lock mutex: {err}"),
         }
     }};
 }
 
 fn kill_children(children: Vec<i64>) {
     for pid in children {
         if let Err(err) = kill(Pid::from_raw(pid as i32), Signal::SIGTERM) {
             log::error!("Failed to stop pid {pid}: {err:?}");
         };
     }
 }
 
 impl Runner {
     pub fn new() -> Self { dump::read() }
 
     pub fn connect(name: String, Server { address, token }: Server, verbose: bool) -> Option<Self> {
         let remote_config = match config::from(&address, token.as_deref()) {
             Ok(config) => config,
             Err(err) => {
                 log::error!("{err}");
                 return None;
             }
         };
 
         if let Ok(dump) = dump::from(&address, token.as_deref()) {
             then!(verbose, println!("{} Fetched remote (name={name}, address={address})", *helpers::SUCCESS));
             Some(Runner {
                 remote: Some(Remote {
                     token,
                     address: string!(address),
                     config: remote_config,
                 }),
                 ..dump
             })
         } else {
             None
         }
     }
 
     pub fn start(&mut self, name: &String, command: &String, path: PathBuf, watch: &Option<String>) -> &mut Self {
         if let Some(remote) = &self.remote {
             if let Err(err) = http::create(remote, name, command, path, watch) {
                 crashln!("{} Failed to start create {name}\nError: {:#?}", *helpers::FAIL, err);
             };
         } else {
             let id = self.id.next();
             let config = config::read().runner;
             let crash = Crash { crashed: false, value: 0 };
 
             let watch = match watch {
                 Some(watch) => Watch {
                     enabled: true,
                     path: string!(watch),
                     hash: hash::create(file::cwd().join(watch)),
                 },
                 None => Watch {
                     enabled: false,
                     path: string!(""),
                     hash: string!(""),
                 },
             };
 
             let pid = run(ProcessMetadata {
                 args: config.args,
                 name: name.clone(),
                 shell: config.shell,
                 command: command.clone(),
                 log_path: config.log_path,
                 env: unix::env(),
             });
 
             self.list.insert(
                 id,
                 Process {
                     id,
                     pid,
                     path,
                     watch,
                     crash,
                     restarts: 0,
                     running: true,
                     children: vec![],
                     name: name.clone(),
                     started: Utc::now(),
                     script: command.clone(),
                     env: env::vars().collect(),
                 },
             );
         }
 
         return self;
     }
 
     pub fn restart(&mut self, id: usize, dead: bool) -> &mut Self {
         if let Some(remote) = &self.remote {
             if let Err(err) = http::restart(remote, id) {
                 crashln!("{} Failed to start process {id}\nError: {:#?}", *helpers::FAIL, err);
             };
         } else {
             let process = self.process(id);
             let config = config::read().runner;
             let Process { path, script, name, .. } = process.clone();
 
             kill_children(process.children.clone());
             stop(process.pid);
 
             if let Err(err) = std::env::set_current_dir(&path) {
                 crashln!("{} Failed to set working directory {:?}\nError: {:#?}", *helpers::FAIL, path, err);
             };
 
             process.pid = run(ProcessMetadata {
                 args: config.args,
                 name: name.clone(),
                 shell: config.shell,
                 log_path: config.log_path,
                 command: script.to_string(),
                 env: unix::env(),
             });
 
-            println!("{:?}", process.pid);
-
             process.running = true;
             process.children = vec![];
             process.started = Utc::now();
             process.crash.crashed = false;
             process.env = env::vars().collect();
 
-            println!("{:?}", process);
-
             then!(dead, process.restarts += 1);
             then!(dead, process.crash.value += 1);
             then!(!dead, process.crash.value = 0);
         }
 
         return self;
     }
 
     pub fn remove(&mut self, id: usize) {
         if let Some(remote) = &self.remote {
             if let Err(err) = http::remove(remote, id) {
                 crashln!("{} Failed to stop remove {id}\nError: {:#?}", *helpers::FAIL, err);
             };
         } else {
             self.stop(id);
             self.list.remove(&id);
             dump::write(&self);
         }
     }
 
     pub fn set_id(&mut self, id: id::Id) {
         self.id = id;
         self.id.next();
         dump::write(&self);
     }
 
     pub fn set_status(&mut self, id: usize, status: Status) {
         self.process(id).running = status.to_bool();
         dump::write(&self);
     }
 
     pub fn items(&self) -> BTreeMap<usize, Process> { self.list.clone() }
+
     pub fn items_mut(&mut self) -> &mut BTreeMap<usize, Process> { &mut self.list }
 
     pub fn save(&self) { then!(self.remote.is_none(), dump::write(&self)) }
+
     pub fn count(&mut self) -> usize { self.list().count() }
+
     pub fn is_empty(&self) -> bool { self.list.is_empty() }
+
     pub fn exists(&self, id: usize) -> bool { self.list.contains_key(&id) }
+
     pub fn info(&self, id: usize) -> Option<&Process> { self.list.get(&id) }
+
     pub fn list<'l>(&'l mut self) -> impl Iterator<Item = (&'l usize, &'l mut Process)> { self.list.iter_mut().map(|(k, v)| (k, v)) }
+
     pub fn process(&mut self, id: usize) -> &mut Process { self.list.get_mut(&id).unwrap_or_else(|| crashln!("{} Process ({id}) not found", *helpers::FAIL)) }
+
     pub fn pid(&self, id: usize) -> i64 { self.list.get(&id).unwrap_or_else(|| crashln!("{} Process ({id}) not found", *helpers::FAIL)).pid }
 
+    pub fn find(&self, name: &str) -> Option<usize> { self.list.iter().find(|(_, p)| p.name == name).map(|(id, _)| *id) }
+
     pub fn get(self, id: usize) -> ProcessWrapper {
         ProcessWrapper {
             id,
             runner: Arc::new(Mutex::new(self)),
         }
     }
 
     pub fn set_crashed(&mut self, id: usize) -> &mut Self {
         self.process(id).crash.crashed = true;
         return self;
     }
 
     pub fn set_children(&mut self, id: usize, children: Vec<i64>) -> &mut Self {
         self.process(id).children = children;
         return self;
     }
 
     pub fn new_crash(&mut self, id: usize) -> &mut Self {
         self.process(id).crash.value += 1;
         return self;
     }
 
     pub fn stop(&mut self, id: usize) -> &mut Self {
         if let Some(remote) = &self.remote {
             if let Err(err) = http::stop(remote, id) {
                 crashln!("{} Failed to stop process {id}\nError: {:#?}", *helpers::FAIL, err);
             };
         } else {
             let process = self.process(id);
 
             kill_children(process.children.clone());
             stop(process.pid);
 
             process.running = false;
             process.crash.crashed = false;
             process.crash.value = 0;
             process.children = vec![];
         }
 
         return self;
     }
 
     pub fn rename(&mut self, id: usize, name: String) -> &mut Self {
         if let Some(remote) = &self.remote {
             if let Err(err) = http::rename(remote, id, name) {
                 crashln!("{} Failed to rename process {id}\nError: {:#?}", *helpers::FAIL, err);
             };
         } else {
             self.process(id).name = name;
         }
 
         return self;
     }
 
     pub fn watch(&mut self, id: usize, path: &str, enabled: bool) -> &mut Self {
         let process = self.process(id);
         process.watch = Watch {
             enabled,
             path: string!(path),
             hash: ternary!(enabled, hash::create(process.path.join(path)), string!("")),
         };
 
         return self;
     }
 
     pub fn fetch(&self) -> Vec<ProcessItem> {
         let mut processes: Vec<ProcessItem> = Vec::new();
 
         for (id, item) in self.items() {
             let mut memory_usage: Option<MemoryInfo> = None;
             let mut cpu_percent: Option<f32> = None;
 
             if let Ok(mut process) = process::Process::new(item.pid as u32) {
                 let mem_info_psutil = process.memory_info().ok();
 
                 cpu_percent = process.cpu_percent().ok();
                 memory_usage = Some(MemoryInfo {
                     rss: mem_info_psutil.as_ref().unwrap().rss(),
                     vms: mem_info_psutil.as_ref().unwrap().vms(),
                 });
             }
 
             let cpu_percent = match cpu_percent {
                 Some(percent) => format!("{:.2}%", percent),
                 None => string!("0.00%"),
             };
 
             let memory_usage = match memory_usage {
                 Some(usage) => helpers::format_memory(usage.rss),
                 None => string!("0b"),
             };
 
             let status = if item.running {
                 string!("online")
             } else {
                 match item.crash.crashed {
                     true => string!("crashed"),
                     false => string!("stopped"),
                 }
             };
 
             processes.push(ProcessItem {
                 id,
                 status,
                 pid: item.pid,
                 cpu: cpu_percent,
                 mem: memory_usage,
                 restarts: item.restarts,
                 name: item.name.clone(),
                 start_time: item.started,
                 watch_path: item.watch.path.clone(),
                 uptime: helpers::format_duration(item.started),
             });
         }
 
         return processes;
     }
 }
 
 impl Process {
     /// Get a log paths of the process item
     pub fn logs(&self) -> LogInfo {
         let name = self.name.replace(" ", "_");
 
         LogInfo {
             out: global!("pmc.logs.out", name.as_str()),
             error: global!("pmc.logs.error", name.as_str()),
         }
     }
 }
 
 impl ProcessWrapper {
     /// Stop the process item
     pub fn stop(&mut self) { lock!(self.runner).stop(self.id).save(); }
 
     /// Restart the process item
     pub fn restart(&mut self) { lock!(self.runner).restart(self.id, false).save(); }
 
     /// Rename the process item
     pub fn rename(&mut self, name: String) { lock!(self.runner).rename(self.id, name).save(); }
 
     /// Enable watching a path on the process item
     pub fn watch(&mut self, path: &str) { lock!(self.runner).watch(self.id, path, true).save(); }
 
     /// Disable watching on the process item
     pub fn disable_watch(&mut self) { lock!(self.runner).watch(self.id, "", false).save(); }
 
     /// Set the process item as crashed
     pub fn crashed(&mut self) { lock!(self.runner).restart(self.id, true).save(); }
 
     /// Get a json dump of the process item
     pub fn fetch(&self) -> ItemSingle {
         let mut runner = lock!(self.runner);
 
         let item = runner.process(self.id);
         let config = config::read().runner;
 
         let mut memory_usage: Option<MemoryInfo> = None;
         let mut cpu_percent: Option<f32> = None;
 
         if let Ok(mut process) = process::Process::new(item.pid as u32) {
             let mem_info_psutil = process.memory_info().ok();
 
             cpu_percent = process.cpu_percent().ok();
             memory_usage = Some(MemoryInfo {
                 rss: mem_info_psutil.as_ref().unwrap().rss(),
                 vms: mem_info_psutil.as_ref().unwrap().vms(),
             });
         }
 
         let status = if item.running {
             string!("online")
         } else {
             match item.crash.crashed {
                 true => string!("crashed"),
                 false => string!("stopped"),
             }
         };
 
         ItemSingle {
             info: Info {
                 status,
                 id: item.id,
                 pid: item.pid,
                 name: item.name.clone(),
                 path: item.path.clone(),
                 children: item.children.clone(),
                 uptime: helpers::format_duration(item.started),
                 command: format!("{} {} '{}'", config.shell, config.args.join(" "), item.script.clone()),
             },
             stats: Stats {
                 cpu_percent,
                 memory_usage,
                 restarts: item.restarts,
                 start_time: item.started.timestamp_millis(),
             },
             watch: Watch {
                 enabled: item.watch.enabled,
                 hash: item.watch.hash.clone(),
                 path: item.watch.path.clone(),
             },
             log: Log {
                 out: item.logs().out,
                 error: item.logs().error,
             },
             raw: Raw {
                 running: item.running,
                 crashed: item.crash.crashed,
                 crashes: item.crash.value,
             },
         }
     }
 }
 
 pub mod dump;
 pub mod hash;
 pub mod http;
 pub mod id;