Workspace API Reference

chevron-rightRelevant source fileshashtag

This page provides a complete REST API reference for workspace operations, including file management, command execution, GitHub integration, and task orchestration. For conceptual overviews of these features, see Workspace Worker Architecture, GitHub Integration, File Operations, Command Execution, and Task Management.


API Architecture

The workspace API is organized into two tiers: a public orchestrator API that handles authentication and request routing, and an internal worker API that executes operations on the persistent volume. Most operations are synchronous proxies (file I/O, command exec), while long-running tasks (git clone, multi-step workflows) use an async queue-based system.

Two-Tier API Design

spinner

Sources: orchestrator/api/workspace_files.py:1-108, orchestrator/api/workspace_github.py:1-294, orchestrator/api/tasks.py:1-396, orchestrator/core/workspace_client.py:1-191, services/workspace-worker/main.py:461-700


File Operations API

Endpoints for browsing workspace files, reading content, and executing commands. All operations are scoped to a single workspace identified by {workspace_id} in the URL path.

GET /api/workspaces/{workspace_id}/files

List directory contents at a given path within the workspace.

Request:

Query Parameters:

Parameter
Type
Required
Default
Description

path

string

No

"."

Relative path inside workspace (workspace-root-relative)

Response (200 OK):

Error Responses:

  • 403 Forbidden - Workspace access denied (mismatched workspace_id)

  • 404 Not Found - Directory does not exist

  • 503 Service Unavailable - Worker unreachable

Sources: orchestrator/api/workspace_files.py:30-51, services/workspace-worker/executor.py:272-300


GET /api/workspaces/{workspace_id}/files/content

Read the text content of a file for code viewing or processing.

Request:

Query Parameters:

Parameter
Type
Required
Description

path

string

Yes

Relative file path inside workspace

Response (200 OK):

Truncation: Content is capped at 500KB by default. If truncated: true, only the first 500KB is returned.

Error Responses:

  • 400 Bad Request - Path traversal detected (e.g. ../../../etc/passwd)

  • 403 Forbidden - Workspace access denied

  • 404 Not Found - File does not exist

  • 503 Service Unavailable - Worker unreachable

Sources: orchestrator/api/workspace_files.py:54-74, services/workspace-worker/executor.py:230-252


POST /api/workspaces/{workspace_id}/exec

Execute a sandboxed shell command in the workspace. Only whitelisted commands are allowed (see Security & Sandboxing).

Request:

Request Body (ExecRequest):

Field
Type
Required
Default
Constraints
Description

command

string

Yes

-

1-4096 chars

Shell command to execute

cwd

string

No

workspace root

-

Working directory (relative to workspace)

timeout

integer

No

120

1-300

Max execution time in seconds

Response (200 OK):

Output Limits:

  • stdout: Max 100KB

  • stderr: Max 50KB

  • If output exceeds limits, truncated: true and content is trimmed

Command Whitelist: Only approved binaries can execute: git, python, node, npm, pytest, ls, cat, grep, etc. See ALLOWED_COMMANDS in executor.py:35-73 for the full list.

Blocked Patterns: Certain dangerous patterns are blocked even if the binary is whitelisted: sudo, rm -rf /, chmod 777, etc. See BLOCKED_PATTERNS in executor.py:76-95.

Error Responses:

  • 400 Bad Request - Command not whitelisted or blocked pattern detected

  • 403 Forbidden - Workspace access denied

  • 503 Service Unavailable - Worker unreachable

Sources: orchestrator/api/workspace_files.py:77-107, services/workspace-worker/executor.py:122-224


GitHub Integration API

Endpoints for browsing GitHub repositories via Composio OAuth and cloning them into the workspace.

GitHub Repository Object

All GitHub endpoints return repositories in this format:


GET /api/workspaces/{workspace_id}/github/repos

List GitHub repositories accessible to the authenticated user via Composio.

Request:

Query Parameters:

Parameter
Type
Required
Default
Constraints
Description

page

