diff --git a/dist/iotAmak-0.0.7-py3-none-any.whl b/dist/iotAmak-0.0.7-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..6b8729469c70282fe1274145a88acef11cfe9f1a
Binary files /dev/null and b/dist/iotAmak-0.0.7-py3-none-any.whl differ
diff --git a/iotAmak/tool/__init__.py b/iotAmak/agent/__init__.py
similarity index 100%
rename from iotAmak/tool/__init__.py
rename to iotAmak/agent/__init__.py
diff --git a/iotAmak/agent/agent.py b/iotAmak/agent/agent.py
new file mode 100644
index 0000000000000000000000000000000000000000..4af7fb9e13b14583ade030d795f85664a4d72f49
--- /dev/null
+++ b/iotAmak/agent/agent.py
@@ -0,0 +1,68 @@
+"""
+Agent class file
+"""
+import json
+import sys
+import pathlib
+from typing import Dict
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+from iotAmak.base.schedulable import Schedulable
+from iotAmak.agent.base_agent import BaseAgent
+
+
+class Agent(Schedulable, BaseAgent):
+    """
+    base class for agent
+    """
+
+    def __init__(self, arguments: str) -> None:
+
+        arguments: Dict = json.loads(arguments)
+
+        broker_ip: str = arguments.get("broker_ip")
+        identifier: int = int(arguments.get("identifier"))
+        seed: int = int(arguments.get("seed"))
+        broker_username: str = str(arguments.get("broker_username"))
+        broker_password: str = str(arguments.get("broker_password"))
+
+        Schedulable.__init__(self, broker_ip, "Agent" + str(identifier), broker_username, broker_password)
+        BaseAgent.__init__(self, identifier, seed)
+
+        self.subscribe("scheduler/agent/wakeup", self.wake_up)
+
+        self.on_initialization()
+
+        self.publish("cycle_done", "")
+
+    def publish(self, topic: str, message) -> None:
+        """
+        publish a message on the topic
+        :param topic: str
+        :param message: content of the message
+        """
+        self.client.publish("agent/" + str(self.id) + "/" + topic, message)
+
+    def run(self) -> None:
+        """
+        Main method of the agent
+        """
+        while not self.exit_bool:
+
+            self.wait()
+            if self.exit_bool:
+                return
+
+            self.on_cycle_begin()
+
+            self.on_perceive()
+
+            self.on_decide()
+
+            self.on_act()
+
+            self.on_cycle_end()
+
+            self.publish("metric", str(self.send_metric()))
+            self.publish("cycle_done", "")
+            self.nbr_cycle += 1
diff --git a/iotAmak/agent/async_agent.py b/iotAmak/agent/async_agent.py
new file mode 100644
index 0000000000000000000000000000000000000000..a2653d552e6e29ca63e450d1a5103fe6dafeb169
--- /dev/null
+++ b/iotAmak/agent/async_agent.py
@@ -0,0 +1,57 @@
+"""
+AsyncAgent class file
+"""
+import pathlib
+import sys
+import json
+from typing import Dict
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+from iotAmak.base.async_controlable import AsyncControlable
+from iotAmak.agent.base_agent import BaseAgent
+
+
+class AsyncAgent(AsyncControlable, BaseAgent):
+    """
+    Async class for agent
+    """
+
+    def __init__(self, arguments: str) -> None:
+
+        arguments: Dict = json.loads(arguments)
+
+        broker_ip: str = arguments.get("broker_ip")
+        identifier: int = int(arguments.get("identifier"))
+        seed: int = int(arguments.get("seed"))
+        broker_username: str = str(arguments.get("broker_username"))
+        broker_password: str = str(arguments.get("broker_password"))
+        wait_delay: float = float(arguments.get("wait_delay"))
+
+        AsyncControlable.__init__(
+            self,
+            broker_ip,
+            "Agent" + str(identifier),
+            broker_username,
+            broker_password,
+            wait_delay
+        )
+        BaseAgent.__init__(self, identifier, seed)
+
+        self.on_initialization()
+
+    def publish(self, topic: str, message) -> None:
+        """
+        publish a message on the topic
+        :param topic: str
+        :param message: content of the message
+        """
+        self.client.publish("agent/" + str(self.id) + "/" + topic, message)
+
+    def behaviour(self) -> None:
+        self.on_cycle_begin()
+        self.on_perceive()
+        self.on_decide()
+        self.on_act()
+        self.on_cycle_end()
+        self.publish("metric", str(self.send_metric()))
+
diff --git a/iotAmak/agent/async_communicating_agent.py b/iotAmak/agent/async_communicating_agent.py
new file mode 100644
index 0000000000000000000000000000000000000000..fb221b413c9cbbe810d1060f27cad3751fcf808a
--- /dev/null
+++ b/iotAmak/agent/async_communicating_agent.py
@@ -0,0 +1,16 @@
+import pathlib
+import sys
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+from iotAmak.agent.async_agent import AsyncAgent
+from iotAmak.agent.base_communicating_agent import BaseCommunicatingAgent
+
+
+class AsyncCommunicatingAgent(AsyncAgent, BaseCommunicatingAgent):
+    """
+    Agent class that can communicate
+    """
+
+    def __init__(self, arguments: str) -> None:
+        AsyncAgent.__init__(self, arguments)
+        BaseCommunicatingAgent.__init__(self)
diff --git a/iotAmak/agent.py b/iotAmak/agent/base_agent.py
similarity index 52%
rename from iotAmak/agent.py
rename to iotAmak/agent/base_agent.py
index 8ccb58e98cad2db0dbdaf60962f57b54ee0b4af7..4d31dd2b8c7a1f3aefa598139eaf385604cf6749 100644
--- a/iotAmak/agent.py
+++ b/iotAmak/agent/base_agent.py
@@ -1,140 +1,81 @@
 """
-Agent class file
+Base Agent class file
 """
