Workspace Management
Purpose and Scope
This document describes how workspaces are resolved, provisioned, and accessed in Automatos AI. A workspace is the primary multi-tenancy boundary that isolates users' agents, workflows, recipes, and data. Every authenticated request must be scoped to a workspace.
For information about authentication mechanisms (Clerk JWT, API keys, anonymous fallback), see Authentication Flow. For details on how workspace-scoped queries enforce data isolation, see Data Isolation.
Sources: orchestrator/core/auth/hybrid.py
Workspace Resolution
The backend resolves the workspace for each request using a priority waterfall. The _get_workspace_id_from_request function checks multiple sources in order, returning the first valid UUID found.
Resolution Priority
Sources: orchestrator/core/auth/hybrid.py:29-68
Resolution Functions
_get_workspace_id_from_request()
Extracts workspace_id from request using priority waterfall
Optional[UUID]
_parse_uuid()
Safely parses string to UUID, returns None on failure
Optional[UUID]
_workspace_exists()
Validates workspace exists and is active in database
bool
The _parse_uuid function handles malformed UUIDs gracefully, stripping whitespace and catching exceptions:
Sources: orchestrator/core/auth/hybrid.py:20-27, orchestrator/core/auth/hybrid.py:71-81
Access Verification
When a client explicitly provides a workspace ID via header or query parameter, the backend verifies the user has access to that workspace. This prevents workspace spoofing attacks where a user attempts to access another workspace's data by manipulating request headers.
The SQL query joins three tables to verify access:
Access is granted if the user either owns the workspace OR is an active member.
Sources: orchestrator/core/auth/hybrid.py:84-107
Auto-Provisioning for New Users
When a user authenticates via Clerk for the first time, the system automatically provisions a complete workspace structure. This happens atomically in _provision_new_user_workspace.
Provisioning Flow
Database Records Created
users
clerk_user_id, email, username, name, is_active
From Clerk claims, is_active=true
workspaces
id, name, slug, owner_id, is_personal, plan, plan_limits
UUID, "User's Workspace", unique slug, user.id, true, "starter", default limits JSON
workspace_members
workspace_id, user_id, role, is_active
workspace.id, user.id, "owner", true
Slug Collision Handling
The provisioning function generates a workspace slug from the user's email. If a slug collision occurs (rare but possible), it retries up to 5 times with a random suffix:
Sources: orchestrator/core/auth/hybrid.py:110-187
Personal vs Organization Workspaces
The system supports two types of workspaces:
Personal Workspaces
Created automatically for each new user
is_personal=trueowner_idpoints to the userUser has full control
Organization Workspaces
Created when users belong to Clerk organizations
clerk_org_idlinks to Clerk organizationis_personal=falseMultiple members via
workspace_memberstableResolved via
_resolve_workspace_for_clerk_user
Resolution Logic
The resolution prioritizes organization workspaces over personal workspaces. If a user belongs to multiple workspaces, the frontend sends x-workspace-id to specify which one.
Sources: orchestrator/core/auth/hybrid.py:190-254
Request Context
The get_request_context_hybrid dependency constructs a RequestContext object for every API request. This context contains the resolved workspace ID and user information.
Context Construction
RequestContext Structure
All API routers inject this context via Depends(get_request_context_hybrid), ensuring every request has a valid workspace scope.
Sources: orchestrator/core/auth/hybrid.py:283-399, orchestrator/core/auth/dependencies.py
Frontend Integration
The frontend maintains workspace context through the WorkspaceProvider component and consumes the /api/workspaces/current endpoint.
Current Workspace Endpoint
The GET /api/workspaces/current endpoint returns workspace metadata and detects new workspaces for onboarding:
Sources: orchestrator/api/workspaces.py:24-54
Response Schema
New Workspace Detection
The system detects new workspaces by checking if the workspace has any agents. This triggers the onboarding flow in the frontend.
Onboarding Flow
The FirstLoginGuard component coordinates this detection:
Sources: frontend/components/onboarding/first-login-guard.tsx:1-35, frontend/lib/shepherd/tour-storage.ts:10-16
Summary Tables
Key Functions Reference
Workspace Resolution Sources
1
request.state.workspace_id
Set by middleware
2
x-workspace-id header
Frontend sets this explicitly
3
x-workspace header
Alternative header name
4
workspace_id query param
?workspace_id=uuid
5
WORKSPACE_ID env var
Docker/Railway config
6
DEFAULT_WORKSPACE_ID env var
System default fallback
Workspace Types
Type
is_personal
clerk_org_id
Owner
Members
Personal
true
null
User who created account
Only owner initially
Organization
false
Set
Org owner
Multiple via workspace_members
Sources: orchestrator/core/auth/hybrid.py, orchestrator/api/workspaces.py, frontend/components/onboarding/first-login-guard.tsx
Last updated

