diff --git a/Build.toml b/Build.toml
new file mode 100644
index 0000000..dfc0c82
--- /dev/null
+++ b/Build.toml
@@ -0,0 +1,43 @@
+[tasks.build_all]
+info = "build all"
+script = [
+   # install packages
+   "apt update --color always",
+   "apt install zip mingw-w64 -y --color always",
+   "mkdir build",
+   
+   # build linux (x86_64)
+   "cargo zigbuild -r --color always",
+   "mv target/release/pmc build/pmc",
+   "zip build/pmc_%{env.VERSION}_linux_amd64.zip build/pmc",
+   "rm build/pmc",
+   
+   # build windows (x86_64)
+   "cargo zigbuild -r --target x86_64-pc-windows-gnu --color always",
+   "mv target/x86_64-pc-windows-gnu/release/pmc.exe build/pmc.exe",
+   "zip build/pmc_%{env.VERSION}_windows_amd64.zip build/pmc.exe",
+   "rm build/pmc.exe",
+   
+   # build macos (x86_64)
+   "cargo zigbuild -r --target x86_64-apple-darwin --color always", 
+   "mv target/x86_64-apple-darwin/release/pmc build/pmc",
+   "zip build/pmc_%{env.VERSION}_darwin_amd64.zip build/pmc",
+   "rm build/pmc",
+   
+   # build macos (aarch64)
+   "cargo zigbuild -r --target aarch64-apple-darwin --color always", 
+   "mv target/aarch64-apple-darwin/release/pmc build/pmc",
+   "zip build/pmc_%{env.VERSION}_darwin_arm.zip build/pmc",
+   "rm build/pmc",
+   
+   # post build
+   "ls -sh build",
+]
+
+[tasks.build_all.remote]
+silent = false
+exclusive = true
+shell = "/bin/bash"
+image = "messense/cargo-zigbuild:latest"
+push = ["src", "Cargo.toml", "Cargo.lock"]
+pull = "build"
diff --git a/Cargo.lock b/Cargo.lock
index c75d6f7..4e9a32d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,1333 +1,1368 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
 version = 3
 
 [[package]]
 name = "aho-corasick"
 version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "android-tzdata"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
 
 [[package]]
 name = "android_system_properties"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "ansi-str"
 version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1cf4578926a981ab0ca955dc023541d19de37112bc24c1a197bd806d3d86ad1d"
 dependencies = [
  "ansitok",
 ]
 
 [[package]]
 name = "ansitok"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "220044e6a1bb31ddee4e3db724d29767f352de47445a6cd75e1a173142136c83"
 dependencies = [
  "nom",
  "vte",
 ]
 
 [[package]]
 name = "anstream"
 version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
 dependencies = [
  "anstyle",
  "anstyle-parse",
  "anstyle-query",
  "anstyle-wincon",
  "colorchoice",
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle"
 version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
 
 [[package]]
 name = "anstyle-parse"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
 dependencies = [
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle-query"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
 dependencies = [
  "windows-sys",
 ]
 
 [[package]]
 name = "anstyle-wincon"
 version = "3.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
 dependencies = [
  "anstyle",
  "windows-sys",
 ]
 
 [[package]]
 name = "anyhow"
 version = "1.0.75"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
 
 [[package]]
 name = "arrayref"
 version = "0.3.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
 
 [[package]]
 name = "arrayvec"
 version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
 
 [[package]]
 name = "arrayvec"
 version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
 
 [[package]]
 name = "autocfg"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
 [[package]]
 name = "bitflags"
 version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
 version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
 
 [[package]]
 name = "blake3"
 version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87"
 dependencies = [
  "arrayref",
  "arrayvec 0.7.4",
  "cc",
  "cfg-if",
  "constant_time_eq",
 ]
 
 [[package]]
 name = "bumpalo"
 version = "3.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
 
 [[package]]
 name = "bytecount"
 version = "0.6.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205"
 
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
 [[package]]
 name = "camino"
 version = "1.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
 
 [[package]]
 name = "cc"
 version = "1.0.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0f8e7c90afad890484a21653d08b6e209ae34770fb5ee298f9c699fcc1e5c856"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
 version = "0.4.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
  "js-sys",
  "num-traits",
  "serde",
  "wasm-bindgen",
  "windows-targets",
 ]
 
 [[package]]
 name = "clap"
 version = "4.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64"
 dependencies = [
  "clap_builder",
  "clap_derive",
 ]
 
 [[package]]
 name = "clap-verbosity-flag"
 version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e5fdbb015d790cfb378aca82caf9cc52a38be96a7eecdb92f31b4366a8afc019"
 dependencies = [
  "clap",
  "log",
 ]
 
 [[package]]
 name = "clap_builder"
 version = "4.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc"
 dependencies = [
  "anstream",
  "anstyle",
  "clap_lex",
  "strsim",
 ]
 
 [[package]]
 name = "clap_derive"
 version = "4.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
 dependencies = [
  "heck",
  "proc-macro2",
  "quote",
  "syn 2.0.39",
 ]
 
 [[package]]
 name = "clap_lex"
 version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
 
 [[package]]
 name = "codespan-reporting"
 version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
 dependencies = [
  "termcolor",
  "unicode-width",
 ]
 
 [[package]]
 name = "colorchoice"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
 
 [[package]]
 name = "colored"
 version = "2.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6"
 dependencies = [
  "is-terminal",
  "lazy_static",
  "windows-sys",
 ]
 
 [[package]]
 name = "constant_time_eq"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
 
 [[package]]
 name = "core-foundation-sys"
 version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
 
 [[package]]
 name = "crossbeam-deque"
 version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
 dependencies = [
  "cfg-if",
  "crossbeam-epoch",
  "crossbeam-utils",
 ]
 
 [[package]]
 name = "crossbeam-epoch"
 version = "0.9.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
 dependencies = [
  "autocfg",
  "cfg-if",
  "crossbeam-utils",
  "memoffset 0.9.0",
  "scopeguard",
 ]
 
 [[package]]
 name = "crossbeam-utils"
 version = "0.8.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
 dependencies = [
  "cfg-if",
 ]
 
 [[package]]
 name = "cxx"
 version = "1.0.110"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7129e341034ecb940c9072817cd9007974ea696844fc4dd582dc1653a7fbe2e8"
 dependencies = [
  "cc",
  "cxxbridge-flags",
  "cxxbridge-macro",
  "link-cplusplus",
 ]
 
 [[package]]
 name = "cxx-build"
 version = "1.0.110"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2a24f3f5f8eed71936f21e570436f024f5c2e25628f7496aa7ccd03b90109d5"
 dependencies = [
  "cc",
  "codespan-reporting",
  "once_cell",
  "proc-macro2",
  "quote",
  "scratch",
  "syn 2.0.39",
 ]
 
 [[package]]
 name = "cxxbridge-flags"
 version = "1.0.110"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "06fdd177fc61050d63f67f5bd6351fac6ab5526694ea8e359cd9cd3b75857f44"
 
 [[package]]
 name = "cxxbridge-macro"
 version = "1.0.110"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "587663dd5fb3d10932c8aecfe7c844db1bcf0aee93eeab08fac13dc1212c2e7f"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn 2.0.39",
 ]
 
 [[package]]
 name = "darwin-libproc"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9fb90051930c9a0f09e585762152048e23ac74d20c10590ef7cf01c0343c3046"
 dependencies = [
  "darwin-libproc-sys",
  "libc",
  "memchr",
 ]
 
 [[package]]
 name = "darwin-libproc-sys"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "57cebb5bde66eecdd30ddc4b9cd208238b15db4982ccc72db59d699ea10867c1"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "derive_more"
 version = "0.99.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn 1.0.109",
 ]
 
 [[package]]
 name = "either"
 version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
 
 [[package]]
 name = "env_logger"
 version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
 dependencies = [
  "humantime",
  "is-terminal",
  "log",
  "regex",
  "termcolor",
 ]
 
 [[package]]
 name = "equivalent"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
 [[package]]
 name = "errno"
 version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e"
 dependencies = [
  "libc",
  "windows-sys",
 ]
 
 [[package]]
 name = "fnv"
 version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
 [[package]]
 name = "glob"
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
 
 [[package]]
 name = "global_placeholders"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d70af3f3fd800923fa445d6fa562e054d8abaf06df926f77dd6dbead1fefb275"
 dependencies = [
  "parking_lot",
 ]
 
 [[package]]
 name = "hashbrown"
 version = "0.14.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
 
 [[package]]
 name = "heck"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 
 [[package]]
 name = "hermit-abi"
 version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
 
 [[package]]
 name = "home"
 version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
 dependencies = [
  "windows-sys",
 ]
 
 [[package]]
 name = "humantime"
 version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
 [[package]]
 name = "iana-time-zone"
 version = "0.1.58"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
  "iana-time-zone-haiku",
  "js-sys",
  "wasm-bindgen",
  "windows-core",
 ]
 
 [[package]]
 name = "iana-time-zone-haiku"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
 dependencies = [
  "cc",
 ]
 
 [[package]]
 name = "indexmap"
 version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
 dependencies = [
  "equivalent",
  "hashbrown",
 ]
 
 [[package]]
 name = "is-terminal"
 version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
 dependencies = [
  "hermit-abi",
  "rustix",
  "windows-sys",
 ]
 
 [[package]]
 name = "itoa"
 version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
 
 [[package]]
 name = "js-sys"
 version = "0.3.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
 dependencies = [
  "wasm-bindgen",
 ]
 
 [[package]]
 name = "lazy_static"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
 version = "0.2.150"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
 
 [[package]]
 name = "link-cplusplus"
 version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9"
 dependencies = [
  "cc",
 ]
 
 [[package]]
 name = "linux-raw-sys"
 version = "0.4.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
 
 [[package]]
 name = "lock_api"
 version = "0.4.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
 dependencies = [
  "autocfg",
  "scopeguard",
 ]
 
 [[package]]
 name = "log"
 version = "0.4.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
 
 [[package]]
 name = "mach"
 version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "macros-rs"