-import json
 import random
 from ast import literal_eval
 from typing import Dict, List
 
-import sys
-import pathlib
 
-sys.path.insert(0, str(pathlib.Path(__file__).parent))
-
-from iotAmak.tool.schedulable import Schedulable
-
-
-class Agent(Schedulable):
+class BaseAgent:
     """
     base class for agent
     """
 
-    def __init__(self, arguments: str) -> None:
-
-        arguments: Dict = json.loads(arguments)
-
-        broker_ip: str = arguments.get("broker_ip")
-        identifier: int = int(arguments.get("identifier"))
-        seed: int = int(arguments.get("seed"))
-        broker_username: str = str(arguments.get("broker_username"))
-        broker_password: str = str(arguments.get("broker_password"))
-
+    def __init__(self, identifier: int, seed: int) -> None:
         self.id: int = identifier
-
         random.seed(seed + 10 + self.id)
 
-        Schedulable.__init__(self, broker_ip, "Agent" + str(self.id), broker_username, broker_password)
-
-        self.subscribe("scheduler/agent/wakeup", self.wake_up)
-
         self.neighbors: List[Dict] = []
         self.next_neighbors: List[Dict] = []
         self.subscribe("amas/agent/" + str(self.id) + "/neighbor", self.add_neighbor)
 
-        self.on_initialization()
-
-        self.publish("cycle_done", "")
-        print("init done")
-
     def on_initialization(self) -> None:
         """
         This method will be executed at the end of __init__()
         """
         pass
 
-    def add_neighbor(self, client, userdata, message) -> None:
-        """
-        Called when the agent, receive metrics
-        put the metric in a list that will be rad during on_perceive
-        param message: metric (dict) of the neighbor
-        """
-        result: Dict = literal_eval(message.payload.decode("utf-8"))
-        self.next_neighbors.append(result)
-
-    def log(self, message: str) -> None:
-        """
-        Convenient method to log things (will be printed in the amas's stdout
-        :param message:
-        """
-        self.client.publish(
-            "agent/" + str(self.id) + "/log",
-            "[AGENT] " + str(self.id) + " : " + message
-        )
-
-    def publish(self, topic: str, message) -> None:
-        """
-        publish a message on the topic
-        :param topic: str
-        :param message: content of the message
-        """
-        self.client.publish("agent/" + str(self.id) + "/" + topic, message)
-
     def on_cycle_begin(self) -> None:
         """
         This method will be executed at the start of each cycle
         """
-        self.log("on_cycle_begin")
+        pass
 
     def on_perceive(self) -> None:
         """
         Method that should be used to open the neighbor metrics and use them
         """
-        self.log("on_perceive")
+        pass
 
     def on_decide(self) -> None:
         """
         Should be override
         """
-        self.log("on_decide")
+        pass
 
     def on_act(self) -> None:
         """
         Should be override
         """
-        self.log("on_act")
+        pass
 
     def on_cycle_end(self) -> None:
         """
         This method will be executed at the end of each cycle
         """
-        self.log("on_cycle_end")
+        pass
 
-    def send_metric(self) -> Dict:
+    def add_neighbor(self, client, userdata, message) -> None:
         """
-        Should be override if the neighbor need to be aware of any other info, should be a dict
+        Called when the agent, receive metrics
+        put the metric in a list that will be rad during on_perceive
+        param message: metric (dict) of the neighbor
         """
-        return {"id": self.id}
+        result: Dict = literal_eval(message.payload.decode("utf-8"))
+        self.next_neighbors.append(result)
 
