diff --git a/CommandBase.js b/CommandBase.js
new file mode 100644
index 0000000000000000000000000000000000000000..2222d7817ef30a2448fe56a97a28123a8513df86
--- /dev/null
+++ b/CommandBase.js
@@ -0,0 +1,7 @@
+class CommandBase {
+    constructor(client) {
+        this.client = client;
+    }
+}
+
+module.exports = CommandBase;
\ No newline at end of file
diff --git a/README.md b/README.md
index d8a9df99017206e29440a175c050d4013b310b22..5e94206b1b1c0f271ee9eba3fd2243abf383e8f7 100644
--- a/README.md
+++ b/README.md
@@ -13,13 +13,13 @@ This bot listens on the Federated Timeline and follows everyone.
 This bot respect the #nobot tag.
 
 If you don't want to be followed by the bot anymore, 
-just DM "unfollow" to the bot, and it'll never follow you again. [WIP]
+just DM "unfollow" to the bot, and it'll never follow you again.
 
 |Command|What is does|
 |---|---|
-|unfollow|[WIP] The bot will unfollow and mure you so it'll never follow you again.|
-|blockuser <user@domain.tld>|[WIP] The bot will mute the targeted user. If followed, it'll unfollow they too. Admin only.|
-|blockdomain <domain.tld>|[WIP] The bot will mute the targeted domain. If users from this domain are followed, it'll unfollow them. Admin only.|
+|unfollow|The bot will unfollow and mure you so it'll never follow you again.|
+|blockuser <user@domain.tld>|The bot will mute the targeted user. If followed, it'll unfollow they too. Admin only.|
+|blockdomain <domain.tld>|The bot will mute the targeted domain. If users from this domain are followed, it'll unfollow them. Admin only.|
 
 ## Running the bot
 
diff --git a/bot.js b/bot.js
index 63dab79cded1e31a2e97d2d555be823df089b216..753137b0c11ee322c94891f4dc952511e58c367b 100644
--- a/bot.js
+++ b/bot.js
@@ -1,9 +1,6 @@
 const EventEmitter = require('events');
 const MastodonAPI = require('mastodon-api');
 
-// Todo: Implements mute_user and block_domain
-// Todo: Implements unfollow
-
 class Bot extends EventEmitter {
     /**
      * Constructor
@@ -110,6 +107,15 @@ class Bot extends EventEmitter {
     follow(id) {
         this.M.post('accounts/' + id + '/follow');
     }
+
+    /**
+     * Unfollow a user
+     * @param {int} id
+     */
+    unfollow(id) {
+        this.M.post('accounts/' + id + '/unfollow');
+    }
+
     /**
      * Mute an user
      * @param {int} id
@@ -118,5 +124,13 @@ class Bot extends EventEmitter {
         this.M.post('accounts/' + id + '/mute');
     }
 
+    /**
+     * Block a domain
+     * @param {string} domain
+     */
+    block_domain(domain) {
+        this.M.post('domain_blocks', { domain });
+    }
 }
+
 module.exports = Bot;
