diff --git a/package.json b/package.json
index 5c9a67c734..a736024da6 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,8 @@
     "react-dom": "^15.0.1",
     "react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#c3d942e",
     "sanitize-html": "^1.11.1",
-    "velocity-vector": "vector-im/velocity#059e3b2"
+    "velocity-vector": "vector-im/velocity#059e3b2",
+    "whatwg-fetch": "^1.0.0"
   },
   "//babelversion": [
     "brief experiments with babel6 seems to show that it generates source ",
diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js
index cc96503316..c7b77ab88c 100644
--- a/src/MatrixClientPeg.js
+++ b/src/MatrixClientPeg.js
@@ -20,7 +20,7 @@ limitations under the License.
 var Matrix = require("matrix-js-sdk");
 var GuestAccess = require("./GuestAccess");
 
-var matrixClient = null;
+let matrixClient: MatrixClient = null;
 
 var localStorage = window.localStorage;
 
@@ -82,7 +82,7 @@ class MatrixClient {
         this.guestAccess = guestAccess;
     }
 
-    get() {
+    get(): MatrixClient {
         return matrixClient;
     }
 
diff --git a/src/autocomplete/AutocompleteProvider.js b/src/autocomplete/AutocompleteProvider.js
index 3b2aae920b..61158d2b56 100644
--- a/src/autocomplete/AutocompleteProvider.js
+++ b/src/autocomplete/AutocompleteProvider.js
@@ -1,3 +1,5 @@
 export default class AutocompleteProvider {
-
+    getName(): string {
+        return 'Default Provider';
+    }
 }
diff --git a/src/autocomplete/Autocompleter.js b/src/autocomplete/Autocompleter.js
index e49dbb7ad6..a8ed2da59a 100644
--- a/src/autocomplete/Autocompleter.js
+++ b/src/autocomplete/Autocompleter.js
@@ -1,7 +1,20 @@
 import CommandProvider from './CommandProvider';
+import DuckDuckGoProvider from './DuckDuckGoProvider';
+import RoomProvider from './RoomProvider';
+import UserProvider from './UserProvider';
 
-const COMPLETERS = [CommandProvider].map(completer => new completer());
+const PROVIDERS = [
+    CommandProvider,
+    DuckDuckGoProvider,
+    RoomProvider,
+    UserProvider
+].map(completer => new completer());
 
 export function getCompletions(query: String) {
-    return COMPLETERS.map(completer => completer.getCompletions(query));
+    return PROVIDERS.map(provider => {
+        return {
+            completions: provider.getCompletions(query),
+            provider
+        };
+    });
 }
diff --git a/src/autocomplete/CommandProvider.js b/src/autocomplete/CommandProvider.js
index cc95d96fd3..e2eac47d16 100644
--- a/src/autocomplete/CommandProvider.js
+++ b/src/autocomplete/CommandProvider.js
@@ -62,4 +62,8 @@ export default class CommandProvider extends AutocompleteProvider {
         }
         return Q.when(completions);
     }
+
+    getName() {
+        return 'Commands';
+    }
 }