-    def run(self) -> None:
+    def log(self, message: str) -> None:
         """
-        Main method of the agent
+        Convenient method to log things (will be printed in the amas's stdout
+        :param message:
         """
-        while not self.exit_bool:
-
-            self.wait()
-            if self.exit_bool:
-                return
-
-            self.on_cycle_begin()
-
-            self.on_perceive()
-
-            self.on_decide()
-
-            self.on_act()
-
-            self.on_cycle_end()
+        self.client.publish(
+            "agent/" + str(self.id) + "/log",
+            "[AGENT] " + str(self.id) + " : " + message
+        )
 
-            self.publish("metric", str(self.send_metric()))
-            self.publish("cycle_done", "")
-            self.nbr_cycle += 1
+    def send_metric(self) -> Dict:
+        """
+        Should be override if the neighbor need to be aware of any other info, should be a dict
+        """
+        return {"id": self.id}
diff --git a/iotAmak/communicating_agent.py b/iotAmak/agent/base_communicating_agent.py
similarity index 86%
rename from iotAmak/communicating_agent.py
rename to iotAmak/agent/base_communicating_agent.py
index 0600ea957d83888b181750ec2b1389e413a3835f..81cc8d1aab8fa4da57f5c8faf0d537c431b2149f 100644
--- a/iotAmak/communicating_agent.py
+++ b/iotAmak/agent/base_communicating_agent.py
@@ -4,20 +4,17 @@ import sys
 from ast import literal_eval
 from typing import List, Any
 
-sys.path.insert(0, str(pathlib.Path(__file__).parent))
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+from iotAmak.agent.mail import Mail
 
-from iotAmak.agent import Agent
-from iotAmak.tool.mail import Mail
 
-
-class CommunicatingAgent(Agent):
+class BaseCommunicatingAgent:
     """
     Agent class that can communicate
     """
 
-    def __init__(self, arguments: str) -> None:
+    def __init__(self) -> None:
         self.mailbox: List[Mail] = []
-        Agent.__init__(self, arguments)
         self.subscribe("agent/" + str(self.id) + "/mail", self.receive_mail)
 
     def receive_mail(self, client, userdata, message) -> None:
