diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 56c1752408f425a87ac3eb07483ac2e35f9000f3..2f2b1ae629abf811792198a03429c39128ee0f9f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -22,14 +22,14 @@ pylint:
   allow_failure: true
   script:
     - pip install pylint
-    - pylint -d C0301,R0902,E0611,E0401 ./pyAmakCore --max-parents=9
+    - pylint -d C0301,R0902,E0611,E0401,C0413,R0201 ./pyAmakCore/classes --max-parents=9
 
 flake8:
   stage: Code Analysis
   allow_failure: true
   script:
     - pip install flake8
-    - flake8 --verbose --max-line-length=120 --max-complexity 8 ./pyAmakCore
+    - flake8 --verbose --max-line-length=120 --max-complexity 8 ./pyAmakCore/classes
 
 isort:
   stage: Code Analysis
diff --git a/note/cycle.txt b/note/cycle.txt
deleted file mode 100644
index 47ad4b11a65ed7e9cc03153878a90ef53c03c950..0000000000000000000000000000000000000000
--- a/note/cycle.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-init :
-    base
-    on_init
-
-    syncro
-
-
-
-cycle :
-
-    on cycle begin
-    syncro
-
-    agent action
-    syncro
-
-    on cycle end
-    syncro
\ No newline at end of file
diff --git a/note/how to use b/note/how to use
deleted file mode 100644
index 94ec796203c44ddf49dde3ed98cd17efdeed89b5..0000000000000000000000000000000000000000
--- a/note/how to use	
+++ /dev/null
@@ -1,13 +0,0 @@
-1 - create env
-2 - create amas
-3 - amas.start()
-
-to end :
-amas.exit_program()
-
-
-to start :
-amas.put_token()
-
-to stop :
-amas.take_token()
\ No newline at end of file
diff --git a/pyAmakCore/classes/agent.py b/pyAmakCore/classes/agent.py
index 93e474f1db24be50a6735fe5789ecf56fe8dad9b..663518650295faed57a764bf60c19d99f0dedad8 100644
--- a/pyAmakCore/classes/agent.py
+++ b/pyAmakCore/classes/agent.py
@@ -7,12 +7,10 @@ from typing import List
 import sys
 import pathlib
 
-from pyAmakCore.exception.override import ToOverrideWarning
-
 sys.path.insert(0, str(pathlib.Path(__file__).parent))
 
+from pyAmakCore.exception.override import ToOverrideWarning
 from pyAmakCore.enumeration.agent_phase import Phase
-from pyAmakCore.enumeration.executionPolicy import ExecutionPolicy
 
 
 class Agent:
@@ -104,13 +102,25 @@ class Agent:
         """
         self.__neighbours = []
 
+    def get_criticality(self) -> float:
+        """
+        return criticality
+        """
+        return self.__criticality
+
     def compute_criticality(self) -> float:
         """
         compute_criticality
         """
         return -inf
 
-    def _get_most_critical_neighbor(self, including_me: bool = False) -> 'Agent':
+    def set_criticality(self, criticality: float) -> None:
+        """
+        set agent criticality to criticality
+        """
+        self.__criticality = criticality
+
+    def get_most_critical_neighbor(self, including_me: bool = False) -> 'Agent':
         """
         Convenient method giving the most critical neighbor at a given moment
         """
@@ -129,10 +139,6 @@ class Agent:
 
         return criticalest[randint(0, len(criticalest) - 1)]
 
-    """
-    Cycle
-    """
-
     def on_cycle_begin(self) -> None:
         """
         this method is called by each agent at the start of their cycle
@@ -163,24 +169,10 @@ class Agent:
         """
         ToOverrideWarning("on_act")
 
-    def __phase1(self) -> None:
+    def next_phase(self) -> None:
         """
-        this is the first phase of a cycle
+        set agent phase to the next phase
         """
-        self.on_perceive()
-        self.compute_criticality()
-        self.__next_phase()
-
-    def __phase2(self) -> None:
-        """
-        this is the second phase of a cycle
-        """
-        self.on_decide()
-        self.on_act()
-        self.compute_criticality()
-        self.__next_phase()
-
-    def __next_phase(self):
         next_phase = {
             Phase.INITIALIZING: Phase.PERCEPTION,
             Phase.PERCEPTION: Phase.PERCEPTION_DONE,
@@ -190,34 +182,11 @@ class Agent:
         }
         self.__phase = next_phase.get(self.__phase)
 
-    def run(self) -> None:
-        """
-        Full cycle of an agent
-        """
-        self.__next_phase()
-
-        execution_policy = self.__amas.get_execution_policy()
-
-        if execution_policy == ExecutionPolicy.TWO_PHASES:
-            if self.__phase == Phase.PERCEPTION:
-                self.on_cycle_begin()
-                self.__phase1()
-                return
-
-            if self.__phase == Phase.DECISION_AND_ACTION:
-                self.__phase2()
-                self.on_cycle_end()
-                return
-
-        if execution_policy == ExecutionPolicy.ONE_PHASE:
-            self.on_cycle_begin()
-            self.__phase1()
-            self.__next_phase()
-            self.__phase2()
-            self.on_cycle_end()
-
     def __eq__(self, other: 'Agent') -> bool:
-        # check class
+        # should check class
         if other is None:
             return False
         return self.__id == other.__id
+
+    def __repr__(self):
+        return str(self.__id)
diff --git a/pyAmakCore/classes/amas.py b/pyAmakCore/classes/amas.py
index 65b2835546bec4e944db7e81c8f69a4c544e9fb2..81ea8f3a8d17229b0b5857e4f9078c19450cff4c 100644
--- a/pyAmakCore/classes/amas.py
+++ b/pyAmakCore/classes/amas.py
@@ -1,56 +1,75 @@
 """
 Amas Class
 """
-from threading import Thread
 from typing import List
+
 import sys
 import pathlib
 
 sys.path.insert(0, str(pathlib.Path(__file__).parent))
 
-from pyAmakCore.classes.schedulable import Schedulable
-from pyAmakCore.classes.scheduler import Scheduler
+from pyAmakCore.classes.tools.loggable import Loggable
+from pyAmakCore.classes.tools.schedulable import Schedulable
 from pyAmakCore.classes.environment import Environment
 from pyAmakCore.classes.agent import Agent
 from pyAmakCore.enumeration.executionPolicy import ExecutionPolicy
 from pyAmakCore.exception.override import ToOverrideWarning
 
 
-class Amas(Schedulable):
+class Amas(Schedulable, Loggable):
     """
     Amas Class
     """
 
-    def __init__(self, environment: Environment) -> None:
+    def __init__(self,
+                 environment: Environment,
+                 execution_policy: ExecutionPolicy = ExecutionPolicy.ONE_PHASE
+                 ) -> None:
 
-        super().__init__()
+        Schedulable.__init__(self)
+        Loggable.__init__(self)
         self.__environment: Environment = environment
-        self.__agents: List[Agent] = []
-        self.__nbrcycle: int = 0
 
-        self.scheduler: Scheduler = Scheduler()
-        self.scheduler.add_schedulable(self)
-        self.__environment.add_scheduler(self.scheduler)
+        self.__agents: List[Agent] = []
+        self.__agent_to_add: List[Agent] = []
+        self.__agent_to_remove: List[Agent] = []
 
-        self.__execution_policy: ExecutionPolicy = ExecutionPolicy.ONE_PHASE
+        self.__execution_policy: ExecutionPolicy = execution_policy
 
+        self.on_initialization()
         self.on_initial_agents_creation()
 
-        for agent in self.__agents:
+    def add_pending_agent(self) -> List[Agent]:
+        """
+        add pending agent into agent and return added agents
+        """
+        for agent in self.__agent_to_add:
             agent.compute_criticality()
+            self.__agents.append(agent)
+        tmp = self.__agent_to_add
+        self.__agent_to_add = []
+        return tmp
 
-        self.on_initialization()
+    def remove_pending_agent(self) -> List[Agent]:
+        """
+        add pending agent into agent and return removed agents
+        """
+        for agent in self.__agent_to_remove:
+            self.__agents.remove(agent)
+        tmp = self.__agent_to_remove
+        self.__agent_to_remove = []
 
-        # tell scheduler that init is done
-        self.give_token_syncro()
+        return tmp
 
-    def add_agent(self, agent: 'Agent') -> None:
+    def add_agent(self, agent: Agent) -> None:
         """
         add agent in the amas agents list without duplicate
         """
         if agent in self.__agents:
             return
-        self.__agents.append(agent)
+        if agent in self.__agent_to_add:
+            return
+        self.__agent_to_add.append(agent)
 
     def add_agents(self, agents: List[Agent]) -> None:
         """
