diff --git a/src/matrixcommandhandler.ts b/src/matrixcommandhandler.ts
index 66ddabb9fbf6853663b5ec354e1688fcc91e2274..9402a9ea3098b60d047eceefb111cc66aedd09b0 100644
--- a/src/matrixcommandhandler.ts
+++ b/src/matrixcommandhandler.ts
@@ -42,8 +42,6 @@ export class MatrixCommandHandler {
             return;
         }
 
-        const {command, args} = Util.MsgToArgs(event.content!.body as string, "!discord");
-
         const actions: ICommandActions = {
             bridge: {
                 description: "Bridges this room to a Discord channel",
@@ -58,7 +56,7 @@ export class MatrixCommandHandler {
                     "   The URL is formatted as https://discordapp.com/channels/GUILD_ID/CHANNEL_ID\n" +
                     "5. Enjoy your new bridge!",
                 // tslint:enable prefer-template
-                params: ["guildid", "channelId"],
+                params: ["guildId", "channelId"],
                 permission: {
                     cat: "events",
                     level: PROVISIONING_DEFAULT_POWER_LEVEL,
@@ -69,7 +67,7 @@ export class MatrixCommandHandler {
                     // TODO: parse guildId/channelId
 
                     if (context.rooms.remote) {
-                        return "This room is already bridged to a Discord guild";
+                        return "This room is already bridged to a Discord guild.";
                     }
                     if (!guildId || !channelId) {
                         return "Invalid syntax. For more information try `!discord help bridge`";
@@ -129,18 +127,38 @@ export class MatrixCommandHandler {
             },
         };
 
+        /*
+        we hack togeather that "guildId/channelId" is the same as "guildId channelId"
+        we do this by assuming that guildId is parsed first, and split the / off and then pass
+        that on to channelId, if applicable
+        */
+        let guildIdRemainder: string | undefined = undefined;
         const parameters: ICommandParameters = {
             guildId: {
                 description: "The ID of a guild/server on discord",
+                get: async (s) => {
+                    if (!s) {
+                        return s;
+                    }
+                    const parts = s.split("/");
+                    guildIdRemainder = parts[1];
+                    return parts[0];
+                },
             },
             channelId: {
                 description: "The ID of a channel on discord",
+                get: async (s) => {
+                    if (!s && guildIdRemainder) {
+                        return guildIdRemainder;
+                    }
+                    return s;
+                },
             },
         };
 
         const permissionCheck: ICommandPermissonCheck = async (permission) => {
             if (permission.selfService && !this.config.bridge.enableSelfServiceBridging) {
-                return false;
+                return "The owner of this bridge does not permit self-service bridging.";
             }
             return await Util.CheckMatrixPermission(
                 this.bridge.getIntent().getClient(),
@@ -152,16 +170,6 @@ export class MatrixCommandHandler {
             );
         };
 
-
-
-        if (!this.config.bridge.enableSelfServiceBridging) {
-            // We can do this here because the only commands we support are self-service bridging
-            return this.bridge.getIntent().sendMessage(event.room_id, {
-                body: "The owner of this bridge does not permit self-service bridging.",
-                msgtype: "m.notice",
-            });
-        }
-
         const reply = await Util.ParseCommand("!discord", event.content!.body!, actions, parameters, permissionCheck);
 
         await this.bridge.getIntent().sendMessage(event.room_id, {
diff --git a/src/matrixtypes.ts b/src/matrixtypes.ts
index 3d54c2d5641aa0ab9f22262ed30a3ef3e4014db1..f71d7debdce3c15efe449f2208264a2efa44a004 100644
--- a/src/matrixtypes.ts
+++ b/src/matrixtypes.ts
@@ -42,6 +42,7 @@ export interface IMatrixEvent {
     unsigned?: any; // tslint:disable-line no-any
     origin_server_ts?: number;
     users?: any; // tslint:disable-line no-any
+    users_default?: any // tslint:disable-line no-any
     notifications?: any; // tslint:disable-line no-any
 }
 
diff --git a/src/util.ts b/src/util.ts
index c5ed597bc17ded67814efee8dda3e0cfbc006fc1..8df0d180186d03a927dad2ba02208dd65a8422d5 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -53,7 +53,7 @@ export interface ICommandParameters {
 }
 
 export interface ICommandPermissonCheck {
-    (permission: PERMISSIONTYPES): Promise<boolean>;
+    (permission: PERMISSIONTYPES): Promise<boolean | string>;
 }
 
 export interface IPatternMap {
@@ -251,8 +251,14 @@ export class Util {
             if (!actions[actionKey]) {
                 return `**ERROR:** unknown command! Try \`${prefix} help\` to see all commands`;
             }
-            if (action.permission !== undefined && permissionCheck && !(await permissionCheck(action.permission))) {
-                return `**ERROR:** permission denied! Try \`${prefix} help\` to see all available commands`;
+            if (action.permission !== undefined && permissionCheck) {
+                const permCheck = await permissionCheck(action.permission);
+                if (typeof permCheck === "string") {
+                    return `**ERROR:** ${permCheck}`;
+                }
+                if (!permCheck) {
+                    return `**ERROR:** permission denied! Try \`${prefix} help\` to see all available commands`;
+                }
             }
             reply += `\`${prefix} ${actionKey}`;
             for (const param of action.params) {
@@ -267,8 +273,11 @@ export class Util {
         reply += "Available Commands:\n";
         for (const actionKey of Object.keys(actions)) {
             const action = actions[actionKey];
-            if (action.permission !== undefined && permissionCheck && !(await permissionCheck(action.permission))) {
-                continue;
+            if (action.permission !== undefined && permissionCheck) {
+                const permCheck = await permissionCheck(action.permission);
+                if (typeof permCheck === "string" || !permCheck) {
+                    continue;
+                }
             }
             reply += ` - \`${prefix} ${actionKey}`;
             for (const param of action.params) {
@@ -301,8 +310,14 @@ export class Util {
             return `**ERROR:** unknown command. Try \`${prefix} help\` to see all commands`;
         }
         const action = actions[command];
-        if (action.permission !== undefined && permissionCheck && !permissionCheck(action.permission)) {
-            return `**ERROR:** insufficiant permissions to use this command`;
+        if (action.permission !== undefined && permissionCheck) {
+            const permCheck = await permissionCheck(action.permission);
+            if (typeof permCheck === "string") {
+                return `**ERROR:** ${permCheck}`;
+            }
+            if (!permCheck) {
+                return `**ERROR:** insufficiant permissions to use this command! Try \`${prefix} help\` to see all available commands`;
+            }
         }
         if (action.params.length === 1) {
             args[0] = args.join(" ");
@@ -392,6 +407,9 @@ export class Util {
         }
 
         let haveLevel = 0;
+        if (res && res.users_default) {
+            haveLevel = res.users_default;
+        }
         if (res && res.users && res.users[userId] !== undefined) {
             haveLevel = res.users[userId];
         }
diff --git a/test/test_discordbot.ts b/test/test_discordbot.ts
index c50c76f502d4310e552499025979f66c3287777a..6cf8e29f9642534d52a1121cddad377f4dc148e8 100644
--- a/test/test_discordbot.ts
+++ b/test/test_discordbot.ts
@@ -175,8 +175,8 @@ describe("DiscordBot", () => {
             discord.channelSync = {
                 GetRoomIdsFromChannel: async (chan) => ["!asdf:localhost"],
             };
-            discord.roomHandler = {
-                HandleDiscordCommand: async (msg) => { HANDLE_COMMAND = true; },
+            discord.discordCommandHandler = {
+                Process: async (msg) => { HANDLE_COMMAND = true; },
             };
             discord.store = {
                 Insert: async (_) => { },
diff --git a/test/test_matrixcommandhandler.ts b/test/test_matrixcommandhandler.ts
index 78f4b13fab38a350fa2e93ab1a71cd3780a513d9..3468a4b3a69df899609f97b80d319db940a500ae 100644
--- a/test/test_matrixcommandhandler.ts
+++ b/test/test_matrixcommandhandler.ts
@@ -1,7 +1,8 @@
 import * as Chai from "chai";
-import { MatrixCommandHandler } from "../src/matrixcommandhandler";
+import { Util } from "../src/util";
 import { DiscordBridgeConfig } from "../src/config";
 import { MockChannel } from "./mocks/channel";
+import * as Proxyquire from "proxyquire";
 
 // we are a test file and thus need those
 /* tslint:disable:no-unused-expression max-file-line-count no-any */
@@ -52,9 +53,6 @@ function createCH(opts: any = {}) {
         config.bridge.enableSelfServiceBridging = true;
     }
     const mxClient = {
-        getStateEvent: async () => {
-            return opts.powerLevels || {};
-        },
         getUserId: () => "@user:localhost",
         joinRoom: async () => {
             USERSJOINED++;
@@ -92,210 +90,119 @@ function createCH(opts: any = {}) {
         },
         Provisioner: provisioner,
     };
-    return new MatrixCommandHandler(bot as any, bridge, config);
+
+    const MatrixCommandHndl = (Proxyquire("../src/matrixcommandhandler", {
+        "./util": {
+            Util: {
+                CheckMatrixPermission: async () => {
+                    return opts.power !== undefined ? opts.power : true;
+                },
+                GetBotLink: Util.GetBotLink,
+                ParseCommand: Util.ParseCommand,
+            }
+        }
+    })).MatrixCommandHandler;
+    return new MatrixCommandHndl(bot as any, bridge, config);
+}
+
+function createEvent(msg: string, room?: string, user_id?: string) {
+    return {
+        content: {
+            body: msg,
+        },
+        room_id: room ? room : "!123:localhost",
+        sender: user_id,
+    };
+}
+
+function createContext(remoteData?: any) {
+    return {
+        rooms: {
+            remote: remoteData,
+        },
+    };
 }
 
 describe("MatrixCommandHandler", () => {
     describe("Process", () => {
         it("should not process command if not in room", async () => {
             const handler: any = createCH({disableSS: true});
-            const ret = await handler.Process({
-                room_id: "!666:localhost",
-            });
-            expect(ret).to.be.undefined;
+            await handler.Process(createEvent("", "!666:localhost"), createContext());
+            expect(MESSAGESENT.body).to.equal(undefined);
         });
         it("should warn if self service is disabled", async () => {
             const handler: any = createCH({disableSS: true});
-            await handler.Process({
-                room_id: "!123:localhost",
-            });
-            expect(MESSAGESENT.body).equals("The owner of this bridge does not permit self-service bridging.");
-        });
-        it("should warn if user is not powerful enough with defaults", async () => {
-            const handler: any = createCH();
-            await handler.Process({
-                room_id: "!123:localhost",
-            });
-            expect(MESSAGESENT.body).equals("You do not have the required power level in this room to " +
-                "create a bridge to a Discord channel.");
+            await handler.Process(createEvent("!discord bridge"), createContext());
+            expect(MESSAGESENT.body).to.equal("**ERROR:** The owner of this bridge does not permit self-service bridging.");
         });
-        it("should warn if user is not powerful enough with custom state default", async () => {
-            const handler: any = createCH({powerLevels: {
-                state_default: 67,
-            }});
-            await handler.Process({
-                room_id: "!123:localhost",
-            });
-            expect(MESSAGESENT.body).equals("You do not have the required power level in this room to " +
-                "create a bridge to a Discord channel.");
-        });
-        it("should allow if user is powerful enough with defaults", async () => {
-            const handler: any = createCH({powerLevels: {
-                users_default: 60,
-            }});
-            const evt = await handler.Process({
-                content: {body: "!discord help"},
-                room_id: "!123:localhost",
-            });
-            expect(evt.body.startsWith("Available commands")).to.be.true;
-        });
-        it("should allow if user is powerful enough with their own state", async () => {
-            const handler: any = createCH({powerLevels: {
-                users: {
-                 "@user:localhost": 100,
-                },
-            }});
-            const evt = await handler.Process({
-                content: {body: "!discord help"},
-                room_id: "!123:localhost",
-                sender: "@user:localhost",
+        it("should warn if user is not powerful enough", async () => {
+            const handler: any = createCH({
+                power: false,
             });
-            expect(evt.body.startsWith("Available commands")).to.be.true;
+            await handler.Process(createEvent("!discord bridge"), createContext());
+            expect(MESSAGESENT.body).to.equal("**ERROR:** insufficiant permissions to use this command! Try `!discord help` to see all available commands");
         });
         describe("!discord bridge", () => {
             it("will bridge a new room, and ask for permissions", async () => {
-                const handler: any = createCH({powerLevels: {
-                        users_default: 100,
-                    }});
-                const context = {rooms: {}};
-                const evt = await handler.Process({
-                    content: {body: "!discord bridge 123 456"},
-                    room_id: "!123:localhost",
-                }, context);
-                expect(evt.body).equals("I have bridged this room to your channel");
+                const handler: any = createCH();
+                await handler.Process(createEvent("!discord bridge 123 456"), createContext());
+                expect(MESSAGESENT.body).to.equal("I have bridged this room to your channel");
             });
             it("will fail to bridge if permissions were denied", async () => {
                 const handler: any = createCH({
                     denyBridgePermission: true,
-                    powerLevels: {
-                        users_default: 100,
-                    },
                 });
-                const context = {rooms: {}};
-                const evt = await handler.Process({
-                    content: {body: "!discord bridge 123 456"},
-                    room_id: "!123:localhost",
-                }, context);
-                expect(evt.body).equals("The bridge has been declined by the Discord guild");
+                await handler.Process(createEvent("!discord bridge 123 456"), createContext());
+                expect(MESSAGESENT.body).to.equal("The bridge has been declined by the Discord guild");
             });
-            it("will fail to bridge if permissions were denied", async () => {
+            it("will fail to bridge if permissions were failed", async () => {
                 const handler: any = createCH({
                     failBridgeMatrix: true,
-                    powerLevels: {
-                        users_default: 100,
-                    },
                 });
-                const context = {rooms: {}};
-                const evt = await handler.Process({
-                    content: {body: "!discord bridge 123 456"},
-                    room_id: "!123:localhost",
-                }, context);
-                expect(evt.body).equals("There was a problem bridging that channel - has " +
+                const evt = await handler.Process(createEvent("!discord bridge 123 456"), createContext());
+                expect(MESSAGESENT.body).to.equal("There was a problem bridging that channel - has " +
                     "the guild owner approved the bridge?");
             });
             it("will not bridge if a link already exists", async () => {
-                const handler: any = createCH({
-                    powerLevels: {
-                        users_default: 100,
-                    },
-                });
-                const context = {rooms: { remote: true }};
-                const evt = await handler.Process({
-                    content: {body: "!discord bridge"},
-                    room_id: "!123:localhost",
-                }, context);
-                expect(evt.body).equals("This room is already bridged to a Discord guild.");
+                const handler: any = createCH();
+                const evt = await handler.Process(createEvent("!discord bridge 123 456"), createContext(true));
+                expect(MESSAGESENT.body).to.equal("This room is already bridged to a Discord guild.");
             });
             it("will not bridge without required args", async () => {
-                const handler: any = createCH({
-                    powerLevels: {
-                        users_default: 100,
-                    },
-                });
-                const context = {rooms: {}};
-                const evt = await handler.Process({
-                    content: {body: "!discord bridge"},
-                    room_id: "!123:localhost",
-                }, context);
-                expect(evt.body).to.contain("Invalid syntax");
+                const handler: any = createCH();
+                const evt = await handler.Process(createEvent("!discord bridge"), createContext());
+                expect(MESSAGESENT.body).to.contain("Invalid syntax");
             });
             it("will bridge with x/y syntax", async () => {
                 const handler: any = createCH({powerLevels: {
                         users_default: 100,
                     }});
-                const context = {rooms: {}};
-                const evt = await handler.Process({
-                    content: {body: "!discord bridge 123/456"},
-                    room_id: "!123:localhost",
-                }, context);
-                expect(evt.body).equals("I have bridged this room to your channel");
+                const evt = await handler.Process(createEvent("!discord bridge 123/456"), createContext());
+                expect(MESSAGESENT.body).equals("I have bridged this room to your channel");
             });
         });
         describe("!discord unbridge", () => {
             it("will unbridge", async () => {
-                const handler: any = createCH({
-                    powerLevels: {
-                        users_default: 100,
-                    },
-                });
-                const context = {rooms: { remote: {
-                    data: {
-                        plumbed: true,
-                    },
-                } }};
-                const evt = await handler.Process({
-                    content: {body: "!discord unbridge"},
-                    room_id: "!123:localhost",
-                }, context);
-                expect(evt.body).equals("This room has been unbridged");
+                const handler: any = createCH();
+                await handler.Process(createEvent("!discord unbridge"), createContext({data:{plumbed:true}}));
+                expect(MESSAGESENT.body).equals("This room has been unbridged");
             });
             it("will not unbridge if a link does not exist", async () => {
-                const handler: any = createCH({
-                    powerLevels: {
-                        users_default: 100,
-                    },
-                });
-                const context = {rooms: { remote: undefined }};
-                const evt = await handler.Process({
-                    content: {body: "!discord unbridge"},
-                    room_id: "!123:localhost",
-                }, context);
-                expect(evt.body).equals("This room is not bridged.");
+                const handler: any = createCH();
+                const evt = await handler.Process(createEvent("!discord unbridge"), createContext());
+                expect(MESSAGESENT.body).equals("This room is not bridged.");
             });
             it("will not unbridge non-plumbed rooms", async () => {
-                const handler: any = createCH({
-                    powerLevels: {
-                        users_default: 100,
-                    },
-                });
-                const context = {rooms: { remote: {
-                    data: {
-                        plumbed: false,
-                    },
-                }}};
-                const evt = await handler.Process({
-                    content: {body: "!discord unbridge"},
-                    room_id: "!123:localhost",
-                }, context);
-                expect(evt.body).equals("This room cannot be unbridged.");
+                const handler: any = createCH();
+                await handler.Process(createEvent("!discord unbridge"), createContext({data:{plumbed:false}}));
+                expect(MESSAGESENT.body).equals("This room cannot be unbridged.");
             });
             it("will show error if unbridge fails", async () => {
                 const handler: any = createCH({
                     failUnbridge: true,
-                    powerLevels: {
-                        users_default: 100,
-                    },
                 });
-                const context = {rooms: { remote: {
-                    data: {
-                        plumbed: true,
-                    },
-                }}};
-                const evt = await handler.Process({
-                    content: {body: "!discord unbridge"},
-                    room_id: "!123:localhost",
-                }, context);
-                expect(evt.body).to.contain("There was an error unbridging this room.");
+                await handler.Process(createEvent("!discord unbridge"), createContext({data:{plumbed:true}}));
+                expect(MESSAGESENT.body).to.contain("There was an error unbridging this room.");
             });
         });
     });
diff --git a/test/test_matrixeventprocessor.ts b/test/test_matrixeventprocessor.ts
index 71ec84bf415758f4abb0e4b1e8a7f234c261802f..eefa16106ec3cb60dc45886d4726299950a33e08 100644
--- a/test/test_matrixeventprocessor.ts
+++ b/test/test_matrixeventprocessor.ts
@@ -89,12 +89,13 @@ let STATE_EVENT_MSG = "";
 let USERSYNC_HANDLED = false;
 let MESSAGE_PROCCESS = "";
 let KICKBAN_HANDLED = false;
+let COMMAND_PROCESSED = false;
 
 function createMatrixEventProcessor(): MatrixEventProcessor {
     USERSYNC_HANDLED = false;
     STATE_EVENT_MSG = "";
     MESSAGE_PROCCESS = "";
-    KICKBAN_HANDLED = true;
+    KICKBAN_HANDLED = false;
     const bridge = {
         getBot: () => {
             return {
@@ -230,7 +231,7 @@ function createMatrixEventProcessor(): MatrixEventProcessor {
         HandleInvite: async (evt) => {
             MESSAGE_PROCCESS = "invited";
         },
-        ProcessCommand: async (evt) => {
+        Process: async (evt) => {
             MESSAGE_PROCCESS = "command_processed";
         },
     });
diff --git a/test/test_util.ts b/test/test_util.ts
index 17664269950452f36138dacec1f8ad3e0ce13a97..70c8d7b57a7c8572d45155ce9c114f4e18973c4a 100644
--- a/test/test_util.ts
+++ b/test/test_util.ts
@@ -16,7 +16,7 @@ limitations under the License.
 
 import * as Chai from "chai";
 
-import { Util, ICommandAction, ICommandParameters } from "../src/util";
+import { Util, ICommandActions, ICommandParameters } from "../src/util";
 
 // we are a test file and thus need those
 /* tslint:disable:no-unused-expression max-file-line-count no-any */
@@ -62,10 +62,12 @@ describe("Util", () => {
     });
     describe("ParseCommand", () => {
         it("parses commands", async () => {
-            const action: ICommandAction = {
-                params: ["param1", "param2"],
-                run: async ({param1, param2}) => {
-                    return `param1: ${param1}\nparam2: ${param2}`;
+            const actions: ICommandActions = {
+                action: {
+                    params: ["param1", "param2"],
+                    run: async ({param1, param2}) => {
+                        return `param1: ${param1}\nparam2: ${param2}`;
+                    },
                 },
             };
             const parameters: ICommandParameters = {
@@ -80,7 +82,12 @@ describe("Util", () => {
                     },
                 },
             };
-            const retStr = await Util.ParseCommand(action, parameters, ["hello", "world"]);
+            const retStr = await Util.ParseCommand(
+                "!fox",
+                "!fox action hello world",
+                actions,
+                parameters,
+            );
             expect(retStr).equal("param1: param1_hello\nparam2: param2_world");
         });
     });