@@ -57,7 +54,3 @@ class CommunicatingAgent(Agent):
         put the mail in the front of the mailbox
         """
         self.mailbox = [mail] + self.mailbox
-
-
-
-
diff --git a/iotAmak/agent/communicating_agent.py b/iotAmak/agent/communicating_agent.py
new file mode 100644
index 0000000000000000000000000000000000000000..8cebdfa5be381a19587fe4aa682500686fe9acfa
--- /dev/null
+++ b/iotAmak/agent/communicating_agent.py
@@ -0,0 +1,16 @@
+import pathlib
+import sys
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+from iotAmak.agent.agent import Agent
+from iotAmak.agent.base_communicating_agent import BaseCommunicatingAgent
+
+
+class CommunicatingAgent(Agent, BaseCommunicatingAgent):
+    """
+    Agent class that can communicate
+    """
+
+    def __init__(self, arguments: str) -> None:
+        Agent.__init__(self, arguments)
+        BaseCommunicatingAgent.__init__(self)
diff --git a/iotAmak/tool/mail.py b/iotAmak/agent/mail.py
similarity index 100%
rename from iotAmak/tool/mail.py
rename to iotAmak/agent/mail.py
diff --git a/iotAmak/amas/__init__.py b/iotAmak/amas/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/iotAmak/amas/amas.py b/iotAmak/amas/amas.py
new file mode 100644
index 0000000000000000000000000000000000000000..391bdbb484dec3be6d3ddbe0bb6c99b9191aadff
--- /dev/null
+++ b/iotAmak/amas/amas.py
@@ -0,0 +1,79 @@
+"""
+Amas class
+"""
+import json
+from ast import literal_eval
+
+import sys
+import pathlib
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+from iotAmak.ssh_module.remote_client import RemoteClient
+from iotAmak.base.schedulable import Schedulable
+from iotAmak.amas.base_amas import BaseAmas
+
+
+class Amas(Schedulable, BaseAmas):
+    """
+    Amas class
+    """
+
+    def __init__(self, arguments: str) -> None:
+
+        arguments = json.loads(arguments)
+
+        broker_ip: str = arguments.get("broker_ip")
+        clients: str = arguments.get("clients")
+        seed: int = int(arguments.get("seed"))
+        broker_username: str = str(arguments.get("broker_username"))
+        broker_password: str = str(arguments.get("broker_password"))
+        iot_path: str = str(arguments.get("iot_path"))
+        true_client = [RemoteClient(i.get("hostname"), i.get("user"), i.get("password")) for i in literal_eval(clients)]
+
+        Schedulable.__init__(self, broker_ip, "Amas", broker_username, broker_password)
+        self.subscribe("scheduler/schedulable/wakeup", self.wake_up)
+        BaseAmas.__init__(self,
+                          broker_ip,
+                          broker_username,
+                          broker_password,
+                          seed,
+                          iot_path,
+                          true_client)
+
+        self.client.publish("amas/action_done", "")
+
+    def on_cycle_begin(self) -> None:
+        """
+        This method will be executed at the start of each cycle
+        """
+        pass
+
+    def on_cycle_end(self) -> None:
+        """
+        This method will be executed at the end of each cycle
+        """
+        pass
+
+    def run(self) -> None:
+        """
+        Main function of the amas class
+        """
+        self.push_agent()
+
+        while not self.exit_bool:
+
+            self.wait()
+            if self.exit_bool:
+                return
+
+            self.publish("amas/all_metric", str(self.agents_metric))
+            self.on_cycle_begin()
+            self.client.publish("amas/action_done", "")
+
+            # agent cycle
+
+            self.wait()
+            self.on_cycle_end()
+            self.client.publish("amas/action_done", "")
+
+            self.nbr_cycle += 1
diff --git a/iotAmak/amas/async_amas.py b/iotAmak/amas/async_amas.py
new file mode 100644
index 0000000000000000000000000000000000000000..34abb213a8b7d41ab20221c4899ded31d87726f2
--- /dev/null
+++ b/iotAmak/amas/async_amas.py
@@ -0,0 +1,114 @@
+import pathlib
+import sys
+import json
+from ast import literal_eval
+from typing import List
+
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+from iotAmak.amas.base_amas import BaseAmas
+from iotAmak.base.async_controlable import AsyncControlable
+from iotAmak.ssh_module.remote_client import RemoteClient
+from iotAmak.ssh_module.ssh_client import Cmd
+
+
+class AsyncAmas(AsyncControlable, BaseAmas):
+    """
+    Amas class
+    """
+
+    def __init__(self, arguments: str) -> None:
+
+        arguments = json.loads(arguments)
+
+        broker_ip: str = arguments.get("broker_ip")
+        clients: str = arguments.get("clients")
+        seed: int = int(arguments.get("seed"))
+        broker_username: str = str(arguments.get("broker_username"))
+        broker_password: str = str(arguments.get("broker_password"))
+        iot_path: str = str(arguments.get("iot_path"))
+        wait_delay: float = float(arguments.get("wait_delay"))
+
+        true_client = [RemoteClient(i.get("hostname"), i.get("user"), i.get("password")) for i in literal_eval(clients)]
+
+        AsyncControlable.__init__(
+            self,
+            broker_ip,
+            "Amas",
+            broker_username,
+            broker_password,
+            wait_delay
+        )
+        BaseAmas.__init__(self,
+                          broker_ip,
+                          broker_username,
+                          broker_password,
+                          seed,
+                          iot_path,
+                          true_client)
+
+        self.push_agent()
+
+    def on_metric(self) -> None:
+        """
+        This method will be executed everytime a metric is send
+        """
+        pass
+
+    def add_agent(
+            self,
+            experience_name: str,
+            client_ip: str = None,
+            agent_name: str = "agent.py",
+            args: List = None
+    ) -> None:
+        """
+        Function that need to be called to create a new agent
+        :param experience_name: name of the experience folder
+        :param client_ip: if the agent should be created in a specific device, you can specify an ip address,
+        otherwise the Amas will try to share the work between the devices
+        :param agent_name: if using multiple kind of agent, you can specify the relative path in the experiment
+        directory to the agent file to use
+        :param args: if any argument is needed to initiate the new agent
+        :return: None
+        """
+        if args is None:
+            args = []
+
+        arg_dict = {
+            "broker_ip": str(self.broker_ip),
+            "seed": self.seed,
+            "identifier": self.next_id,
+            "broker_username": self.broker_username,
+            "broker_password": self.broker_password,
+            "wait_delay": self.wait_delay
+        }
+
+        command = "nohup python "
+        command += "\'" + self.iot_path + experience_name + "/" + agent_name + "\' \'"
+        command += json.dumps(arg_dict) + "\' "
+        for arg in args:
+            command += str(arg) + " "
+        command += "&"
+
+        if client_ip is None:
+            # find the most suitable pi
+            i_min = 0
+            for elem in range(len(self.clients)):
+                if len(self.agents_cmd[i_min]) > len(self.agents_cmd[elem]):
+                    i_min = elem
+            self.agents_cmd[i_min].append(Cmd(command))
+        else:
+            have_found = False
+            for i_client in range(len(self.clients)):
+                if self.clients[i_client].hostname == client_ip:
+                    self.agents_cmd[i_client].append(Cmd(command))
+                    have_found = True
+                    break
+            if not have_found:
+                self.agents_cmd[0].append(Cmd(command))
+
+        self.subscribe("agent/" + str(self.next_id) + "/metric", self.agent_metric)
+
+        self.client.publish("amas/agent/new", self.next_id)
+        self.next_id += 1
\ No newline at end of file
diff --git a/iotAmak/amas.py b/iotAmak/amas/base_amas.py
similarity index 63%
rename from iotAmak/amas.py
rename to iotAmak/amas/base_amas.py
index d335985a42748eb028d8a15a840c78307adadfd2..c3da4e0e80706e5ed92560374f6ce4f0a9987ccf 100644
--- a/iotAmak/amas.py
+++ b/iotAmak/amas/base_amas.py
@@ -1,56 +1,48 @@
-"""
-Amas class
-"""
 import json
-from ast import literal_eval
-from typing import List, Dict
-
+import random
 import sys
 import pathlib
-import random
-
-sys.path.insert(0, str(pathlib.Path(__file__).parent))
-
-from iotAmak.tool.remote_client import RemoteClient
-from iotAmak.tool.schedulable import Schedulable
-from iotAmak.tool.ssh_client import SSHClient, Cmd
+from ast import literal_eval
+from typing import List, Dict
 
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+from iotAmak.ssh_module.ssh_client import SSHClient, Cmd
+from iotAmak.ssh_module.remote_client import RemoteClient
 
-class Amas(Schedulable, SSHClient):
-    """
-    Amas class
-    """
 
-    def __init__(self, arguments: str) -> None:
+class BaseAmas(SSHClient):
 
-        arguments = json.loads(arguments)
+    def __init__(
+            self,
+            broker_ip: str,
+            broker_username: str,
+            broker_password: str,
+            seed: int,
+            iot_path: str,
+            clients: List[RemoteClient]
+    ):
+        self.broker_ip: str = broker_ip
+        self.broker_username: str = broker_username
+        self.broker_password: str = broker_password
 
-        self.broker_ip: str = arguments.get("broker_ip")
-        clients: str = arguments.get("clients")
-        self.seed: int = int(arguments.get("seed"))
-        self.broker_username: str = str(arguments.get("broker_username"))
-        self.broker_password: str = str(arguments.get("broker_password"))
-        iot_path: str = str(arguments.get("iot_path"))
+        self.next_id: int = 0
 
+        self.seed: int = seed
         random.seed(self.seed)
 
-        Schedulable.__init__(self, self.broker_ip, "Amas", self.broker_username, self.broker_password)
+        self.agents_cmd: List[List[Cmd]] = [[] for _ in range(len(clients))]
 
-        true_client = [RemoteClient(i.get("hostname"), i.get("user"), i.get("password")) for i in literal_eval(clients)]
-
-        SSHClient.__init__(self, true_client, iot_path)
-
-        self.subscribe("scheduler/schedulable/wakeup", self.wake_up)
-
-        self.next_id: int = 0
-
-        self.agents_cmd: List[List[Cmd]] = [[] for _ in range(len(self.clients))]
+        SSHClient.__init__(self, clients, iot_path)
 
         self.on_initialization()
         self.on_initial_agents_creation()
         self.agents_metric: List[Dict] = [{} for _ in range(self.next_id)]
 
-        self.client.publish("amas/action_done", "")
+    def on_initialization(self) -> None:
+        """
+        This method will be executed at the end of __init__()
+        """
+        pass
 
     def on_initial_agents_creation(self) -> None:
         """