@@ -65,7 +84,9 @@ class Amas(Schedulable):
         """
         if agent not in self.__agents:
             return
-        self.__agents.remove(agent)
+        if agent in self.__agent_to_remove:
+            return
+        self.__agent_to_remove.append(agent)
 
     def get_environment(self) -> Environment:
         """
@@ -85,91 +106,8 @@ class Amas(Schedulable):
         """
         return self.__execution_policy
 
-    def set_execution_policy(self, execution_policy: ExecutionPolicy) -> None:
-        """
-        set system execution_policy
-        """
-        self.__execution_policy = execution_policy
-
-    def get_cycle(self) -> int:
-        """
-        return nbr of cycle
-        """
-        return self.__nbrcycle
-
     def on_initial_agents_creation(self) -> None:
         """
         This method is called at the end of __init__()
         """
         ToOverrideWarning("on_initial_agents_creation")
-
-    def synchronization(self) -> None:
-        """
-        Unlock Scheduler and wait for his response
-        """
-        self.give_token_syncro()
-        self.scheduler.take_amas_token()
-
-    def cycle(self) -> None:
-        """
-        Main behavior of Amas
-        """
-        print("Cycle : ", self.__nbrcycle)
-        self.__nbrcycle += 1
-
-        self.on_cycle_begin()
-        self.synchronization()
-
-        threads = []
-        # suffle
-        for agent in self.__agents:
-            current_thread = Thread(target=agent.run)
-            threads.append(current_thread)
-            current_thread.start()
-
-        for thread in threads:
-            thread.join()
-
-        if self.__execution_policy == ExecutionPolicy.TWO_PHASES:
-            threads = []
-            for agent in self.__agents:
-                current_thread = Thread(target=agent.run)
-                threads.append(current_thread)
-                current_thread.start()
-
-            for thread in threads:
-                thread.join()
-
-        self.synchronization()
-
-        self.on_cycle_end()
-
-    def put_token(self) -> None:
-        """
-        Tell scheduler to start
-        """
-        self.scheduler.give_semaphore_start_stop()
-
-    def take_token(self) -> None:
-        """
-        Tell scheduler to stop
-        """
-        self.scheduler.take_semaphore_start_stop()
-
-    def exit_program(self) -> None:
-        """
-        exit the program at the end of the cycle
-        """
-        self.scheduler.exit_bool = True
-
-    def set_sleep(self, sleep_time) -> None:
-        """
-        set sleep between 2 cycles
-        """
-        self.scheduler.sleep_time = sleep_time
-
-    def start(self) -> None:
-        """
-        launch the system
-        """
-        self.scheduler.run()
diff --git a/pyAmakCore/classes/communicating_agent.py b/pyAmakCore/classes/communicating_agent.py
new file mode 100644
index 0000000000000000000000000000000000000000..d70cb0cd6636f4d142ca075a8355c78ccf11d118
--- /dev/null
+++ b/pyAmakCore/classes/communicating_agent.py
@@ -0,0 +1,122 @@
+"""
+Class Mail Mailbox and CommunicatingAgent
+"""
+from typing import Any, List
+import pathlib
+import sys
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent))
+
+from pyAmakCore.exception.mailbox import ReceiverIsNotSelf, ReceiverDontExist
+from pyAmakCore.classes.agent import Agent
+
+
+class Mail:
+    """
+    Class message
+    """
+
+    def __init__(self, id_sender: int, id_receiver: int, message: Any, sending_date: int) -> None:
+        self.__id_sender: int = id_sender
+        self.__id_receiver: int = id_receiver
+        self.__message: Any = message
+        self.__sending_date: int = sending_date
+
+    def get_id_sender(self) -> int:
+        """
+        return sender id
+        """
+        return self.__id_sender
+
+    def get_id_receiver(self) -> int:
+        """
+        return receiver id
+        """
+        return self.__id_receiver
+
+    def get_message(self) -> Any:
+        """
+        return message
+        """
+        return self.__message
+
+    def get_sending_date(self) -> int:
+        """
+        return sending_date
+        """
+        return self.__sending_date
+
+
+class Mailbox:
+    """
+    Each agent have 1 unique mailbox that they can call to send or receive mail
+    """
+
+    def __init__(self, owner_id: int, amas: 'Amas') -> None:
+        self.__mail_list: List['Mail'] = []
+        self.__owner_id: int = owner_id
+        self.__amas: 'Amas' = amas
+
+    def get_mail(self) -> 'Mail':
+        """
+        return the next mail in the box, None if the mailBox is empty
+        """
+        if len(self.__mail_list) == 0:
+            return None
+        mail = self.__mail_list.pop()
+        if mail.get_id_receiver() != self.__owner_id:
+            raise ReceiverIsNotSelf(self.__owner_id, mail.get_id_receiver())
+        return mail
+
+    def receive_mail(self, mail: 'Mail'):
+        """
+        this method is called to put a mail in this mailbox
+        """
+        self.__mail_list.append(mail)
+
+    def send_message(self, message: Any, id_receiver: int) -> None:
+        """
+        this method is called to send a message
+        """
+        mail = Mail(self.__owner_id, id_receiver, message, self.__amas.get_cycle())
+
+        for agent in self.__amas.get_agents():
+            if agent.get_id() == id_receiver:
+                return agent.receive_mail(mail)
+        raise ReceiverDontExist(id_receiver)
+
+
+class CommunicatingAgent(Agent):
+    """
+    Agent class that can communicate
+    """
+
+    def __init__(self, amas: 'Amas') -> None:
+        super().__init__(amas)
+        self.__mailbox: 'Mailbox' = Mailbox(self.get_id(), amas)
+
+    def send_message(self, message: Any, id_receiver: int) -> None:
+        """
+        send a message to another agent
+        """
+        self.__mailbox.send_message(message, id_receiver)
+
+    def receive_mail(self, mail: 'Mail') -> None:
+        """
+        this method is called by another mailbox to add a mail in the mailbox
+        """
+        self.__mailbox.receive_mail(mail)
+
+    def read_mails(self) -> None:
+        """
+        method that open all mail in the mailbox
+        """
+        mail = self.__mailbox.get_mail()
+        while mail is not None:
+            self.read_mail(mail)
+            mail = self.__mailbox.get_mail()
+
+    def read_mail(self, mail: 'Mail') -> None:
+        """
+        This method should be override to make an action whenever you read a mail
+        """
diff --git a/pyAmakCore/classes/environment.py b/pyAmakCore/classes/environment.py
index 06ff97236235c47ee56263bea333b9c0cf50075e..b811398e0659b7d460003f7ff86007c08f9dedf7 100644
--- a/pyAmakCore/classes/environment.py
+++ b/pyAmakCore/classes/environment.py
@@ -5,10 +5,10 @@ from random import seed
 
 import sys
 import pathlib
+
 sys.path.insert(0, str(pathlib.Path(__file__).parent))
 
-from pyAmakCore.classes.schedulable import Schedulable
-from pyAmakCore.classes.scheduler import Scheduler
+from pyAmakCore.classes.tools.schedulable import Schedulable
 
 
 class Environment(Schedulable):
@@ -19,10 +19,7 @@ class Environment(Schedulable):
     def __init__(self) -> None:
         self.set_seed()
         super().__init__()
-        self.scheduler: Scheduler = None
         self.on_initialization()
-        # tell scheduler that init is done
-        self.give_token_syncro()
 
     def set_seed(self):
         """