-version = "0.4.2"
+version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fb0c4278fff6f86cf9a14ed6c8e1a393d798587303418a5706dbec35f667946"
+checksum = "e7c58c98c7eca51b61c85c1cb5201582377b21ccf82731910d7bef8c12115024"
 
 [[package]]
 name = "memchr"
 version = "2.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
 
 [[package]]
 name = "memoffset"
 version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
 name = "memoffset"
 version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
 name = "merkle_hash"
 version = "3.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c2019c22dd07fa00549b671a150d126929eb1af56a4f4808a2e62aca8676995d"
 dependencies = [
  "anyhow",
  "blake3",
  "camino",
  "rayon",
 ]
 
 [[package]]
 name = "minimal-lexical"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 
 [[package]]
 name = "nix"
 version = "0.23.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
 dependencies = [
  "bitflags 1.3.2",
  "cc",
  "cfg-if",
  "libc",
  "memoffset 0.6.5",
 ]
 
 [[package]]
 name = "nom"
 version = "7.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
 dependencies = [
  "memchr",
  "minimal-lexical",
 ]
 
 [[package]]
 name = "num-traits"
 version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
 name = "num_cpus"
 version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
 dependencies = [
  "hermit-abi",
  "libc",
 ]
 
 [[package]]
 name = "once_cell"
 version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
 
 [[package]]
 name = "papergrid"
 version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2ccbe15f2b6db62f9a9871642746427e297b0ceb85f9a7f1ee5ff47d184d0c8"
 dependencies = [
  "ansi-str",
  "ansitok",
  "bytecount",
  "fnv",
  "unicode-width",
 ]
 
 [[package]]
 name = "parking_lot"
 version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
 dependencies = [
  "lock_api",
  "parking_lot_core",
 ]
 
 [[package]]
 name = "parking_lot_core"
 version = "0.9.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
 dependencies = [
  "cfg-if",
  "libc",
  "redox_syscall 0.4.1",
  "smallvec",
  "windows-targets",
 ]
 