@@ -83,11 +75,11 @@ class Amas(Schedulable, SSHClient):
             "seed": self.seed,
             "identifier": self.next_id,
             "broker_username": self.broker_username,
-            "broker_password":  self.broker_password
+            "broker_password": self.broker_password
         }
 
         command = "nohup python "
-        command += "\'" + self.iot_path + experience_name + "/"+agent_name+"\' \'"
+        command += "\'" + self.iot_path + experience_name + "/" + agent_name + "\' \'"
         command += json.dumps(arg_dict) + "\' "
         for arg in args:
             command += str(arg) + " "
@@ -138,45 +130,3 @@ class Amas(Schedulable, SSHClient):
         result = literal_eval(message.payload.decode("utf-8"))
         agent_id = result.get("id")
         self.agents_metric[agent_id] = result
-
-    def on_initialization(self) -> None:
-        """
-        This method will be executed at the end of __init__()
-        """
-        pass
-
-    def on_cycle_begin(self) -> None:
-        """
-        This method will be executed at the start of each cycle
-        """
-        pass
-
-    def on_cycle_end(self) -> None:
-        """
-        This method will be executed at the end of each cycle
-        """
-        pass
-
-    def run(self) -> None:
-        """
-        Main function of the amas class
-        """
-        self.push_agent()
-
-        while not self.exit_bool:
-
-            self.wait()
-            if self.exit_bool:
-                return
-
-            self.publish("amas/all_metric", str(self.agents_metric))
-            self.on_cycle_begin()
-            self.client.publish("amas/action_done", "")
-
-            # agent cycle
-
-            self.wait()
-            self.on_cycle_end()
-            self.client.publish("amas/action_done", "")
-
-            self.nbr_cycle += 1
diff --git a/iotAmak/base/__init__.py b/iotAmak/base/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/iotAmak/base/async_controlable.py b/iotAmak/base/async_controlable.py
new file mode 100644
index 0000000000000000000000000000000000000000..c0c71b80b51aee29bb0916f0c700ff59a0317890
--- /dev/null
+++ b/iotAmak/base/async_controlable.py
@@ -0,0 +1,92 @@
+"""
+MQTT client class file
+"""
+import sys
+import pathlib
+from threading import Semaphore
+from time import sleep
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+from iotAmak.base.mqtt_client import MqttClient
+
+
+class AsyncControlable(MqttClient):
+    """
+    Base class to any instance that need to interact with the broker
+    """
+
+    def __init__(
+            self,
+            broker_ip: str,
+            client_id: str,
+            broker_username: str,
+            broker_password: str,
+            wait_delay: float
+    ):
+        MqttClient.__init__(self, broker_ip, client_id, broker_username, broker_password)
+
+        # exit
+        self.exit_bool: bool = False
+        self.subscribe("ihm/exit", self.exit_procedure)
+
+        # pause
+        self.paused: bool = True
+        self.pause_semaphore = Semaphore(0)
+        self.subscribe("ihm/pause", self.pause)
+        self.subscribe("ihm/unpause", self.unpause)
+
+        # time to wait
+        self.wait_delay: float = wait_delay
+
+        self.nbr_cycle: int = 0
+
+    def exit_procedure(self, client, userdata, message) -> None:
+        """
+        Called by the Ihm to exit as soon as possible
+        """
+        self.exit_bool = True
+
+    def pause(self, client, userdata, message) -> None:
+        """
+        Function called when the IHM pause the scheduler
+        """
+        self.paused = True
+
+    def unpause(self, client, userdata, message) -> None:
+        """
+        Function called when the IHM unpause the scheduler
+        """
+        self.paused = False
+        self.pause_semaphore.release()
+
+    def wait(self) -> None:
+        """
+        If the element is paused, wait until unpause was received
+        """
+        if not self.paused:
+            return
+        self.pause_semaphore.acquire()
+
+    def behaviour(self) -> None:
+        """
+        method to override
+        """
+        return
+
+    def run(self) -> None:
+        """
+        Main method of the client
+        """
+
+        while not self.exit_bool:
+            # wait to be unpause
+            self.wait()
+
+            # check the need to exit
+            if self.exit_bool:
+                return
+
+            self.behaviour()
+
+            sleep(self.wait_delay)
+            self.nbr_cycle += 1
diff --git a/iotAmak/tool/mqtt_client.py b/iotAmak/base/mqtt_client.py
similarity index 100%
rename from iotAmak/tool/mqtt_client.py
rename to iotAmak/base/mqtt_client.py
diff --git a/iotAmak/tool/schedulable.py b/iotAmak/base/schedulable.py
similarity index 89%
rename from iotAmak/tool/schedulable.py
rename to iotAmak/base/schedulable.py
index 0a2730446df42961b68d420fbac4134879f3ea71..33ec1ff512b9df28eaf8813473797b33ffccfd06 100644
--- a/iotAmak/tool/schedulable.py
+++ b/iotAmak/base/schedulable.py
@@ -8,7 +8,7 @@ import threading
 
 sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
 