@@ -30,29 +27,3 @@ class Environment(Schedulable):
         """
         seed()
 
-    def add_scheduler(self, scheduler: Scheduler) -> None:
-        """
-        set scheduler pointer to scheduler
-        add add self to schedulables of scheduler
-        """
-        self.scheduler = scheduler
-        self.scheduler.add_schedulable(self)
-
-    def synchronization(self) -> None:
-        """
-        Unlock Scheduler and wait for his response
-        """
-        self.give_token_syncro()
-        self.scheduler.take_environment_token()
-
-    def cycle(self) -> None:
-        """
-        Main behavior of Environment
-        """
-        self.on_cycle_begin()
-        self.synchronization()
-
-        # mileu de cycle
-        self.synchronization()
-
-        self.on_cycle_end()
diff --git a/pyAmakCore/classes/scheduler.py b/pyAmakCore/classes/scheduler.py
index 48a2248237d3c42ce1aed02190c90ac8b588a128..2326a7dcbf7836ef228781fa04259a7dcd1c801a 100644
--- a/pyAmakCore/classes/scheduler.py
+++ b/pyAmakCore/classes/scheduler.py
@@ -1,117 +1,96 @@
 """
 Scheduler class
 """
-from threading import Semaphore, Thread
-from time import sleep
 from typing import List
+
 import sys
 import pathlib
+from threading import Thread
+
 sys.path.insert(0, str(pathlib.Path(__file__).parent))
 
-from pyAmakCore.classes.schedulable import Schedulable
+from pyAmakCore.classes.amas import Amas
+from pyAmakCore.classes.thread_tool.schedulable_thread import SchedulableThread
+from pyAmakCore.classes.thread_tool.amas_thread import AmasThread
+from pyAmakCore.classes.tools.schedulable import Schedulable
+from pyAmakCore.classes.scheduler_tool.scheduler_core import SchedulerCore
 
 
-class Scheduler():
+class Scheduler(SchedulerCore):
     """
     Scheduler class, to make sure that environment and amas are always sync together
     """
 
-    def __init__(self) -> None:
-
-        # List of all schedulables
-        self.__schedulables: List[Schedulable] = []
-        # Sleep timer between 2 cycle
-        self.sleep_time: float = 0
+    def __init__(self, amas: Amas) -> None:
+        SchedulerCore.__init__(self, amas)
 
-        # Semaphore for start/stop button
-        self.__semaphore_start_stop: Semaphore = Semaphore(0)
-        # Semaphore to tell amas to continue
-        self.__semaphore_amas: Semaphore = Semaphore(0)
-        # Semaphore to tell environment to continue
-        self.__semaphore_environment: Semaphore = Semaphore(0)
+        self.__schedulables: List[SchedulableThread] = []
+        self.__schedulables_threads: List[Thread] = []
 
-        self.exit_bool = False
+        self.__add_schedulables(amas, AmasThread)
+        self.__add_schedulables(amas.get_environment(), SchedulableThread)
 
-    def add_schedulable(self, schedulable: Schedulable) -> None:
+    def __add_schedulables(self, schedulable: Schedulable, cls) -> None:
         """
-        add schedulable in schedulables list
+        add a schedulable in scheduler
         """
-        self.__schedulables.append(schedulable)
+        schedulable_thread = cls(schedulable)
+        self.__schedulables.append(schedulable_thread)
+        current_thread = Thread(target=schedulable_thread.run)
+        self.__schedulables_threads.append(current_thread)
+        current_thread.start()
 
-    def take_amas_token(self) -> None:
+    def __wait_schedulables(self) -> None:
         """
-        make amas wait here for a token
+        wait for all schedulable to release a token
         """
-        self.__semaphore_amas.acquire()
+        for schedulable in self.__schedulables:
+            schedulable.action_done.acquire()
 
-    def give_amas_token(self) -> None:
+    def __start_schedulables(self) -> None:
         """
-        unlock amas
+        wait for all schedulable to release a token
         """
-        self.__semaphore_amas.release()
+        for schedulable in self.__schedulables:
+            schedulable.is_waiting.release()
 
-    def take_environment_token(self) -> None:
+    def first_part(self) -> None:
         """
-        make environment wait here for a token
+        first part of a cycle
         """
-        self.__semaphore_environment.acquire()
+        self.__start_schedulables()
+        # on cycle begin
+        self.__wait_schedulables()
 
-    def give_environment_token(self) -> None:
+    def main_part(self) -> None:
         """
-        unlock environment
+        main part of a cycle
         """
-        self.__semaphore_environment.release()
+        self.__start_schedulables()
+        # agent cycle
+        self.__wait_schedulables()
 
-    def take_semaphore_start_stop(self) -> None:
+    def last_part(self) -> None:
         """
-        Scheduler will wait for a token to start the cycle
+        last part of a cycle
         """
-        self.__semaphore_start_stop.acquire()
+        self.__start_schedulables()
+        # on cycle end
+        self.__wait_schedulables()
 
-    def give_semaphore_start_stop(self) -> None:
+    def run(self) -> None:
         """
-        give a token to unlock Scheduler
+        override super run to close child thread before stopping
         """
-        self.__semaphore_start_stop.release()
+        super().run()
+        self.__close_child()
 
-    def syncro_schedulable(self) -> None:
+    def __close_child(self) -> None:
         """
