workspace.json
Each workspace has its own config file at <workDir>/workspaces/<wsId>/workspace.json. This is where bundles, skill directories, named agent profiles, and optional model or identity overrides live — not in nimblebrain.json.
In dev mode (no instance.json, no auth configured) the runtime uses a single workspace with ID _dev, so you’ll find its config at <workDir>/workspaces/_dev/workspace.json. Under auth, workspaces are created and managed via the nb__manage_workspaces tool or the HTTP API; their files are maintained by the runtime. Team workspace ids are opaque (ws_<16-hex>) and name-independent.
Example
Section titled “Example”{ "id": "ws_a1b2c3d4e5f60718", "name": "Product", "about": "Product team workspace — roadmap, metrics, and customer research.", "members": [ { "userId": "usr_default", "role": "admin" }, { "userId": "usr_alex01", "role": "member" } ], "bundles": [ { "name": "@nimblebraininc/ipinfo" }, { "name": "@nimblebraininc/granola", "env": { "API_KEY": "grn_..." }, "trustScore": 85 }, { "path": "../mcp-servers/hello" } ], "skillDirs": ["./skills", "/opt/nimblebrain/skills"], "agents": { "researcher": { "description": "Deep research agent with search tools", "systemPrompt": "You are a research agent. Use search tools to find information.", "tools": ["granola__*", "nb__*"], "maxIterations": 8, "model": "fast" } }, "models": { "default": "anthropic:claude-opus-4-6" }, "identity": "You are the Acme Product Copilot. Be concise. Prefer data-backed answers.", "createdAt": "2026-03-05T10:00:00.000Z", "updatedAt": "2026-04-15T09:15:00.000Z"}Fields
Section titled “Fields”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Workspace ID. Opaque ws_<16-hex> for team workspaces, ws_user_<userId> for personal, _dev in dev mode. Name-independent — never parse it. |
name | string | Yes | Human-readable workspace name shown in the UI. Freely editable; changing it does not change the id or on-disk path. |
about | string | null | No | Short human-readable description, set in the workspace settings UI. Surfaced on the org “About” view and the workspace directory. Defaults to null. |
members | array | Yes | Users with access. Each entry is { userId, role } where role is "admin" or "member". |
bundles | array | Yes | MCP bundles installed in this workspace. See Bundle Configuration. |
connectorsAllowList | string[] | No | Per-workspace catalog allow-list. When set, only catalog entries whose id is in this array appear on the workspace’s Connectors page. When unset, the full loaded catalog is visible. Filters the catalog UI only — already-installed bundles keep running regardless. |
oauthOperatorApps | object | No | Per-workspace OAuth app config for auth: static catalog entries. Keyed by catalog id (reverse-DNS ServerDetail.name, e.g. "io.asana/mcp"); each value carries the public client_id plus an audit trail. The matching client_secret lives in the workspace credential store, not here. See Connectors Catalog → Where the secrets live. |
skillDirs | string[] | No | Directories scanned for skill markdown files, in addition to the built-in skills. |
agents | object | No | Named agent profiles available to nb__delegate. See Agent Profiles. |
models | object | No | Per-workspace model slot overrides. Partial — missing slots inherit from nimblebrain.json. |
identity | string | No | Markdown prompt appended as a context skill for this workspace. |
isPersonal | boolean | No | true for a user’s auto-provisioned personal workspace. Frozen post-create; never parse the id to infer it. |
ownerUserId | string | When isPersonal | Owner of a personal workspace. Required when isPersonal: true, forbidden otherwise. |
createdAt | string (ISO 8601) | Yes | Timestamp, maintained by the runtime. |
updatedAt | string (ISO 8601) | Yes | Timestamp, maintained by the runtime. |
Workspace isolation
Section titled “Workspace isolation”Bundles, tool registries, and conversation data are scoped to a workspace. Every tool handler resolves its workspace via runtime.requireWorkspaceId() before touching data.
Two workspaces that install the same bundle spawn independent subprocesses. Each gets its own data directory at <workDir>/workspaces/<wsId>/data/<bundle>/, so entity data never crosses the workspace boundary. Sidebar placements, briefing facets, and the app list are filtered per workspace.
Model slot overrides
Section titled “Model slot overrides”Any workspace can override individual model slots. Slots you don’t specify fall through to the instance-level models in nimblebrain.json:
{ "models": { "default": "anthropic:claude-opus-4-6" }}Here the workspace uses Opus for default but still uses the instance defaults for fast and reasoning.
Identity override
Section titled “Identity override”identity is a markdown block appended to the agent’s system prompt as a context skill. Use it to give a workspace a distinct persona or domain focus:
{ "identity": "You are the Acme Product Copilot. When asked about metrics, always cite the underlying query." }Related
Section titled “Related”nimblebrain.json— instance-level config- Bundle Configuration — bundle entry fields
- Agent Profiles — the
agentsobject structure - Features — feature flags (set instance-wide, not per-workspace)