feat(export): Add workflow export as standalone Python/FastAPI service
Summary
Adds the ability to export Sim Studio workflows as standalone, self-contained Python services that can be deployed independently via Docker, Railway, or any container platform.
Features
Multi-Provider LLM Support
- Anthropic: Claude 3/4 models (Opus, Sonnet, Haiku)
- OpenAI: GPT-4, GPT-4o, o1, o3 models
- Google: Gemini Pro, Gemini Flash models
- Automatic provider detection from model name
- Provider-specific API key environment variables
Supported Block Types
- Start/Trigger blocks
- Agent blocks (with multi-provider support)
- Function blocks (JavaScript transpiled to Python)
- Condition/Router blocks
- API blocks (HTTP requests)
- Loop blocks (for, forEach, while, doWhile)
- Variables blocks
- Response blocks
File Operations
Agents can perform file operations in two ways:
Option 1: Local File Tools (WORKSPACE_DIR)
Set the WORKSPACE_DIR environment variable to enable local file operations:
# In .env
WORKSPACE_DIR=./workspace
When enabled, agents automatically get access to these tools:
| Tool | Description |
|---|---|
local_write_file |
Write text content to a file |
local_write_bytes |
Write binary data (images, PDFs) as base64 |
local_append_file |
Append text to a file (creates if not exists) |
local_read_file |
Read text content from a file |
local_read_bytes |
Read binary data as base64 |
local_delete_file |
Delete a file |
local_list_directory |
List files with metadata (size, modified time) |
Enable Command Execution (opt-in for security):
# In .env
WORKSPACE_DIR=./workspace
ENABLE_COMMAND_EXECUTION=true
When enabled, agents also get:
| Tool | Description |
|---|---|
local_execute_command |
Run commands like python script.py or node process.js |
Shell operators (|, >, &&, etc.) are blocked for security.
File Size Limits:
# Default: 100MB. Set custom limit in bytes:
MAX_FILE_SIZE=52428800 # 50MB
All paths are sandboxed to WORKSPACE_DIR - agents cannot access files outside this directory. Path traversal attacks (../) and symlink escapes are blocked.
With Docker: The docker-compose.yml mounts ./output to the container workspace:
docker compose up -d
# Files written by agents appear in ./output/
Option 2: MCP Filesystem Tools
If your workflow uses MCP filesystem servers, those tools work as configured. MCP servers handle file operations on their own systems - paths and permissions are determined by the MCP server's configuration.
Using Both
You can use both options together. If WORKSPACE_DIR is set, agents will have access to both local file tools AND any MCP tools configured in the workflow. Tool descriptions help the LLM choose the appropriate tool for each operation.
Health Check with Workspace Status
The /health endpoint returns workspace configuration status:
{
"status": "healthy",
"workspace": {
"enabled": true,
"workspace_dir": "/app/workspace",
"command_execution_enabled": false,
"max_file_size": 104857600
}
}
Export Validation
- Pre-export validation for unsupported block types
- Pre-export validation for unsupported providers
- Clear error messages shown to users via notification system
- Prevents silent failures with actionable feedback
Security
- No eval(): All condition evaluation uses safe AST-based parsing
- No shell=True: Commands executed without shell to prevent injection
- File operations sandboxed to WORKSPACE_DIR
- Shell operators rejected with clear error messages
- Path traversal attacks blocked (no
..or symlink escapes) - File size limits (configurable, default 100MB)
- Command execution is opt-in (disabled by default)
Production Features
- FastAPI server with /execute, /health, /ready endpoints
- Rate limiting (configurable, default 60 req/min)
- Request size limits (configurable, default 10MB)
- Automatic retry with exponential backoff
- MCP tool support via official Python SDK
- Docker and docker-compose configuration
- Environment variable management (.env, .env.example)
Production Configuration
| Environment Variable | Default | Description |
|---|---|---|
HOST |
0.0.0.0 |
Server bind address |
PORT |
8080 |
Server port |
WORKSPACE_DIR |
(disabled) | Enable local file tools with sandbox path |
ENABLE_COMMAND_EXECUTION |
false |
Allow agents to execute commands |
MAX_FILE_SIZE |
104857600 (100MB) |
Maximum file size in bytes |
WORKFLOW_PATH |
workflow.json |
Path to workflow definition |
RATE_LIMIT_REQUESTS |
60 |
Max requests per rate limit window |
RATE_LIMIT_WINDOW |
60 |
Rate limit window in seconds |
MAX_REQUEST_SIZE |
10485760 (10MB) |
Maximum HTTP request body size |
LOG_LEVEL |
INFO |
Logging level |
UI Integration
- "Export as Service" context menu option
- Single workflow export only (no bulk)
- Error notifications via existing notification system
- Uses ref pattern to avoid stale closure issues
Architecture
┌────────────────────────────────────────────────────────────────┐
│ File Operations │
├────────────────────────────────────────────────────────────────┤
│ │
│ WORKSPACE_DIR set in .env? │
│ │ │
│ ├─ YES → Local tools auto-registered (7-8 tools): │
│ │ • local_write_file (sandboxed) │
│ │ • local_write_bytes (binary/base64) │
│ │ • local_append_file (sandboxed) │
│ │ • local_read_file (sandboxed) │
│ │ • local_read_bytes (binary/base64) │
│ │ • local_delete_file (sandboxed) │
│ │ • local_list_directory (with metadata) │
│ │ • local_execute_command (if ENABLE_COMMAND_ │
│ │ EXECUTION=true) │
│ │ │
│ └─ NO → Local tools disabled, returns helpful error: │
│ "Set WORKSPACE_DIR or use MCP filesystem tools" │
│ │
│ MCP tools in workflow? → Always available, hit external server │
│ │
│ Both enabled? → LLM picks based on tool descriptions │
└────────────────────────────────────────────────────────────────┘
Files Changed
-
apps/sim/app/api/workflows/[id]/export-service/route.ts- API endpoint (refactored to 161 lines) -
apps/sim/app/api/workflows/[id]/export-service/validate.ts- Workflow validation -
apps/sim/app/api/workflows/[id]/export-service/transpile.ts- JS to Python transpilation -
apps/sim/app/api/workflows/[id]/export-service/generate-zip.ts- ZIP generation -
apps/sim/app/api/workflows/[id]/export-service/templates/- 16 Python template files -
apps/sim/app/api/workflows/[id]/export-service/route.test.ts- 13 unit tests -
apps/sim/app/workspace/.../hooks/use-export-service.ts- React hook -
apps/sim/app/workspace/.../context-menu/context-menu.tsx- UI menu -
apps/sim/app/workspace/.../workflow-item/workflow-item.tsx- UI wiring -
README.md- Updated with comprehensive export documentation
Testing
cd apps/sim && bun run vitest run "export-service"
# 13 tests passing
Usage
- Right-click workflow in sidebar
- Select "Export as Service"
- Extract ZIP and configure .env with API keys
- Optionally set
WORKSPACE_DIRfor local file operations - Optionally set
ENABLE_COMMAND_EXECUTION=truefor command execution - Run:
docker compose uporuvicorn main:app - Call:
POST /executewith workflow inputs
@aadamsx is attempting to deploy a commit to the Sim Team on Vercel.
A member of the Team first needs to authorize it.
Greptile Summary
This PR adds workflow export as standalone Python/FastAPI services. The implementation includes pre-export validation for unsupported block types and providers, JavaScript-to-Python transpilation, and comprehensive ZIP generation with all necessary runtime files.
Key Changes:
- API endpoint (
route.ts) validates workflows, transpiles JS function blocks to Python, and generates deployable service ZIP with FastAPI server, executor, Docker config, and environment files - React hook (
use-export-service.ts) properly uses refs to avoid stale closures and integrates with notification system - UI integration adds "Export as Service" to context menu for single workflow selection
- 13 comprehensive tests cover authentication, validation, provider detection, and error handling
Architecture:
- Follows established patterns: proper import aliases, hook structure with refs for stable dependencies, TSDoc documentation
- Security-conscious: no
eval(), AST-based condition parsing, sandboxed file operations in exported Python code - Good error handling with user-facing notifications for validation failures
Minor Observations:
- The 2799-line route file is very large and contains embedded Python code as template strings, which is appropriate for this use case but makes the file substantial
Confidence Score: 4/5
- This PR is safe to merge with minimal risk
- Well-tested feature with comprehensive validation, proper error handling, and security measures. The code follows project patterns and includes 13 passing tests. The large route file is justified by embedded Python templates. Minor score reduction only due to the complexity and size of the implementation.
- No files require special attention
Important Files Changed
| Filename | Overview |
|---|---|
| apps/sim/app/api/workflows/[id]/export-service/route.ts | Adds API endpoint to export workflows as standalone Python/FastAPI services with validation, transpilation, and ZIP generation |
| apps/sim/app/workspace/[workspaceId]/w/hooks/use-export-service.ts | React hook for exporting workflows with proper ref usage to avoid stale closures, error handling, and notification integration |
| apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/workflow-item.tsx | Integrates export service hook with workflow item, wires up context menu handler for single workflow exports |
Sequence Diagram
sequenceDiagram
participant User
participant UI as WorkflowItem
participant Hook as useExportService
participant API as /api/workflows/[id]/export-service
participant DB as Database
participant Validator as Workflow Validator
participant Transpiler as JS→Python Transpiler
participant ZipGen as ZIP Generator
User->>UI: Right-click workflow
UI->>UI: Show context menu
User->>UI: Click "Export as Service"
UI->>Hook: handleExportService()
Hook->>Hook: Check isExportingRef
Hook->>Hook: setIsExporting(true)
Hook->>API: GET /api/workflows/{id}/export-service
API->>API: Authenticate user/API key
API->>DB: Query workflow by ID
DB-->>API: Return workflow data
API->>API: Fetch workflow state & variables
API->>Validator: validateWorkflowForExport(state)
Validator->>Validator: Check block types
Validator->>Validator: Check provider support
alt Has unsupported blocks/providers
Validator-->>API: Return validation errors
API-->>Hook: 400 with error details
Hook->>Hook: addNotification(error)
Hook->>Hook: setIsExporting(false)
Hook-->>User: Show error notification
else Validation passes
Validator-->>API: Valid workflow
API->>Transpiler: preTranspileWorkflow(state)
Transpiler->>Transpiler: Convert JS blocks to Python
Transpiler-->>API: Transpiled workflow
API->>ZipGen: Generate service ZIP
ZipGen->>ZipGen: Create workflow.json
ZipGen->>ZipGen: Create .env with API keys
ZipGen->>ZipGen: Add Python executor files
ZipGen->>ZipGen: Add Dockerfile & docker-compose
ZipGen->>ZipGen: Add README.md
ZipGen-->>API: ZIP buffer
API-->>Hook: 200 with ZIP file
Hook->>Hook: Create blob & download link
Hook->>Hook: Trigger browser download
Hook->>Hook: setIsExporting(false)
Hook->>Hook: onSuccess?.()
Hook-->>User: Download workflow-service.zip
end