-        wait for all schedulable to release a token
+        tell all child to shut down
         """
         for schedulable in self.__schedulables:
-            schedulable.take_token_syncro()
-
-    def run(self) -> None:
-        """
-        main part of amak core
-        """
-        # wait that all schedulable are ready
-        self.syncro_schedulable()
-
-        while not self.exit_bool:
-
-            self.__semaphore_start_stop.acquire()
-            self.__semaphore_start_stop.release()
-
-            threads = []
-            for schedulable in self.__schedulables:
-                current_thread = Thread(target=schedulable.run)
-                threads.append(current_thread)
-                current_thread.start()
-
-            # on cycle begin
-            self.syncro_schedulable()
-            self.give_amas_token()
-            self.give_environment_token()
-
-            # main part of the cycle
-            self.syncro_schedulable()
-            self.give_amas_token()
-            self.give_environment_token()
-
-            # on cycle end
-
-            for thread in threads:
-                thread.join()
-
-            sleep(self.sleep_time)
+            schedulable.exit_bool = True
+            schedulable.is_waiting.release()
+        for thread in self.__schedulables_threads:
+            thread.join(0)
diff --git a/pyAmakCore/classes/scheduler_mono_threading.py b/pyAmakCore/classes/scheduler_mono_threading.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f3bbc30bd288ce36591b8d53c8ba016e8ef52c9
--- /dev/null
+++ b/pyAmakCore/classes/scheduler_mono_threading.py
@@ -0,0 +1,99 @@
+"""
+SchedulerMono class
+"""
+from random import shuffle
+from typing import List
+
+import sys
+import pathlib
+
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent))
+
+from pyAmakCore.classes.scheduler_tool.scheduler_core import SchedulerCore
+from pyAmakCore.classes.amas import Amas
+from pyAmakCore.classes.agent import Agent
+from pyAmakCore.classes.tools.schedulable import Schedulable
+from pyAmakCore.classes.communicating_agent import CommunicatingAgent
+from pyAmakCore.enumeration.executionPolicy import ExecutionPolicy
+
+
+class SchedulerMono(SchedulerCore):
+    """
+    Scheduler class, without threading
+    """
+
+    def __init__(self, amas: Amas) -> None:
+        SchedulerCore.__init__(self, amas)
+
+        self.schedulables: List[Schedulable] = []
+
+        self.schedulables.append(self.amas)
+        self.amas.add_pending_agent()
+        self.schedulables.append(self.amas.get_environment())
+
+    def first_part(self) -> None:
+        """
+        first part of a cycle
+        """
+        self.amas.add_pending_agent()
+
+        for schedulable in self.schedulables:
+            schedulable.on_cycle_begin()
+
+    def main_part(self) -> None:
+        """
+        main part of a cycle
+        """
+
+        def phase1(current_agent: Agent) -> None:
+            """
+            this is the first phase of a cycle
+            """
+            current_agent.next_phase()
+            current_agent.on_cycle_begin()
+            if isinstance(current_agent, CommunicatingAgent):
+                current_agent.read_mails()
+
+            current_agent.on_perceive()
+            current_agent.set_criticality(current_agent.compute_criticality())
+            current_agent.next_phase()
+
+        def phase2(current_agent: Agent) -> None:
+            """
+            this is the second phase of a cycle
+            """
+            current_agent.next_phase()
+            current_agent.on_decide()
+            current_agent.on_act()
+            current_agent.set_criticality(current_agent.compute_criticality())
+            current_agent.next_phase()
+            current_agent.on_cycle_end()
+
+        agents: List[Agent] = self.amas.get_agents()
+
+        if self.amas.get_execution_policy() == ExecutionPolicy.ONE_PHASE:
+            shuffle(agents)
+            for agent in agents:
+                phase1(agent)
+                phase2(agent)
+        else:
+            shuffle(agents)
+            for agent in agents:
+                phase1(agent)
+            shuffle(agents)
+            for agent in agents:
+                phase2(agent)
+
+    def last_part(self) -> None:
+        """
+        last part of a cycle
+        """
+        for schedulable in self.schedulables:
+            schedulable.on_cycle_end()
+
+        self.amas.remove_pending_agent()
+        self.amas.to_csv(self.amas.get_cycle(), self.amas.get_agents())
+
+        for schedulable in self.schedulables:
+            schedulable.cycle()
diff --git a/pyAmakCore/classes/scheduler_tool/__init__.py b/pyAmakCore/classes/scheduler_tool/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/pyAmakCore/classes/scheduler_tool/callable.py b/pyAmakCore/classes/scheduler_tool/callable.py
new file mode 100644
index 0000000000000000000000000000000000000000..f6f4a5163efae0eff9ab707f287bef727788eb33
--- /dev/null
+++ b/pyAmakCore/classes/scheduler_tool/callable.py
@@ -0,0 +1,41 @@
+"""
+class Callable
+"""
+from threading import Semaphore
+
+
+class Callable:
+    """
+    Class that implement useful method to interact with the program
+    """
+
+    def __init__(self) -> None:
+        self.exit_bool: bool = False
+        self.sleep_time: float = 0
+
+        self.semaphore_start_stop: Semaphore = Semaphore(0)
+
+    def exit_program(self) -> None:
+        """
+        Exit the system as soon as possible
+        """
+        self.exit_bool = True
+        self.semaphore_start_stop.release()
+
+    def start(self) -> None:
+        """
+        Unlock the scheduler
+        """
+        self.semaphore_start_stop.release()
+
+    def stop(self) -> None:
+        """
+        Lock the scheduler
+        """
+        self.semaphore_start_stop.acquire()
+
+    def set_sleep(self, sleep_time: int) -> None:
+        """
+        Set sleep value between 2 cycles
+        """
+        self.sleep_time = sleep_time
diff --git a/pyAmakCore/classes/scheduler_tool/savable.py b/pyAmakCore/classes/scheduler_tool/savable.py
new file mode 100644
index 0000000000000000000000000000000000000000..fcffd31d7d9ea1f53ca2c4752f6bd7508c33036d
--- /dev/null
+++ b/pyAmakCore/classes/scheduler_tool/savable.py
@@ -0,0 +1,41 @@
+"""
+Savable Class
+"""
+import pickle
+import sys
+import pathlib
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent))
+
+from pyAmakCore.classes.amas import Amas
+
+
+class Savable:
+    """
+    Class that implement convenient method to save and load an amas
+    """
+    def __init__(self, amas: Amas) -> None:
+        self.amas = amas
+
+    def get_amas(self):
+        """
+        return amas
+        """
+        return self.amas
+
+    def save(self) -> None:
+        """
+        Save the current state of the system
+        """
+        with open('filename.pickle', 'wb') as handle:
+            pickle.dump(self.amas, handle, protocol=pickle.HIGHEST_PROTOCOL)
+
+    @classmethod
+    def load(cls) -> 'Savable':
+        """
+        Load the last save of the system
+        """
+        with open('filename.pickle', 'rb') as handle:
+            amas_object = pickle.load(handle)
+
+        return cls(amas_object)
\ No newline at end of file
diff --git a/pyAmakCore/classes/scheduler_tool/scheduler_core.py b/pyAmakCore/classes/scheduler_tool/scheduler_core.py
new file mode 100644
index 0000000000000000000000000000000000000000..15ef702597b505a1f5266d772d4ca3940dd96484
--- /dev/null
+++ b/pyAmakCore/classes/scheduler_tool/scheduler_core.py
@@ -0,0 +1,57 @@
+"""
+Scheduler class
+"""
+from time import sleep
+
+import sys
+import pathlib
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent))
+
+from pyAmakCore.classes.scheduler_tool.callable import Callable
+from pyAmakCore.classes.scheduler_tool.savable import Savable
+from pyAmakCore.classes.amas import Amas
+
+
+class SchedulerCore(Callable, Savable):
+    """
+    Core part of Scheduler
+    """
+
+    def __init__(self, amas: Amas) -> None:
+
+        Callable.__init__(self)
+        Savable.__init__(self, amas)
+
+    def first_part(self) -> None:
+        """
+        first part of a cycle
+        """
+
+    def main_part(self) -> None:
+        """
+        main part of a cycle
+        """
+
+    def last_part(self) -> None:
+        """
+        last part of a cycle
+        """
+
+    def run(self) -> None:
+        """
+        main part of amak core
+        """
+        while not self.exit_bool:
+            print("Cycle : ", self.amas.get_cycle())
+
+            self.semaphore_start_stop.acquire()
+            if self.exit_bool:
+                break
+            self.semaphore_start_stop.release()
+
+            self.first_part()
+            self.main_part()
+            self.last_part()
+
+            sleep(self.sleep_time)
diff --git a/pyAmakCore/classes/thread_tool/__init__.py b/pyAmakCore/classes/thread_tool/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/pyAmakCore/classes/thread_tool/agent_thread.py b/pyAmakCore/classes/thread_tool/agent_thread.py
new file mode 100644
index 0000000000000000000000000000000000000000..493562d726a8ef2225310a8e4296fa9858025292
--- /dev/null
+++ b/pyAmakCore/classes/thread_tool/agent_thread.py
@@ -0,0 +1,74 @@
+"""
+Class Agent thread
+"""
+from threading import Semaphore
+import sys
+import pathlib
+
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+
+from pyAmakCore.classes.communicating_agent import CommunicatingAgent
+from pyAmakCore.classes.agent import Agent
+from pyAmakCore.enumeration.executionPolicy import ExecutionPolicy
+
+
+class AgentThread:
+    """
+    thread class used to thread agent
+    """
+    action_done = Semaphore(0)
+    execution_policy = ExecutionPolicy.ONE_PHASE
+
+    def __init__(self, agent: Agent) -> None:
+
+        self.agent: Agent = agent
+        self.is_waiting: Semaphore = Semaphore(0)
+        self.exit_bool: bool = False
+
+    def phase1(self) -> None:
+        """
+        this is the first phase of a cycle
+        """
+        if isinstance(self.agent, CommunicatingAgent):
+            self.agent.read_mails()
+
+        self.agent.on_perceive()
+        self.agent.set_criticality(self.agent.compute_criticality())
+        self.agent.next_phase()
+
+    def phase2(self) -> None:
+        """
+        this is the second phase of a cycle
+        """
+        self.agent.on_decide()
+        self.agent.on_act()
+        self.agent.set_criticality(self.agent.compute_criticality())
+        self.agent.next_phase()
+
+    def run(self) -> None:
+        """
+        main part of an agent thread
+        """
+        while not self.exit_bool:
+
+            self.is_waiting.acquire()
+            if self.exit_bool:
+                return
+
+            self.agent.next_phase()
+            self.agent.on_cycle_begin()
+
+            self.phase1()
+
+            if AgentThread.execution_policy == ExecutionPolicy.TWO_PHASES:
+                AgentThread.action_done.release()
+                self.is_waiting.acquire()
+
+            self.agent.next_phase()
+
+            self.phase2()
+
+            self.agent.on_cycle_end()
+
+            AgentThread.action_done.release()
diff --git a/pyAmakCore/classes/thread_tool/amas_thread.py b/pyAmakCore/classes/thread_tool/amas_thread.py
new file mode 100644
index 0000000000000000000000000000000000000000..e2516386afcb278a06c08854c7e70bcb6575d4c7
--- /dev/null
+++ b/pyAmakCore/classes/thread_tool/amas_thread.py
@@ -0,0 +1,125 @@
+"""
+thread class for amas
+"""
+from threading import Thread
+from typing import List
+
+import sys
+import pathlib
+
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+
+from pyAmakCore.enumeration.executionPolicy import ExecutionPolicy
+from pyAmakCore.classes.thread_tool.agent_thread import AgentThread
+from pyAmakCore.classes.amas import Amas
+from pyAmakCore.classes.agent import Agent
+from pyAmakCore.classes.thread_tool.schedulable_thread import SchedulableThread
+
+
+class AmasThread(SchedulableThread):
+    """
+    thread class used to thread amas
+    """
+
+    def __init__(self, amas: Amas) -> None:
+        super().__init__(amas)
+
+        self.agents: List[AgentThread] = []
+        self.agents_thread: List[Thread] = []
+
+        AgentThread.execution_policy = self.schedulable.get_execution_policy()
+
+        self.schedulable.add_pending_agent()
+        for agent in self.schedulable.get_agents():
+            self.add_agent(agent)
+
+    def add_agent(self, agent: Agent) -> None:
+        """
+        make agent a thread and start the thread
+        """
+        agent_thread = AgentThread(agent)
+        self.agents.append(agent_thread)
+        current_thread = Thread(target=agent_thread.run)
+        self.agents_thread.append(current_thread)
+        current_thread.start()
+
+    def add_agents(self) -> None:
+        """
+        if there are new agents, add them
+        """
+        added_agent = self.schedulable.add_pending_agent()
+        for agent in added_agent:
+            self.add_agent(agent)
+
+    def remove_agents(self) -> None:
+        """
+        if some agents are removed, close their thread
+        """
+        removed_agent = self.schedulable.remove_pending_agent()
+        for agent in removed_agent:
+            for i in range(len(self.agents)):
+                if agent == self.agents[i].agent:
+                    self.agents[i].exit_bool = True
+                    self.agents[i].is_waiting.release()
+                    self.agents_thread[i].join()
+
+                    self.agents.remove(self.agents[i])
+                    self.agents_thread.remove(self.agents_thread[i])
+
+    def on_cycle_begin(self) -> None:
+        """
+        start of cycle
+        """
+        self.add_agents()
+        self.schedulable.on_cycle_begin()
+
+    def main_cycle_part(self) -> None:
+        """
+        main part of the cycle
+        """
+        for agent in self.agents:
+            agent.is_waiting.release()
+        # agent cycle
+
+        if self.schedulable.get_execution_policy() == ExecutionPolicy.TWO_PHASES:
+            # wait agents
+            for i in range(len(self.agents)):
+                AgentThread.action_done.acquire()
+            # start phase 2 for all agents
+            for agent in self.agents:
+                agent.is_waiting.release()
+
+        for i in range(len(self.agents)):
+            AgentThread.action_done.acquire()
+
+    def on_cycle_end(self) -> None:
+        """
+        end of cycle
+        """
+        self.schedulable.on_cycle_end()
+
+        self.remove_agents()
+        self.schedulable.to_csv(self.schedulable.get_cycle(), self.schedulable.get_agents())
+
+        self.schedulable.cycle()
+
+    def run(self) -> None:
+        """
+        override run so when amas_thread try to stop, he closes all agents threads
+        """
+        super().run()
+        self.close_child()
+
+    def close_child(self) -> None:
+        """
+        tell all child threads to close
+        """
+        for agent in self.agents:
+            agent.exit_bool = True
+            agent.is_waiting.release()
+
+        for thread in self.agents_thread:
+            thread.join(0)
+
+
diff --git a/pyAmakCore/classes/thread_tool/schedulable_thread.py b/pyAmakCore/classes/thread_tool/schedulable_thread.py
new file mode 100644
index 0000000000000000000000000000000000000000..9429e269b2c5ca42b94d28d3ac856236d3f1fee3
--- /dev/null
+++ b/pyAmakCore/classes/thread_tool/schedulable_thread.py
@@ -0,0 +1,61 @@
+"""
+thread class for Schedulable
+"""
+from threading import Semaphore
+
+import sys
+import pathlib
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+
+from pyAmakCore.classes.tools.schedulable import Schedulable
+
+
+class SchedulableThread:
+    """
+    thread class used to thread schedulable
+    """
+
+    def __init__(self, schedulable: Schedulable) -> None:
+
+        self.schedulable: Schedulable = schedulable
+        self.is_waiting: Semaphore = Semaphore(0)
+        self.exit_bool: bool = False
+        self.action_done: Semaphore = Semaphore(0)
+
+    def on_cycle_begin(self) -> None:
+        """
+        first part of the cycle
+        """
+        self.schedulable.on_cycle_begin()
+
+    def main_cycle_part(self) -> None:
+        """
+        main part of the cycle
+        """
+
+    def on_cycle_end(self) -> None:
+        """
+        last part of the cycle
+        """
+        self.schedulable.on_cycle_end()
+        self.schedulable.cycle()
+
+    def run(self) -> None:
+        """
+        main part of a schedulable thread
+        """
+        while not self.exit_bool:
+            self.is_waiting.acquire()
+            if self.exit_bool:
+                break
+            self.on_cycle_begin()
+            self.action_done.release()
+
+            self.is_waiting.acquire()
+            self.main_cycle_part()
+            self.action_done.release()
+
+            self.is_waiting.acquire()
+            self.on_cycle_end()
+            self.action_done.release()
diff --git a/pyAmakCore/classes/tools/__init__.py b/pyAmakCore/classes/tools/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/pyAmakCore/classes/tools/loggable.py b/pyAmakCore/classes/tools/loggable.py
new file mode 100644
index 0000000000000000000000000000000000000000..97584df4d166bcf7cea1e9d28e5392e4da7b59f4
--- /dev/null
+++ b/pyAmakCore/classes/tools/loggable.py
@@ -0,0 +1,61 @@
+"""
+class allowing to save the state of the system at a given moment
+"""
+from os import path
+from typing import List
+from pandas import DataFrame
+
+
+class Loggable:
+    """
+    class Loggable
+    """
+    def __init__(self):
+        self.__do_log = False
+        self.__file_path = None
+        self.__ignore_attribute: List[str] = ["_Agent__amas", "_Agent__environment"]
+
+    def to_csv(self, cycle: int, var_list: List['Agent']) -> None:
+        """
+        get cycle and agent list and print them
+        """
+        if not self.__do_log:
+            return
+
+        table = [{**{e: x[e] for e in x if e not in self.__ignore_attribute},
+                  **{'nombre_cycle': cycle}} for x in map(vars, var_list)]
+        dataframe = DataFrame(table)
+
+        if self.__file_path is None:
+            print(dataframe.to_csv(index=False))
+        else:
+            if path.exists(self.__file_path):
+                dataframe.to_csv(path_or_buf=self.__file_path, mode='a', header=False, index=False)
+            else:
+                dataframe.to_csv(path_or_buf=self.__file_path, index=False)
+
+    def set_do_log(self, boolean: bool) -> None:
+        """
+        tell the amas if it should log or not
+        """
+        self.__do_log = boolean
+
+    def set_file_path(self, path_to_file: str) -> None:
+        """
+        specify path to csv
+        """
+        self.__file_path = path_to_file
+
+    def add_ignore_attribute(self, attribute: str) -> None:
+        """
+        add attribute in ignored attribute
+        """
+        self.__ignore_attribute.append(attribute)
+
+    def remove_ignore_attribute(self, attribute: str) -> None:
+        """
+        remove attribute in ignored attribute
+        """
+        if attribute not in self.__ignore_attribute:
+            return
+        self.__ignore_attribute.remove(attribute)
diff --git a/pyAmakCore/classes/schedulable.py b/pyAmakCore/classes/tools/schedulable.py
similarity index 54%
rename from pyAmakCore/classes/schedulable.py
rename to pyAmakCore/classes/tools/schedulable.py
index 45d906cfd98594f3447dec26f4d314c88aaaeecc..dda929cf0f60f62cc7238eaf134f03b92a33e5a2 100644
--- a/pyAmakCore/classes/schedulable.py
+++ b/pyAmakCore/classes/tools/schedulable.py
@@ -1,19 +1,34 @@
 """
 Schedulable interface
 """
-from threading import Semaphore
 import sys
 import pathlib
-sys.path.insert(0, str(pathlib.Path(__file__).parent))
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
 
 from pyAmakCore.exception.override import ToOverrideWarning
 
 
-class Schedulable():
+class Schedulable:
     """
     Class Schedulable
     """
-    syncro_semaphore: Semaphore = Semaphore(0)
+
+    def __init__(self):
+
+        self.__nbr_cycle: int = 0
+
+    def get_cycle(self) -> int:
+        """
+        return nbr_cycle
+        """
+        return self.__nbr_cycle
+
+    def cycle(self) -> None:
+        """
+        add 1 to nbr_cycle
+        """
+        self.__nbr_cycle += 1
 
     def on_initialization(self) -> None:
         """