+[[package]]
+name = "paste"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
+
 [[package]]
 name = "platforms"
 version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e8d0eef3571242013a0d5dc84861c3ae4a652e56e12adf8bdc26ff5f8cb34c94"
 
 [[package]]
 name = "pmc"
-version = "1.3.1"
+version = "1.4.0"
 dependencies = [
  "anyhow",
  "chrono",
  "clap",
  "clap-verbosity-flag",
  "colored",
  "cxx",
  "cxx-build",
  "env_logger",
  "global_placeholders",
  "home",
  "libc",
  "log",
  "macros-rs",
  "merkle_hash",
  "once_cell",
  "pretty_env_logger",
  "psutil",
  "regex",
+ "rmp-serde",
  "serde",
  "serde_json",
  "simple-logging",
  "tabled",
  "termcolor",
  "toml",
 ]
 
 [[package]]
 name = "pretty_env_logger"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c"
 dependencies = [
  "env_logger",
  "log",
 ]
 
 [[package]]
 name = "proc-macro-error"
 version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
 dependencies = [
  "proc-macro-error-attr",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
  "version_check",
 ]
 
 [[package]]
 name = "proc-macro-error-attr"
 version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
 dependencies = [
  "proc-macro2",
  "quote",
  "version_check",
 ]
 
 [[package]]
 name = "proc-macro2"
 version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "psutil"
 version = "3.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f866af2b0f8e4b0d2d00aad8a9c5fc48fad33466cd99a64cbb3a4c1505f1a62d"
 dependencies = [
  "cfg-if",
  "darwin-libproc",
  "derive_more",
  "glob",
  "mach",
  "nix",
  "num_cpus",
  "once_cell",
  "platforms",
  "thiserror",
  "unescape",
 ]
 
 [[package]]
 name = "quote"
 version = "1.0.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
 name = "rayon"
 version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
 dependencies = [
  "either",
  "rayon-core",
 ]
 
 [[package]]
 name = "rayon-core"
 version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
 dependencies = [
  "crossbeam-deque",
  "crossbeam-utils",
 ]
 
 [[package]]
 name = "redox_syscall"
 version = "0.1.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
 
 [[package]]
 name = "redox_syscall"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
 dependencies = [
  "bitflags 1.3.2",
 ]
 
 [[package]]
 name = "regex"
 version = "1.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
 dependencies = [
  "aho-corasick",
  "memchr",
  "regex-automata",
  "regex-syntax",
 ]
 
 [[package]]
 name = "regex-automata"
 version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
 dependencies = [
  "aho-corasick",
  "memchr",
  "regex-syntax",
 ]
 
 [[package]]
 name = "regex-syntax"
 version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
 
