diff --git a/api/pom.xml b/api/pom.xml
index b6455baf..eb6b8c20 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -9,4 +9,12 @@
         <version>${revision}</version>
     </parent>
     <artifactId>api</artifactId>
+    <dependencies>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.4</version>
+            <scope>compile</scope>
+        </dependency>
+    </dependencies>
 </project>
\ No newline at end of file
diff --git a/api/src/main/java/org/geysermc/api/Connector.java b/api/src/main/java/org/geysermc/api/Connector.java
new file mode 100644
index 00000000..68478b65
--- /dev/null
+++ b/api/src/main/java/org/geysermc/api/Connector.java
@@ -0,0 +1,48 @@
+/*
+ * GNU LESSER GENERAL PUBLIC LICENSE
+ * Version 3, 29 June 2007
+ *
+ * Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ *
+ * You can view the LICENCE file for details.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.api;
+
+import org.geysermc.api.command.CommandMap;
+import org.geysermc.api.logger.Logger;
+import org.geysermc.api.plugin.PluginManager;
+
+public interface Connector {
+
+    /**
+     * Returns the logger
+     *
+     * @return the logger
+     */
+    Logger getLogger();
+
+    /**
+     * Returns the command map
+     *
+     * @return the command map
+     */
+    CommandMap getCommandMap();
+
+    /**
+     * Returns the plugin manager
+     *
+     * @return the plugin manager
+     */
+    PluginManager getPluginManager();
+
+    /**
+     * Shuts down the connector
+     */
+    void shutdown();
+}
diff --git a/api/src/main/java/org/geysermc/api/Geyser.java b/api/src/main/java/org/geysermc/api/Geyser.java
index e8f68d16..cbbc01bd 100644
--- a/api/src/main/java/org/geysermc/api/Geyser.java
+++ b/api/src/main/java/org/geysermc/api/Geyser.java
@@ -1,18 +1,55 @@
 package org.geysermc.api;
 
-import org.geysermc.api.plugin.Plugin;
-
-import java.util.ArrayList;
-import java.util.List;
+import org.geysermc.api.command.CommandMap;
+import org.geysermc.api.logger.Logger;
+import org.geysermc.api.plugin.PluginManager;
 
 public class Geyser {
-    private static final List<Plugin> plugins = new ArrayList<>();
 
-    public static List<Plugin> getPlugins() {
-        return new ArrayList<>(plugins);
+    private static Connector connector;
+
+    /**
+     * Returns the connector instance for Geyser
+     *
+     * @return the connector instance for Geyser
+     */
+    public static Connector getConnector() {
+        return connector;
     }
 
-    public static void add(Plugin p) {
-        plugins.add(p);
+    /**
+     * Sets the connector instance for Geyser
+     *
+     * @param connector the connector instance
+     */
+    public static void setConnector(Connector connector) {
+        Geyser.connector = connector;
+    }
+
+    /**
+     * Returns the logger
+     *
+     * @return the logger
+     */
+    public static Logger getLogger() {
+        return connector.getLogger();
+    }
+
+    /**
+     * Returns the plugin manager
+     *
+     * @return the plugin manager
+     */
+    public static PluginManager getPluginManager() {
+        return connector.getPluginManager();
+    }
+
+    /**
+     * Returns the command map
+     *
+     * @return the command map
+     */
+    public static CommandMap getCommandMap() {
+        return connector.getCommandMap();
     }
 }
diff --git a/api/src/main/java/org/geysermc/api/command/CommandMap.java b/api/src/main/java/org/geysermc/api/command/CommandMap.java
new file mode 100644
index 00000000..41db01d6
--- /dev/null
+++ b/api/src/main/java/org/geysermc/api/command/CommandMap.java
@@ -0,0 +1,42 @@
+/*
+ * GNU LESSER GENERAL PUBLIC LICENSE
+ * Version 3, 29 June 2007
+ *
+ * Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ *
+ * You can view the LICENCE file for details.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.api.command;
+
+import java.util.Map;
+
+public interface CommandMap {
+
+    /**
+     * Registers a new command
+     *
+     * @param command the command to register
+     */
+    void registerCommand(Command command);
+
+    /**
+     * Runs a command for the given command sender
+     *
+     * @param sender the sender to run the command for
+     * @param command the command to run
+     */
+    void runCommand(CommandSender sender, String command);
+
+    /**
+     * Returns a map of the commands
+     *
+     * @return a map of the commands
+     */
+    Map<String, Command> getCommands();
+}
diff --git a/api/src/main/java/org/geysermc/api/logger/Logger.java b/api/src/main/java/org/geysermc/api/logger/Logger.java
new file mode 100644
index 00000000..3a58714d
--- /dev/null
+++ b/api/src/main/java/org/geysermc/api/logger/Logger.java
@@ -0,0 +1,46 @@
+/*
+ * GNU LESSER GENERAL PUBLIC LICENSE
+ * Version 3, 29 June 2007
+ *
+ * Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ *
+ * You can view the LICENCE file for details.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.api.logger;
+
+public interface Logger {
+
+    /**
+     * Logs an info message to console
+     *
+     * @param message the message to log
+     */
+    void info(String message);
+
+    /**
+     * Logs a severe message to console
+     *
+     * @param message the message to log
+     */
+    void severe(String message);
+
+    /**
+     * Logs a warning message to console
+     *
+     * @param message the message to log
+     */
+    void warning(String message);
+
+    /**
+     * Logs a debug message to console
+     *
+     * @param message the message to log
+     */
+    void debug(String message);
+}
diff --git a/api/src/main/java/org/geysermc/api/plugin/Plugin.java b/api/src/main/java/org/geysermc/api/plugin/Plugin.java
index 90299b6d..fb7b09f1 100644
--- a/api/src/main/java/org/geysermc/api/plugin/Plugin.java
+++ b/api/src/main/java/org/geysermc/api/plugin/Plugin.java
@@ -1,14 +1,31 @@
 package org.geysermc.api.plugin;
 