@@ -32,27 +47,3 @@ class Schedulable():
         This method will be executed at the end of each cycle
         """
         ToOverrideWarning("on_cycle_end")
-
-    def run(self) -> None:
-        """
-        Method that will be called by the thread
-        """
-        self.cycle()
-
-    def cycle(self) -> None:
-        """
-        Main behavior of the Schedulable
-        """
-        ToOverrideWarning("cycle")
-
-    def take_token_syncro(self) -> None:
-        """
-        Scheduler will wait here that the schedulable release a token
-        """
-        self.syncro_semaphore.acquire()
-
-    def give_token_syncro(self) -> None:
-        """
-        Unlock scheduler
-        """
-        self.syncro_semaphore.release()
diff --git a/pyAmakCore/classes/tools/schedulerIHM.py b/pyAmakCore/classes/tools/schedulerIHM.py
new file mode 100644
index 0000000000000000000000000000000000000000..a9358b53a8a0c64c1a56ddfd2decdab59c3b806a
--- /dev/null
+++ b/pyAmakCore/classes/tools/schedulerIHM.py
@@ -0,0 +1,30 @@
+"""
+Scheduler class that need to be used for pyAmakIhm
+"""
+import pathlib
+import sys
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+
+from pyAmakCore.classes.amas import Amas
+from pyAmakCore.classes.scheduler import Scheduler
+
+
+class SchedulerIHM(Scheduler):
+    """
+    Convenient class to override while using pyAmakIHM
+    """
+
+    def __init__(self, amas: Amas):
+        self.__observer = None
+        super().__init__(amas)
+
+    def last_part(self) -> None:
+        super().last_part()
+        self.__observer.updateCycle()
+
+    def attach(self, observer: 'Controleur') -> None:
+        """
+        set observer pointer to observer
+        """
+        self.__observer = observer
diff --git a/pyAmakCore/classes/tools/scheduler_monoIHM.py b/pyAmakCore/classes/tools/scheduler_monoIHM.py
new file mode 100644
index 0000000000000000000000000000000000000000..827b998956b5bb7f150fd7d92035ffe74fb26e3a
--- /dev/null
+++ b/pyAmakCore/classes/tools/scheduler_monoIHM.py
@@ -0,0 +1,31 @@
+"""
+Scheduler class that need to be used for pyAmakIhm
+"""
+import pathlib
+import sys
+
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+
+from pyAmakCore.classes.amas import Amas
+from pyAmakCore.classes.scheduler_mono_threading import SchedulerMono
+
+
+class SchedulerMonoIHM(SchedulerMono):
+    """
+    Convenient class to override while using pyAmakIHM
+    """
+
+    def __init__(self, amas: Amas):
+        self.__observer = None
+        super().__init__(amas)
+
+    def last_part(self) -> None:
+        super().last_part()
+        self.__observer.updateCycle()
+
+    def attach(self, observer: 'Controleur') -> None:
+        """
+        set observer pointer to observer
+        """
+        self.__observer = observer
diff --git a/pyAmakCore/enumeration/agent_phase.py b/pyAmakCore/enumeration/agent_phase.py
index 56464f8aa0030c6e3fca7cc0ba585b617bbbaa5a..259a21e87d72f749556e4580280c7dc51a30c6ef 100644
--- a/pyAmakCore/enumeration/agent_phase.py
+++ b/pyAmakCore/enumeration/agent_phase.py
@@ -1,3 +1,6 @@
+"""
+Agent phases
+"""
 from enum import Enum, auto
 
 
diff --git a/pyAmakCore/enumeration/executionPolicy.py b/pyAmakCore/enumeration/executionPolicy.py
index 78fc09cd586362c974118a760a6dc53c0fbf6fd2..7adbd01392977e72e0a719d28a1ca57a5283e441 100644
--- a/pyAmakCore/enumeration/executionPolicy.py
+++ b/pyAmakCore/enumeration/executionPolicy.py
@@ -1,3 +1,6 @@
+"""
+Agent execution policy
+"""
 from enum import Enum, auto
 
 
diff --git a/pyAmakCore/exception/mailbox.py b/pyAmakCore/exception/mailbox.py
new file mode 100644
index 0000000000000000000000000000000000000000..f7e7dd00c1144b47debffb0eab4ea58b42e809c3
--- /dev/null
+++ b/pyAmakCore/exception/mailbox.py
@@ -0,0 +1,30 @@
+"""
+exception for mailbox
+"""
+
+
+class ReceiverIsNotSelf(Exception):
+    """
+    this exception is called whenever you received a mail that is not sent to you
+    """
+
+    def __init__(self, self_id, message_id):
+        self.self_id = self_id
+        self.message_id = message_id
+        super().__init__("Mail id is not self id")
+
+    def __str__(self):
+        return f' [Mailbox] : Mail id is not self id -> {self.message_id} != {self.self_id}'
+
+
+class ReceiverDontExist(Exception):
+    """
+    this exception is called whenever you try to send a mail to someone that doesn't exist
+    """
+
+    def __init__(self, receiver_id):
+        self.receiver_id = receiver_id
+        super().__init__("receiver_id doesn't exist")
+
+    def __str__(self):
+        return f' [Mailbox] : Receiver_id could not be found -> {self.receiver_id}'
diff --git a/pyAmakCore/exception/override.py b/pyAmakCore/exception/override.py
index 455dd26731c65c7596e5045dd33114843c91905c..4dcca40aab2646cd893104f5b93b74fc3d60b086 100644
--- a/pyAmakCore/exception/override.py
+++ b/pyAmakCore/exception/override.py
@@ -18,4 +18,7 @@ class ToOverrideWarning:
 
     @classmethod
     def enable_warning(cls, condition: bool) -> None:
+        """
+        enable or disable custom warning for method that should be override
+        """
         cls.__enable_warning = condition
diff --git a/pyAmakCore/tests/memory_leak/main.py b/pyAmakCore/tests/memory_leak/main.py
index 0210fbd3dc99c0d843fa42de40e0bced3df3e700..bf6126ad4094e2c0070beda58cda0a19adf4d0e1 100644
--- a/pyAmakCore/tests/memory_leak/main.py
+++ b/pyAmakCore/tests/memory_leak/main.py
@@ -1,42 +1,45 @@
+from pyAmakCore.classes.scheduler_mono_threading import SchedulerMono
+
+from pyAmakCore.exception.override import ToOverrideWarning
+from pyAmakCore.classes.agent import Agent
 from pyAmakCore.classes.amas import Amas
 from pyAmakCore.classes.environment import Environment
-from pyAmakCore.classes.agent import Agent
+from pyAmakCore.classes.scheduler import Scheduler
 
 
 class SimpleAgent(Agent):
-    """
-    test
-    """
+    pass
 
 
 class SimpleAmas(Amas):
-    """
-    test
-    """
+    def on_initialization(self) -> None:
+        # self.set_do_log(True)
+        pass
 
     def on_initial_agents_creation(self) -> None:
         for i in range(10):
             self.add_agent(SimpleAgent(self))
 
-
 class SimpleEnv(Environment):
-    """
-    test
-    """
+    pass
 
+import time
+start_time = time.time()
+ToOverrideWarning.enable_warning(False)
 
 env = SimpleEnv()
 amas = SimpleAmas(env)
 
-amas.put_token()
+#scheduler = Scheduler(amas)
+scheduler = SchedulerMono(amas)
 
-amas.start()
+scheduler.start()
+scheduler.run()
+print("--- %s seconds ---" % (time.time() - start_time))
 
 
 """
 There are no visible memory leak in pyAmakCore