+[[package]]
+name = "rmp"
+version = "0.8.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20"
+dependencies = [
+ "byteorder",
+ "num-traits",
+ "paste",
+]
+
+[[package]]
+name = "rmp-serde"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a"
+dependencies = [
+ "byteorder",
+ "rmp",
+ "serde",
+]
+
 [[package]]
 name = "rustix"
 version = "0.38.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "80109a168d9bc0c7f483083244543a6eb0dba02295d33ca268145e6190d6df0c"
 dependencies = [
  "bitflags 2.4.1",
  "errno",
  "libc",
  "linux-raw-sys",
  "windows-sys",
 ]
 
 [[package]]
 name = "ryu"
 version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
 
 [[package]]
 name = "scopeguard"
 version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "scratch"
 version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152"
 
 [[package]]
 name = "serde"
 version = "1.0.192"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
 version = "1.0.192"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn 2.0.39",
 ]
 
 [[package]]
 name = "serde_json"
 version = "1.0.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
 dependencies = [
  "itoa",
  "ryu",
  "serde",
 ]
 
 [[package]]
 name = "serde_spanned"
 version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "simple-logging"
 version = "2.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b00d48e85675326bb182a2286ea7c1a0b264333ae10f27a937a72be08628b542"
 dependencies = [
  "lazy_static",
  "log",
  "thread-id",
 ]
 
 [[package]]
 name = "smallvec"
 version = "1.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
 
 [[package]]
 name = "strsim"
 version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 
 [[package]]
 name = "syn"
 version = "1.0.109"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
 dependencies = [
  "proc-macro2",
  "quote",
  "unicode-ident",
 ]
 
 [[package]]
 name = "syn"
 version = "2.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
 dependencies = [
  "proc-macro2",
  "quote",
  "unicode-ident",
 ]
 
 [[package]]
 name = "tabled"
 version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dfe9c3632da101aba5131ed63f9eed38665f8b3c68703a6bb18124835c1a5d22"
 dependencies = [
  "ansi-str",
  "ansitok",
  "papergrid",
  "tabled_derive",
  "unicode-width",
 ]
 
 [[package]]
 name = "tabled_derive"
 version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "99f688a08b54f4f02f0a3c382aefdb7884d3d69609f785bd253dc033243e3fe4"
 dependencies = [
  "heck",
  "proc-macro-error",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
 ]
 
 [[package]]
 name = "termcolor"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
 dependencies = [
  "winapi-util",
 ]
 
 [[package]]
 name = "thiserror"
 version = "1.0.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
 version = "1.0.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn 2.0.39",
 ]
 
 [[package]]
 name = "thread-id"
 version = "3.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1"
 dependencies = [
  "libc",
  "redox_syscall 0.1.57",
  "winapi",
 ]
 
 [[package]]
 name = "toml"
 version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
 dependencies = [
  "serde",
  "serde_spanned",
  "toml_datetime",
  "toml_edit",
 ]
 
 [[package]]
 name = "toml_datetime"
 version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "toml_edit"
 version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
 dependencies = [
  "indexmap",
  "serde",
  "serde_spanned",
  "toml_datetime",
  "winnow",
 ]
 
 [[package]]
 name = "unescape"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ccb97dac3243214f8d8507998906ca3e2e0b900bf9bf4870477f125b82e68f6e"
 
 [[package]]
 name = "unicode-ident"
 version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "unicode-width"
 version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
 
 [[package]]
 name = "utf8parse"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
 
 [[package]]
 name = "version_check"
 version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
 [[package]]
 name = "vte"
 version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983"
 dependencies = [
  "arrayvec 0.5.2",
  "utf8parse",
  "vte_generate_state_changes",
 ]
 
 [[package]]
 name = "vte_generate_state_changes"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff"
 dependencies = [
  "proc-macro2",
  "quote",
 ]
 
 [[package]]
 name = "wasm-bindgen"
 version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
 version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
 dependencies = [
  "bumpalo",
  "log",
  "once_cell",
  "proc-macro2",
  "quote",
  "syn 2.0.39",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro"
 version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro-support"
 version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn 2.0.39",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
 version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
 
 [[package]]
 name = "winapi"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
 dependencies = [
  "winapi-i686-pc-windows-gnu",
  "winapi-x86_64-pc-windows-gnu",
 ]
 
 [[package]]
 name = "winapi-i686-pc-windows-gnu"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 
 [[package]]
 name = "winapi-util"
 version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
 dependencies = [
  "winapi",
 ]
 
 [[package]]
 name = "winapi-x86_64-pc-windows-gnu"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows-core"
 version = "0.51.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
 dependencies = [
  "windows-targets",
 ]
 
 [[package]]
 name = "windows-sys"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
 dependencies = [
  "windows-targets",
 ]
 
 [[package]]
 name = "windows-targets"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
 dependencies = [
  "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
  "windows_i686_gnu",
  "windows_i686_msvc",
  "windows_x86_64_gnu",
  "windows_x86_64_gnullvm",
  "windows_x86_64_msvc",
 ]
 
 [[package]]
 name = "windows_aarch64_gnullvm"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_msvc"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_i686_gnu"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_msvc"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_x86_64_gnu"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_msvc"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "winnow"
 version = "0.5.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b"
 dependencies = [
  "memchr",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index 26294f7..e26c7da 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,36 +1,37 @@
 [package]
 name = "pmc"
-version = "1.3.1"
+version = "1.4.0"
 edition = "2021"
 license = "MIT"
 repository = "https://lab.themackabu.dev/crates/pmc"
 description = "Process management controller"
 
 [dependencies]
 clap = "4.4.8"
 log = "0.4.20"
 toml = "0.8.8"
 home = "0.5.5"
 cxx = "1.0.110"
 psutil = "3.2.2"
 regex = "1.10.2"
 libc = "0.2.150"
 anyhow = "1.0.75"
 colored = "2.0.4"
-macros-rs = "0.4.2"
+macros-rs = "0.4.4"
 termcolor = "1.4.0"
+rmp-serde = "1.1.2"
 once_cell = "1.18.0"
 env_logger = "0.10.1"
 merkle_hash = "3.5.0"
 serde_json = "1.0.108"
 simple-logging = "2.0.2"
 pretty_env_logger = "0.5.0"
 clap-verbosity-flag = "2.1.0"
 global_placeholders = "0.1.0"
 tabled = { version = "0.14.0", features = ["color"] }
 chrono = { version = "0.4.23", features = ["serde"] }
 serde = { version = "1.0.192", features = ["derive"] }
 
 [build-dependencies]
 chrono = "0.4.23"
 cxx-build = "1.0.110"
diff --git a/Maidfile.toml b/Maidfile.toml
index 6bde9da..7ba9139 100644
--- a/Maidfile.toml
+++ b/Maidfile.toml
@@ -1,24 +1,26 @@
+import = ["Build.toml"]
+
 [project]
 name = "pmc"
-version = "1.3.1"
+version = "1.4.0"
 
 [tasks]
 clean = { script = ["rm -rf bin", "mkdir bin"] }
 
 [tasks.build]
 depends = ["clean"]
 script = [
    "cargo zigbuild --release", 
    "cp target/release/pmc bin/pmc"
 ]
 
 [tasks.build.cache]
 path = "src"
 target = ["bin/pmc"]
 
 [tasks.install]
 script = [
    "maid build -q", 
    "sudo cp bin/pmc /usr/local/bin",
     "echo Copied binary!"
 ]
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..6be0237
--- /dev/null
+++ b/index.js
@@ -0,0 +1 @@
+console.log('hello world');
diff --git a/src/api/mod.rs b/src/api/mod.rs
new file mode 100644
index 0000000..e69de29
diff --git a/src/cc/process.cc b/src/cc/process.cc
index a92024c..abf7f6a 100644
--- a/src/cc/process.cc
+++ b/src/cc/process.cc
@@ -1,84 +1,93 @@
 #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, 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);
+    
+    std::vector<const char*> argsArray;
+    argsArray.push_back(shell.c_str());
 
-    if (execl(shell.c_str(), args[0].c_str(), args[1].c_str(), command.c_str(), (char *)nullptr) == -1) {
+    transform(args.begin(), args.end(), std::back_inserter(argsArray),
+      [](rust::String& arg) { return arg.c_str(); });
+
+    argsArray.push_back(command.c_str());
+    argsArray.push_back((char *)nullptr); 
+
+    if (execvp(shell.c_str(), const_cast<char* const*>(argsArray.data())) == -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 faf57a1..629d8b9 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -1,303 +1,338 @@
 use crate::structs::Args;
 use colored::Colorize;
 use global_placeholders::global;
 use macros_rs::{crashln, string, ternary};
-use pmc::file;
-use pmc::helpers::{self, ColoredString};
-use pmc::process::Runner;
 use psutil::process::{MemoryInfo, Process};
 use serde::Serialize;
 use serde_json::json;
 use std::env;
 
+use pmc::{
+    config,
+    file::{self, Exists},
+    helpers::{self, ColoredString},
+    process::Runner,
+};
+
 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>, watch: &Option<String>) {
     let mut runner = Runner::new();
+    let config = config::read();
 
     match args {
         Some(Args::Id(id)) => {
             println!("{} Applying action restartProcess on ({id})", *helpers::SUCCESS);
-            runner.restart(*id, name, watch, false);
+
+            let item = runner.get(*id).restart();
+
+            if let Some(name) = name {
+                item.rename(name.clone())
+            }
+
+            if let Some(path) = watch {
+                item.watch(path.clone())
+            }
 
             println!("{} restarted ({id}) ✓", *helpers::SUCCESS);
             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, script, watch);
+            if name.ends_with(".ts") || name.ends_with(".js") {
+                let script = format!("{} {script}", config.runner.node);
+                runner.start(&name, &script, watch).save();
+            } else {
+                runner.start(&name, script, watch).save();
+            }
 
             println!("{} created ({name}) ✓", *helpers::SUCCESS);
             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);
+    runner.get(*id).stop();
     println!("{} stopped ({id}) ✓", *helpers::SUCCESS);
     list(&string!("default"));
 }
 
 pub fn remove(id: &usize) {
     println!("{} Applying action removeProcess on ({id})", *helpers::SUCCESS);
-    let mut runner = Runner::new();
-    runner.remove(*id);
+    Runner::new().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 = "path hash")]
+        hash: String,
         #[tabled(rename = "watching")]
         watch: 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,
                 "watch": &self.watch.trim(),
+                "watch": &self.hash.trim(),
                 "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)
         }
     }
 
     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;
