diff --git a/src/cmd/package.rs b/src/cmd/package.rs
index a66d2d6fb30947ee175f604d66f2ab1f2df07725..097e4a19ce9ca11bd77a7868ffd8cb1a499a4da4 100644
--- a/src/cmd/package.rs
+++ b/src/cmd/package.rs
@@ -16,6 +16,21 @@ pub struct CmdPackage {
 }
 
 impl CmdPackage {
+    #[allow(dead_code)]
+    pub fn has_command(&self, user_cmd: &Vec<String>) -> bool {
+        match user_cmd.split_first() {
+            None => false,
+            Some((name, args)) => match self
+                .commands
+                .iter()
+                .find(|x| x.matches(name, &args.to_vec()))
+            {
+                None => false,
+                Some(_) => true,
+            },
+        }
+    }
+
     #[allow(dead_code)]
     pub fn handle(&self, room: &JoinedRoom, user_id: &UserId, user_cmd: Vec<String>) -> String {
         match CmdAcl::action_permited(&self.admin_register, &self.acl, room, user_id) {
diff --git a/src/main.rs b/src/main.rs
index 6d6be28c79dc41dc6ea7fb24633546781932d427..607249d6448c8dd17b8d661721d288534db89942 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,4 @@
-#![feature(clone_closures)]
+#![feature(new_uninit, once_cell)]
 
 mod cmd;
 mod config;
diff --git a/src/matrix.rs b/src/matrix.rs
index 84d27f19955cda13b56dcbded3703b84f63a49ad..030ccb621f248eacfe21326015017f7e22668e6f 100644
--- a/src/matrix.rs
+++ b/src/matrix.rs
@@ -10,13 +10,13 @@ use matrix_sdk::{
                 member::MemberEventContent,
                 message::{MessageEventContent, MessageType, TextMessageEventContent},
             },
-            SyncMessageEvent, SyncStateEvent,
+            AnyMessageEventContent, SyncMessageEvent, SyncStateEvent,
         },
         UserId,
     },
     Client, Result, SyncSettings,
 };
-use std::{convert::TryFrom, process::abort, sync::Arc};
+use std::{convert::TryFrom, lazy::SyncLazy, process::abort, sync::Arc, sync::Mutex};
 use tokio::time::{sleep, Duration};
 
 async fn join_room(room: &Invited) {
@@ -80,15 +80,14 @@ async fn startup_and_log_rooms(client: &Client) {
     join_all(list_to_wait_for).await;
 }
 
+static GLOBAL_PKG: SyncLazy<Arc<Mutex<Vec<CmdPackage>>>> =
+    SyncLazy::new(|| Arc::new(Mutex::new(Vec::<CmdPackage>::new())));
+
 pub async fn connect_and_handle(config: Config) -> Result<()> {
     // TODO: Refactor
     let pkg_commands_vec = vec![
         Cmd::new_simple(format!("ping"), 0, Arc::new(|_x| true)),
-        Cmd::new_echo(
-            format!("bot_name"),
-            0,
-            Arc::new(move |_x| format!("toto")),
-        ),
+        Cmd::new_echo(format!("bot_name"), 0, Arc::new(move |_x| format!("toto"))),
     ];
     let pkg = match config.section("basic") {
         Some(section) => CmdPackage::from_config(&section, pkg_commands_vec),
@@ -97,6 +96,59 @@ pub async fn connect_and_handle(config: Config) -> Result<()> {
         }
     };
 
+    GLOBAL_PKG.lock().unwrap().push(pkg);
+
+    let on_msg_room_event =
+        move |ev: SyncMessageEvent<MessageEventContent>,
+              room: Room,
+              _encryption_info: Option<EncryptionInfo>| async move {
+            let sender_id = ev.sender;
+            if sender_id.as_str() == room.own_user_id().as_str() {
+                return;
+            }
+
+            if room.name().is_none() {
+                warn!("Unsupported rooms without names");
+                return;
+            }
+
+            if let Room::Joined(joined) = room {
+                if let MessageType::Text(TextMessageEventContent { body, .. }) = ev.content.msgtype
+                {
+                    if body.starts_with("%") {
+                        let args = vec![];
+                        let mut res: String = format!("Command not found");
+                        if let Some(pkg) = GLOBAL_PKG
+                            .lock()
+                            .unwrap()
+                            .iter()
+                            .find(|x| x.has_command(&args))
+                        {
+                            res = pkg.handle(&joined, &sender_id, args);
+                        }
+
+                        joined
+                            .send(
+                                AnyMessageEventContent::RoomMessage(
+                                    MessageEventContent::text_plain(res),
+                                ),
+                                None,
+                            )
+                            .await
+                            .unwrap();
+                    }
+                }
+            }
+
+            // if let Room::Invited(_) = room {
+            //     warn!("Bot was invited by {sender_id} to room {room_id} a.k.a. {room_name}",);
+            // }
+
+            // if let Room::Left(_) = room {
+            //     error!("Bot left room {room_id} a.k.a. {room_name}")
+            // }
+        };
+
     let alice = UserId::try_from(config.user_name)?;
     let client = Client::new(config.homeserver_url)?;
 
@@ -120,45 +172,7 @@ pub async fn connect_and_handle(config: Config) -> Result<()> {
         warn!("Ignore state member events");
     }
 
-    client
-        .register_event_handler(
-            move |ev: SyncMessageEvent<MessageEventContent>,
-                  room: Room,
-                  _encryption_info: Option<EncryptionInfo>| async {
-                let sender_id = ev.sender;
-                if sender_id.as_str() == room.own_user_id().as_str() {
-                    return;
-                }
-
-                if room.name().is_none() {
-                    warn!("Unsupported rooms without names");
-                    return;
-                }
-
-                if let Room::Joined(joined) = room {
-                let room_id = joined.room_id();
-                let room_name = joined.name().unwrap();
-                    if let MessageType::Text(TextMessageEventContent { body, .. }) =
-                        ev.content.msgtype
-                    {
-                        if body.starts_with("%") {
-                            info!("Got message from {sender_id} in {room_id} a.k.a. {room_name}");
-                            let args = vec![];
-                            let locked_pkg = pkg.handle(&joined, &sender_id, args);
-                        }
-                    }
-                }
-
-                // if let Room::Invited(_) = room {
-                //     warn!("Bot was invited by {sender_id} to room {room_id} a.k.a. {room_name}",);
-                // }
-
-                // if let Room::Left(_) = room {
-                //     error!("Bot left room {room_id} a.k.a. {room_name}")
-                // }
-            },
-        )
-        .await;
+    client.register_event_handler(on_msg_room_event).await;
 
     info!("Entering sync loop");
     let token = client.sync_token().await.unwrap();