-"""
-"""
 TODO : 
 We could test add agent / get most critical neighbor ... also
-"""
\ No newline at end of file
+"""
diff --git a/pyAmakCore/tests/test_agent/test_get_most_critical_neighbor.py b/pyAmakCore/tests/test_agent/test_get_most_critical_neighbor.py
index 4dff5c44a84625b18c6826c1d0b88cd9a21b2a2c..c190a4a6be87f19a87bacd81998dcb1368adcd99 100644
--- a/pyAmakCore/tests/test_agent/test_get_most_critical_neighbor.py
+++ b/pyAmakCore/tests/test_agent/test_get_most_critical_neighbor.py
@@ -11,9 +11,6 @@ class SimpleAgent(Agent):
     def set_criticality(self, i):
         self._Agent__criticality = i
 
-    def get_most_critical(self, i):
-        return self._get_most_critical_neighbor(i)
-
 
 class TestAgentGetMostCriticalNeighbor(TestCase):
     """
@@ -44,7 +41,7 @@ class TestAgentGetMostCriticalNeighbor(TestCase):
         n4.set_criticality(25)
         agent.add_neighbour(n4)
 
-        self.assertEqual(agent.get_most_critical(False), n4)
+        self.assertEqual(agent.get_most_critical_neighbor(False), n4)
 
     def test_get_most_critical_neighbor_with_self(self):
         Agent.reset_agent()
@@ -70,7 +67,7 @@ class TestAgentGetMostCriticalNeighbor(TestCase):
         n4.set_criticality(25)
         agent.add_neighbour(n4)
 
-        self.assertEqual(agent.get_most_critical(True), agent)
+        self.assertEqual(agent.get_most_critical_neighbor(True), agent)
 
 
 if __name__ == '__main__':
diff --git a/pyAmakCore/tests/test_agent/test_run.py b/pyAmakCore/tests/test_agent/test_run.py
deleted file mode 100644
index 991cb562b9fa394cda7aff988ffaa8171da595e0..0000000000000000000000000000000000000000
--- a/pyAmakCore/tests/test_agent/test_run.py
+++ /dev/null
@@ -1,52 +0,0 @@
-"""
-test that run of Agent work as intended
-"""
-from unittest import TestCase, main
-
-from pyAmakCore.classes.agent import Agent
-from pyAmakCore.classes.amas import Amas
-from pyAmakCore.classes.environment import Environment
-from pyAmakCore.enumeration.agent_phase import Phase
-from pyAmakCore.enumeration.executionPolicy import ExecutionPolicy
-
-
-class TestAgentRun(TestCase):
-    """
-    Test class for Agent run
-    """
-
-    def test_run_one_phase(self):
-        """
-        test that run() work and return correct phase with 1 phase policy
-        """
-        Agent.reset_agent()
-        environment = Environment()
-        amas = Amas(environment)
-        amas.set_execution_policy(ExecutionPolicy.ONE_PHASE)
-
-        agent = Agent(amas)
-        self.assertEqual(agent.get_phase(), Phase.INITIALIZING)
-        agent.run()
-        self.assertEqual(agent.get_phase(), Phase.DECISION_AND_ACTION_DONE)
-        agent.run()
-        self.assertEqual(agent.get_phase(), Phase.DECISION_AND_ACTION_DONE)
-
-    def test_run_two_phase(self):
-        """
-        test that run() work and return correct phase with 2 phase policy
-        """
-        Agent.reset_agent()
-        environment = Environment()
-        amas = Amas(environment)
-        amas.set_execution_policy(ExecutionPolicy.TWO_PHASES)
-
-        agent = Agent(amas)
-        self.assertEqual(agent.get_phase(), Phase.INITIALIZING)
-        agent.run()
-        self.assertEqual(agent.get_phase(), Phase.PERCEPTION_DONE)
-        agent.run()
-        self.assertEqual(agent.get_phase(), Phase.DECISION_AND_ACTION_DONE)
-
-
-if __name__ == '__main__':
-    main()
diff --git a/pyAmakCore/tests/test_amas/test_agent.py b/pyAmakCore/tests/test_amas/test_agent.py
index 5726bce9394dd991bd47160002d645f03c2b2c9b..b5a9b187db038f3165b0ee0a2baaac9a722c03a5 100644
--- a/pyAmakCore/tests/test_amas/test_agent.py
+++ b/pyAmakCore/tests/test_amas/test_agent.py
@@ -8,6 +8,11 @@ from pyAmakCore.classes.amas import Amas
 from pyAmakCore.classes.environment import Environment
 from pyAmakCore.classes.agent import Agent
 
+class SimplerAmas(Amas):
+
+    def synchronization(self):
+        self._Amas__scheduler.give_amas_token()
+        super().synchronization()
 
 class TestAmasAgents(TestCase):
     """
