*** title: Workspaces description: >- Workspaces are isolated environments where AI agents access concurrently running resources. ------------------ A workspace is an isolated container for an AI agent's resources. When you create a workspace, you define what the agent has access to — AI credentials, secrets, storage — and then launch runtimes inside it. ## Creating a workspace ```ts import { Bctrl } from "@bctrl/sdk"; const bctrl = new Bctrl({ apiKey: process.env.BCTRL_API_KEY! }); const workspace = await bctrl.workspaces.create({ name: "sales-automation", }); ``` The `name` identifies this workspace. You get back a `WorkspaceClient` that you use to launch runtimes, execute steps, and manage the workspace's lifecycle. ## Mounting resources Most workspaces need access to AI providers, a secret vault, or shared storage. You attach these at creation time via `mounts`: ```ts const workspace = await bctrl.workspaces.create({ name: "sales-automation", mounts: { ai: { allow: ["openai-prod", "anthropic-prod"], defaults: { openai: "openai-prod", anthropic: "anthropic-prod", }, }, vault: { allow: ["prod/crm/", "prod/email/"], deny: ["prod/admin/"], allowRawReads: true, }, storage: { workspace: "shared-exports", }, }, }); ``` Controls which AI provider credentials the workspace can use. `allow` is a list of credential IDs (managed via `bctrl.aiCredentials`). `defaults` sets the default credential per provider — runtimes and agents will use these unless overridden. Controls which secrets from your vault the workspace can access. Scoped by key prefix — `allow: ["prod/crm/"]` means the workspace can read any secret under `prod/crm/` but nothing else. `deny` explicitly blocks prefixes. `allowRawReads` controls whether plaintext secret values can be read directly. Connects a storage namespace to the workspace. Files uploaded by runtimes (screenshots, downloads, exports) are stored here. Multiple workspaces can share the same storage namespace. All runtimes launched inside the workspace inherit these mounts. See [Scopes & Inheritance](/sdk/concepts/scopes-and-inheritance) for how narrowing works. ## Opening an existing workspace If you already have a workspace ID: ```ts const workspace = await bctrl.workspaces.open("ws_abc123"); ``` ## Listing workspaces ```ts const workspaces = await bctrl.workspaces.list(); ``` ## Workspace state Query the current state of a workspace — its active runtimes, mounted resources, and configuration: ```ts const state = await workspace.state(); ``` ## Execute For low-level control, you can execute structured automation steps directly on the workspace without going through a driver: ```ts const result = await workspace.execute({ steps: [ { call: "browser.newContext" }, { call: "context.newPage", bind: "p" }, { call: "page.goto", ref: "p", args: ["https://example.com"] }, { call: "page.content", ref: "p" }, ], }); ``` This is the HTTP-equivalent execution model. Most users should prefer the [fluent driver APIs](/sdk/concepts/runtimes) instead. ## Related * [Runtimes](/sdk/concepts/runtimes) — launch and automate resources inside a workspace * [Scopes & Inheritance](/sdk/concepts/scopes-and-inheritance) — how mounts flow to runtimes * [API Reference: Workspaces](/api/workspaces) — the underlying HTTP endpoints