+        let item = Runner::new().get(*id).clone();
+        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();
-            }
+        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 {
+        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 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 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),
-                restarts: item.restarts,
-                name: item.name.clone(),
-                path: format!("{} ", path),
-                log_out: global!("pmc.logs.out", item.name.as_str()),
-                log_error: global!("pmc.logs.error", item.name.as_str()),
-                command: format!("/bin/bash -c '{}'", item.script.clone()),
-                pid: ternary!(item.running, format!("{}", item.pid), string!("n/a")),
-                status: ColoredString(ternary!(item.running, "online".green().bold(), "stopped".red().bold())),
-                watch: ternary!(item.watch.enabled, format!("{path}/{}  ", item.watch.path), string!("disabled  ")),
-                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());
-                    }
-                };
+        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),
+            restarts: item.restarts,
+            name: item.name.clone(),
+            path: format!("{} ", path),
+            status: ColoredString(status),
+            log_out: global!("pmc.logs.out", item.name.as_str()),
+            log_error: global!("pmc.logs.error", item.name.as_str()),
+            command: format!("/bin/bash -c '{}'", item.script.clone()),
+            pid: ternary!(item.running, format!("{}", item.pid), string!("n/a")),
+            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")),
+        }];
+
+        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();
+    let item = Runner::new().get(*id).clone();
+    let log_error = global!("pmc.logs.error", item.name.as_str());
+    let log_out = global!("pmc.logs.out", item.name.as_str());
 