+import lombok.Getter;
+import lombok.Setter;
+
 public class Plugin {
+
+    @Getter
+    @Setter
+    private boolean enabled = true;
+
+    /**
+     * Called when a plugin is enabled
+     */
     public void onEnable() {
 
     }
 
+    /**
+     * Called when a plugin is disabled
+     */
     public void onDisable() {
 
     }
 
+    /**
+     * Called when a plugin is loaded
+     */
     public void onLoad() {
 
     }
diff --git a/api/src/main/java/org/geysermc/api/plugin/PluginManager.java b/api/src/main/java/org/geysermc/api/plugin/PluginManager.java
new file mode 100644
index 00000000..6a8567ef
--- /dev/null
+++ b/api/src/main/java/org/geysermc/api/plugin/PluginManager.java
@@ -0,0 +1,55 @@
+/*
+ * GNU LESSER GENERAL PUBLIC LICENSE
+ * Version 3, 29 June 2007
+ *
+ * Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ *
+ * You can view the LICENCE file for details.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.api.plugin;
+
+import java.util.Set;
+
+public interface PluginManager {
+
+    /**
+     * Loads a plugin and all its class files
+     *
+     * @param plugin the plugin to load
+     */
+    void loadPlugin(Plugin plugin);
+
+    /**
+     * Enables a plugin
+     *
+     * @param plugin the plugin to enable
+     */
+    void enablePlugin(Plugin plugin);
+
+    /**
+     * Disables a plugin
+     *
+     * @param plugin the plugin to disable
+     */
+    void disablePlugin(Plugin plugin);
+
+    /**
+     * Unloads a plugin
+     *
+     * @param plugin the plugin to unload
+     */
+    void unloadPlugin(Plugin plugin);
+
+    /**
+     * Returns a set of the loaded plugins
+     *
+     * @return a set of the loaded plugins
+     */
+    Set<Plugin> getPlugins();
+}
diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java
index ec3ac0b1..b6dc1d1e 100644
--- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java
+++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java
@@ -20,11 +20,17 @@ import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
 import com.nukkitx.protocol.bedrock.v354.Bedrock_v354;
 import lombok.Getter;
 import org.geysermc.api.ChatColor;
+import org.geysermc.api.Connector;
+import org.geysermc.api.Geyser;
+import org.geysermc.api.command.CommandMap;
+import org.geysermc.api.logger.Logger;
+import org.geysermc.api.plugin.Plugin;
 import org.geysermc.connector.command.GeyserCommandMap;
 import org.geysermc.connector.configuration.GeyserConfiguration;
 import org.geysermc.connector.console.ConsoleCommandReader;
 import org.geysermc.connector.console.GeyserLogger;