@@ -33,30 +38,31 @@ class TestAmasAgents(TestCase):
         """
 
         environment = Environment()
-        amas = Amas(environment)
+        amas = SimplerAmas(environment)
 
         agent1 = Agent(amas)
         agent2 = Agent(amas)
         agent3 = Agent(amas)
-        agent4 = Agent(amas)
-        agent5 = Agent(amas)
-
         # add 1 agent
         amas.add_agent(agent1)
+        amas.add_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1])
 
         # don't remove previous agent
         amas.add_agent(agent2)
+        amas.add_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent2])
 
         # add agent in good order
         amas.add_agent(agent3)
+        amas.add_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent2, agent3])
 
         # don't add duplicate
         amas.add_agent(agent1)
         amas.add_agent(agent2)
         amas.add_agent(agent3)
+        amas.add_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent2, agent3])
 
     def test_add_agents(self) -> None:
@@ -65,7 +71,7 @@ class TestAmasAgents(TestCase):
         """
 
         environment = Environment()
-        amas = Amas(environment)
+        amas = SimplerAmas(environment)
 
         agent1 = Agent(amas)
         agent2 = Agent(amas)
@@ -74,36 +80,44 @@ class TestAmasAgents(TestCase):
         agent5 = Agent(amas)
 
         amas.add_agents([agent1, agent2, agent3, agent4, agent5])
