diff --git a/src/graph.py b/src/graph.py
index 7252cb32fac66539d67797dc9c53c127f2a37663..925f15f5989aa30b5ceea892fbb689bcb56af0c4 100644
--- a/src/graph.py
+++ b/src/graph.py
@@ -292,11 +292,14 @@ class Graph():
     def generate_user_view(self, relevant_processes = [], render_graphs = True):
         #For now i'm only gonna work from the flattened dico
         self.initialise_flattened_dico(self.dico_process_dependency_graph)
+        #self.initialise_flattened_dico(self.full_dico)
         dico = self.dico_flattened
 
         user_view = relev_user_view_builder(dico, relevant_modules=relevant_processes)
+        
         with open(self.get_output_dir()/ "graphs/user_view.json", 'w') as output_file :
             json.dump(user_view, output_file, indent=4)
+        
         generate_graph(self.get_output_dir()/'graphs'/"user_view", user_view, label_edge=True, label_node=True, render_graphs = render_graphs)
         
 
diff --git a/src/outils_annotate.py b/src/outils_annotate.py
new file mode 100644
index 0000000000000000000000000000000000000000..0f968a8e48a7254dc72ad44b6ba60c386eadab6d
--- /dev/null
+++ b/src/outils_annotate.py
@@ -0,0 +1,201 @@
+import copy
+import numpy as np
+import re
+
+tools = []
+commands = []
+
+
+
+
+def get_propositions(process, tools = -1, commands = -1):
+    temp = []
+    if(tools!=-1):
+        for tool in tools:
+            #for character in char_after_tool:
+            for match in re.finditer(r"(\s|\(|\/|\|)"+tool+r"(\s|\-|\\|\.)", process):
+                #if(f"{tool}{character}" in process):
+                temp.append(tool)
+    if(commands!=-1):
+        for commands in commands:
+            tool, command = commands.split()
+            command = command.replace('+', '\+')
+            for match in re.finditer(tool+r"\s+\-[^\s]+\s+"+command, process):
+                temp.append(commands)
+            for match in re.finditer(tool+r"\s+"+command, process):
+                temp.append(commands)
+            for match in re.finditer(tool+r"\s+\\\s+"+command, process):
+                temp.append(commands)
+            for match in re.finditer(tool+r"\s+\-[^\s]+\s+[^\s]+\s+"+command, process):
+                temp.append(commands)
+            for match in re.finditer(tool+r"\.\w+\s+"+command, process):
+                temp.append(commands)
+            for match in re.finditer(tool+r"\.jar\s+[^\s]+\s+"+command, process):
+                temp.append(commands)
+
+    return list(set(temp))
+
+
+def get_propositions_from_user():
+    propositions = []
+    nb_prop = 1
+    input_val = "a"
+    while(input_val!=""):
+        input_val = input(f"Proposition {nb_prop} : ")
+        if(input_val!=""):
+            propositions.append(input_val)
+        nb_prop+=1
+    return propositions
+
+def print_colored_words(text, words):
+    temp_words = []
+    for word in words:
+        temp_words+= word.split()
+    words = temp_words
+
+    colors = ['\033[31m', '\033[32m', '\033[33m', '\033[34m', '\033[35m', '\033[36m']  # Colors: Red, Green, Yellow, Blue, Magenta, Cyan
+    color_index = 0
+    
+    for i in range(len(words)):
+        word = words[i]
+        color = colors[color_index % len(colors)]
+        text = text.replace(word, f"{color}{word}\033[0m")
+        color_index += 1
+    print(text)
+
+def get_tools_commands_from_user_for_process(p, exiting_tools, existing_commands):
+    tools_found, commands_found = [], []
+    codes = []
+    codes.append(p.get_code())
+    codes+=p.get_external_scripts_code()
+
+    for c in codes:
+        print_colored_words(c, get_propositions(p, commands=existing_commands)+get_propositions(p, tools=exiting_tools))
+        print("\nTOOLS")
+        confirmation = 'a'
+        while(confirmation!=""):
+            propositions = get_propositions_from_user()
+            confirmation = input(f"Press 'ENTER' to validate this propostion of tools {propositions} (press any key otherwise) : ")
+        tools_found += propositions
+        print("\nCOMMANDS")
+        confirmation = 'a'
+        while(confirmation!=""):
+            propositions = get_propositions_from_user()
+            confirmation = input(f"Press 'ENTER' to validate this propostion of commands {propositions} (press any key otherwise) : ")
+        commands_found += propositions
+    
+    exiting_tools+= tools_found
+    existing_commands+= commands_found
+    return tools_found, commands_found, exiting_tools, existing_commands
+
+
+
+
+index = 0
+for process_id in process_2_annotations_pre_verification:
+    p = process_2_annotations_pre_verification[process_id]["process"]
+    try:
+        tmp = process_2_annotation[process_id]
+    except:
+        current_tools = process_2_annotations_pre_verification[process_id]["tools"]
+        current_commands = process_2_annotations_pre_verification[process_id]["commands"]
+
+        print(f"\n* Current progess : {index/len(process_2_annotations_pre_verification)*100:.2f}% ({len(process_2_annotations_pre_verification)-index} left)")
+        print("--------------------------------------------------")
+        print_colored_words(p, current_commands+current_tools+get_propositions(p, commands=commands)+get_propositions(p, tools=tools))
+        
+        validate_annoation = False
+        while(not validate_annoation):
+            print()
+            print_colored_words(f" - Current tools: {current_tools}", current_commands+current_tools)
+            print_colored_words(f" - Current commands: {current_commands}", current_commands+current_tools)
+            print()
+            annotation = input("Validate current annotations (press enter/ anykey otherwise):")
+            if(annotation==""):
+                validate_annoation = True
+            else:
+                print("\nTOOLS")
+                confirmation = 'a'
+                while(confirmation!=""):
+                    propositions = get_propositions_from_user()
+                    confirmation = input(f"Press 'ENTER' to validate this propostion of tools {propositions} (press any key otherwise) : ")
+                current_tools = propositions
+                print("\nCOMMANDS")
+                confirmation = 'a'
+                while(confirmation!=""):
+                    propositions = get_propositions_from_user()
+                    confirmation = input(f"Press 'ENTER' to validate this propostion of commands {propositions} (press any key otherwise) : ")
+                current_commands = propositions
+
+        tools+=current_tools
+        commands+=current_commands
+        tools = list(set(tools))
+        commands = list(set(commands))
+
+        ext_tools, ext_commands = [], []
+        for ext in process_2_annotations_pre_verification[process_id]["external_scripts"]:
+            envs = ["env python", "env Rscript"]
+            show_it = True
+            for env in envs:
+                if(env in ext):
+                    show_it = False
+
+            if(show_it):
+                print("\n--------------------------------------------------")
+                propositions = get_propositions(ext, tools=tools)
+                print_colored_words(ext, propositions)
+
+                print("\nTOOLS")
+                print_colored_words(f"Propositions are : {propositions}", propositions)
+                val = input("Press 'ENTER' to validate (press any key otherwise) : ")
+                if(val==''):
+                    ext_tools+=propositions
+                else:
+                    confirmation = 'a'
+                    while(confirmation!=""):
+                        propositions = get_propositions_from_user()
+                        confirmation = input(f"Press 'ENTER' to validate this propostion of tools {propositions} (press any key otherwise) : ")
+                    ext_tools+=propositions
+                
+                propositions = get_propositions(ext, commands=commands)
+                print_colored_words(ext, propositions)
+                print("\nCOMMANDS")
+                print_colored_words(f"Propositions are : {propositions}", propositions)
+                val = input("Press 'ENTER' to validate (press any key otherwise) : ")
+                if(val==''):
+                    ext_commands+=propositions
+                else:
+                    confirmation = 'a'
+                    while(confirmation!=""):
+                        propositions = get_propositions_from_user()
+                        confirmation = input(f"Press 'ENTER' to validate this propostion of commands {propositions} (press any key otherwise) : ")
+                    current_commands = propositions
+                    ext_commands+=propositions
+
+        current_tools+=ext_tools
+        current_commands+=ext_commands
+        current_tools = list(set(current_tools))
+        current_commands = list(set(current_commands))
+
+        tools+=current_tools
+        commands+=current_commands
+        tools = list(set(tools))
+        commands = list(set(commands))
+
+        process_2_annotation[process_id] = {}     
+        process_2_annotation[process_id]['process'] = process_2_annotations_pre_verification[process_id]['process']  
+        process_2_annotation[process_id]['has_external_scripts'] = process_2_annotations_pre_verification[process_id]['has_external_scripts']
+        process_2_annotation[process_id]['external_scripts'] = process_2_annotations_pre_verification[process_id]['external_scripts'] 
+        process_2_annotation[process_id]['R_modules'] = process_2_annotations_pre_verification[process_id]['R_modules']
+        process_2_annotation[process_id]['python_modules'] = process_2_annotations_pre_verification[process_id]['python_modules']
+        process_2_annotation[process_id]['perl_modules'] = process_2_annotations_pre_verification[process_id]['perl_modules']
+        process_2_annotation[process_id]['tools'] = current_tools
+        process_2_annotation[process_id]['commands'] = current_commands
+
+    with open("process_2_annotation.json", "w") as outfile:
+        json.dump(process_2_annotation, outfile, indent=4)
+
+
+    index+=1
+
+
diff --git a/src/outils_graph.py b/src/outils_graph.py
index fc5d4c67f458e8842ee3abaf2e30779eb8873009..4f17a58cc4d36d3cf8a949a7430345dc79b55694 100644
--- a/src/outils_graph.py
+++ b/src/outils_graph.py
@@ -414,19 +414,24 @@ def get_neighbors(edges, A):
             Bs.append(e['B'])
     return Bs
 