\ No newline at end of file
diff --git a/commands/BlockDomain.js b/commands/BlockDomain.js
new file mode 100644
index 0000000000000000000000000000000000000000..1a9753e0c4281c330e9f9ca436799fa2cc07aca1
--- /dev/null
+++ b/commands/BlockDomain.js
@@ -0,0 +1,18 @@
+const CommandBase = require('../CommandBase');
+
+class BlockDomain extends CommandBase {
+    constructor(client) {
+        super(client);
+        this.name = 'blockdomain';
+        this.admin_only = true;
+        this.required_args = 1;
+    }
+
+    execute(msg, args) {
+        this.client.block_domain(args[0]);
+
+        this.client.fav(msg.status.id);
+    }
+}
+
+module.exports = BlockDomain;
\ No newline at end of file
diff --git a/commands/MuteUser.js b/commands/MuteUser.js
new file mode 100644
index 0000000000000000000000000000000000000000..116465be9057e7edd002fb61cdcc2323a5bb345a
--- /dev/null
+++ b/commands/MuteUser.js
@@ -0,0 +1,18 @@
+const CommandBase = require('../CommandBase');
+
+class MuteUser extends CommandBase {
+    constructor(client) {
+        super(client);
+        this.name = 'muteuser';
+        this.admin_only = true;
+        this.required_args = 1;
+    }
+
+    execute(msg, args) {
+        this.client.mute_user(args[0]);
+
+        this.client.fav(msg.status.id);
+    }
+}
+
+module.exports = MuteUser;
\ No newline at end of file
diff --git a/commands/Unfollow.js b/commands/Unfollow.js
new file mode 100644
index 0000000000000000000000000000000000000000..9505c02d51384d57b9af97395d3c682472b68a6e
--- /dev/null
+++ b/commands/Unfollow.js
@@ -0,0 +1,18 @@
+const CommandBase = require('../CommandBase');
+
+class Unfollow extends CommandBase {
+    constructor(client) {
+        super(client);
+        this.name = 'unfollow';
+    }
+
+    execute(msg) {
+        this.client.unfollow(msg.account.id);
+
+        this.client.mute_user(msg.account.id);
+
+        this.client.fav(msg.status.id);
+    }
+}
+
+module.exports = Unfollow;
\ No newline at end of file
diff --git a/index.js b/index.js
index 7e3c39a6c24a6e83a48e6c7c75c9f66fef72c7a3..fadc7a84a9164414e114877495b70fe12240b340 100644
--- a/index.js
+++ b/index.js
@@ -1,10 +1,23 @@
 const Bot = require("./bot");
 const striptags = require('striptags');
+const fs = require('fs');
+const Dict = require('collections/dict');
 const config = require('./config.json');
 
+// Hardcode admins since Mastodon API doesn't provide such thing...
+const admins = ['tagadmin', 'Dhveszak', 'Incandescente'];
+
 const client = new Bot(config, [{api_point: "public", events: ["update"]},
                                 {api_point: "user", events: ["notification"]}]);
 
+const commands = new Dict();
+const commandFiles = fs.readdirSync(__dirname + "/commands/");
+for (const file of commandFiles) {
+    const commandClass = require(__dirname + "/commands/" + file);
+    const command = new commandClass(client);
+    commands.set(command.name, command)
+}
+
 // Following list
 const following = [];
 
@@ -16,6 +29,7 @@ client.start().then(() => {
     });
 });
 
+// When a toot arrives in Federated Timeline
 client.on('update', (msg) => {
     const acct = msg.account.acct;
     const id = parseInt(msg.account.id);
@@ -45,10 +59,43 @@ client.on('update', (msg) => {
     console.log("NOW FOLLOWS: " + acct);
 });
 
+// When a toto arrives in notifications (mentions)
 client.on("notification", (msg) => {
     if (msg.type !== "mention") return;
 
-    // Todo: Implement unfollow command
-    // Todo: Implement blockuser command
-    // Todo: Implement blockdomain command
+    if (!admins.some((e) => { return e === msg.account.acct;})) return;
+
+    const status = striptags(msg.status.content);
+
+    if (!status.startsWith(client.me.acct)) return;
+
+    const args = stripped.slice(client.me.acct + 1).trim().split(/ +/);
+    const commandName = args.shift().toLowerCase();
+
+    //Check if command exists
+    if (!this.commands.has(commandName)) {
+        return;
+    }
+    const command = this.commands.get(commandName);
+
+    //Check if command is disabled
+    if (command.disabled === true) return;
+
+    //Check if command is AdminOnly
+    if(command.admin_only === true && !admins.some((e) => { return e === msg.account.acct;})) return;
+
+    //Check args length
+    if (command.required_args > args) {
+        return;
+    }
+
+    console.log(`CMD: ${commandName} from ${msg.account.acct}`);
+
+    //Execute the command
+    try {
+        command.execute(msg, args);
+    }
+    catch (error) {
+        console.error(error);
+    }
 });
\ No newline at end of file
diff --git a/package.json b/package.json
index 8f668da0e0a835395877e8698e018cdbd40f81fc..cd1f73ea62ce5e47e1bd3532ae2b7b072f003c58 100644
--- a/package.json
+++ b/package.json
@@ -2,6 +2,7 @@
   "name": "federationbot",
   "version": "0.0.1",
   "dependencies": {
+    "collections": "^5.1.2",
     "mastodon-api": "^1.3.0",
     "striptags": "^3.1.1"
   }