integer

No

1

≥1

Page number for pagination

per_page

integer

No

30

1-100

Repositories per page

Response (200 OK):

Prerequisites:

  • Workspace must have GitHub connected via Composio (EntityConnection with composio_entity_id)

  • User must have authorized GitHub OAuth via Composio app assignment

Error Responses:

  • 403 Forbidden - Workspace access denied

  • 404 Not Found - No Composio entity found for workspace (GitHub not connected)

  • 501 Not Implemented - Composio SDK not installed

  • 502 Bad Gateway - GitHub API error

Sources: orchestrator/api/workspace_github.py:97-161, orchestrator/core/composio/entity_manager.py


POST /api/workspaces/{workspace_id}/github/clone

Clone a GitHub repository into the workspace via task submission. Supports both public and private repos (private requires GitHub OAuth token from Composio).

Request:

Request Body (CloneRequest):

Field
Type
Required
Validation
Description

repo_url

string

Yes

HTTPS only, allowed hosts

Git clone URL (HTTPS)

branch

string

No

Safe branch pattern

Branch to clone (default: repo default)

URL Validation:

  • Scheme must be https://

  • Host must be in allowlist: github.com, gitlab.com, bitbucket.org

  • No embedded credentials (username:password in URL)

Branch Validation:

  • Must match pattern: ^[A-Za-z0-9._/\-]+$

  • Cannot contain .., @{, or leading -

Response (200 OK):

Execution Flow:

  1. Orchestrator attempts to retrieve GitHub OAuth token from Composio

  2. If token found, injects into HTTPS URL: https://x-access-token:{token}@github.com/...

  3. Submits git_clone task to Redis queue with injected URL

  4. Worker executes: git clone --depth 1 --branch {branch} -- {url} /workspaces/{id}/repos/{name}

  5. Task transitions: queuedrunningcompleted

Token Injection Security (PRD-70):

  • OAuth token is injected server-side (never exposed to client)

  • URL uses x-access-token authentication format

  • Worker executes with -- separator to prevent argument injection

  • Branch name validated to prevent --upload-pack injection attacks

Error Responses:

  • 400 Bad Request - Invalid URL, branch, or worker backend not queued

  • 403 Forbidden - Workspace access denied

  • 404 Not Found - No Composio entity for workspace

  • 503 Service Unavailable - Redis enqueue failed

Sources: orchestrator/api/workspace_github.py:167-293, services/workspace-worker/executor.py:368-419


Task Management API

Endpoints for submitting workspace tasks, monitoring execution, and streaming real-time events.

Task Lifecycle State Machine

spinner

POST /api/tasks/submit

Submit a workspace task with explicit steps for immediate execution. Bypasses LLM agent — runs steps directly on the worker.

Request:

Request Body (SubmitTaskRequest):

Field
Type
Required
Default
Constraints
Description

steps

array

Yes

-

≥1 step

Steps to execute in order

priority

string

No

"normal"

low, normal, high, critical

Queue priority

timeout_seconds

integer

No

300

10-3600

Max execution time

Step Actions:

Action
Required Fields
Optional Fields
Description

execute_command

command

cwd, timeout

Run shell command

git_clone

repo

branch, shallow

Clone git repository

git_pull

repo_name

branch

Pull latest changes

read_file

path

-

Read file content

write_file

path, content

-

Write or create file

list_directory

-

path

List directory entries

create_directory

path

-

Create directory

Response (200 OK):

Queue Priority: Tasks are enqueued to priority-specific Redis lists:

  • workspace:tasks:critical — dequeued first

  • workspace:tasks:high

  • workspace:tasks:normal (default)

  • workspace:tasks:low

Atomic Submission: Task row is inserted into task_executions table before Redis enqueue. If Redis enqueue fails, the DB row is marked failed with error message.

Prerequisites:

  • TASK_RUNNER_BACKEND=queued (returns 400 if local/kubernetes backend)

Error Responses:

  • 400 Bad Request - Invalid steps, wrong backend, or validation failure

  • 503 Service Unavailable - Redis queue unavailable

Sources: orchestrator/api/tasks.py:62-173, services/workspace-worker/main.py:227-357


GET /api/tasks

List recent tasks for the current workspace with optional filtering.

Request:

Query Parameters:

Parameter
Type
Required
Default
Constraints
Description

status

string

No

-

queued, running, completed, failed, timed_out, cancelled

Filter by status

task_type

string

No

-

-

Filter by task type

limit

integer

No

20

1-100

Results per page

offset

integer

No

0

≥0

Pagination offset

Response (200 OK):

Ordering: Tasks are returned in reverse chronological order (newest first) by submitted_at.

Sources: orchestrator/api/tasks.py:176-247


GET /api/tasks/{task_id}

Get full task detail including result payload and execution metadata.

Request:

Response (200 OK):

Result Structure: The result field contains:

  • status: Final status (completed, failed, timed_out)

  • result.steps: Array of step results with stdout/stderr/exit codes

  • result.repos_cached: List of repositories cached in workspace

  • execution_time_ms: Total execution time in milliseconds

  • error: Error message if any step failed

Error Responses:

  • 404 Not Found - Task not found or workspace mismatch

Sources: orchestrator/api/tasks.py:250-298


POST /api/tasks/{task_id}/cancel

Cancel a queued or running task. Cancellation is best-effort: queued tasks are guaranteed to cancel, running tasks check between steps.

Request:

Response (200 OK):

Cancellation Behavior:

State
Behavior

queued

Status updated to cancelled in Redis. Worker skips on dequeue.

running

Status updated to cancelled in Redis. Worker checks between steps and aborts.

completed, failed, timed_out

Returns 400 (already terminal state)

Inter-Step Cancellation: Workers check Redis status between each step execution. If status is cancelled, the worker publishes a status_changed event and stops execution.

Error Responses:

  • 400 Bad Request - Task already in terminal state

  • 404 Not Found - Task not found or workspace mismatch

Sources: orchestrator/api/tasks.py:304-355, services/workspace-worker/main.py:282-285


GET /api/tasks/{task_id}/events

Server-Sent Events (SSE) stream of real-time task execution events. Subscribe to this endpoint to receive progress updates, status changes, and error notifications.

Request:

Response (200 OK - SSE Stream):

Event Types:

Event Type
Data Fields
Description

status_changed

status

Task transitioned to new status

progress_update

step, total_steps, description

Step execution started

error

error, step (optional)

Error occurred during step

Event Schema:

Stream Lifecycle:

  1. Client connects, receives connected SSE comment

  2. Worker publishes events to Redis channel workspace:task:{task_id}:events

  3. Orchestrator subscribes to channel and forwards as SSE

  4. On task completion/failure, stream sends final event and closes

  5. If task already complete when client connects, sends final state immediately

Timeout: Stream auto-closes after 10 minutes of inactivity or when task reaches terminal state.

Error Responses:

  • 404 Not Found - Task not found or workspace mismatch

Sources: orchestrator/api/tasks.py:358-396, services/workspace-worker/main.py:422-434


Request/Response Models

Pydantic Schemas

All request bodies are validated using Pydantic models defined in the endpoint files.

ExecRequest (workspace_files.py:80-83):

CloneRequest (workspace_github.py:65-91):

TaskStep (tasks.py:39-49):

SubmitTaskRequest (tasks.py:52-56):

Sources: orchestrator/api/workspace_files.py:80-83, orchestrator/api/workspace_github.py:65-91, orchestrator/api/tasks.py:39-56


Error Handling

All endpoints follow a consistent error response format.

HTTP Status Codes

Code
Meaning
Common Causes

200

OK

Successful operation

400

Bad Request

Invalid parameters, validation failure, wrong backend

403

Forbidden

Workspace access denied (X-Workspace-ID mismatch)

404

Not Found

Resource not found (task, file, directory, Composio entity)

501

Not Implemented

Composio SDK not installed

502

Bad Gateway

External API error (GitHub, Composio)

503

Service Unavailable

Worker unreachable, Redis queue unavailable

Error Response Format

FastAPI HTTPException: All errors are raised as HTTPException with appropriate status code and detail message.

Worker Connection Errors: When the workspace worker is unreachable, the WorkspaceClient returns:

Sources: orchestrator/core/workspace_client.py:47-53, orchestrator/api/workspace_files.py:42-49


Authentication & Authorization

Clerk JWT Authentication

All workspace endpoints require Clerk JWT authentication via the Authorization: Bearer {token} header.

Request Context Extraction:

Workspace Isolation: Every endpoint validates that ctx.workspace_id matches the {workspace_id} path parameter before executing operations. This ensures users can only access their own workspaces.

Internal Worker Authentication: Requests from orchestrator to worker use X-Internal-Token header (not Clerk JWT). This token is configured via WORKER_INTERNAL_TOKEN environment variable.

Sources: orchestrator/api/workspace_files.py:19-42, orchestrator/core/workspace_client.py:33-38


Internal Worker HTTP API

While most operations proxy through the orchestrator API, the workspace worker also exposes a direct HTTP API on port 8081. This is internal-only and should not be exposed to public internet.

Worker Endpoints

Method
Path
Description

GET

/health

Health check with worker stats

GET

/workspaces/{id}/files

List directory (direct, no auth check)

GET

/workspaces/{id}/files/content

Read file content (direct)

POST

/workspaces/{id}/exec

Execute command (direct)

GET

/workspaces/{id}/grep

Search files with regex pattern

Authentication: All worker endpoints check for X-Internal-Token header. If configured, unauthorized requests return 403.

Health Endpoint Response:

Grep Endpoint: Provides regex search across workspace files:

Response:

Sources: services/workspace-worker/main.py:461-700


WorkspaceClient Proxy

The orchestrator uses WorkspaceClient to proxy requests to the worker HTTP API. This provides a typed, async interface for backend code.

Usage Example

Available Methods

Method
Parameters
Returns

read_file(path)

path: str

Dict[str, Any]

write_file(path, content)

path: str, content: str

Dict[str, Any]

list_dir(path)

path: str

Dict[str, Any]

exec_command(command, cwd, timeout)

command: str, cwd: Optional[str], timeout: int

Dict[str, Any]

grep(pattern, path, include, max_results)

pattern: str, ...

Dict[str, Any]

Connection Pooling: WorkspaceClient uses a singleton httpx.AsyncClient shared across all instances. Connection is reused for performance.

Timeout Configuration:

  • Connect: 10 seconds

  • Read: 130 seconds (allows for long command execution)

  • Write: 30 seconds

  • Pool: 10 seconds

Error Handling: All methods return {"success": False, "error": "..."} on connection/timeout errors. Callers should check for this pattern.

Sources: orchestrator/core/workspace_client.py:1-191


Rate Limiting (Widget API)

Widget SDK endpoints (/api/widgets/*) have per-API-key rate limiting enforced by WidgetRateLimitMiddleware.

Limits:

  • Public keys (ak_pub_*): 30 requests/minute

  • Server keys (ak_srv_*): 1000 requests/minute

  • Unauthenticated (IP-based): 30 requests/minute

Rate Limit Headers:

429 Response:

Sliding Window: Uses in-memory sliding window counter with 60-second window size. Requests older than 60 seconds are dropped from the window.

Sources: orchestrator/api/widgets/rate_limit.py:1-166


Request Flow Examples

File Read Flow

spinner

Sources: orchestrator/api/workspace_files.py:54-74, orchestrator/core/workspace_client.py:68-78, services/workspace-worker/executor.py:230-252


GitHub Clone Flow

spinner

Sources: orchestrator/api/workspace_github.py:167-293, services/workspace-worker/main.py:227-357, services/workspace-worker/executor.py:368-419


See Also


Last updated