-    if let Some(item) = runner.info(*id) {
+    if Exists::file(log_error.clone()).unwrap() && Exists::file(log_out.clone()).unwrap() {
         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);
+        crashln!("{} Logs for 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);
+    let item = Runner::new().get(*id).clone();
+    for (key, value) in item.env.iter() {
+        println!("{}: {}", key, value.green());
     }
 }
 
 pub fn list(format: &String) {
-    let runner = Runner::new();
+    let mut runner = Runner::new();
     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.list().is_empty() {
+    if runner.is_empty() {
         println!("{} Process table empty", *helpers::SUCCESS);
     } else {
-        for (id, item) in runner.list() {
+        for (id, item) in runner.items() {
             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"),
             };
 
+            let status = if item.running {
+                "online   ".green().bold()
+            } else {
+                match item.crash.crashed {
+                    true => "crashed   ",
+                    false => "stopped   ",
+                }
+                .red()
+                .bold()
+            };
+
             processes.push(ProcessItem {
+                status: ColoredString(status),
                 cpu: format!("{cpu_percent}   "),
                 mem: format!("{memory_usage}   "),
-                id: ColoredString(id.cyan().bold()),
                 restarts: format!("{}  ", item.restarts),
                 name: format!("{}   ", item.name.clone()),
+                id: ColoredString(id.to_string().cyan().bold()),
                 pid: ternary!(item.running, format!("{}  ", item.pid), string!("n/a  ")),
                 watch: ternary!(item.watch.enabled, format!("{}  ", item.watch.path), string!("disabled  ")),
-                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
index 10cc14b..4f50b2a 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -1,45 +1,47 @@
 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")],
+                        shell: string!("bash"),
+                        args: vec![string!("-c")],
+                        node: string!("node"),
                         log_path: format!("{path}/.pmc/logs"),
                     },
                     daemon: Daemon {
+                        restarts: 10,
                         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
index a3d8a0e..6a516b1 100644
--- a/src/config/structs.rs
+++ b/src/config/structs.rs
@@ -1,20 +1,22 @@
 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 node: String,
     pub log_path: String,
 }
 
 #[derive(Debug, Deserialize, Serialize)]
 pub struct Daemon {
+    pub restarts: u64,
     pub interval: u64,
     pub kind: String,
 }
diff --git a/src/daemon/mod.rs b/src/daemon/mod.rs
index b3202db..97a97d4 100644
--- a/src/daemon/mod.rs
+++ b/src/daemon/mod.rs
@@ -1,267 +1,263 @@
 mod fork;
 mod log;
 
 use chrono::{DateTime, Utc};
 use colored::Colorize;
 use fork::{daemon, Fork};
 use global_placeholders::global;
 use log::Logger;
 use macros_rs::{crashln, fmtstr, str, string, ternary, then};
 use psutil::process::{MemoryInfo, Process};
 use serde::Serialize;
 use serde_json::json;
-use std::{collections::BTreeMap, process, thread::sleep, time::Duration};
+use std::{process, thread::sleep, time::Duration};
 
 use pmc::{
     config, file,
     helpers::{self, ColoredString},
     process::{hash, id::Id, Runner, Status},
 };
 
 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();
     let mut log = Logger::new().unwrap();
     log.write(fmtstr!("daemon killed (pid={})", process::id()));
     unsafe { libc::_exit(0) }
 }
 
-fn restart_process(mut log: Logger, items: &BTreeMap<String, pmc::process::Process>) {
-    let items = items.iter().filter_map(|(id, item)| Some((id.trim().parse::<usize>().ok()?, item)));
-
-    for (id, item) in items {
-        if item.running {
+fn restart_process(mut log: Logger) {
+    for (id, item) in Runner::new().items() {
+        if item.running && item.watch.enabled {
             let path = item.path.join(item.watch.path.clone());
             let hash = hash::create(path);
 
-            if item.watch.enabled && hash != item.watch.hash {
-                let name = &Some(item.name.clone());
-                let watch = &Some(item.watch.path.clone());
-                let mut runner_instance = Runner::new();
-
-                runner_instance.restart(id, name, watch, false);
+            if hash != item.watch.hash {
+                item.restart();
                 log.write(fmtstr!("watch reload {} (id={id}, hash={hash})", item.name));
                 continue;
             }
         }
 
         if !item.running && pid::running(item.pid as i32) {
-            let mut runner_instance = Runner::new();
-            runner_instance.set_status(id, Status::Running);
+            Runner::new().set_status(*id, Status::Running);
             continue;
         }
 
         then!(!item.running || pid::running(item.pid as i32), continue);
-        let name = &Some(item.name.clone());
-        let watch = &Some(item.watch.path.clone());
-        let mut runner_instance = Runner::new();
 
-        runner_instance.restart(id, name, watch, true);
-        log.write(fmtstr!("restarted {} ({id})", item.name));
+        if item.running && item.crash.value == 10 {
+            log.write(fmtstr!("{} has crashed ({id})", item.name));
+            item.stop();
+            Runner::new().set_crashed(*id).save();
+            continue;
+        } else {
+            item.crashed();
+            log.write(fmtstr!("restarted {} (id={id}, crashes={})", item.name, item.crash.value));
+        }
     }
 }
 
 pub fn health(format: &String) {
     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;
-    let runner: Runner = file::read(global!("pmc.dump"));
+    let mut runner: Runner = file::read_rmp(global!("pmc.dump"));
 
     #[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 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"),
         external: global!("pmc.daemon.kind"),
-        process_count: runner.list().keys().len(),
+        process_count: runner.count(),
         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() {
         let mut log = Logger::new().unwrap();
         println!("{} Stopping PMC daemon", *helpers::SUCCESS);
 
         match pid::read() {
             Ok(pid) => {
                 pmc::service::stop(pid as i64);
                 pid::remove();
                 log.write(fmtstr!("daemon stopped (pid={pid})"));
                 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,
-    };
+    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 (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),
         }
     }
 
     extern "C" fn init() {
         let config = config::read();
         let mut log = Logger::new().unwrap();
 
         unsafe { libc::signal(libc::SIGTERM, handle_termination_signal as usize) };
         pid::write(process::id());
         log.write(fmtstr!("new daemon forked (pid={})", process::id()));
 
         loop {
-            let runner = Runner::new();
-            let items = runner.list();
-
-            then!(!runner.list().is_empty(), restart_process(log.clone(), items));
+            then!(!Runner::new().is_empty(), restart_process(log.clone()));
             sleep(Duration::from_millis(config.daemon.interval));
         }
     }
 
     println!("{} PMC Successfully daemonized (type={})", *helpers::SUCCESS, global!("pmc.daemon.kind"));
     if external {
         let callback = pmc::Callback(init);
         pmc::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();
 }
 
 pub fn reset() {
     let mut runner = Runner::new();
-    let largest = runner.list().keys().last().cloned();
+    let largest = runner.list().map(|(key, _)| *key).max();
 
     match largest {
-        Some(id) => runner.set_id(Id::from(str!(id))),
+        Some(id) => runner.set_id(Id::from(str!(id.to_string()))),
         None => println!("{} Cannot reset index, no ID found", *helpers::FAIL),
     }
 
     println!("{} PMC Successfully reset (index={})", *helpers::SUCCESS, runner.id);
 }
 
 pub mod pid;
diff --git a/src/file.rs b/src/file.rs
index ab525aa..d93327e 100644
--- a/src/file.rs
+++ b/src/file.rs
@@ -1,84 +1,121 @@
 use crate::helpers;
 use anyhow::Error;
 use colored::Colorize;
 use macros_rs::{crashln, str, string, ternary};
 
 use std::{
     env,
     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));
     }
 }
+
+pub fn read_rmp<T: serde::de::DeserializeOwned>(path: String) -> T {
+    let mut retry_count = 0;
+    let max_retries = 5;
+
+    let bytes = loop {
+        match fs::read(&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 rmp_serde::from_slice(&bytes) {
+            Ok(parsed) => break parsed,
+            Err(err) => {
+                retry_count += 1;
+                if retry_count >= max_retries {
+                    crashln!("{} Cannot parse dumpfile.\n{}", *helpers::FAIL, string!(err).white());
+                } else {
+                    println!("{} Error parsing dumpfile. Retrying... (Attempt {}/{})", *helpers::FAIL, retry_count, max_retries);
+                }
+            }
+        }
+        sleep(Duration::from_secs(1));
+    }
+}
diff --git a/src/main.rs b/src/main.rs
index 0514367..ab5d0f8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,134 +1,135 @@
+mod api;
 mod cli;
 mod daemon;
 mod globals;
 mod structs;
 
 use crate::structs::Args;
 use clap::{Parser, Subcommand};
 use clap_verbosity_flag::Verbosity;
 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 {
         /// Process name
         #[arg(long)]
         name: Option<String>,
         #[clap(value_parser = validate_id_script)]
         args: Option<Args>,
         /// Watch to reload path
         #[arg(long)]
         watch: Option<String>,
     },
 
     /// 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();
 
     match &cli.command {
         Commands::Start { name, args, watch } => cli::start(name, args, watch),
         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::Stop => daemon::stop(),
             Daemon::Reset => daemon::reset(),
             Daemon::Restore => daemon::restart(),
             Daemon::Health { format } => daemon::health(format),
         },
     };
 
     if !matches!(&cli.command, Commands::Daemon { .. }) {
         then!(!daemon::pid::exists(), daemon::start());
     }
 }
diff --git a/src/process/dump.rs b/src/process/dump.rs
index 47f2e44..458c989 100644
--- a/src/process/dump.rs
+++ b/src/process/dump.rs
@@ -1,35 +1,35 @@
 use crate::{
     file::{self, Exists},
     helpers,
     process::{id::Id, Runner},
 };
 
 use colored::Colorize;
 use global_placeholders::global;
 use macros_rs::{crashln, string};
 use std::{collections::BTreeMap, fs};
 
 pub fn read() -> Runner {
     if !Exists::file(global!("pmc.dump")).unwrap() {
         let runner = Runner {
             id: Id::new(0),
-            process_list: BTreeMap::new(),
+            list: BTreeMap::new(),
         };
 
         write(&runner);
         log::info!("created dump file");
     }
 
-    file::read(global!("pmc.dump"))
+    file::read_rmp(global!("pmc.dump"))
 }
 
 pub fn write(dump: &Runner) {
-    let contents = match toml::to_string(dump) {
+    let encoded: Vec<u8> = match rmp_serde::to_vec(&dump) {
         Ok(contents) => contents,
-        Err(err) => crashln!("{} Cannot parse dump.\n{}", *helpers::FAIL, string!(err).white()),
+        Err(err) => crashln!("{} Cannot encode dump.\n{}", *helpers::FAIL, string!(err).white()),
     };
 
-    if let Err(err) = fs::write(global!("pmc.dump"), contents) {
+    if let Err(err) = fs::write(global!("pmc.dump"), encoded) {
         crashln!("{} Error writing dumpfile.\n{}", *helpers::FAIL, string!(err).white())
     }
 }
diff --git a/src/process/hash.rs b/src/process/hash.rs
index 389cf7b..a7dfa4e 100644
--- a/src/process/hash.rs
+++ b/src/process/hash.rs
@@ -1,12 +1,14 @@
 use macros_rs::crashln;
 use merkle_hash::{bytes_to_hex, Algorithm, MerkleTree};
 use std::path::PathBuf;
 
 pub fn create(path: PathBuf) -> String {
+    log::debug!("creating hash for {:?}", path);
     let tree = match MerkleTree::builder(&path.to_str().unwrap()).algorithm(Algorithm::Blake3).hash_names(false).build() {
         Ok(v) => v,
         Err(e) => crashln!("Invalid UTF-8 sequence: {}", e),
     };
 
+    log::trace!("hash {:?}", tree.root.item.hash);
     bytes_to_hex(tree.root.item.hash)
 }
diff --git a/src/process/mod.rs b/src/process/mod.rs
index 43f4925..fba7498 100644
--- a/src/process/mod.rs
+++ b/src/process/mod.rs
@@ -1,204 +1,246 @@
+macro_rules! assign {
+    ($obj:expr, {$($field:ident),* $(,)?}) => {$($obj.$field = $field.clone();)*};
+}
+
 mod dump;
 mod log;
 
 use crate::{
     config, file, helpers,
     service::{run, stop, ProcessMetadata},
 };
 
 use chrono::serde::ts_milliseconds;
 use chrono::{DateTime, Utc};
-use macros_rs::{crashln, string, ternary};
+use macros_rs::{clone, crashln, string, then};
 use serde::{Deserialize, Serialize};
 use std::collections::{BTreeMap, HashMap};
 use std::{env, path::PathBuf};
 
 #[derive(Clone, Debug, Deserialize, Serialize)]
 pub struct Process {
+    pub id: usize,
     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 restarts: u64,
     pub running: bool,
+    pub crash: Crash,
     pub watch: Watch,
 }
 
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Crash {
+    pub crashed: bool,
+    pub value: u64,
+}
+
 #[derive(Clone, Debug, Deserialize, Serialize)]
 pub struct Watch {
     pub enabled: bool,
     pub path: String,
     pub hash: String,
 }
 
 #[derive(Clone, Debug, Deserialize, Serialize)]
 pub struct Runner {
     pub id: id::Id,
-    pub process_list: BTreeMap<String, Process>,
+    pub list: BTreeMap<usize, Process>,
 }
 
 pub enum Status {
     Offline,
     Running,
 }
 
 impl Status {
     pub fn to_bool(&self) -> bool {
         match self {
             Status::Offline => false,
             Status::Running => true,
         }
     }
 }
 
 impl Runner {
     pub fn new() -> Self {
         let dump = dump::read();
-
-        let runner = Runner {
-            id: dump.id,
-            process_list: dump.process_list,
-        };
+        let runner = Runner { id: dump.id, list: dump.list };
 
         dump::write(&runner);
         return runner;
     }
 
-    pub fn start(&mut self, name: &String, command: &String, watch: &Option<String>) {
+    pub fn start(&mut self, name: &String, command: &String, watch: &Option<String>) -> &mut Self {
+        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!(""),
-            },
+            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,
         });
 
-        self.process_list.insert(
-            self.id.next().to_string(),
+        self.list.insert(
+            id,
             Process {
+                id,
                 pid,
                 watch,
+                crash,
                 restarts: 0,
                 running: true,
                 path: file::cwd(),
                 name: name.clone(),
                 started: Utc::now(),
                 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);
-            self.set_status(id, Status::Offline);
-            dump::write(&self);
-        } else {
-            crashln!("{} Process ({id}) not found", *helpers::FAIL);
-        }
+        return self;
     }
 
-    pub fn restart(&mut self, id: usize, name: &Option<String>, watch: &Option<String>, dead: bool) {
-        if let Some(item) = self.info(id) {
-            let Process { path, script, .. } = item.clone();
-            let restarts = ternary!(dead, item.restarts + 1, item.restarts);
-
-            let watch = match watch {
-                Some(watch) => Watch {
-                    enabled: true,
-                    path: string!(watch),
-                    hash: hash::create(path.join(watch)),
-                },
-                None => Watch {
-                    enabled: false,
-                    path: string!(""),
-                    hash: string!(""),
-                },
-            };
+    pub fn restart(&mut self, id: usize, name: String, dead: bool) -> &mut Self {
+        let item = self.get(id);
+        let Process { path, script, .. } = item.clone();
 
-            let name = match name {
-                Some(name) => string!(name.trim()),
-                None => string!(item.name.clone()),
-            };
+        if let Err(err) = std::env::set_current_dir(&item.path) {
+            crashln!("{} Failed to set working directory {:?}\nError: {:#?}", *helpers::FAIL, path, err);
+        };
 
-            if let Err(err) = std::env::set_current_dir(&item.path) {
-                crashln!("{} Failed to set working directory {:?}\nError: {:#?}", *helpers::FAIL, path, err);
-            };
+        item.stop();
 
-            self.stop(id);
+        let config = config::read().runner;
 
-            let config = config::read().runner;
-            let pid = run(ProcessMetadata {
-                command: script,
-                args: config.args,
-                name: name.clone(),
-                shell: config.shell,
-                log_path: config.log_path,
-            });
+        item.crash.crashed = false;
+        item.pid = run(ProcessMetadata {
+            command: script,
+            args: config.args,
+            name: name.clone(),
+            shell: config.shell,
+            log_path: config.log_path,
+        });
 
-            self.process_list.insert(string!(id), Process { pid, name, watch, restarts, ..item });
-            self.set_status(id, Status::Running);
-            self.set_started(id, Utc::now());
+        item.watch = Watch {
+            enabled: false,
+            path: string!(""),
+            hash: string!(""),
+        };
 
-            dump::write(&self);
-        } else {
-            crashln!("{} Failed to restart process ({})", *helpers::FAIL, id);
-        }
+        item.name = name;
+        item.running = true;
+        item.started = Utc::now();
+        then!(dead, item.restarts += 1);
+
+        // assign!(item, {name, pid, watch});
+
+        return self;
     }
 
     pub fn remove(&mut self, id: usize) {
         self.stop(id);
-        self.process_list.remove(&string!(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) {
-        if let Some(item) = self.process_list.get_mut(&string!(id)) {
-            item.running = status.to_bool();
-            dump::write(&self);
-        } else {
-            crashln!("{} Process ({id}) not found", *helpers::FAIL);
-        }
+        let item = self.get(id);
+        item.running = status.to_bool();
+        dump::write(&self);
     }
 
-    pub fn set_started(&mut self, id: usize, time: DateTime<Utc>) {
-        if let Some(item) = self.process_list.get_mut(&string!(id)) {
-            item.started = time;
-            dump::write(&self);
-        } else {
-            crashln!("{} Process ({id}) not found", *helpers::FAIL);
-        }
+    pub fn save(&self) { dump::write(&self); }
+    pub fn count(&mut self) -> usize { self.list().count() }
+    pub fn is_empty(&self) -> bool { self.list.is_empty() }
+    pub fn items(&mut self) -> &mut BTreeMap<usize, Process> { &mut self.list }
+    pub fn list<'a>(&'a mut self) -> impl Iterator<Item = (&'a usize, &'a mut Process)> { self.list.iter_mut().map(|(k, v)| (k, v)) }
+    pub fn get(&mut self, id: usize) -> &mut Process { self.list.get_mut(&id).unwrap_or_else(|| crashln!("{} Process ({id}) not found", *helpers::FAIL)) }
+
+    pub fn set_crashed(&mut self, id: usize) -> &mut Self {
+        let item = self.get(id);
+        item.crash.crashed = true;
+        return self;
+    }
+
+    pub fn new_crash(&mut self, id: usize) -> &mut Self {
+        let item = self.get(id);
+        item.crash.value += 1;
+        return self;
+    }
+
+    pub fn stop(&mut self, id: usize) -> &mut Self {
+        let item = self.get(id);
+        stop(item.pid);
+        item.running = false;
+        item.crash.crashed = false;
+        item.crash.value = 0;
+        return self;
     }
 
-    pub fn info(&self, id: usize) -> Option<Process> { self.process_list.get(&string!(id)).cloned() }
-    pub fn list(&self) -> &BTreeMap<String, Process> { &self.process_list }
+    pub fn rename(&mut self, id: usize, name: String) -> &mut Self {
+        let item = self.get(id);
+        item.name = name;
+        return self;
+    }
+
+    pub fn watch(&mut self, id: usize, path: String) -> &mut Self {
+        let item = self.get(id);
+        item.watch = Watch {
+            enabled: true,
+            path: clone!(path),
+            hash: hash::create(item.path.join(path)),
+        };
+
+        return self;
+    }
+}
+
+impl Process {
+    pub fn stop(&mut self) { Runner::new().stop(self.id).save(); }
+    pub fn watch(&mut self, path: String) { Runner::new().watch(self.id, path).save(); }
+    pub fn rename(&mut self, name: String) { Runner::new().rename(self.id, name).save(); }
+
+    pub fn restart(&mut self) -> &mut Process {
+        Runner::new().restart(self.id, clone!(self.name), false).save();
+        return self;
+    }
+
+    pub fn crashed(&mut self) -> &mut Process {
+        Runner::new().new_crash(self.id).save();
+        Runner::new().restart(self.id, clone!(self.name), true).save();
+        return self;
+    }
 }
 
 pub mod hash;
 pub mod id;