diff --git a/package.json b/package.json
index a85fd235..2e60495b 100644
--- a/package.json
+++ b/package.json
@@ -311,6 +311,7 @@
     "date-fns": "^3.6.0",
     "eventsource": "^3.0.6",
     "find-process": "https://github.com/coder/find-process#fix/sequoia-compat",
+    "ip-range-check": "^0.2.0",
     "jsonc-parser": "^3.3.1",
     "memfs": "^4.9.3",
     "node-forge": "^1.3.1",
diff --git a/src/api.ts b/src/api.ts
index fdb83b81..0c78d7cd 100644
--- a/src/api.ts
+++ b/src/api.ts
@@ -1,7 +1,7 @@
-import { AxiosInstance } from "axios"
+import { AxiosInstance, isAxiosError } from "axios"
 import { spawn } from "child_process"
 import { Api } from "coder/site/src/api/api"
-import { ProvisionerJobLog, Workspace } from "coder/site/src/api/typesGenerated"
+import { ProvisionerJobLog, SSHConfigResponse, Workspace } from "coder/site/src/api/typesGenerated"
 import { FetchLikeInit } from "eventsource"
 import fs from "fs/promises"
 import { ProxyAgent } from "proxy-agent"
@@ -280,3 +280,30 @@ export async function waitForBuild(
   writeEmitter.fire(`Workspace is now ${updatedWorkspace.latest_build.status}\r\n`)
   return updatedWorkspace
 }
+
+export async function fetchSSHConfig(restClient: Api): Promise<SSHConfigResponse> {
+  try {
+    const sshConfig = await restClient.getDeploymentSSHConfig()
+    return {
+      hostname_prefix: sshConfig.hostname_prefix,
+      hostname_suffix: sshConfig.hostname_suffix ?? "coder",
+      ssh_config_options: sshConfig.ssh_config_options,
+    }
+  } catch (error) {
+    if (!isAxiosError(error)) {
+      throw error
+    }
+    switch (error.response?.status) {
+      case 404: {
+        // Very old deployment that doesn't support SSH config
+        return {
+          hostname_prefix: "coder",
+          hostname_suffix: "coder",
+          ssh_config_options: {},
+        }
+      }
+      default:
+        throw error
+    }
+  }
+}
diff --git a/src/commands.ts b/src/commands.ts
index d24df729..f9019856 100644
--- a/src/commands.ts
+++ b/src/commands.ts
@@ -1,12 +1,13 @@
+import { isAxiosError } from "axios"
 import { Api } from "coder/site/src/api/api"
 import { getErrorMessage } from "coder/site/src/api/errors"
 import { User, Workspace, WorkspaceAgent } from "coder/site/src/api/typesGenerated"
 import * as vscode from "vscode"
-import { makeCoderSdk, needToken } from "./api"
+import { fetchSSHConfig, makeCoderSdk, needToken } from "./api"
 import { extractAgents } from "./api-helper"
 import { CertificateError } from "./error"
 import { Storage } from "./storage"