-from iotAmak.tool.mqtt_client import MqttClient
+from iotAmak.base.mqtt_client import MqttClient
 
 
 class Schedulable(MqttClient):
@@ -31,15 +31,12 @@ class Schedulable(MqttClient):
         Called by the scheduler to wake up the schedulable
         """
         self.semaphore.release()
-        # print("Waked up")
 
     def wait(self) -> None:
         """
         Basic wait method
         """
-        # print("Waiting")
         self.semaphore.acquire()
-        # print("End wait")
 
     def exit_procedure(self, client, userdata, message) -> None:
         """
diff --git a/iotAmak/env/__init__.py b/iotAmak/env/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/iotAmak/env/async_env.py b/iotAmak/env/async_env.py
new file mode 100644
index 0000000000000000000000000000000000000000..6d0fceda540ccc95df8fd3b8ba19bf1774b3c8ac
--- /dev/null
+++ b/iotAmak/env/async_env.py
@@ -0,0 +1,36 @@
+"""
+Environment class
+"""
+import json
+import sys
+import pathlib
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+from iotAmak.env.base_env import BaseEnv
+from iotAmak.base.async_controlable import AsyncControlable
+
+
+class AsyncEnvironment(BaseEnv, AsyncControlable):
+    """
+    Environment class
+    """
+
+    def __init__(self, arguments: str) -> None:
+
+        arguments = json.loads(arguments)
+
+        broker_ip: str = arguments.get("broker_ip")
+        seed: int = int(arguments.get("seed"))
+        broker_username: str = str(arguments.get("broker_username"))
+        broker_password: str = str(arguments.get("broker_password"))
+        wait_delay: float = float(arguments.get("wait_delay"))
+
+        AsyncControlable.__init__(
+            self,
+            broker_ip,
+            "Env",
+            broker_username,
+            broker_password,
+            wait_delay
+        )
+        BaseEnv.__init__(self, seed)
diff --git a/iotAmak/env/base_env.py b/iotAmak/env/base_env.py
new file mode 100644
index 0000000000000000000000000000000000000000..905f8fe723365af0d91462c24a7311751dd5aa0d
--- /dev/null
+++ b/iotAmak/env/base_env.py
@@ -0,0 +1,13 @@
+import random
+
+
+class BaseEnv:
+    def __init__(self, seed: int) -> None:
+        random.seed(seed + 1)
+        self.on_initialization()
+
+    def on_initialization(self) -> None:
+        """
+        This method will be executed at the end of __init__()
+        """
+        pass
diff --git a/iotAmak/environment.py b/iotAmak/env/environment.py
similarity index 83%
rename from iotAmak/environment.py
rename to iotAmak/env/environment.py
index b054cbce1c02e029460c69fdc97c85de139da7db..68bbbc17dcd77be91e4dbb56df6e755a97f47453 100644
--- a/iotAmak/environment.py
+++ b/iotAmak/env/environment.py
@@ -7,11 +7,11 @@ import sys
 import pathlib
 
 sys.path.insert(0, str(pathlib.Path(__file__).parent))