-import org.geysermc.connector.plugin.Loader;
+import org.geysermc.connector.plugin.GeyserPluginLoader;
+import org.geysermc.connector.plugin.GeyserPluginManager;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -33,7 +39,7 @@ import java.io.InputStream;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 
-public class GeyserConnector {
+public class GeyserConnector implements Connector {
 
     public static final BedrockPacketCodec BEDROCK_PACKET_CODEC = Bedrock_v354.V354_CODEC;
 
@@ -43,14 +49,17 @@ public class GeyserConnector {
     private static GeyserConnector instance;
 
     @Getter
-    private GeyserLogger logger;
+    private Logger logger;
 
     @Getter
-    private GeyserCommandMap commandMap;
+    private CommandMap commandMap;
 
     @Getter
     private GeyserConfiguration config;
 
+    @Getter
+    private GeyserPluginManager pluginManager;
+
     @Getter
     private boolean shuttingDown = false;
 
@@ -95,13 +104,21 @@ public class GeyserConnector {
             shutdown();
         }
 
-        Loader.start();
-
         commandMap = new GeyserCommandMap(this);
+
+        Geyser.setConnector(this);
+
+        pluginManager = new GeyserPluginManager(new GeyserPluginLoader(this));
+        pluginManager.getLoader().loadPlugins();
     }
 
     public void shutdown() {
         logger.info("Shutting down connector.");
+        for (Plugin plugin : pluginManager.getPlugins()) {
+            pluginManager.disablePlugin(plugin);
+            pluginManager.unloadPlugin(plugin);
+        }
+
         shuttingDown = true;
 
         generalThreadPool.shutdown();
diff --git a/connector/src/main/java/org/geysermc/connector/command/GeyserCommandMap.java b/connector/src/main/java/org/geysermc/connector/command/GeyserCommandMap.java
index c1d58d32..54f94b5a 100644
--- a/connector/src/main/java/org/geysermc/connector/command/GeyserCommandMap.java
+++ b/connector/src/main/java/org/geysermc/connector/command/GeyserCommandMap.java
@@ -15,6 +15,7 @@
 package org.geysermc.connector.command;
 
 import org.geysermc.api.command.Command;
+import org.geysermc.api.command.CommandMap;
 import org.geysermc.api.command.CommandSender;
 import org.geysermc.connector.GeyserConnector;
 import org.geysermc.connector.command.defaults.HelpCommand;
@@ -24,7 +25,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
-public class GeyserCommandMap {
+public class GeyserCommandMap implements CommandMap {
 
     private final Map<String, Command> commandMap = Collections.synchronizedMap(new HashMap<String, Command>());
     private GeyserConnector connector;
diff --git a/connector/src/main/java/org/geysermc/connector/console/GeyserLogger.java b/connector/src/main/java/org/geysermc/connector/console/GeyserLogger.java
index c8be0642..699de483 100644
--- a/connector/src/main/java/org/geysermc/connector/console/GeyserLogger.java
+++ b/connector/src/main/java/org/geysermc/connector/console/GeyserLogger.java
@@ -30,7 +30,7 @@ import java.util.logging.LogRecord;
 import java.util.logging.Logger;
 import java.util.logging.SimpleFormatter;
 
-public class GeyserLogger {
+public class GeyserLogger implements org.geysermc.api.logger.Logger {
 
     private Logger logger;
 
diff --git a/connector/src/main/java/org/geysermc/connector/plugin/GeyserPluginLoader.java b/connector/src/main/java/org/geysermc/connector/plugin/GeyserPluginLoader.java
new file mode 100644
index 00000000..df3bdeb4
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/plugin/GeyserPluginLoader.java
@@ -0,0 +1,89 @@
+package org.geysermc.connector.plugin;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import org.geysermc.api.Connector;
+import org.geysermc.api.Geyser;
+import org.geysermc.api.plugin.Plugin;
+import org.geysermc.connector.GeyserConnector;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class GeyserPluginLoader extends ClassLoader {
+
+    private Connector connector;
+
+    public GeyserPluginLoader(Connector connector) {
+        this.connector = connector;
+    }
+
+    public void loadPlugins() {
+        File dir = new File("plugins");
+
+        if (!dir.exists()) {
+            dir.mkdir();
+        }
+
+        for (File f : dir.listFiles()) {
+            if (!f.getName().endsWith(".jar"))
+                continue;
+
+            try {
+                ZipFile file = new ZipFile(f);
+                ZipEntry e = file.getEntry("plugin.yml");
+
+                if (e == null || e.isDirectory()) {
+                    connector.getLogger().severe("Plugin " + f.getName() + " has no valid plugin.yml!");
+                    continue;
+                }
+
+                file.stream().forEach((x) -> {
+                    if (x.getName().endsWith(".class")) {
+                        try {
+                            InputStream is = file.getInputStream(x);
+                            byte[] b = new byte[is.available()];
+                            is.read(b);
+                            this.defineClass(x.getName().replace(".class", "").replaceAll("/", "."), b, 0, b.length);
+                            is.close();
+                        } catch (Exception e1) {
+                            e1.printStackTrace();
+                        }
+                    }
+                });
+
+                ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
+                InputStream is = file.getInputStream(e);
+
+                PluginYML yml = mapper.readValue(is, PluginYML.class);
+                is.close();
+                Plugin plugin = (Plugin) Class.forName(yml.main, true, this).newInstance();
+                connector.getLogger().info("Loading plugin " + yml.name + " version " + yml.version);
+                connector.getPluginManager().loadPlugin(plugin);
+            } catch (Exception e) {
+                connector.getLogger().severe("Error loading plugin " + f.getName());
+                e.printStackTrace();
+            }
+        }
+
+        for (Plugin plugin : connector.getPluginManager().getPlugins()) {
+            connector.getPluginManager().enablePlugin(plugin);
+        }
+    }
+
+    public void loadPlugin(Plugin plugin) {
+        plugin.onLoad();
+    }
+
+    public void enablePlugin(Plugin plugin) {
+        plugin.setEnabled(true);
+        plugin.onEnable();
+    }
+
+    public void disablePlugin(Plugin plugin) {
+        plugin.setEnabled(false);
+        plugin.onDisable();
+    }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/plugin/GeyserPluginManager.java b/connector/src/main/java/org/geysermc/connector/plugin/GeyserPluginManager.java
new file mode 100644
index 00000000..895d5cd0
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/plugin/GeyserPluginManager.java
@@ -0,0 +1,56 @@
+/*
+ * GNU LESSER GENERAL PUBLIC LICENSE
+ * Version 3, 29 June 2007
+ *
+ * Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ *
+ * You can view the LICENCE file for details.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.plugin;
+
+import lombok.Getter;
+import org.geysermc.api.plugin.Plugin;
+import org.geysermc.api.plugin.PluginManager;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class GeyserPluginManager implements PluginManager {
+
+    @Getter
+    private GeyserPluginLoader loader;
+
+    @Getter
+    private Set<Plugin> plugins = new HashSet<Plugin>();
+
+    public GeyserPluginManager(GeyserPluginLoader loader) {
+        this.loader = loader;
+    }
+
+    public void loadPlugin(Plugin plugin) {
+        loader.loadPlugin(plugin);
+        plugins.add(plugin);
+    }
+
+    public void unloadPlugin(Plugin plugin) {
+        plugins.remove(plugin);
+    }
+
+    public void enablePlugin(Plugin plugin) {
+        loader.enablePlugin(plugin);
+    }
+
+    public void disablePlugin(Plugin plugin) {
+        loader.disablePlugin(plugin);
+    }
+
+    public Set<Plugin> getPlugins() {
+        return plugins;
+    }
+}
\ No newline at end of file
diff --git a/connector/src/main/java/org/geysermc/connector/plugin/Loader.java b/connector/src/main/java/org/geysermc/connector/plugin/Loader.java
deleted file mode 100644
index e51bbd48..00000000
--- a/connector/src/main/java/org/geysermc/connector/plugin/Loader.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package org.geysermc.connector.plugin;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
-import org.geysermc.api.Geyser;
-import org.geysermc.api.plugin.Plugin;
-
-import java.io.File;
-import java.io.InputStream;
-import java.util.Map;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-public class Loader extends ClassLoader {
-    static {
-        System.out.println("a");
-        Loader l = new Loader();
-        System.out.println("b");
-        File dir = new File("plugins");
-        System.out.println(dir.getAbsoluteFile());
-
-        if(!dir.exists()) {
-            dir.mkdir();
-        }
-
-        for(File f : dir.listFiles()) {
-            if(f.getName().endsWith(".jar")) {
-                try {
-                    ZipFile file = new ZipFile(f);
-
-                    ZipEntry e = file.getEntry("plugin.yml");
-
-                    if(e == null || e.isDirectory()) {
-                        System.err.println("Plugin " + f.getName() + " has no valid plugin.yml!");
-                        continue;
-                    }
-
-                    file.stream().forEach((x) -> {
-                        if(x.getName().endsWith(".class")) {
-                            try {
-                                InputStream is = file.getInputStream(x);
-                                byte[] b = new byte[is.available()];
-                                is.read(b);
-                                l.defineClass(x.getName().replace(".class", "").replaceAll("/", "."), b, 0, b.length);
-                                is.close();
-                            } catch (Exception e1) {
-                                e1.printStackTrace();
-                            }
-                        }
-                    });
-
-                    ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
-
-                    InputStream is = file.getInputStream(e);
-
-                    PluginYML yml;
-
-                    yml = mapper.readValue(is, PluginYML.class);
-
-                    is.close();
-
-                    Plugin plugin = (Plugin) Class.forName(yml.main, true, l).newInstance();
-
-                    plugin.onLoad();
-
-                    Geyser.add(plugin);
-
-                } catch (Exception e) {
-                    System.out.println("Error loading plugin " + f.getName());
-                    e.printStackTrace();
-                }
-            }
-        }
-        for(Plugin p : Geyser.getPlugins()) {
-            p.onEnable();
-        }
-        LOADER = l;
-    }
-
-    public static final Loader LOADER;
-
-    public static void start() {
-
-    }
-
-    private Loader() {
-
-    }
-}