diff --git a/src/autocomplete/DuckDuckGoProvider.js b/src/autocomplete/DuckDuckGoProvider.js
new file mode 100644
index 0000000000..6545b96cbd
--- /dev/null
+++ b/src/autocomplete/DuckDuckGoProvider.js
@@ -0,0 +1,35 @@
+import AutocompleteProvider from './AutocompleteProvider';
+import Q from 'q';
+import 'whatwg-fetch';
+
+const DDG_REGEX = /\/ddg\w+(.+)$/;
+const REFERER = 'vector';
+
+export default class DuckDuckGoProvider extends AutocompleteProvider {
+    static getQueryUri(query: String) {
+        return `http://api.duckduckgo.com/?q=${encodeURIComponent(query)}&format=json&t=${encodeURIComponent(REFERER)}`;
+    }
+
+    getCompletions(query: String) {
+        if(!query)
+            return Q.when([]);
+
+        let promise = Q.defer();
+        fetch(DuckDuckGoProvider.getQueryUri(query), {
+            method: 'GET'
+        }).then(response => {
+            let results = response.Results.map(result => {
+                return {
+                    title: result.Text,
+                    description: result.Result
+                };
+            });
+            promise.resolve(results);
+        });
+        return promise;
+    }
+
+    getName() {
+        return 'Results from DuckDuckGo';
+    }
+}
diff --git a/src/autocomplete/RoomProvider.js b/src/autocomplete/RoomProvider.js
new file mode 100644
index 0000000000..26dc5733da
--- /dev/null
+++ b/src/autocomplete/RoomProvider.js
@@ -0,0 +1,31 @@
+import AutocompleteProvider from './AutocompleteProvider';
+import Q from 'q';
+import MatrixClientPeg from '../MatrixClientPeg';
+
+const ROOM_REGEX = /(?=#)[^\s]*/g;
+
+export default class RoomProvider extends AutocompleteProvider {
+    constructor() {
+        super();
+    }
+
+    getCompletions(query: String) {
+        let client = MatrixClientPeg.get();
+        let completions = [];
+        const matches = query.match(ROOM_REGEX);
+        if(!!matches) {
+            const command = matches[0];
+            completions = client.getRooms().map(room => {
+                return {
+                    title: room.name,
+                    subtitle: room.roomId
+                };
+            });
+        }
+        return Q.when(completions);
+    }
+
+    getName() {
+        return 'Rooms';
+    }
+}
diff --git a/src/autocomplete/UserProvider.js b/src/autocomplete/UserProvider.js
new file mode 100644
index 0000000000..791dd55a33
--- /dev/null
+++ b/src/autocomplete/UserProvider.js
@@ -0,0 +1,31 @@
+import AutocompleteProvider from './AutocompleteProvider';
+import Q from 'q';
+import MatrixClientPeg from '../MatrixClientPeg';
+
+const ROOM_REGEX = /@[^\s]*/g;
+
+export default class UserProvider extends AutocompleteProvider {
+    constructor() {
+        super();
+    }
+
+    getCompletions(query: String) {
+        let client = MatrixClientPeg.get();
+        let completions = [];
+        const matches = query.match(ROOM_REGEX);
+        if(!!matches) {
+            const command = matches[0];
+            completions = client.getUsers().map(user => {
+                return {
+                    title: user.displayName,
+                    description: user.userId
+                };
+            });
+        }
+        return Q.when(completions);
+    }
+
+    getName() {
+        return 'Users';
+    }
+}
diff --git a/src/components/views/rooms/Autocomplete.js b/src/components/views/rooms/Autocomplete.js
index 80208892b0..4bc4102070 100644
--- a/src/components/views/rooms/Autocomplete.js
+++ b/src/components/views/rooms/Autocomplete.js
@@ -11,11 +11,28 @@ export default class Autocomplete extends React.Component {
     }
 
     componentWillReceiveProps(props, state) {
-        getCompletions(props.query)[0].then(completions => {
-            console.log(completions);
-            this.setState({
-                completions
-            });
+        getCompletions(props.query).map(completionResult => {
+            try {
+                completionResult.completions.then(completions => {
+                    let i = this.state.completions.findIndex(
+                        completion => completion.provider === completionResult.provider
+                    );
+
+                    i = i == -1 ? this.state.completions.length : i;
+                    console.log(completionResult);
+                    let newCompletions = Object.assign([], this.state.completions);
+                    completionResult.completions = completions;
+                    newCompletions[i] = completionResult;
+                    console.log(newCompletions);
+                    this.setState({
+                        completions: newCompletions
+                    });
+                }, err => {
+
+                });
+            } catch (e) {
+                // An error in one provider shouldn't mess up the rest.
+            }
         });
     }
 
@@ -33,18 +50,28 @@ export default class Autocomplete extends React.Component {
         };
 
         this.props.pinTo.forEach(direction => {
-            console.log(`${direction} = ${position[direction]}`);
             style[direction] = position[direction];
         });
 
-        const renderedCompletions = this.state.completions.map((completion, i) => {
-            return (
-                <div key={i} class="mx_Autocomplete_Completion">
-                    <strong>{completion.title}</strong>
-                    <em>{completion.subtitle}</em>
-                    <span style={{color: 'gray', float: 'right'}}>{completion.description}</span>
+        const renderedCompletions = this.state.completions.map((completionResult, i) => {
+            console.log(completionResult);
+            let completions = completionResult.completions.map((completion, i) => {
+                return (
+                    <div key={i} class="mx_Autocomplete_Completion">
+                        <strong>{completion.title}</strong>
+                        <em>{completion.subtitle}</em>
+                        <span style={{color: 'gray', float: 'right'}}>{completion.description}</span>
+                    </div>
+                );
+            });
+
+
+            return completions.length > 0 ? (
+                <div key={i} class="mx_Autocomplete_ProviderSection">
+                    <strong>{completionResult.provider.getName()}</strong>
+                    {completions}
                 </div>
-            );
+            ) : null;
         });
 
         return (