diff --git a/.gitignore b/.gitignore
index d535c22b..75f80c5f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,5 @@
 /.vscode-test/
 /.nyc_output/
 /coverage/
-*.vsix
\ No newline at end of file
+*.vsix
+yarn-error.log
diff --git a/package.json b/package.json
index 1553bdff..0c114daf 100644
--- a/package.json
+++ b/package.json
@@ -41,24 +41,25 @@
     "views": {
       "coder": [
         {
-          "id": "coderRemote",
-          "name": "",
+          "id": "myWorkspaces",
+          "name": "My Workspaces",
+          "visibility": "visible",
+          "icon": "media/logo.svg"
+        },
+        {
+          "id": "allWorkspaces",
+          "name": "All Workspaces",
           "visibility": "visible",
           "icon": "media/logo.svg",
-          "contextualTitle": "Coder Remote"
+          "when": "coder.authenticated && coder.isOwner"
         }
       ]
     },
     "viewsWelcome": [
       {
-        "view": "coderRemote",
+        "view": "myWorkspaces",
         "contents": "Coder is a platform that provisions remote development environments. \n[Login](command:coder.login)",
         "when": "!coder.authenticated && coder.loaded"
-      },
-      {
-        "view": "coderRemote",
-        "contents": "You're logged in! \n[Open Workspace](command:coder.open)",
-        "when": "coder.authenticated && coder.loaded"
       }
     ],
     "commands": [
@@ -68,18 +69,84 @@
       },
       {
         "command": "coder.logout",
-        "title": "Coder: Logout"
+        "title": "Coder: Logout",
+        "when": "coder.authenticated",
+        "icon": "$(sign-out)"
       },
       {
         "command": "coder.open",
-        "title": "Coder: Open Workspace"
+        "title": "Coder: Open Workspace",
+        "icon": "$(play)"
+      },
+      {
+        "command": "coder.createWorkspace",
+        "title": "Create Workspace",
+        "when": "coder.authenticated",
+        "icon": "$(add)"
+      },
+      {
+        "command": "coder.navigateToWorkspace",
+        "title": "Navigate to Workspace Page",
+        "when": "coder.authenticated",
+        "icon": "$(link-external)"
+      },
+      {
+        "command": "coder.navigateToWorkspaceSettings",
+        "title": "Edit Workspace Settings",
+        "when": "coder.authenticated",
+        "icon": "$(settings-gear)"
       },
       {
         "command": "coder.workspace.update",
         "title": "Coder: Update Workspace",
         "when": "coder.workspace.updatable"
+      },
+      {
+        "command": "coder.refreshWorkspaces",
+        "title": "Coder: Refresh Workspace",
+        "icon": "$(refresh)",
+        "when": "coder.authenticated"
       }