+from iotAmak.env.base_env import BaseEnv
+from iotAmak.base.schedulable import Schedulable
 
-from iotAmak.tool.schedulable import Schedulable
 
-
-class Environment(Schedulable):
+class Environment(Schedulable, BaseEnv):
     """
     Environment class
     """
@@ -25,22 +25,11 @@ class Environment(Schedulable):
         broker_username: str = str(arguments.get("broker_username"))
         broker_password: str = str(arguments.get("broker_password"))
 
-        random.seed(seed + 1)
-
         Schedulable.__init__(self, broker_ip, "Env", broker_username, broker_password)
-
         self.subscribe("scheduler/schedulable/wakeup", self.wake_up)
-
-        self.on_initialization()
-
+        BaseEnv.__init__(self, seed)
         self.client.publish("env/action_done", "")
 
-    def on_initialization(self) -> None:
-        """
-        This method will be executed at the end of __init__()
-        """
-        pass
-
     def on_cycle_begin(self) -> None:
         """
         This method will be executed at the start of each cycle
diff --git a/iotAmak/ihm/__init__.py b/iotAmak/ihm/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/iotAmak/tool/confi_reader.py b/iotAmak/ihm/confi_reader.py
similarity index 90%
rename from iotAmak/tool/confi_reader.py
rename to iotAmak/ihm/confi_reader.py
index 5070707f8f3489928519b3870e7632e9d5503888..f761a9c78d982bce57668e2c3905ce1fd9cf80a0 100644
--- a/iotAmak/tool/confi_reader.py
+++ b/iotAmak/ihm/confi_reader.py
@@ -4,7 +4,7 @@ import pathlib
 
 sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
 
-from iotAmak.tool.remote_client import RemoteClient
+from iotAmak.ssh_module.remote_client import RemoteClient
 
 
 def read_ssh(path):
diff --git a/iotAmak/ihm.py b/iotAmak/ihm/ihm.py
similarity index 93%
rename from iotAmak/ihm.py
rename to iotAmak/ihm/ihm.py
index 11b4f190f04962ce01c8e4289f65e01fc9bb03ef..5032f41834a5c734e7a016512c75e54dd22c2dd8 100644
--- a/iotAmak/ihm.py
+++ b/iotAmak/ihm/ihm.py
@@ -9,9 +9,9 @@ import pathlib
 
 sys.path.insert(0, str(pathlib.Path(__file__).parent))
 
-from iotAmak.tool.confi_reader import read_ssh, read_broker
-from iotAmak.tool.mqtt_client import MqttClient
-from iotAmak.tool.ssh_client import SSHClient, Cmd
+from iotAmak.ihm.confi_reader import read_ssh, read_broker
+from iotAmak.base.mqtt_client import MqttClient
+from iotAmak.ssh_module.ssh_client import SSHClient, Cmd
 
 
 class Ihm(MqttClient, SSHClient):
@@ -29,10 +29,10 @@ class Ihm(MqttClient, SSHClient):
     def loading(self):
         print("[LOADING]")
         print("Check experiment:")
-        print(" | -> agent.py : ", path.exists("./agent.py"))
-        print(" | -> amas.py : ", path.exists("./amas.py"))
+        print(" | -> agent.py : ", path.exists("../agent/agent.py"))
+        print(" | -> amas.py : ", path.exists("../amas/amas.py"))
         print(" | -> env.py : ", path.exists("./env.py"))
-        if path.exists("./agent.py") and path.exists("./amas.py") and path.exists("./env.py"):
+        if path.exists("../agent/agent.py") and path.exists("../amas/amas.py") and path.exists("./env.py"):
             self.experiment_loaded = True
             print("Experiment loaded")
         else:
diff --git a/iotAmak/scheduler/__init__.py b/iotAmak/scheduler/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/iotAmak/scheduler.py b/iotAmak/scheduler/scheduler.py
similarity index 97%
rename from iotAmak/scheduler.py
rename to iotAmak/scheduler/scheduler.py
index 19e21ead3e01ca697db0c230f40a2dd5d5abcf2e..d5f22374b54becec8fafe7c8fb8cb96e23852200 100644
--- a/iotAmak/scheduler.py
+++ b/iotAmak/scheduler/scheduler.py
@@ -7,9 +7,8 @@ from time import sleep, time
 import sys
 import pathlib
 
-sys.path.insert(0, str(pathlib.Path(__file__).parent))
-
-from iotAmak.tool.schedulable import Schedulable
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+from iotAmak.base.schedulable import Schedulable
 
 
 class Scheduler(Schedulable):
diff --git a/iotAmak/ssh_module/__init__.py b/iotAmak/ssh_module/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/iotAmak/tool/remote_client.py b/iotAmak/ssh_module/remote_client.py
similarity index 100%
rename from iotAmak/tool/remote_client.py
rename to iotAmak/ssh_module/remote_client.py
diff --git a/iotAmak/tool/ssh_client.py b/iotAmak/ssh_module/ssh_client.py
similarity index 91%
rename from iotAmak/tool/ssh_client.py
rename to iotAmak/ssh_module/ssh_client.py
index 858df6dccd0c6336ba77046e2a76fe2f8e952a8c..a208519b893ed36ef16803776b23e6f61b354061 100644
--- a/iotAmak/tool/ssh_client.py
+++ b/iotAmak/ssh_module/ssh_client.py
@@ -9,8 +9,7 @@ from pexpect import pxssh
 
 sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
 
-from iotAmak.tool.remote_client import RemoteClient
-
+from iotAmak.ssh_module.remote_client import RemoteClient
 
 class Cmd:
 
@@ -19,15 +18,14 @@ class Cmd:
         self.do_print = do_print
         self.prefix = prefix
 
-
 class SSHClient:
 
     def __init__(self, clients: List[RemoteClient], iot_path: str):
-        self.clients = clients
-        self.iot_path = iot_path
+        self.clients: List[RemoteClient] = clients
+        self.iot_path: str = iot_path
 
-    def run_cmd(self, client: int, cmd: list, repeat: bool = False) -> list[str]:
-        ret = []
+    def run_cmd(self, client: int, cmd: list, repeat: bool = False) -> List[str]:
+        ret: List[str] = []
         try:
             s = pxssh.pxssh()
             dest = self.clients[client]
@@ -48,7 +46,7 @@ class SSHClient:
                 self.run_cmd(client, cmd, True)
         return ret
 
-    def update(self, experiment_name, path_to_experiment):
+    def update(self, experiment_name: str, path_to_experiment: str):
         for client in self.clients:
             transport = paramiko.Transport((client.hostname, 22))
             transport.connect(username=client.user, password=client.password)
diff --git a/setup.py b/setup.py
index c88411713ae214b66f3a100c867e7e5b73574f30..fc4ebef897683b5adf56cb036be306c88c90b48e 100644
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
 setup(
     name='iotAmak',
     packages=find_packages(),
-    version='0.0.6',
+    version='0.0.7',
     description='AmakFramework in python',
     author='SMAC - GOYON Sebastien',
     install_requires=[