+        amas.add_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent2, agent3, agent4, agent5])
 
-        amas = Amas(environment)
+        amas = SimplerAmas(environment)
         amas.add_agents([agent1, agent2])
+        amas.add_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent2])
 
         amas.add_agents([agent1, agent2, agent4, agent2, agent3])
+        amas.add_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent2, agent4, agent3])
 
     def test_remove_agent(self) -> None:
         environment = Environment()
-        amas = Amas(environment)
+        amas = SimplerAmas(environment)
 
         agent1 = Agent(amas)
         agent2 = Agent(amas)
         agent3 = Agent(amas)
 
         amas.remove_agent(agent2)
+        amas.remove_pending_agent()
         self.assertEqual(amas.get_agents(), [])
 
         amas.add_agents([agent1, agent2, agent3])
+        amas.add_pending_agent()
 
         amas.remove_agent(agent2)
+        amas.remove_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent3])
 
         amas.remove_agent(agent2)
+        amas.remove_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent3])
 
         amas.remove_agent(agent1)
         amas.remove_agent(agent3)
+        amas.remove_pending_agent()
         self.assertEqual(amas.get_agents(), [])
 
 
diff --git a/pyAmakCore/tests/test_amas/test_nbr_cycle.py b/pyAmakCore/tests/test_amas/test_nbr_cycle.py
index 7bc3a8e2cb5e871c9b05c15fcf8898fe19eddb00..e4341b38daeb7eb8fa9f24a3bf6f2b0e86e3856e 100644
--- a/pyAmakCore/tests/test_amas/test_nbr_cycle.py
+++ b/pyAmakCore/tests/test_amas/test_nbr_cycle.py
@@ -12,7 +12,7 @@ from pyAmakCore.classes.environment import Environment
 class SimplerAmas(Amas):
 
     def synchronization(self):
-        self.scheduler.give_amas_token()
+        self._Amas__scheduler.give_amas_token()
         super().synchronization()
 
 
diff --git a/pyAmakCore/tests/test_communicating_agent/__init__.py b/pyAmakCore/tests/test_communicating_agent/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/pyAmakCore/tests/test_communicating_agent/test_mail.py b/pyAmakCore/tests/test_communicating_agent/test_mail.py
new file mode 100644
index 0000000000000000000000000000000000000000..444505df65d027c74ab77e81a8d50fa82d365a2f
--- /dev/null
+++ b/pyAmakCore/tests/test_communicating_agent/test_mail.py
@@ -0,0 +1,32 @@
+"""
+test that Mail work as intended
+"""
+from unittest import TestCase, main
+
+from pyAmakCore.classes.communicating_agent import Mail
+
+
+class TestMail(TestCase):
+    """
+    Test class Mail
+    """
+
+    def test_mail(self) -> None:
+        """
+        Test mail init
+        """
+        mail = Mail(1, 5, None, 0)
+
+        self.assertEqual(mail.get_id_sender(), 1)
+        self.assertEqual(mail.get_id_receiver(), 5)
+        self.assertEqual(mail.get_message(), None)
+        self.assertEqual(mail.get_sending_date(), 0)
+
+        mail = Mail(255, 0, "test", 12)
+        self.assertEqual(mail.get_id_sender(), 255)
+        self.assertEqual(mail.get_id_receiver(), 0)
+        self.assertEqual(mail.get_message(), "test")
+        self.assertEqual(mail.get_sending_date(), 12)
+
+if __name__ == '__main__':
+    main()
diff --git a/pyAmakCore/tests/test_communicating_agent/test_mailbox.py b/pyAmakCore/tests/test_communicating_agent/test_mailbox.py
new file mode 100644
index 0000000000000000000000000000000000000000..905820cd1ded49d0c0cca67ff5c6168ef34695c2
--- /dev/null
+++ b/pyAmakCore/tests/test_communicating_agent/test_mailbox.py
@@ -0,0 +1,45 @@
+"""
+test that Mailbox work as intended
+"""
+from unittest import TestCase, main
+
+from pyAmakCore.classes.amas import Amas
+from pyAmakCore.classes.communicating_agent import Mailbox
+from pyAmakCore.classes.environment import Environment
+
+
+class SimpleMailbox(Mailbox):
+
+    def get_amas(self):
+        return self._Mailbox__amas
+
+    def get_owner_id(self):
+        return self._Mailbox__owner_id
+
+    def get_mail_list(self):
+        return self._Mailbox__mail_list
+
+
+class TestMailbox(TestCase):
+    """
+    Test class Mailbox
+    """
+
+    def test_init_mailbox(self) -> None:
+        """
+        Test mailbox init
+        """
+
+        environment = Environment()
+        amas = Amas(environment)
+
+        mailbox = SimpleMailbox(0, amas)
+
+        self.assertEqual(mailbox.get_amas(), amas)
+        self.assertEqual(mailbox.get_owner_id(), 0)
+        self.assertEqual(mailbox.get_mail_list(), [])
+        self.assertEqual(mailbox.get_mail(), None)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/release/changelog.txt b/release/changelog.txt
new file mode 100644
index 0000000000000000000000000000000000000000..92fbf8586225a596d06bf490eb5cc7b5c492fd4a
--- /dev/null
+++ b/release/changelog.txt
@@ -0,0 +1,17 @@
+v0.1.0:
+ WARNING : all previous example will no longer work in this version, and all v0.1.0+ example won't work in previous version
+ * Way better thread management
+ * Add save and load
+
+v0.0.5:
+ * Fix rare bugs : an agent that would be removed in the cycle could be called by another agent
+ * CSV : Add method : add_ignore_attribute(self, attribute: str) -> None, remove_ignore_attribute(self, attribute: str) -> None
+	to manage ignored attribute
+
+v0.0.4:
+ * add AmasIHM (old examples will no longer work from now on if using AmasIHM )
+
+v0.0.3 :
+ * Add communicating agent
+
+v0.0.2
diff --git a/release/pyAmakCore-0.0.2-py3-none-any.whl b/release/pyAmakCore-0.0.2-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..6cdca8943d9a7dc1f3bb5b900aea91220a4a16e3
Binary files /dev/null and b/release/pyAmakCore-0.0.2-py3-none-any.whl differ
diff --git a/release/pyAmakCore-0.0.3-py3-none-any.whl b/release/pyAmakCore-0.0.3-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..9a5070130b134c9adc743c60e39fb2ca73374c8e
Binary files /dev/null and b/release/pyAmakCore-0.0.3-py3-none-any.whl differ
diff --git a/release/pyAmakCore-0.0.4-py3-none-any.whl b/release/pyAmakCore-0.0.4-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..904c43441aa8ff18808817250b162d8ea6d94d88
Binary files /dev/null and b/release/pyAmakCore-0.0.4-py3-none-any.whl differ
diff --git a/release/pyAmakCore-0.0.5-py3-none-any.whl b/release/pyAmakCore-0.0.5-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..1475c4083eac33230b399e4722b27ce678b43692
Binary files /dev/null and b/release/pyAmakCore-0.0.5-py3-none-any.whl differ
diff --git a/release/pyAmakCore-0.1.0-py3-none-any.whl b/release/pyAmakCore-0.1.0-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..d177b6bcb2b542909ce76368d6b1cff0e4260035
Binary files /dev/null and b/release/pyAmakCore-0.1.0-py3-none-any.whl differ
diff --git a/requirements.txt b/requirements.txt
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1411a4a0b5ab886adfb744e685d150151ab10023 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -0,0 +1 @@
+pandas
\ No newline at end of file
diff --git a/setup.py b/setup.py
index a8ca080289a4566be251c03b56a40094f8028dd9..3d73d5dccd4434e871c2cf07eb5550230a49ab19 100644
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
 setup(
     name='pyAmakCore',
     packages=find_packages(),
-    version='0.0.2',
+    version='0.1.0',
     description='AmakFramework in python',
     author='BE',
     install_requires=[],