-def exist_path(A, B, edges):
-    N = get_nodes_from_edges(edges=edges)
-    visited = {}
-    for n in N:
-        visited[n] = False
+
+def exist_path_rec(A, B, edges, visited):
     visited[A] = True
     if(A==B):
         return True
     for neigh in get_neighbors(edges, A):
-        if(exist_path(neigh, B, edges)):
-            return True
+        if(not visited[neigh]):
+            if(exist_path_rec(neigh, B, edges, visited = visited)):
+                return True
     return False
 
+def exist_path(A, B, edges):
+    N = get_nodes_from_edges(edges=edges)
+    visited = {}
+    for n in N:
+        visited[n] = False
+    return exist_path_rec(A, B, edges, visited)
+
 
 def nr_path_succ(n, r, dico, R):
     rest_of_R = set(R)-set([r])
@@ -533,6 +538,7 @@ def relev_user_view_builder(dico, relevant_modules):
     R = []
     for r in relevant_modules:
         R+=get_id_from_name(dico, r)
+    R = list(set(R))
     outputs = get_output_nodes(dico)
     inputs = get_input_nodes(dico)
     #dico['nodes'].append({'id':"input", 'name':"input"})
diff --git a/src/workflow.py b/src/workflow.py
index 77ccd87a1b807159df1b7ad9003095625aed40c9..96bc4bbd22c19f73f24c66547e9336bae1152eee 100644
--- a/src/workflow.py
+++ b/src/workflow.py
@@ -4,6 +4,7 @@ from .nextflow_file import Nextflow_File
 from .ro_crate import RO_Crate
 from . import constant
 from .outils_graph import flatten_dico, initia_link_dico_rec, get_number_cycles
