diff --git a/Cargo.toml b/Cargo.toml
index 6730082ae8164f6d04d93c83da89e248e6e4c779..64347951aa7f46121b296e89d4542d298f6d171d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,6 +7,7 @@ license = "AGPL-3.0"
 
 [dependencies]
 duniter-core = { path = "./core" }
+# durs-skeleton-module = { path = "./skeleton-module" }
 durs-ws2p = { path = "./ws2p" }
 durs-ws2p-v1-legacy = { path = "./ws2p-v1-legacy" }
 structopt= "0.2.*"
@@ -32,6 +33,7 @@ members = [
     "module",
     "network",
     "network-documents",
+    # "skeleton-module",
     "tui",
     "wot",
     "ws2p",
diff --git a/blockchain/lib.rs b/blockchain/lib.rs
index b4e8a9bf1cd3e398cb78e1332e9d6e5b1f766a94..b348315e179c7a1d487045bea99cf34e15335e36 100644
--- a/blockchain/lib.rs
+++ b/blockchain/lib.rs
@@ -95,8 +95,8 @@ pub static DISTANCE_CALCULATOR: &'static RustyDistanceCalculator = &RustyDistanc
 /// Blockchain Module
 #[derive(Debug)]
 pub struct BlockchainModule {
-    /// Rooter sender
-    pub rooter_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
+    /// Router sender
+    pub router_sender: mpsc::Sender<RouterThreadMessage<DursMsg>>,
     /// Name of the user datas profile
     pub profile: String,
     /// Currency
@@ -152,7 +152,7 @@ impl BlockchainModule {
     }
     /// Loading blockchain configuration
     pub fn load_blockchain_conf<DC: DuniterConf>(
-        rooter_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
+        router_sender: mpsc::Sender<RouterThreadMessage<DursMsg>>,
         profile: &str,
         conf: &DC,
         _keys: RequiredKeysContent,
@@ -185,7 +185,7 @@ impl BlockchainModule {
 
         // Instanciate BlockchainModule
         BlockchainModule {
-            rooter_sender,
+            router_sender,
             profile: profile.to_string(),
             currency: conf.currency(),
             currency_params,
@@ -271,12 +271,12 @@ impl BlockchainModule {
     }
     /// Send network request
     fn request_network(&self, _req_id: ModuleReqId, request: &OldNetworkRequest) -> ModuleReqId {
-        self.rooter_sender
-            .send(RooterThreadMessage::ModuleMessage(DursMsg(
+        self.router_sender
+            .send(RouterThreadMessage::ModuleMessage(DursMsg(
                 DursMsgReceiver::Role(ModuleRole::InterNodesNetwork),
                 DursMsgContent::OldNetworkRequest(*request),
             )))
-            .unwrap_or_else(|_| panic!("Fail to send OldNetworkRequest to rooter"));
+            .unwrap_or_else(|_| panic!("Fail to send OldNetworkRequest to router"));
         request.get_req_id()
     }
     /// Send blockchain event
@@ -286,20 +286,20 @@ impl BlockchainModule {
             DALEvent::RevertBlocks(_) => ModuleEvent::RevertBlocks,
             _ => return,
         };
-        self.rooter_sender
-            .send(RooterThreadMessage::ModuleMessage(DursMsg(
+        self.router_sender
+            .send(RouterThreadMessage::ModuleMessage(DursMsg(
                 DursMsgReceiver::Event(module_event),
                 DursMsgContent::DALEvent(event.clone()),
             )))
-            .unwrap_or_else(|_| panic!("Fail to send DalEvent to rooter"));
+            .unwrap_or_else(|_| panic!("Fail to send DalEvent to router"));
     }
     fn send_req_response(&self, requester: DursMsgReceiver, response: &DALResponse) {
-        self.rooter_sender
-            .send(RooterThreadMessage::ModuleMessage(DursMsg(
+        self.router_sender
+            .send(RouterThreadMessage::ModuleMessage(DursMsg(
                 requester,
                 DursMsgContent::DALResponse(Box::new(response.clone())),
             )))
-            .unwrap_or_else(|_| panic!("Fail to send ReqRes to rooter"));
+            .unwrap_or_else(|_| panic!("Fail to send ReqRes to router"));
     }
     fn receive_network_documents<W: WebOfTrust>(
         &mut self,
diff --git a/core/lib.rs b/core/lib.rs
index ba7b2c047f2d96223a3ed69433800bfbf49aaeaa..6a9a8ded2dea5c357f873961c26c2b6b7746a843 100644
--- a/core/lib.rs
+++ b/core/lib.rs
@@ -48,7 +48,7 @@ extern crate threadpool;
 
 pub mod change_conf;
 pub mod cli;
-pub mod rooter;
+pub mod router;
 
 use duniter_blockchain::{BlockchainModule, DBExQuery, DBExTxQuery, DBExWotQuery};
 pub use duniter_conf::{ChangeGlobalConf, DuRsConf, DuniterKeyPairs};
@@ -172,8 +172,8 @@ pub struct DuniterCore<'a, 'b: 'a, DC: DuniterConf> {
     pub keypairs: Option<DuniterKeyPairs>,
     /// Run duration. Zero = infinite duration.
     pub run_duration_in_secs: u64,
-    /// Sender channel of rooter thread
-    pub rooter_sender: Option<mpsc::Sender<RooterThreadMessage<DursMsg>>>,
+    /// Sender channel of router thread
+    pub router_sender: Option<mpsc::Sender<RouterThreadMessage<DursMsg>>>,
     ///  Count the number of plugged modules
     pub modules_count: usize,
     ///  Count the number of plugged network modules
@@ -206,7 +206,7 @@ impl<'a, 'b: 'a> DuniterCore<'b, 'a, DuRsConf> {
             },
             keypairs: None,
             run_duration_in_secs,
-            rooter_sender: None,
+            router_sender: None,
             modules_count: 1, // Count blockchain module
             network_modules_count: 0,
             thread_pool: ThreadPool::new(*THREAD_POOL_SIZE),
@@ -214,8 +214,9 @@ impl<'a, 'b: 'a> DuniterCore<'b, 'a, DuRsConf> {
     }
     /// Inject cli subcommand
     pub fn inject_cli_subcommand<M: DuniterModule<DuRsConf, DursMsg>>(&mut self) {
-        //self.cli_conf = TupleApp(&self.cli_conf.0.clone().subcommand(M::ModuleOpt::clap()));
-        self.plugins_cli_conf.push(M::ModuleOpt::clap());
+        if M::have_subcommand() {
+            self.plugins_cli_conf.push(M::ModuleOpt::clap());
+        }
     }
     /// Execute user command
     pub fn match_user_command(&mut self) -> bool {
@@ -287,15 +288,15 @@ impl<'a, 'b: 'a> DuniterCore<'b, 'a, DuRsConf> {
             // Store user command
             self.user_command = Some(UserCommand::ListModules(ListModulesOpt::from_clap(matches)));
 
-            // Start rooter thread
-            self.rooter_sender = Some(rooter::start_rooter(0, profile.clone(), conf, vec![]));
+            // Start router thread
+            self.router_sender = Some(router::start_router(0, profile.clone(), conf, vec![]));
             true
         } else if let Some(_matches) = cli_args.subcommand_matches("start") {
             // Store user command
             self.user_command = Some(UserCommand::Start());
 
-            // Start rooter thread
-            self.rooter_sender = Some(rooter::start_rooter(
+            // Start router thread
+            self.router_sender = Some(router::start_router(
                 self.run_duration_in_secs,
                 profile.clone(),
                 conf,
@@ -316,8 +317,8 @@ impl<'a, 'b: 'a> DuniterCore<'b, 'a, DuRsConf> {
                 cautious: opts.cautious_mode,
                 verif_hashs: opts.unsafe_mode,
             }));
-            // Start rooter thread
-            self.rooter_sender = Some(rooter::start_rooter(0, profile.clone(), conf, vec![]));
+            // Start router thread
+            self.router_sender = Some(router::start_router(0, profile.clone(), conf, vec![]));
             true
         } else if let Some(matches) = cli_args.subcommand_matches("sync_ts") {
             let opts = SyncTsOpt::from_clap(matches);
@@ -436,20 +437,20 @@ impl<'a, 'b: 'a> DuniterCore<'b, 'a, DuRsConf> {
                 mpsc::Receiver<DursMsg>,
             ) = mpsc::channel();
 
-            let rooter_sender = if let Some(ref rooter_sender) = self.rooter_sender {
-                rooter_sender
+            let router_sender = if let Some(ref router_sender) = self.router_sender {
+                router_sender
             } else {
-                panic!("Try to start core without rooter_sender !");
+                panic!("Try to start core without router_sender !");
             };
 
-            // Send expected modules count to rooter thread
-            rooter_sender
-                .send(RooterThreadMessage::ModulesCount(self.modules_count))
-                .expect("Fatal error: fail to send expected modules count to rooter thread !");
+            // Send expected modules count to router thread
+            router_sender
+                .send(RouterThreadMessage::ModulesCount(self.modules_count))
+                .expect("Fatal error: fail to send expected modules count to router thread !");
 
-            // Send blockchain module registration to rooter thread
-            rooter_sender
-                .send(RooterThreadMessage::ModuleRegistration(
+            // Send blockchain module registration to router thread
+            router_sender
+                .send(RouterThreadMessage::ModuleRegistration(
                     BlockchainModule::name(),
                     blockchain_sender,
                     vec![ModuleRole::BlockchainDatas, ModuleRole::BlockValidation],
@@ -457,11 +458,11 @@ impl<'a, 'b: 'a> DuniterCore<'b, 'a, DuRsConf> {
                     vec![],
                     vec![],
                 ))
-                .expect("Fatal error: fail to send blockchain registration to rooter thread !");
+                .expect("Fatal error: fail to send blockchain registration to router thread !");
 
             // Instantiate blockchain module and load is conf
             let mut blockchain_module = BlockchainModule::load_blockchain_conf(
-                rooter_sender.clone(),
+                router_sender.clone(),
                 &self.soft_meta_datas.profile,
                 &self.soft_meta_datas.conf,
                 RequiredKeysContent::MemberKeyPair(None),
@@ -479,10 +480,10 @@ impl<'a, 'b: 'a> DuniterCore<'b, 'a, DuRsConf> {
             self.network_modules_count += 1;
             if let Some(UserCommand::Sync(ref network_sync)) = self.user_command {
                 // Start module in a new thread
-                let rooter_sender = self
-                    .rooter_sender
+                let router_sender = self
+                    .router_sender
                     .clone()
-                    .expect("Try to start a core without rooter_sender !");
+                    .expect("Try to start a core without router_sender !");
                 let soft_meta_datas = self.soft_meta_datas.clone();
                 let module_conf_json = self
                     .soft_meta_datas
@@ -503,7 +504,7 @@ impl<'a, 'b: 'a> DuniterCore<'b, 'a, DuRsConf> {
                         &soft_meta_datas,
                         required_keys,
                         module_conf,
-                        rooter_sender,
+                        router_sender,
                         sync_params,
                     )
                     .unwrap_or_else(|_| {
@@ -534,10 +535,10 @@ impl<'a, 'b: 'a> DuniterCore<'b, 'a, DuRsConf> {
         if enabled {
             if let Some(UserCommand::Start()) = self.user_command {
                 // Start module in a new thread
-                let rooter_sender_clone = self
-                    .rooter_sender
+                let router_sender_clone = self
+                    .router_sender
                     .clone()
-                    .expect("Try to start a core without rooter_sender !");
+                    .expect("Try to start a core without router_sender !");
                 let soft_meta_datas = self.soft_meta_datas.clone();
                 let module_conf_json = self
                     .soft_meta_datas
@@ -557,7 +558,7 @@ impl<'a, 'b: 'a> DuniterCore<'b, 'a, DuRsConf> {
                         &soft_meta_datas,
                         required_keys,
                         module_conf,
-                        rooter_sender_clone,
+                        router_sender_clone,
                         false,
                     )
                     .unwrap_or_else(|_| {
diff --git a/core/rooter.rs b/core/router.rs
similarity index 92%
rename from core/rooter.rs
rename to core/router.rs
index 1dce12f5578f4450a9617700c031d7c51839bb9b..51c3758a2b770ec5fffc8d5640e362e469f71c36 100644
--- a/core/rooter.rs
+++ b/core/router.rs
@@ -33,7 +33,7 @@ static MAX_REGISTRATION_DELAY: &'static u64 = &20;
 fn start_broadcasting_thread(
     start_time: SystemTime,
     run_duration_in_secs: u64,
-    receiver: &mpsc::Receiver<RooterThreadMessage<DursMsg>>,
+    receiver: &mpsc::Receiver<RouterThreadMessage<DursMsg>>,
     external_followers: &[mpsc::Sender<DursMsgContent>],
 ) {
     // Define variables
@@ -50,10 +50,10 @@ fn start_broadcasting_thread(
         match receiver.recv_timeout(Duration::from_secs(1)) {
             Ok(mess) => {
                 match mess {
-                    RooterThreadMessage::ModulesCount(modules_count) => {
+                    RouterThreadMessage::ModulesCount(modules_count) => {
                         expected_registrations_count = Some(modules_count)
                     }
-                    RooterThreadMessage::ModuleRegistration(
+                    RouterThreadMessage::ModuleRegistration(
                         module_static_name,
                         module_sender,
                         sender_roles,
@@ -144,7 +144,7 @@ fn start_broadcasting_thread(
                         // Add this sender to modules_senders
                         modules_senders.insert(module_static_name, module_sender);
                     }
-                    RooterThreadMessage::ModuleMessage(msg) => match msg.0 {
+                    RouterThreadMessage::ModuleMessage(msg) => match msg.0 {
                         DursMsgReceiver::One(_) => {}
                         DursMsgReceiver::All => {
                             for (module_static_name, module_sender) in &modules_senders {
@@ -219,7 +219,7 @@ fn start_broadcasting_thread(
             Err(e) => match e {
                 RecvTimeoutError::Timeout => continue,
                 RecvTimeoutError::Disconnected => {
-                    panic!("Fatal error : rooter thread disconnnected !")
+                    panic!("Fatal error : router thread disconnnected !")
                 }
             },
         }
@@ -241,17 +241,13 @@ fn start_broadcasting_thread(
 }
 
 /// Start conf thread
-fn start_conf_thread(
-    profile: &str,
-    conf: &mut DuRsConf,
-    receiver: &mpsc::Receiver<DursMsgContent>,
-) {
+fn start_conf_thread(profile: &str, mut conf: DuRsConf, receiver: &mpsc::Receiver<DursMsgContent>) {
     loop {
         match receiver.recv() {
             Ok(msg) => {
                 if let DursMsgContent::SaveNewModuleConf(module_static_name, new_json_conf) = msg {
                     conf.set_module_conf(module_static_name.to_string(), new_json_conf);
-                    duniter_conf::write_conf_file(&profile, conf)
+                    duniter_conf::write_conf_file(&profile, &conf)
                         .expect("Fail to write new module conf in conf file ! ");
                 }
             }
@@ -312,27 +308,27 @@ fn store_msg_in_pool(
     }
 }
 
-/// Start rooter thread
-pub fn start_rooter(
+/// Start router thread
+pub fn start_router(
     run_duration_in_secs: u64,
     profile: String,
     conf: DuRsConf,
     external_followers: Vec<mpsc::Sender<DursMsgContent>>,
-) -> mpsc::Sender<RooterThreadMessage<DursMsg>> {
+) -> mpsc::Sender<RouterThreadMessage<DursMsg>> {
     let start_time = SystemTime::now();
 
-    // Create rooter channel
-    let (rooter_sender, rooter_receiver): (
-        mpsc::Sender<RooterThreadMessage<DursMsg>>,
-        mpsc::Receiver<RooterThreadMessage<DursMsg>>,
+    // Create router channel
+    let (router_sender, router_receiver): (
+        mpsc::Sender<RouterThreadMessage<DursMsg>>,
+        mpsc::Receiver<RouterThreadMessage<DursMsg>>,
     ) = mpsc::channel();
 
-    // Create rooter thread
+    // Create router thread
     thread::spawn(move || {
         // Create broadcasting thread channel
         let (broadcasting_sender, broadcasting_receiver): (
-            mpsc::Sender<RooterThreadMessage<DursMsg>>,
-            mpsc::Receiver<RooterThreadMessage<DursMsg>>,
+            mpsc::Sender<RouterThreadMessage<DursMsg>>,
+            mpsc::Receiver<RouterThreadMessage<DursMsg>>,
         ) = mpsc::channel();
 
         // Create broadcasting thread
@@ -353,7 +349,7 @@ pub fn start_rooter(
 
         // Create conf thread
         thread::spawn(move || {
-            start_conf_thread(&profile, &mut conf.clone(), &conf_receiver);
+            start_conf_thread(&profile, conf, &conf_receiver);
         });
 
         // Define variables
@@ -362,20 +358,20 @@ pub fn start_rooter(
 
         // Wait to receiver modules senders
         loop {
-            match rooter_receiver.recv_timeout(Duration::from_secs(1)) {
+            match router_receiver.recv_timeout(Duration::from_secs(1)) {
                 Ok(mess) => {
                     match mess {
-                        RooterThreadMessage::ModulesCount(expected_registrations_count) => {
+                        RouterThreadMessage::ModulesCount(expected_registrations_count) => {
                             // Relay to broadcasting thread
                             broadcasting_sender
-                                .send(RooterThreadMessage::ModulesCount(
+                                .send(RouterThreadMessage::ModulesCount(
                                     expected_registrations_count,
                                 ))
                                 .expect(
                                     "Fail to relay ModulesCount message to broadcasting thread !",
                                 );
                         }
-                        RooterThreadMessage::ModuleRegistration(
+                        RouterThreadMessage::ModuleRegistration(
                             module_static_name,
                             module_sender,
                             events_subscription,
@@ -403,7 +399,7 @@ pub fn start_rooter(
                             modules_senders.insert(module_static_name, module_sender.clone());
                             // Relay to broadcasting thread
                             broadcasting_sender
-                                .send(RooterThreadMessage::ModuleRegistration(
+                                .send(RouterThreadMessage::ModuleRegistration(
                                     module_static_name,
                                     module_sender,
                                     events_subscription,
@@ -416,12 +412,12 @@ pub fn start_rooter(
                                 );
                             // Log the number of modules_senders received
                             info!(
-                                "Rooter thread receive {} module senders",
+                                "Router thread receive {} module senders",
                                 modules_senders.len()
                             );
                         }
-                        RooterThreadMessage::ModuleMessage(msg) => {
-                            trace!("Rooter thread receive ModuleMessage({:?})", msg);
+                        RouterThreadMessage::ModuleMessage(msg) => {
+                            trace!("Router thread receive ModuleMessage({:?})", msg);
                             match msg.0 {
                                 DursMsgReceiver::All => {
                                     let stop = if let DursMsgContent::Stop() = msg.1 {
@@ -430,7 +426,7 @@ pub fn start_rooter(
                                         false
                                     };
                                     broadcasting_sender
-                                        .send(RooterThreadMessage::ModuleMessage(msg))
+                                        .send(RouterThreadMessage::ModuleMessage(msg))
                                         .expect("Fail to relay message to broadcasting thread !");
                                     if stop {
                                         break;
@@ -445,14 +441,14 @@ pub fn start_rooter(
                                             .expect("Fail to reach conf thread !");
                                     } else {
                                         broadcasting_sender
-                                            .send(RooterThreadMessage::ModuleMessage(msg))
+                                            .send(RouterThreadMessage::ModuleMessage(msg))
                                             .expect(
                                                 "Fail to relay specific role message to broadcasting thread !",
                                             );
                                     }
                                 }
                                 DursMsgReceiver::Event(_module_event) => broadcasting_sender
-                                    .send(RooterThreadMessage::ModuleMessage(msg))
+                                    .send(RouterThreadMessage::ModuleMessage(msg))
                                     .expect("Fail to relay specific event message to broadcasting thread !"),
                                 DursMsgReceiver::One(module_static_name) => {
                                     if let Some(module_sender) =
@@ -491,7 +487,8 @@ pub fn start_rooter(
                 Err(e) => match e {
                     RecvTimeoutError::Timeout => continue,
                     RecvTimeoutError::Disconnected => {
-                        panic!("Fatal error : rooter thread disconnnected !")
+                        warn!("Router thread disconnnected... break main loop.");
+                        break;
                     }
                 },
             }
@@ -503,7 +500,7 @@ pub fn start_rooter(
                     > run_duration_in_secs
             {
                 broadcasting_sender
-                    .send(RooterThreadMessage::ModuleMessage(DursMsg(
+                    .send(RouterThreadMessage::ModuleMessage(DursMsg(
                         DursMsgReceiver::All,
                         DursMsgContent::Stop(),
                     )))
@@ -511,8 +508,8 @@ pub fn start_rooter(
                 break;
             }
         }
-        info!("Rooter thread stop.")
+        info!("Router thread stop.")
     });
 
-    rooter_sender
+    router_sender
 }
diff --git a/module/lib.rs b/module/lib.rs
index 55625dd376819d2481f3ae56db23317a3618b1fa..251afbdad3d800925504d595e32a8c731da403dc 100644
--- a/module/lib.rs
+++ b/module/lib.rs
@@ -207,17 +207,17 @@ pub enum ModuleEvent {
 /// Type returned by module initialization function
 pub enum ModuleInitError {
     /// Fail to load configuration
-    FailToLoadConf(),
+    FailToLoadConf(&'static str),
     /// Unknow error
     UnknowError(),
 }
 
 #[derive(Debug, Clone)]
-/// Type sent by each module to the rooter during initialization
-pub enum RooterThreadMessage<M: ModuleMessage> {
+/// Type sent by each module to the router during initialization
+pub enum RouterThreadMessage<M: ModuleMessage> {
     /// Number of expected modules
     ModulesCount(usize),
-    /// Registration of the module at the rooter
+    /// Registration of the module at the router
     ModuleRegistration(
         ModuleStaticName,
         mpsc::Sender<M>,
@@ -343,17 +343,18 @@ pub trait DuniterModule<DC: DuniterConf, M: ModuleMessage> {
     }
     /// Execute injected subcommand
     fn exec_subcommand(
-        soft_meta_datas: &SoftwareMetaDatas<DC>,
-        keys: RequiredKeysContent,
-        module_conf: Self::ModuleConf,
-        subcommand_args: Self::ModuleOpt,
-    );
+        _soft_meta_datas: &SoftwareMetaDatas<DC>,
+        _keys: RequiredKeysContent,
+        _module_conf: Self::ModuleConf,
+        _subcommand_args: Self::ModuleOpt,
+    ) {
+    }
     /// Launch the module
     fn start(
         soft_meta_datas: &SoftwareMetaDatas<DC>,
         keys: RequiredKeysContent,
         module_conf: Self::ModuleConf,
-        main_sender: mpsc::Sender<RooterThreadMessage<M>>,
+        main_sender: mpsc::Sender<RouterThreadMessage<M>>,
         load_conf_only: bool,
     ) -> Result<(), ModuleInitError>;
 }
diff --git a/network/lib.rs b/network/lib.rs
index 16d3bc43baa844c1f8a45aa6de3d23eca87b915d..a27bad7b0c08a64d7e30d201e7115241494bd93c 100644
--- a/network/lib.rs
+++ b/network/lib.rs
@@ -67,7 +67,7 @@ pub trait NetworkModule<DC: DuniterConf, M: ModuleMessage>: ApiModule<DC, M> {
         soft_meta_datas: &SoftwareMetaDatas<DC>,
         keys: RequiredKeysContent,
         module_conf: <Self as DuniterModule<DC, M>>::ModuleConf,
-        main_sender: mpsc::Sender<RooterThreadMessage<M>>,
+        main_sender: mpsc::Sender<RouterThreadMessage<M>>,
         sync_params: SyncParams,
     ) -> Result<(), ModuleInitError>;
 }
diff --git a/skeleton-module/Cargo.toml b/skeleton-module/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..278f80893862bed3b66a7c14ad7ae187ffac2b95
--- /dev/null
+++ b/skeleton-module/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "durs-skeleton-module"
+version = "0.1.0"
+authors = ["name <mail@domain.tld>"]
+description = "Module template to copy to create a new Durs module."
+license = "AGPL-3.0"
+
+[lib]
+path = "lib.rs"
+
+[dependencies]
+duniter-conf = { path = "../conf" }
+duniter-dal = { path = "../dal" }
+duniter-message =  { path = "../message" }
+duniter-module = { path = "../module" }
+duniter-network = { path = "../network" }
+dup-crypto = { path = "../crypto" }
+log = "0.4.*"
+serde = "1.0.*"
+serde_derive = "1.0.*"
+serde_json = "1.0.*"
+structopt= "0.2.*"
+
+[features]
+# Treat warnings as a build error.
+strict = []
\ No newline at end of file
diff --git a/skeleton-module/lib.rs b/skeleton-module/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8b9f579986f47e8d4736cbd8b36e994d4d59082b
--- /dev/null
+++ b/skeleton-module/lib.rs
@@ -0,0 +1,307 @@
+//  Copyright (C) 2018  The Duniter Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Module template to copy to create a new Durs module.
+
+#![cfg_attr(feature = "strict", deny(warnings))]
+#![deny(
+    missing_docs,
+    missing_debug_implementations,
+    missing_copy_implementations,
+    trivial_casts,
+    trivial_numeric_casts,
+    unsafe_code,
+    unstable_features,
+    unused_import_braces,
+    unused_qualifications
+)]
+
+#[macro_use]
+extern crate log;
+#[macro_use]
+extern crate serde_derive;
+#[macro_use]
+extern crate structopt;
+
+extern crate duniter_conf;
+extern crate duniter_dal;
+extern crate duniter_message;
+extern crate duniter_module;
+extern crate dup_crypto;
+extern crate serde;
+extern crate serde_json;
+
+use duniter_conf::DuRsConf;
+use duniter_dal::dal_event::DALEvent;
+use duniter_message::*;
+use duniter_module::*;
+use std::ops::Deref;
+use std::sync::mpsc;
+use std::thread;
+use std::time::{Duration, SystemTime};
+
+/// Name of your module
+pub static MODULE_NAME: &'static str = "skeleton";
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+/// Skeleton Module Configuration
+pub struct SkeletonConf {
+    test_fake_conf_field: String,
+}
+
+impl Default for SkeletonConf {
+    fn default() -> Self {
+        SkeletonConf {
+            test_fake_conf_field: String::from("default value"),
+        }
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+/// Message from others thread of skeleton module
+pub enum SkeletonThreadMsg {}
+
+#[derive(Debug, Clone)]
+/// Format of messages received by the skeleton module
+pub enum SkeletonMsg {
+    /// Message from another module
+    DursMsg(Box<DursMsg>),
+    /// Message from others thread of skeleton module
+    SkeletonThreadMsg(SkeletonThreadMsg),
+}
+
+#[derive(StructOpt, Debug, Clone)]
+#[structopt(
+    name = "skeleton",
+    raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+)]
+/// Skeleton subcommand options
+pub struct SkeletonOpt {
+    /// Change test conf fake field
+    pub new_conf_field: String,
+}
+
+#[derive(Debug, Clone)]
+/// Data that the Skeleton module needs to cache
+pub struct SkeletonModuleDatas {
+    /// Sender of all child threads (except the proxy thread)
+    pub child_threads: Vec<mpsc::Sender<SkeletonMsg>>,
+    /// Any data
+    pub field: usize,
+}
+
+#[derive(Debug, Copy, Clone)]
+/// Skeleton module
+pub struct SkeletonModule {}
+
+impl Default for SkeletonModule {
+    fn default() -> SkeletonModule {
+        SkeletonModule {}
+    }
+}
+
+impl DuniterModule<DuRsConf, DursMsg> for SkeletonModule {
+    type ModuleConf = SkeletonConf;
+    type ModuleOpt = SkeletonOpt;
+
+    fn name() -> ModuleStaticName {
+        ModuleStaticName(MODULE_NAME)
+    }
+    fn priority() -> ModulePriority {
+        //ModulePriority::Recommended()
+        ModulePriority::Optional()
+    }
+    fn ask_required_keys() -> RequiredKeys {
+        RequiredKeys::None()
+    }
+    fn have_subcommand() -> bool {
+        true
+    }
+    fn exec_subcommand(
+        soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
+        _keys: RequiredKeysContent,
+        module_conf: Self::ModuleConf,
+        subcommand_args: Self::ModuleOpt,
+    ) {
+        let mut conf = soft_meta_datas.conf.clone();
+        let new_skeleton_conf = SkeletonConf {
+            test_fake_conf_field: subcommand_args.new_conf_field.clone(),
+        };
+        conf.set_module_conf(
+            MODULE_NAME.to_owned(),
+            serde_json::value::to_value(new_skeleton_conf)
+                .expect("Fail to jsonifie SkeletonConf !"),
+        );
+        duniter_conf::write_conf_file(&soft_meta_datas.profile, &conf)
+            .expect("Fail to write new conf file ! ");
+        println!(
+            "Succesfully exec skeleton subcommand whit terminal name : {} and conf={:?}!",
+            subcommand_args.new_conf_field, module_conf
+        )
+    }
+    fn start(
+        _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
+        _keys: RequiredKeysContent,
+        _conf: Self::ModuleConf,
+        router_sender: mpsc::Sender<RouterThreadMessage<DursMsg>>,
+        load_conf_only: bool,
+    ) -> Result<(), ModuleInitError> {
+        let _start_time = SystemTime::now();
+
+        // load conf
+        if load_conf_only {
+            // Check conf validity
+            // ...
+            let conf_valid = true;
+
+            // If the configuration is valid, we return OK.
+            if conf_valid {
+                return Ok(());
+            } else {
+                // If the configuration is invalid, an error message is returned
+                return Err(ModuleInitError::FailToLoadConf(
+                    "write the details of the error here",
+                ));
+            }
+        }
+
+        // Instanciate Skeleton module datas
+        let datas = SkeletonModuleDatas {
+            child_threads: Vec::new(),
+            field: 3,
+        };
+
+        // Create skeleton main thread channel
+        let (skeleton_sender, skeleton_receiver): (
+            mpsc::Sender<SkeletonMsg>,
+            mpsc::Receiver<SkeletonMsg>,
+        ) = mpsc::channel();
+
+        // Create proxy channel
+        let (proxy_sender, proxy_receiver): (
+            mpsc::Sender<DursMsg>,
+            mpsc::Receiver<DursMsg>,
+        ) = mpsc::channel();
+
+        // Launch a proxy thread that transform DursMsgContent() to SkeleonMsg::DursMsgContent(DursMsgContent())
+        let router_sender_clone = router_sender.clone();
+        let skeleton_sender_clone = skeleton_sender.clone();
+        thread::spawn(move || {
+            // Send skeleton module registration to router thread
+            router_sender_clone
+                .send(RouterThreadMessage::ModuleRegistration(
+                    ModuleStaticName(MODULE_NAME),
+                    proxy_sender, // Messages sent by the router will be received by your proxy thread
+                    vec![ModuleRole::UserInterface], // Roles assigned to your module
+                    vec![ModuleEvent::NewValidBlock], // Events to which your module subscribes
+                    vec![],
+                    vec![],
+                ))
+                .expect("Fatal error : skeleton module fail to register to router !"); // The registration of your module must be successful, in case of failure the program must be interrupted.
+
+            // If we are here it means that your module has successfully registered, we indicate it in the debug level log, it can be helpful.
+            debug!("Send skeleton module registration to router thread.");
+
+            /*
+             * Main loop of your proxy thread
+             */
+            loop {
+                match proxy_receiver.recv() {
+                    Ok(message) => {
+                        let stop = if let DursMsg(_, DursMsgContent::Stop()) = message {
+                            true
+                        } else {
+                            false
+                        };
+                        if skeleton_sender_clone
+                            .send(SkeletonMsg::DursMsg(Box::new(message)))
+                            .is_err()
+                        {
+                            // Log error
+                            warn!(
+                                "Skeleton proxy : fail to relay DursMsg to skeleton main thread !"
+                            )
+                        }
+                        if stop {
+                            break;
+                        }
+                    }
+                    Err(e) => {
+                        // Log error
+                        warn!("{}", e);
+                        break;
+                    }
+                }
+            }
+        });
+
+        /*
+         * Main loop of your module
+         */
+        loop {
+            // Get messages
+            match skeleton_receiver.recv_timeout(Duration::from_millis(250)) {
+                Ok(ref message) => match *message {
+                    SkeletonMsg::DursMsg(ref duniter_message) => {
+                        match (*duniter_message.deref()).1 // Match Durs message content
+                        {
+                            DursMsgContent::Stop() => {
+                                // Relay stop signal to all child threads
+                                let _result_stop_propagation: Result<
+                                    (),
+                                    mpsc::SendError<SkeletonMsg>,
+                                > = datas
+                                    .child_threads
+                                    .iter()
+                                    .map(|t| t.send(SkeletonMsg::DursMsg(Box::new(DursMsg(DursMsgReceiver::All, DursMsgContent::Stop())))))
+                                    .collect();
+                                // Relay stop signal to router
+                                let _result = router_sender.send(RouterThreadMessage::ModuleMessage(DursMsg(DursMsgReceiver::All, DursMsgContent::Stop())));
+                                // Break main loop
+                                break;
+                            }
+                            DursMsgContent::DALEvent(ref dal_event) => match *dal_event {
+                                DALEvent::StackUpValidBlock(ref _block, ref _blockstamp) => {
+                                    // Do something when the node has stacked a new block at its local blockchain
+                                }
+                                DALEvent::RevertBlocks(ref _blocks) => {
+                                    // Do something when the node has destacked blocks from its local blockchain (roll back)
+                                }
+                                _ => {} // Do nothing for events that don't concern your module.
+                            },
+                            _ => {} // Do nothing for DursMsgContent variants that don't concern your module.
+                        }
+                    }
+                    SkeletonMsg::SkeletonThreadMsg(ref _child_thread_msg) => {
+                        // Do something when receive a message from child thread.
+                    }
+                },
+                Err(e) => match e {
+                    mpsc::RecvTimeoutError::Disconnected => {
+                        panic!("Disconnected skeleton module !");
+                    }
+                    mpsc::RecvTimeoutError::Timeout => {
+                        // If you arrive here it's because your main thread did not receive anything at the end of the timeout.
+                        // This is quite normal and happens regularly when there is little activity, there is nothing particular to do.
+                    }
+                },
+            }
+            // If you want your module's main thread to do things even when it doesn't receive any messages, this is the place where it can do them.
+            // ...
+        }
+        // If we reach this point it means that the module has stopped correctly, so we return OK.
+        Ok(())
+    }
+}
diff --git a/src/main.rs b/src/main.rs
index 0ef666e3306801eb8c037a5ad749443cbc36cf6e..2fcc961973d70e01098216cbbab4220a4afd003c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -33,6 +33,7 @@ extern crate duniter_core;
 
 #[cfg(unix)]
 extern crate duniter_tui;
+//extern crate durs_skeleton_module;
 extern crate durs_ws2p_v1_legacy;
 //extern crate durs_ws2p;
 extern crate structopt;
@@ -40,6 +41,7 @@ extern crate structopt;
 pub use duniter_core::{cli::DursOpt, DuRsConf, DuniterCore, UserCommand};
 #[cfg(unix)]
 pub use duniter_tui::TuiModule;
+//pub use durs_skeleton_module::SkeletonModule;
 pub use durs_ws2p_v1_legacy::WS2PModule;
 //pub use durs_ws2p::WS2Pv2Module;
 use structopt::StructOpt;
@@ -49,8 +51,8 @@ use structopt::StructOpt;
 #[cfg(not(target_arch = "arm"))]
 fn main() {
     durs_core_server!(
-        durs_inject_cli![WS2PModule, TuiModule /*,DasaModule*/],
-        durs_plug!([WS2PModule], [TuiModule /*,DasaModule*/])
+        durs_inject_cli![WS2PModule /*, SkeletonModule ,DasaModule*/],
+        durs_plug!([WS2PModule], [TuiModule /*, SkeletonModule ,DasaModule*/])
     );
 }
 #[cfg(unix)]
diff --git a/tui/lib.rs b/tui/lib.rs
index 21beb0fe31b9155653149ca65d27ddff0db1e634..2d4dbb1abaa267b55c5a528e9e87754c47b06ded 100644
--- a/tui/lib.rs
+++ b/tui/lib.rs
@@ -93,16 +93,13 @@ pub enum TuiMess {
 /// Tui module
 pub struct TuiModule {}
 
-#[derive(StructOpt, Debug, Clone)]
+#[derive(StructOpt, Debug, Copy, Clone)]
 #[structopt(
     name = "tui",
     raw(setting = "structopt::clap::AppSettings::ColoredHelp")
 )]
 /// Tui subcommand options
-pub struct TuiOpt {
-    /// Change test conf fake field
-    pub new_conf_field: String,
-}
+pub struct TuiOpt {}
 
 #[derive(Debug, Clone)]
 /// Network connexion (data to display)
@@ -405,35 +402,11 @@ impl DuniterModule<DuRsConf, DursMsg> for TuiModule {
     fn ask_required_keys() -> RequiredKeys {
         RequiredKeys::None()
     }
-    fn have_subcommand() -> bool {
-        true
-    }
-    fn exec_subcommand(
-        soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
-        _keys: RequiredKeysContent,
-        module_conf: Self::ModuleConf,
-        subcommand_args: TuiOpt,
-    ) {
-        let mut conf = soft_meta_datas.conf.clone();
-        let new_tui_conf = TuiConf {
-            test_fake_conf_field: subcommand_args.new_conf_field.clone(),
-        };
-        conf.set_module_conf(
-            Self::name().to_string(),
-            serde_json::value::to_value(new_tui_conf).expect("Fail to jsonifie TuiConf !"),
-        );
-        duniter_conf::write_conf_file(&soft_meta_datas.profile, &conf)
-            .expect("Fail to write new Tui conf file ! ");
-        println!(
-            "Succesfully exec tui subcommand whit terminal name : {} and conf={:?}!",
-            subcommand_args.new_conf_field, module_conf
-        )
-    }
     fn start(
         _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
         _keys: RequiredKeysContent,
         _conf: Self::ModuleConf,
-        main_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
+        main_sender: mpsc::Sender<RouterThreadMessage<DursMsg>>,
         load_conf_only: bool,
     ) -> Result<(), ModuleInitError> {
         let start_time = SystemTime::now(); //: DateTime<Utc> = Utc::now();
@@ -467,7 +440,7 @@ impl DuniterModule<DuRsConf, DursMsg> for TuiModule {
         thread::spawn(move || {
             // Send proxy sender to main
             main_sender
-                .send(RooterThreadMessage::ModuleRegistration(
+                .send(RouterThreadMessage::ModuleRegistration(
                     TuiModule::name(),
                     proxy_sender,
                     vec![ModuleRole::UserInterface],
diff --git a/ws2p-v1-legacy/datas.rs b/ws2p-v1-legacy/datas.rs
index 8eda264256f9351a62cd24200dffa133acb2f84c..fecfb7aecad44c9e623fab5421966acebb3dc0c5 100644
--- a/ws2p-v1-legacy/datas.rs
+++ b/ws2p-v1-legacy/datas.rs
@@ -28,7 +28,7 @@ use *;
 
 #[derive(Debug)]
 pub struct WS2PModuleDatas {
-    pub rooter_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
+    pub router_sender: mpsc::Sender<RouterThreadMessage<DursMsg>>,
     pub currency: Option<String>,
     pub key_pair: Option<KeyPairEnum>,
     pub conf: WS2PConf,
@@ -66,8 +66,8 @@ impl WS2PModuleDatas {
         if self.count_dal_requests == std::u32::MAX {
             self.count_dal_requests = 0;
         }
-        self.rooter_sender
-            .send(RooterThreadMessage::ModuleMessage(DursMsg(
+        self.router_sender
+            .send(RouterThreadMessage::ModuleMessage(DursMsg(
                 DursMsgReceiver::Role(ModuleRole::BlockchainDatas),
                 DursMsgContent::Request(DursReq {
                     requester: WS2PModule::name(),
@@ -75,19 +75,19 @@ impl WS2PModuleDatas {
                     content: DursReqContent::DALRequest(req.clone()),
                 }),
             )))
-            .expect("Fail to send message to rooter !");
+            .expect("Fail to send message to router !");
     }
     pub fn send_network_req_response(
         &self,
         requester: ModuleStaticName,
         response: NetworkResponse,
     ) {
-        self.rooter_sender
-            .send(RooterThreadMessage::ModuleMessage(DursMsg(
+        self.router_sender
+            .send(RouterThreadMessage::ModuleMessage(DursMsg(
                 DursMsgReceiver::One(requester),
                 DursMsgContent::NetworkResponse(response),
             )))
-            .expect("Fail to send message to rooter !");
+            .expect("Fail to send message to router !");
     }
     pub fn send_network_event(&self, event: &NetworkEvent) {
         let module_event = match event {
@@ -108,12 +108,12 @@ impl WS2PModuleDatas {
             NetworkEvent::ReceiveHeads(_) => ModuleEvent::NewValidHeadFromNetwork,
             NetworkEvent::ReceivePeers(_) => ModuleEvent::NewValidPeerFromNodeNetwork,
         };
-        self.rooter_sender
-            .send(RooterThreadMessage::ModuleMessage(DursMsg(
+        self.router_sender
+            .send(RouterThreadMessage::ModuleMessage(DursMsg(
                 DursMsgReceiver::Event(module_event),
                 DursMsgContent::NetworkEvent(event.clone()),
             )))
-            .expect("Fail to send network event to rooter !");
+            .expect("Fail to send network event to router !");
     }
     pub fn get_network_consensus(&self) -> Result<Blockstamp, NetworkConsensusError> {
         let mut count_known_blockstamps = 0;
diff --git a/ws2p-v1-legacy/lib.rs b/ws2p-v1-legacy/lib.rs
index a8e71cae6215544fd33aa38c4f0faf899d9913fe..c7c6112d526ba5449c9e115e24770d1c700c7d45 100644
--- a/ws2p-v1-legacy/lib.rs
+++ b/ws2p-v1-legacy/lib.rs
@@ -225,7 +225,7 @@ impl NetworkModule<DuRsConf, DursMsg> for WS2PModule {
         _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
         _keys: RequiredKeysContent,
         _conf: WS2PConf,
-        _main_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
+        _main_sender: mpsc::Sender<RouterThreadMessage<DursMsg>>,
         _sync_params: SyncParams,
     ) -> Result<(), ModuleInitError> {
         println!("Downlaod blockchain from network...");
@@ -270,7 +270,7 @@ impl DuniterModule<DuRsConf, DursMsg> for WS2PModule {
         soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
         keys: RequiredKeysContent,
         conf: WS2PConf,
-        rooter_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
+        router_sender: mpsc::Sender<RouterThreadMessage<DursMsg>>,
         load_conf_only: bool,
     ) -> Result<(), ModuleInitError> {
         // Get start time
@@ -278,7 +278,7 @@ impl DuniterModule<DuRsConf, DursMsg> for WS2PModule {
 
         // Define WS2PModuleDatas
         let mut ws2p_module = WS2PModuleDatas {
-            rooter_sender: rooter_sender.clone(),
+            router_sender: router_sender.clone(),
             key_pair: None,
             currency: None,
             conf,
@@ -324,8 +324,8 @@ impl DuniterModule<DuRsConf, DursMsg> for WS2PModule {
         // Launch a proxy thread that transform DursMsg to WS2PThreadSignal(DursMsg)
         thread::spawn(move || {
             // Send proxy sender to main
-            rooter_sender
-                .send(RooterThreadMessage::ModuleRegistration(
+            router_sender
+                .send(RouterThreadMessage::ModuleRegistration(
                     WS2PModule::name(),
                     proxy_sender_clone,
                     vec![ModuleRole::InterNodesNetwork],
diff --git a/ws2p/lib.rs b/ws2p/lib.rs
index 4e1ba400daa26a212b8864028d92650d38315522..4a37782acf12c28b0557ffed4ccb99dcfbea52fa 100644
--- a/ws2p/lib.rs
+++ b/ws2p/lib.rs
@@ -124,7 +124,7 @@ impl NetworkModule<DuRsConf, DursMsg> for WS2Pv2Module {
         _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
         _keys: RequiredKeysContent,
         _conf: WS2PConf,
-        _main_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
+        _main_sender: mpsc::Sender<RouterThreadMessage<DursMsg>>,
         _sync_params: SyncParams,
     ) -> Result<(), ModuleInitError> {
         unimplemented!()
@@ -167,7 +167,7 @@ impl DuniterModule<DuRsConf, DursMsg> for WS2Pv2Module {
         _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
         _keys: RequiredKeysContent,
         _conf: WS2PConf,
-        _rooter_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
+        _router_sender: mpsc::Sender<RouterThreadMessage<DursMsg>>,
         _load_conf_only: bool,
     ) -> Result<(), ModuleInitError> {
         unimplemented!()