-    ]
+    ],
+    "menus": {
+      "view/title": [
+        {
+          "command": "coder.logout",
+          "when": "coder.authenticated && view == myWorkspaces"
+        },
+        {
+          "command": "coder.login",
+          "when": "!coder.authenticated && view == myWorkspaces"
+        },
+        {
+          "command": "coder.createWorkspace",
+          "when": "coder.authenticated && view == myWorkspaces",
+          "group": "navigation"
+        },
+        {
+          "command": "coder.refreshWorkspaces",
+          "when": "coder.authenticated && view == myWorkspaces",
+          "group": "navigation"
+        }
+      ],
+      "view/item/context": [
+        {
+          "command": "coder.open",
+          "when": "coder.authenticated && view == myWorkspaces || coder.authenticated && view == allWorkspaces",
+          "group": "inline"
+        },
+        {
+          "command": "coder.navigateToWorkspace",
+          "when": "coder.authenticated && view == myWorkspaces || coder.authenticated && view == allWorkspaces",
+          "group": "inline"
+        },
+        {
+          "command": "coder.navigateToWorkspaceSettings",
+          "when": "coder.authenticated && view == myWorkspaces || coder.authenticated && view == allWorkspaces",
+          "group": "inline"
+        }
+      ]
+    }
   },
   "scripts": {
     "vscode:prepublish": "yarn package",
diff --git a/src/api-helper.ts b/src/api-helper.ts
new file mode 100644
index 00000000..75c0af83
--- /dev/null
+++ b/src/api-helper.ts
@@ -0,0 +1,16 @@
+import { Workspace, WorkspaceAgent } from "coder/site/src/api/typesGenerated"
+
+export function extractAgentsAndFolderPath(
+  workspace: Workspace,
+): [agents: WorkspaceAgent[], folderPath: string | undefined] {
+  // TODO: multiple agent support
+  const agents = workspace.latest_build.resources.reduce((acc, resource) => {
+    return acc.concat(resource.agents || [])
+  }, [] as WorkspaceAgent[])
+
+  let folderPath = undefined
+  if (agents.length === 1) {
+    folderPath = agents[0].expanded_directory
+  }
+  return [agents, folderPath]
+}
diff --git a/src/commands.ts b/src/commands.ts
index ccc2c653..bd4fc1b5 100644
--- a/src/commands.ts
+++ b/src/commands.ts
@@ -1,9 +1,11 @@
 import axios from "axios"
 import { getAuthenticatedUser, getWorkspaces, updateWorkspaceVersion } from "coder/site/src/api/api"
-import { Workspace, WorkspaceAgent } from "coder/site/src/api/typesGenerated"
+import { Workspace } from "coder/site/src/api/typesGenerated"
 import * as vscode from "vscode"
+import { extractAgentsAndFolderPath } from "./api-helper"
 import { Remote } from "./remote"
 import { Storage } from "./storage"
+import { WorkspaceTreeItem } from "./workspacesProvider"
 
 export class Commands {
   public constructor(private readonly vscodeProposed: typeof vscode, private readonly storage: Storage) {}
@@ -79,6 +81,9 @@ export class Commands {
         throw new Error("Failed to get authenticated user")
       }
       await vscode.commands.executeCommand("setContext", "coder.authenticated", true)
+      if (user.roles.find((role) => role.name === "owner")) {
+        await vscode.commands.executeCommand("setContext", "coder.isOwner", true)
+      }
       vscode.window
         .showInformationMessage(
           `Welcome to Coder, ${user.username}!`,
@@ -108,7 +113,37 @@ export class Commands {
     })
   }
 
-  public async open(...args: string[]): Promise<void> {
+  public async createWorkspace(): Promise<void> {
+    const uri = this.storage.getURL() + "/templates"
+    await vscode.commands.executeCommand("vscode.open", uri)
+  }
+
+  public async navigateToWorkspace(workspace: WorkspaceTreeItem) {
+    if (workspace) {
+      const uri = this.storage.getURL() + `/@${workspace.workspaceOwner}/${workspace.workspaceName}`
+      await vscode.commands.executeCommand("vscode.open", uri)
+    } else if (this.storage.workspace) {
+      const uri = this.storage.getURL() + `/@${this.storage.workspace.owner_name}/${this.storage.workspace.name}`
+      await vscode.commands.executeCommand("vscode.open", uri)
+    } else {
+      vscode.window.showInformationMessage("No workspace found.")
+    }
+  }
+
+  public async navigateToWorkspaceSettings(workspace: WorkspaceTreeItem) {
+    if (workspace) {
+      const uri = this.storage.getURL() + `/@${workspace.workspaceOwner}/${workspace.workspaceName}/settings`
+      await vscode.commands.executeCommand("vscode.open", uri)
+    } else if (this.storage.workspace) {
+      const uri =
+        this.storage.getURL() + `/@${this.storage.workspace.owner_name}/${this.storage.workspace.name}/settings`
+      await vscode.commands.executeCommand("vscode.open", uri)
+    } else {
+      vscode.window.showInformationMessage("No workspace found.")
+    }
+  }
+
+  public async open(...args: unknown[]): Promise<void> {
     let workspaceOwner: string
     let workspaceName: string
     let folderPath: string | undefined
@@ -165,19 +200,19 @@ export class Commands {
       workspaceOwner = workspace.owner_name
       workspaceName = workspace.name
 
-      // TODO: multiple agent support
-      const agents = workspace.latest_build.resources.reduce((acc, resource) => {
-        return acc.concat(resource.agents || [])
-      }, [] as WorkspaceAgent[])
-
-      if (agents.length === 1) {
-        folderPath = agents[0].expanded_directory
-      }
+      const [, folderPathExtracted] = extractAgentsAndFolderPath(workspace)
+      folderPath = folderPathExtracted
+    } else if (args.length === 2) {
+      // opening a workspace from the sidebar
+      const workspaceTreeItem = args[0] as WorkspaceTreeItem
+      workspaceOwner = workspaceTreeItem.workspaceOwner
+      workspaceName = workspaceTreeItem.workspaceName
+      folderPath = workspaceTreeItem.workspaceFolderPath
     } else {
-      workspaceOwner = args[0]
-      workspaceName = args[1]
+      workspaceOwner = args[0] as string
+      workspaceName = args[1] as string
       // workspaceAgent is reserved for args[2], but multiple agents aren't supported yet.
-      folderPath = args[3]
+      folderPath = args[3] as string | undefined
     }
 
     // A workspace can have multiple agents, but that's handled
diff --git a/src/extension.ts b/src/extension.ts
index e5e73cd7..7131dd95 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -6,15 +6,27 @@ import * as vscode from "vscode"
 import { Commands } from "./commands"
 import { Remote } from "./remote"
 import { Storage } from "./storage"
+import { WorkspaceQuery, WorkspaceProvider } from "./workspacesProvider"
 
 export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
   const output = vscode.window.createOutputChannel("Coder")
   const storage = new Storage(output, ctx.globalState, ctx.secrets, ctx.globalStorageUri, ctx.logUri)
   await storage.init()
 
+  const myWorkspacesProvider = new WorkspaceProvider(WorkspaceQuery.Mine)
+  const allWorkspacesProvider = new WorkspaceProvider(WorkspaceQuery.All)
+
+  vscode.window.registerTreeDataProvider("myWorkspaces", myWorkspacesProvider)
+  vscode.window.registerTreeDataProvider("allWorkspaces", allWorkspacesProvider)
+
   getAuthenticatedUser()
-    .then(() => {
-      vscode.commands.executeCommand("setContext", "coder.authenticated", true)
+    .then(async (user) => {
+      if (user) {
+        vscode.commands.executeCommand("setContext", "coder.authenticated", true)
+        if (user.roles.find((role) => role.name === "owner")) {
+          await vscode.commands.executeCommand("setContext", "coder.isOwner", true)
+        }
+      }
     })
     .catch(() => {
       // Not authenticated!
@@ -76,6 +88,16 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
   vscode.commands.registerCommand("coder.logout", commands.logout.bind(commands))
   vscode.commands.registerCommand("coder.open", commands.open.bind(commands))
   vscode.commands.registerCommand("coder.workspace.update", commands.updateWorkspace.bind(commands))
+  vscode.commands.registerCommand("coder.createWorkspace", commands.createWorkspace.bind(commands))
+  vscode.commands.registerCommand("coder.navigateToWorkspace", commands.navigateToWorkspace.bind(commands))
+  vscode.commands.registerCommand(
+    "coder.navigateToWorkspaceSettings",
+    commands.navigateToWorkspaceSettings.bind(commands),
+  )
+  vscode.commands.registerCommand("coder.refreshWorkspaces", () => {
+    myWorkspacesProvider.refresh()
+    allWorkspacesProvider.refresh()
+  })
 
   // Since the "onResolveRemoteAuthority:ssh-remote" activation event exists
   // in package.json we're able to perform actions before the authority is
diff --git a/src/workspacesProvider.ts b/src/workspacesProvider.ts
new file mode 100644
index 00000000..f09b29e4
--- /dev/null
+++ b/src/workspacesProvider.ts
@@ -0,0 +1,60 @@
+import { getWorkspaces } from "coder/site/src/api/api"
+import * as path from "path"
+import * as vscode from "vscode"
+import { extractAgentsAndFolderPath } from "./api-helper"
+
+export enum WorkspaceQuery {
+  Mine = "owner:me",
+  All = "",
+}
+
+export class WorkspaceProvider implements vscode.TreeDataProvider<WorkspaceTreeItem> {
+  constructor(private readonly getWorkspacesQuery: WorkspaceQuery) {}
+
+  private _onDidChangeTreeData: vscode.EventEmitter<WorkspaceTreeItem | undefined | null | void> =
+    new vscode.EventEmitter<WorkspaceTreeItem | undefined | null | void>()
+  readonly onDidChangeTreeData: vscode.Event<WorkspaceTreeItem | undefined | null | void> =
+    this._onDidChangeTreeData.event
+
+  refresh(): void {
+    this._onDidChangeTreeData.fire()
+  }
+
+  getTreeItem(element: WorkspaceTreeItem): vscode.TreeItem {
+    return element
+  }
+
+  getChildren(): Thenable<WorkspaceTreeItem[]> {
+    return getWorkspaces({ q: this.getWorkspacesQuery }).then((workspaces) => {
+      return workspaces.workspaces.map((workspace) => {
+        const status =
+          workspace.latest_build.status.substring(0, 1).toUpperCase() + workspace.latest_build.status.substring(1)
+
+        const label =
+          this.getWorkspacesQuery === WorkspaceQuery.All
+            ? `${workspace.owner_name} / ${workspace.name}`
+            : workspace.name
+        const detail = `Template: ${workspace.template_display_name || workspace.template_name} • Status: ${status}`
+        const [, folderPath] = extractAgentsAndFolderPath(workspace)
+        return new WorkspaceTreeItem(label, detail, workspace.owner_name, workspace.name, folderPath)
+      })
+    })
+  }
+}
+
+export class WorkspaceTreeItem extends vscode.TreeItem {
+  constructor(
+    public readonly label: string,
+    public readonly tooltip: string,
+    public readonly workspaceOwner: string,
+    public readonly workspaceName: string,
+    public readonly workspaceFolderPath: string | undefined,
+  ) {
+    super(label, vscode.TreeItemCollapsibleState.None)
+  }
+
+  iconPath = {
+    light: path.join(__filename, "..", "..", "media", "logo.svg"),
+    dark: path.join(__filename, "..", "..", "media", "logo.svg"),
+  }
+}