+from .outils_annotate import get_tools_commands_from_user_for_process
 from .bioflowinsighterror import BioFlowInsightError
 
 #Outside packages
@@ -46,7 +47,8 @@ class Workflow:
                  version = None, keywords = None, producer = None,
                  publisher = None, processes_2_remove = None,
                  processes_annotation = None,
-                 personnal_acces_token = None):
+                 personnal_acces_token = None,
+                 processes_2_tools = None):
 
         if(not os.path.isfile(file)):
             nextflow_files = glob.glob(f'{file}/*.nf')
@@ -83,6 +85,7 @@ class Workflow:
         self.producer = producer
         self.publisher = publisher
         self.personnal_acces_token = personnal_acces_token
+        self.processes_2_tools = processes_2_tools
         if(processes_2_remove==""):
             processes_2_remove = None
         self.processes_2_remove = processes_2_remove
@@ -532,4 +535,21 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
             temp = self.processes_2_remove.split(",")
             for t in temp:
                 tab_processes_2_remove.append(t.strip())
-        self.nextflow_file.generate_user_view(relevant_processes = relevant_processes, render_graphs = render_graphs, processes_2_remove = tab_processes_2_remove)
\ No newline at end of file
+        self.nextflow_file.generate_user_view(relevant_processes = relevant_processes, render_graphs = render_graphs, processes_2_remove = tab_processes_2_remove)
+
+    def build_processes_2_tools(self):
+        if(self.processes_2_tools==None):
+            exiting_tools, existing_commands = [], []
+            processes = self.get_processes_used()
+            dico = {}
+            for p in processes:
+                tools_found, commands_found, exiting_tools, existing_commands = get_tools_commands_from_user_for_process(p, exiting_tools, existing_commands)
+                dico[p.get_code()] = {}
+                dico[p.get_code()]["tools"] = tools_found
+                dico[p.get_code()]["commands"] = commands_found
+            self.processes_2_tools = dico
+            with open(f"{self.get_output_dir()}/processes_2_tools.json", 'w') as output_file :
+                json.dump(self.processes_2_tools, output_file, indent=2)
+            return self.processes_2_tools
+        else:
+            return self.processes_2_tools