-import { toRemoteAuthority, toSafeHost } from "./util"
+import { maybeCoderConnectAddr, toRemoteAuthority, toSafeHost } from "./util"
 import { OpenableTreeItem } from "./workspacesProvider"
 
 export class Commands {
@@ -392,7 +393,7 @@ export class Commands {
       if (!baseUrl) {
         throw new Error("You are not logged in")
       }
-      await openWorkspace(
+      await this.openWorkspace(
         baseUrl,
         treeItem.workspaceOwner,
         treeItem.workspaceName,
@@ -491,12 +492,12 @@ export class Commands {
     } else {
       workspaceOwner = args[0] as string
       workspaceName = args[1] as string
-      // workspaceAgent is reserved for args[2], but multiple agents aren't supported yet.
+      workspaceAgent = args[2] as string | undefined
       folderPath = args[3] as string | undefined
       openRecent = args[4] as boolean | undefined
     }
 
-    await openWorkspace(baseUrl, workspaceOwner, workspaceName, workspaceAgent, folderPath, openRecent)
+    await this.openWorkspace(baseUrl, workspaceOwner, workspaceName, workspaceAgent, folderPath, openRecent)
   }
 
   /**
@@ -512,11 +513,18 @@ export class Commands {
 
     const workspaceOwner = args[0] as string
     const workspaceName = args[1] as string
-    const workspaceAgent = undefined // args[2] is reserved, but we do not support multiple agents yet.
+    const workspaceAgent = args[2] as string | undefined
     const devContainerName = args[3] as string
     const devContainerFolder = args[4] as string
 
-    await openDevContainer(baseUrl, workspaceOwner, workspaceName, workspaceAgent, devContainerName, devContainerFolder)
+    await this.openDevContainerInner(
+      baseUrl,
+      workspaceOwner,
+      workspaceName,
+      workspaceAgent,
+      devContainerName,
+      devContainerFolder,
+    )
   }
 
   /**
@@ -540,107 +548,206 @@ export class Commands {
       await this.workspaceRestClient.updateWorkspaceVersion(this.workspace)
     }
   }
-}
 
-/**
- * Given a workspace, build the host name, find a directory to open, and pass
- * both to the Remote SSH plugin in the form of a remote authority URI.
- */
-async function openWorkspace(
-  baseUrl: string,
-  workspaceOwner: string,
-  workspaceName: string,
-  workspaceAgent: string | undefined,
-  folderPath: string | undefined,
-  openRecent: boolean | undefined,
-) {
-  // A workspace can have multiple agents, but that's handled
-  // when opening a workspace unless explicitly specified.
-  const remoteAuthority = toRemoteAuthority(baseUrl, workspaceOwner, workspaceName, workspaceAgent)
-
-  let newWindow = true
-  // Open in the existing window if no workspaces are open.
-  if (!vscode.workspace.workspaceFolders?.length) {
-    newWindow = false
-  }
+  /**
+   * Given a workspace, build the host name, find a directory to open, and pass
+   * both to the Remote SSH plugin in the form of a remote authority URI.
+   */
+  private async openWorkspace(
+    baseUrl: string,
+    workspaceOwner: string,
+    workspaceName: string,
+    workspaceAgent: string | undefined,
+    folderPath: string | undefined,
+    openRecent: boolean | undefined,
+  ) {
+    let remoteAuthority = toRemoteAuthority(baseUrl, workspaceOwner, workspaceName, workspaceAgent)
+
+    // We can't connect using Coder Connect straightaway if `workspaceAgent`
+    // is undefined. This happens when:
+    // 1. The workspace is stopped
+    // 2. A `vscode://coder.coder-remote` URI does not include the agent as a
+    // query parameter.
+    //
+    // For 1. `Remote.setup` will migrate us to Coder Connect once the workspace is built.
+    // For 2. `Remote.setup` will call `maybeAskAgent` and then migrate us to Coder Connect
+    if (workspaceAgent) {
+      let sshConfig
+      try {
+        // Fetch (or get defaults) for the SSH config.
+        sshConfig = await fetchSSHConfig(this.restClient)
+      } catch (error) {
+        return this.handleInitialRequestError(error, workspaceName, baseUrl, async () => {
+          await this.openWorkspace(baseUrl, workspaceOwner, workspaceName, workspaceAgent, folderPath, openRecent)
+        })
+      }
 
-  // If a folder isn't specified or we have been asked to open the most recent,
-  // we can try to open a recently opened folder/workspace.
-  if (!folderPath || openRecent) {
-    const output: {
-      workspaces: { folderUri: vscode.Uri; remoteAuthority: string }[]
-    } = await vscode.commands.executeCommand("_workbench.getRecentlyOpened")
-    const opened = output.workspaces.filter(
-      // Remove recents that do not belong to this connection.  The remote
-      // authority maps to a workspace or workspace/agent combination (using the
-      // SSH host name).  This means, at the moment, you can have a different
-      // set of recents for a workspace versus workspace/agent combination, even
-      // if that agent is the default for the workspace.
-      (opened) => opened.folderUri?.authority === remoteAuthority,
-    )
+      const coderConnectAddr = await maybeCoderConnectAddr(
+        workspaceAgent,
+        workspaceName,
+        workspaceOwner,
+        sshConfig.hostname_suffix,
+      )
+      if (coderConnectAddr) {
+        remoteAuthority = `ssh-remote+${coderConnectAddr}`
+      }
+    }
 
-    // openRecent will always use the most recent.  Otherwise, if there are
-    // multiple we ask the user which to use.
-    if (opened.length === 1 || (opened.length > 1 && openRecent)) {
-      folderPath = opened[0].folderUri.path
-    } else if (opened.length > 1) {
-      const items = opened.map((f) => f.folderUri.path)
-      folderPath = await vscode.window.showQuickPick(items, {
-        title: "Select a recently opened folder",
-      })
-      if (!folderPath) {
-        // User aborted.
-        return
+    let newWindow = true
+    // Open in the existing window if no workspaces are open.
+    if (!vscode.workspace.workspaceFolders?.length) {
+      newWindow = false
+    }
+
+    // If a folder isn't specified or we have been asked to open the most recent,
+    // we can try to open a recently opened folder/workspace.
+    if (!folderPath || openRecent) {
+      const output: {
+        workspaces: { folderUri: vscode.Uri; remoteAuthority: string }[]
+      } = await vscode.commands.executeCommand("_workbench.getRecentlyOpened")
+      const opened = output.workspaces.filter(
+        // Remove recents that do not belong to this connection.  The remote
+        // authority maps to a workspace or workspace/agent combination (using the
+        // SSH host name).  This means, at the moment, you can have a different
+        // set of recents for a workspace versus workspace/agent combination, even
+        // if that agent is the default for the workspace.
+        (opened) => opened.folderUri?.authority === remoteAuthority,
+      )
+
+      // openRecent will always use the most recent.  Otherwise, if there are
+      // multiple we ask the user which to use.
+      if (opened.length === 1 || (opened.length > 1 && openRecent)) {
+        folderPath = opened[0].folderUri.path
+      } else if (opened.length > 1) {
+        const items = opened.map((f) => f.folderUri.path)
+        folderPath = await vscode.window.showQuickPick(items, {
+          title: "Select a recently opened folder",
+        })
+        if (!folderPath) {
+          // User aborted.
+          return
+        }
       }
     }
+
+    if (folderPath) {
+      await vscode.commands.executeCommand(
+        "vscode.openFolder",
+        vscode.Uri.from({
+          scheme: "vscode-remote",
+          authority: remoteAuthority,
+          path: folderPath,
+        }),
+        // Open this in a new window!
+        newWindow,
+      )
+      return
+    }
+
+    // This opens the workspace without an active folder opened.
+    await vscode.commands.executeCommand("vscode.newWindow", {
+      remoteAuthority: remoteAuthority,
+      reuseWindow: !newWindow,
+    })
   }
 
-  if (folderPath) {
+  private async openDevContainerInner(
+    baseUrl: string,
+    workspaceOwner: string,
+    workspaceName: string,
+    workspaceAgent: string | undefined,
+    devContainerName: string,
+    devContainerFolder: string,
+  ) {
+    let remoteAuthority = toRemoteAuthority(baseUrl, workspaceOwner, workspaceName, workspaceAgent)
+
+    if (workspaceAgent) {
+      let sshConfig
+      try {
+        // Fetch (or get defaults) for the SSH config.
+        sshConfig = await fetchSSHConfig(this.restClient)
+      } catch (error) {
+        return this.handleInitialRequestError(error, workspaceName, baseUrl, async () => {
+          await this.openDevContainerInner(
+            baseUrl,
+            workspaceOwner,
+            workspaceName,
+            workspaceAgent,
+            devContainerName,
+            devContainerFolder,
+          )
+        })
+      }
+
+      const coderConnectAddr = await maybeCoderConnectAddr(
+        workspaceAgent,
+        workspaceName,
+        workspaceOwner,
+        sshConfig.hostname_suffix,
+      )
+      if (coderConnectAddr) {
+        remoteAuthority = `ssh-remote+${coderConnectAddr}`
+      }
+    }
+
+    const devContainer = Buffer.from(JSON.stringify({ containerName: devContainerName }), "utf-8").toString("hex")
+    const devContainerAuthority = `attached-container+${devContainer}@${remoteAuthority}`
+
+    let newWindow = true
+    if (!vscode.workspace.workspaceFolders?.length) {
+      newWindow = false
+    }
+
     await vscode.commands.executeCommand(
       "vscode.openFolder",
       vscode.Uri.from({
         scheme: "vscode-remote",
-        authority: remoteAuthority,
-        path: folderPath,
+        authority: devContainerAuthority,
+        path: devContainerFolder,
       }),
-      // Open this in a new window!
       newWindow,
     )
-    return
   }
 
-  // This opens the workspace without an active folder opened.
-  await vscode.commands.executeCommand("vscode.newWindow", {
-    remoteAuthority: remoteAuthority,
-    reuseWindow: !newWindow,
-  })
-}
-
-async function openDevContainer(
-  baseUrl: string,
-  workspaceOwner: string,
-  workspaceName: string,
-  workspaceAgent: string | undefined,
-  devContainerName: string,
-  devContainerFolder: string,
-) {
-  const remoteAuthority = toRemoteAuthority(baseUrl, workspaceOwner, workspaceName, workspaceAgent)
-
-  const devContainer = Buffer.from(JSON.stringify({ containerName: devContainerName }), "utf-8").toString("hex")
-  const devContainerAuthority = `attached-container+${devContainer}@${remoteAuthority}`
-
-  let newWindow = true
-  if (!vscode.workspace.workspaceFolders?.length) {
-    newWindow = false
+  private async handleInitialRequestError(
+    error: unknown,
+    workspaceName: string,
+    baseUrl: string,
+    retryCallback: () => Promise<void>,
+  ) {
+    if (!isAxiosError(error)) {
+      throw error
+    }
+    switch (error.response?.status) {
+      case 401: {
+        const result = await this.vscodeProposed.window.showInformationMessage(
+          "Your session expired...",
+          {
+            useCustom: true,
+            modal: true,
+            detail: `You must log in to access ${workspaceName}.`,
+          },
+          "Log In",
+        )
+        if (!result) {
+          // User declined to log in.
+          return
+        }
+        // Log in then try again
+        await vscode.commands.executeCommand("coder.login", baseUrl, undefined, undefined)
+        await retryCallback()
+        return
+      }
+      default: {
+        const message = getErrorMessage(error, "no response from the server")
+        this.storage.writeToCoderOutputChannel(`Failed to open workspace: ${message}`)
+        this.vscodeProposed.window.showErrorMessage("Failed to open workspace", {
+          detail: message,
+          modal: true,
+          useCustom: true,
+        })
+        return
+      }
+    }
   }
-
-  await vscode.commands.executeCommand(
-    "vscode.openFolder",
-    vscode.Uri.from({
-      scheme: "vscode-remote",
-      authority: devContainerAuthority,
-      path: devContainerFolder,
-    }),
-    newWindow,
-  )
 }
diff --git a/src/remote.ts b/src/remote.ts
index 5b8a9694..5ef942a9 100644
--- a/src/remote.ts
+++ b/src/remote.ts
@@ -1,6 +1,6 @@
 import { isAxiosError } from "axios"
 import { Api } from "coder/site/src/api/api"
-import { Workspace } from "coder/site/src/api/typesGenerated"
+import { SSHConfigResponse, Workspace } from "coder/site/src/api/typesGenerated"
 import find from "find-process"
 import * as fs from "fs/promises"
 import * as jsonc from "jsonc-parser"
@@ -9,7 +9,14 @@ import * as path from "path"
 import prettyBytes from "pretty-bytes"
 import * as semver from "semver"
 import * as vscode from "vscode"
-import { createHttpAgent, makeCoderSdk, needToken, startWorkspaceIfStoppedOrFailed, waitForBuild } from "./api"
+import {
+  createHttpAgent,
+  fetchSSHConfig,
+  makeCoderSdk,
+  needToken,
+  startWorkspaceIfStoppedOrFailed,
+  waitForBuild,
+} from "./api"
 import { extractAgents } from "./api-helper"
 import * as cli from "./cliManager"
 import { Commands } from "./commands"
@@ -19,7 +26,7 @@ import { Inbox } from "./inbox"
 import { SSHConfig, SSHValues, mergeSSHConfigValues } from "./sshConfig"
 import { computeSSHProperties, sshSupportsSetEnv } from "./sshSupport"
 import { Storage } from "./storage"
-import { AuthorityPrefix, expandPath, parseRemoteAuthority } from "./util"
+import { AuthorityPrefix, expandPath, maybeCoderConnectAddr, parseRemoteAuthority } from "./util"
 import { WorkspaceMonitor } from "./workspaceMonitor"
 
 export interface RemoteDetails extends vscode.Disposable {
@@ -469,9 +476,19 @@ export class Remote {
     //
     // If we didn't write to the SSH config file, connecting would fail with
     // "Host not found".
+    let sshConfigResponse: SSHConfigResponse
     try {
       this.storage.writeToCoderOutputChannel("Updating SSH config...")
-      await this.updateSSHConfig(workspaceRestClient, parts.label, parts.host, binaryPath, logDir, featureSet)
+      sshConfigResponse = await fetchSSHConfig(workspaceRestClient)
+      await this.updateSSHConfig(
+        workspaceRestClient,
+        parts.label,
+        parts.host,
+        binaryPath,
+        logDir,
+        featureSet,
+        sshConfigResponse,
+      )
     } catch (error) {
       this.storage.writeToCoderOutputChannel(`Failed to configure SSH: ${error}`)
       throw error
@@ -503,6 +520,42 @@ export class Remote {
 
     this.storage.writeToCoderOutputChannel("Remote setup complete")
 
+    // If Coder Connect is available for this workspace, switch to that
+    const coderConnectAddr = await maybeCoderConnectAddr(
+      agent.name,
+      parts.workspace,
+      parts.username,
+      sshConfigResponse.hostname_suffix,
+    )
+    if (coderConnectAddr) {
+      // Find the path of the current workspace, which will have the same authority
+      const folderPath = this.vscodeProposed.workspace.workspaceFolders?.find(
+        (folder) => folder.uri.authority === remoteAuthority,
+      )?.uri.path
+      let newRemoteAuthority = `ssh-remote+${coderConnectAddr}`
+      if (parts.containerNameHex) {
+        newRemoteAuthority = `attached-container+${parts.containerNameHex}@${newRemoteAuthority}`
+      }
+
+      if (folderPath) {
+        await vscode.commands.executeCommand(
+          "vscode.openFolder",
+          vscode.Uri.from({
+            scheme: "vscode-remote",
+            authority: newRemoteAuthority,
+            path: folderPath,
+          }),
+          //`ForceNewWindow`
+          false,
+        )
+      } else {
+        await vscode.commands.executeCommand("vscode.newWindow", {
+          remoteAuthority: newRemoteAuthority,
+          reuseWindow: true,
+        })
+      }
+    }
+
     // Returning the URL and token allows the plugin to authenticate its own
     // client, for example to display the list of workspaces belonging to this
     // deployment in the sidebar.  We use our own client in here for reasons
@@ -550,30 +603,8 @@ export class Remote {
     binaryPath: string,
     logDir: string,
     featureSet: FeatureSet,
+    sshConfigResponse: SSHConfigResponse,
   ) {
-    let deploymentSSHConfig = {}
-    try {
-      const deploymentConfig = await restClient.getDeploymentSSHConfig()
-      deploymentSSHConfig = deploymentConfig.ssh_config_options
-    } catch (error) {
-      if (!isAxiosError(error)) {
-        throw error
-      }
-      switch (error.response?.status) {
-        case 404: {
-          // Deployment does not support overriding ssh config yet. Likely an
-          // older version, just use the default.
-          break
-        }
-        case 401: {
-          await this.vscodeProposed.window.showErrorMessage("Your session expired...")
-          throw error
-        }
-        default:
-          throw error
-      }
-    }
-
     // deploymentConfig is now set from the remote coderd deployment.
     // Now override with the user's config.
     const userConfigSSH = vscode.workspace.getConfiguration("coder").get<string[]>("sshConfig") || []
@@ -596,7 +627,7 @@ export class Remote {
       },
       {} as Record<string, string>,
     )
-    const sshConfigOverrides = mergeSSHConfigValues(deploymentSSHConfig, userConfig)
+    const sshConfigOverrides = mergeSSHConfigValues(sshConfigResponse.ssh_config_options, userConfig)
 
     let sshConfigFile = vscode.workspace.getConfiguration().get<string>("remote.SSH.configFile")
     if (!sshConfigFile) {
diff --git a/src/util.test.ts b/src/util.test.ts
index 4fffcc75..b3583da1 100644
--- a/src/util.test.ts
+++ b/src/util.test.ts
@@ -9,6 +9,7 @@ it("ignore unrelated authorities", async () => {
     "vscode://ssh-remote+coder-vscode-test--foo--bar",
     "vscode://ssh-remote+coder-vscode-foo--bar",
     "vscode://ssh-remote+coder--foo--bar",
+    "vscode://attached-container+namehash@ssh-remote+dev.foo.admin.coder",
   ]
   for (const test of tests) {
     expect(parseRemoteAuthority(test)).toBe(null)
@@ -29,6 +30,7 @@ it("should error on invalid authorities", async () => {
 
 it("should parse authority", async () => {
   expect(parseRemoteAuthority("vscode://ssh-remote+coder-vscode--foo--bar")).toStrictEqual({
+    containerNameHex: undefined,
     agent: "",
     host: "coder-vscode--foo--bar",
     label: "",
@@ -36,6 +38,7 @@ it("should parse authority", async () => {
     workspace: "bar",
   })
   expect(parseRemoteAuthority("vscode://ssh-remote+coder-vscode--foo--bar--baz")).toStrictEqual({
+    containerNameHex: undefined,
     agent: "baz",
     host: "coder-vscode--foo--bar--baz",
     label: "",
@@ -43,6 +46,7 @@ it("should parse authority", async () => {
     workspace: "bar",
   })
   expect(parseRemoteAuthority("vscode://ssh-remote+coder-vscode.dev.coder.com--foo--bar")).toStrictEqual({
+    containerNameHex: undefined,
     agent: "",
     host: "coder-vscode.dev.coder.com--foo--bar",
     label: "dev.coder.com",
@@ -50,6 +54,7 @@ it("should parse authority", async () => {
     workspace: "bar",
   })
   expect(parseRemoteAuthority("vscode://ssh-remote+coder-vscode.dev.coder.com--foo--bar--baz")).toStrictEqual({
+    containerNameHex: undefined,
     agent: "baz",
     host: "coder-vscode.dev.coder.com--foo--bar--baz",
     label: "dev.coder.com",
@@ -57,6 +62,17 @@ it("should parse authority", async () => {
     workspace: "bar",
   })
   expect(parseRemoteAuthority("vscode://ssh-remote+coder-vscode.dev.coder.com--foo--bar.baz")).toStrictEqual({
+    containerNameHex: undefined,
+    agent: "baz",
+    host: "coder-vscode.dev.coder.com--foo--bar.baz",
+    label: "dev.coder.com",
+    username: "foo",
+    workspace: "bar",
+  })
+  expect(
+    parseRemoteAuthority("vscode://attached-container+namehash@ssh-remote+coder-vscode.dev.coder.com--foo--bar.baz"),
+  ).toStrictEqual({
+    containerNameHex: "namehash",
     agent: "baz",
     host: "coder-vscode.dev.coder.com--foo--bar.baz",
     label: "dev.coder.com",
diff --git a/src/util.ts b/src/util.ts
index 8253f152..c42dcd72 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -1,7 +1,11 @@
+import { lookup } from "dns"
+import ipRangeCheck from "ip-range-check"
 import * as os from "os"
 import url from "url"
+import { promisify } from "util"
 
 export interface AuthorityParts {
+  containerNameHex: string | undefined
   agent: string | undefined
   host: string
   label: string
@@ -21,14 +25,20 @@ export const AuthorityPrefix = "coder-vscode"
  * Throw an error if the host is invalid.
  */
 export function parseRemoteAuthority(authority: string): AuthorityParts | null {
-  // The authority looks like: vscode://ssh-remote+<ssh host name>
-  const authorityParts = authority.split("+")
+  // The Dev Container authority looks like: vscode://attached-container+containerNameHex@ssh-remote+<ssh host name>
+  // The SSH authority looks like: vscode://ssh-remote+<ssh host name>
+  const authorityURI = authority.startsWith("vscode://") ? authority : `vscode://${authority}`
+  const authorityParts = new URL(authorityURI)
+  const containerParts = authorityParts.username.split("+")
+  const containerNameHex = containerParts[1]
+  const sshAuthority = authorityParts.host
+  const sshAuthorityParts = sshAuthority.split("+")
 
   // We create SSH host names in a format matching:
   // coder-vscode(--|.)<username>--<workspace>(--|.)<agent?>
   // The agent can be omitted; the user will be prompted for it instead.
   // Anything else is unrelated to Coder and can be ignored.
-  const parts = authorityParts[1].split("--")
+  const parts = sshAuthorityParts[1].split("--")
   if (parts.length <= 1 || (parts[0] !== AuthorityPrefix && !parts[0].startsWith(`${AuthorityPrefix}.`))) {
     return null
   }
@@ -53,14 +63,32 @@ export function parseRemoteAuthority(authority: string): AuthorityParts | null {
   }
 
   return {
+    containerNameHex: containerNameHex,
     agent: agent,
-    host: authorityParts[1],
+    host: sshAuthorityParts[1],
     label: parts[0].replace(/^coder-vscode\.?/, ""),
     username: parts[1],
     workspace: workspace,
   }
 }
 
+export async function maybeCoderConnectAddr(
+  agent: string,
+  workspace: string,
+  owner: string,
+  hostnameSuffix: string,
+): Promise<string | undefined> {
+  const coderConnectHostname = `${agent}.${workspace}.${owner}.${hostnameSuffix}`
+  try {
+    const res = await promisify(lookup)(coderConnectHostname)
+    // Captive DNS portals may return an unrelated address, so we check it's
+    // within the Coder Service Prefix.
+    return res.family === 6 && ipRangeCheck(res.address, "fd60:627a:a42b::/48") ? coderConnectHostname : undefined
+  } catch {
+    return undefined
+  }
+}
+
 export function toRemoteAuthority(
   baseUrl: string,
   workspaceOwner: string,
diff --git a/src/workspacesProvider.ts b/src/workspacesProvider.ts
index 0709487e..12718546 100644
--- a/src/workspacesProvider.ts
+++ b/src/workspacesProvider.ts
@@ -353,7 +353,7 @@ export class WorkspaceTreeItem extends OpenableTreeItem {
       showOwner ? vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.Expanded,
       workspace.owner_name,
       workspace.name,
-      undefined,
+      agents[0]?.name,
       agents[0]?.expanded_directory,
       agents.length > 1 ? "coderWorkspaceMultipleAgents" : "coderWorkspaceSingleAgent",
     )
diff --git a/yarn.lock b/yarn.lock
index efc2df73..72bc49da 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1749,7 +1749,7 @@ co@3.1.0:
 
 "coder@https://github.com/coder/coder#main":
   version "0.0.0"
-  resolved "https://github.com/coder/coder#3ac844ad3d341d2910542b83d4f33df7bd0be85e"
+  resolved "https://github.com/coder/coder#f8971bb3cc01d81b3085b2b3c9253d8d340d125c"
 
 collapse-white-space@^1.0.2:
   version "1.0.6"
@@ -3441,6 +3441,18 @@ ip-address@^9.0.5:
     jsbn "1.1.0"
     sprintf-js "^1.1.3"
 
+ip-range-check@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/ip-range-check/-/ip-range-check-0.2.0.tgz#e67f126c8fb36c8f11d4c07d7924b7e364365157"
+  integrity sha512-oaM3l/3gHbLlt/tCWLvt0mj1qUaI+STuRFnUvARGCujK9vvU61+2JsDpmkMzR4VsJhuFXWWgeKKVnwwoFfzCqw==
+  dependencies:
+    ipaddr.js "^1.0.1"
+
+ipaddr.js@^1.0.1:
+  version "1.9.1"
+  resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
+  integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
+
 irregular-plurals@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/irregular-plurals/-/irregular-plurals-2.0.0.tgz#39d40f05b00f656d0b7fa471230dd3b714af2872"