# Overview Source: https://docs.blaxel.ai/Agent-drive/Overview Agent Drive is a distributed filesystem mountable to multiple sandboxes or agents simultaneously, with concurrent read-write access and built-in replication. This feature is currently in private preview. During the preview, the Agent Drive feature is only available in the `us-was-1` region. Both your drive and your sandbox must be created in this region. Drive size is not configurable at the moment. Similarly, drive access control is currently only possible at workspace level: once a drive is mounted in a sandbox, the sandbox has sufficient credentials to access all other drives in the same workspace. A quotas system for drive storage and more fine-grained access control features are coming soon. [Request access](https://blaxel.fillout.com/t/pbTXmanx3Sus). Agent Drive is a distributed filesystem that can be mounted to multiple sandboxes or agents at any time, including while they are already running. Drives support concurrent read-write access (RWX) from multiple sandboxes simultaneously, with built-in replication for durability. Unlike [volumes](../Volumes/Overview), which are block storage devices attached at sandbox creation to a single sandbox, drives behave like a shared cloud filesystem, but mounted directly into a sandbox's file tree. An optimized FUSE client built specifically for this filesystem is added directly to the sandbox or agent to give a POSIX-compliant interface. * A drive can be attached to an already-running sandbox at any mount path, without needing to recreate the sandbox * Multiple sandboxes can mount the same drive simultaneously with full read-write access. * A specific subdirectory of a drive can be mounted using `drivePath` (instead of mounting the entire drive). * Drives scale automatically with no fixed capacity limits. Pre-provisioning or run-time resizing is not required. ## Use cases Some examples of use cases are: * Passing data or files from one sandbox to another directly, without needing intermediary storage or services * Storing tool call outputs and context histories for use in other agents * Sharing common datasets across agents * Creating a shared filesystem cache of package dependencies to speed up future agent/sandbox deployments ## Create a drive The Blaxel SDK requires two environment variables to authenticate: | Variable | Description | | -------------- | -------------------------- | | `BL_WORKSPACE` | Your Blaxel workspace name | | `BL_API_KEY` | Your Blaxel API key | You can create an API key from the [Blaxel console](https://app.blaxel.ai/profile/security). Your workspace name is visible in the URL when you log in to the console (e.g. `app.blaxel.ai/{workspace}`). Set them as environment variables or add them to a `.env` file at the root of your project: ```bash theme={null} export BL_WORKSPACE=my-workspace export BL_API_KEY=my-api-key ``` When developing locally, you can also **log in to your workspace with Blaxel CLI** (as shown above). This allows you to run Blaxel SDK functions that will automatically connect to your workspace without additional setup. When you deploy on Blaxel, authentication is handled automatically — no environment variables needed. Create a standalone drive by specifying a unique `name` and `region`. You can also optionally specify the display name and labels for the drive. ```tsx TypeScript theme={null} import { DriveInstance } from "@blaxel/core"; const drive = await DriveInstance.create({ name: "my-drive", region: "us-was-1", displayName: "My Project Drive", // optional; defaults to `name` labels: { env: "dev", project: "my-project" }, // optional; labels }); ``` ```python Python theme={null} from blaxel.core.drive import DriveInstance drive = await DriveInstance.create( { "name": "my-drive", "region": "us-was-1", "display_name": "My Project Drive", # optional; defaults to `name` "labels": {"env": "dev", "project": "my-project"}, # optional; labels } ) ``` You can also use `createIfNotExists()` to retrieve an existing drive or create a new one if it doesn't exist: ```tsx TypeScript theme={null} const drive = await DriveInstance.createIfNotExists({ name: "my-drive", region: "us-was-1", displayName: "My Project Drive", // optional; defaults to `name` labels: { env: "dev", project: "my-project" }, // optional; labels }); ``` ```python Python theme={null} from blaxel.core.drive import DriveInstance drive = await DriveInstance.create_if_not_exists( { "name": "my-drive", "region": "us-was-1", "display_name": "My Project Drive", # optional; defaults to `name` "labels": {"env": "dev", "project": "my-project"}, # optional; labels } ) ``` ## Mount a drive to a sandbox Mount a drive to a running sandbox by specifying the `driveName`, the `mountPath` (where the drive will appear in the sandbox's filesystem), and optionally the `drivePath` (a subdirectory within the drive to mount). ```tsx TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.get("my-sandbox"); await sandbox.drives.mount({ driveName: "my-drive", mountPath: "/mnt/data", drivePath: "/", // optional; defaults to root of the drive }); ``` ```python Python theme={null} from blaxel.core import SandboxInstance sandbox = await SandboxInstance.get("my-sandbox") await sandbox.drives.mount( drive_name="my-drive", mount_path="/mnt/data", drive_path="/", # optional; defaults to root of the drive ) ``` Once mounted, any file written to `/mnt/data` inside the sandbox will be stored on the drive and persist even after the sandbox is deleted. ### Mount a subdirectory You can mount a specific subdirectory of a drive rather than its root. This is useful when a single drive contains multiple project directories: ```tsx TypeScript theme={null} await sandbox.drives.mount({ driveName: "my-drive", mountPath: "/app/project", drivePath: "/projects/alpha", }); ``` ```python Python theme={null} await sandbox.drives.mount( drive_name="my-drive", mount_path="/app/project", drive_path="/projects/alpha", ) ``` `drivePath` / `drive_path` is a mount point convenience, not a security boundary. Once a drive is mounted at any location in a sandbox, the sandbox has sufficient credentials to access all other drives in the same workspace. This is a temporary constraint during the preview phase; the final release will include fine-grained access control. ## List mounted drives List all drives currently mounted to a sandbox: ```tsx TypeScript theme={null} const mounts = await sandbox.drives.list(); console.log(mounts); ``` ```python Python theme={null} mounts = await sandbox.drives.list() print(mounts) ``` ## List all drives ```tsx TypeScript theme={null} import { DriveInstance } from "@blaxel/core"; const drives = await DriveInstance.list(); ``` ```python Python theme={null} from blaxel.core.drive import DriveInstance drives = await DriveInstance.list() ``` Or via CLI: ```bash theme={null} bl get drives ``` ## Unmount a drive Unmount a drive from a running sandbox by specifying the mount path: ```tsx TypeScript theme={null} await sandbox.drives.unmount("/mnt/data"); ``` ```python Python theme={null} await sandbox.drives.unmount("/mnt/data") ``` ## Delete a drive ```tsx TypeScript theme={null} import { DriveInstance } from "@blaxel/core"; // Class-level await DriveInstance.delete("my-drive"); // Or instance-level const drive = await DriveInstance.get("my-drive"); await drive.delete(); ``` ```python Python theme={null} from blaxel.core.drive import DriveInstance # Class-level await DriveInstance.delete("my-drive") # Or instance-level drive = await DriveInstance.get("my-drive") await drive.delete() ``` Complete code examples demonstrating all operations are available in Blaxel's GitHub repositories, [for TypeScript](https://github.com/blaxel-ai/sdk-typescript/tree/main/tests/integration/sandbox), [for Python](https://github.com/blaxel-ai/sdk-python/tree/main/tests/integration/core/sandbox), and [for Go](https://github.com/blaxel-ai/sdk-go/tree/main/integration_tests). ## Full example The following example creates a drive, creates a sandbox from the custom sandbox template using its image ID, mounts the drive, writes a file to the mounted path, and reads it back: ```tsx TypeScript theme={null} import { SandboxInstance, DriveInstance } from "@blaxel/core"; // 1. Create a drive const drive = await DriveInstance.createIfNotExists({ name: "agent-storage", region: "us-was-1", }); // 2. Create a sandbox // Use the image ID of the custom sandbox template const sandbox = await SandboxInstance.createIfNotExists({ name: "my-agent-sandbox", image: "my-sandbox-image-id", memory: 2048, region: "us-was-1", }); // 3. Mount the drive to the sandbox await sandbox.drives.mount({ driveName: "agent-storage", mountPath: "/mnt/storage", drivePath: "/", }); // 4. Write a file to the mounted drive await sandbox.fs.write("/mnt/storage/hello.txt", "Hello from the drive!"); // 5. Read it back const content = await sandbox.fs.read("/mnt/storage/hello.txt"); console.log(content); // "Hello from the drive!" // 6. List mounted drives const mounts = await sandbox.drives.list(); console.log(mounts); ``` ```python Python theme={null} import asyncio from blaxel.core.drive import DriveInstance from blaxel.core import SandboxInstance async def main(): # 1. Create a drive drive = await DriveInstance.create_if_not_exists( { "name": "agent-storage", "region": "us-was-1", } ) # 2. Create a sandbox sandbox = await SandboxInstance.create_if_not_exists( { "name": "my-agent-sandbox", "image": "my-sandbox-image-id", "memory": 2048, "region": "us-was-1", } ) # 3. Mount the drive to the sandbox await sandbox.drives.mount( drive_name="agent-storage", mount_path="/mnt/storage", drive_path="/", ) # 4. Write a file to the mounted drive await sandbox.fs.write("/mnt/storage/hello.txt", "Hello from the drive!") # 5. Read it back content = await sandbox.fs.read("/mnt/storage/hello.txt") print(content) # "Hello from the drive!" # 6. List mounted drives mounts = await sandbox.drives.list() print(mounts) asyncio.run(main()) ``` # Asynchronous triggers Source: https://docs.blaxel.ai/Agents/Asynchronous-triggers Run agent requests asynchronously with optional callbacks for tasks up to 15 minutes, without keeping HTTP connections open. Asynchronous triggers allow you to run an agent request asynchronously. The agent responds immediately while it continues processing the task in the background. You can optionally receive the result through a callback. This lets tasks run for up to 15 minutes without keeping an HTTP connection open. ## Create an asynchronous request To create an asynchronous request, call your agent URL as shown below: ```http theme={null} POST https://run.blaxel.ai/{your-workspace}/agents/{your-agent}?async=true ``` Your agent should immediately return: ```json theme={null} { "success": true } ``` Meanwhile, the full request is processed asynchronously in the background. ## Set a callback URL Callback URLs are only supported on Mark 3 infrastructure. You can provide an optional callback URL to receive the result when the background job completes. The callback URL must be specified when the agent is deployed, either via the [Blaxel Console](#blaxel-console) or the [`blaxel.toml` configuration file](#blaxel-configuration-file). When a callback URL is set, a POST request is automatically sent to that URL when the background job completes. The POST request contains a JSON payload with the agent response. Here is an example: ```json theme={null} { "status_code": 200, "response_body": "{\"result\":\"ok\"}", "response_length": 123, "timestamp": 1735891200 } ``` You can inspect and verify callbacks by using [https://webhook.site](https://webhook.site). ## Verify a callback using its signature If you set a callback URL, Blaxel automatically generates a callback secret and uses it to sign the request. This is included in the response payload headers: ```http theme={null} X-Blaxel-Signature: sha256= X-Blaxel-Timestamp: ``` The signature can be verified using the Blaxel SDK. If no callback URL is set, no secret is generated. Here is an example of a webhook running at the `/callback` URL endpoint to validate and process signed responses from an agent running an asynchronous request: ```ts TypeScript theme={null} import express from "express"; import { verifyWebhookFromRequest } from "@blaxel/core"; const app = express(); const CALLBACK_SECRET = process.env.CALLBACK_SECRET!; app.use(express.text({ type: "application/json" })); app.post("/callback", (req, res) => { if (!verifyWebhookFromRequest(req, CALLBACK_SECRET)) { return res.status(401).json({ error: "Invalid signature" }); } const data = JSON.parse(req.body); console.log("Job completed:", data); res.json({ received: true }); }); ``` ```python Python theme={null} from flask import Flask, request, jsonify from blaxel.core import verify_webhook_from_request import os, json app = Flask(__name__) CALLBACK_SECRET = os.environ["CALLBACK_SECRET"] class ReqWrapper: def __init__(self, req): self.body = req.get_data() self.headers = {k.lower(): v for k, v in req.headers.items()} @app.post("/callback") def callback(): if not verify_webhook_from_request(ReqWrapper(request), CALLBACK_SECRET): return jsonify({"error": "Invalid signature"}), 401 data = request.json print("Job completed:", data) return jsonify({"received": True}) ``` To create the asynchronous request, use the following example command: ```shell theme={null} curl -X POST "https://run.blaxel.ai/$(bl workspace --current)/agents/{your-agent}?async=true" \ -H "Content-Type: application/json" \ -d '{"input": "Hello"}' ``` ## Configure asynchronous triggers Asynchronous triggers are configured in two ways: via the Blaxel Console or in the `blaxel.toml` configuration file. ### Blaxel Console In the Blaxel Console, you can configure asynchronous triggers by clicking the **Triggers** tab on the agent detail page. This page lets you list, add, edit, or delete triggers for your agent. Triggers List To add a new asynchronous trigger, click **Add Trigger**. You can also optionally configure a callback URL for the trigger. Trigger Configuration If no callback URL is set, the request will still be processed asynchronously but the callback URL will not be triggered. When you create a trigger with a callback URL, Blaxel automatically generates a callback secret. You can use this secret to verify incoming requests to the callback URL using the Blaxel SDK. Callback Secret The callback secret is only shown once, so you should save it securely. ### Blaxel configuration file You can configure asynchronous triggers directly in your `blaxel.toml` file, as in the example below: ```toml theme={null} type = "agent" name = "async-agent" [[triggers]] # unique trigger ID id = "async" # marks trigger as asynchronous type = "http-async" [triggers.configuration] # callback URL - optional callbackUrl = "https://webhook.site/3955e30a-e4b6-4fa5-8a28-598ce0f53386" ``` This approach allows you to version-control triggers and manage them as part of your agent codebase. # Deploy agents Source: https://docs.blaxel.ai/Agents/Deploy-an-agent Host your custom AI agents on Blaxel as serverless autoscalable endpoints. Blaxel Agents Hosting lets you bring your agent code **and deploys it as a serverless auto-scalable endpoint** — no matter your development framework. The main way to deploy an agent on Blaxel is by **using Blaxel CLI.** This method is detailed down below on the page. Alternatively you can [**connect a GitHub repository**](/Agents/Github-integration): any push to the *main* branch will automatically update the deployment on Blaxel — or deploy from a variety of **pre-built templates** on the Blaxel Console. ## Deploy an agent with Blaxel CLI This section assumes you have developed an agent locally, as presented [in this documentation](/Agents/Develop-an-agent), and are ready to deploy it. [Blaxel SDK](../sdk-reference/introduction) provides methods to programmatically access and integrate various resources hosted on Blaxel into your agent's code, such as: [model APIs](../Models/Overview), [tool servers](../Functions/Overview), [sandboxes](../Sandboxes/Overview), [batch jobs](../Jobs/Overview), or [other agents](Overview). The SDK handles authentication, secure connection management and telemetry automatically. This packaging makes Blaxel **fully agnostic of the framework** used to develop your agent and doesn’t prevent you from deploying your software on another platform. Read [this guide first](/Agents/Develop-an-agent) on how to leverage the Blaxel SDK when developing a custom agent to deploy. ### Serve locally You can serve the agent locally in order to make the entrypoint function (by default: `main.py` / `main.ts`) available on a local endpoint. Run the following command to serve the agent: ```bash theme={null} bl serve ``` Calling the provided endpoint will execute the agent locally while sandboxing the core agent logic, function calls and model API calls exactly as it would be when deployed on Blaxel. Add the flag `--hotreload` to get live changes. ```bash theme={null} bl serve --hotreload ``` ### Deploy on production You can deploy the agent in order to make the entrypoint function (by default: `main.py` / `main.ts`) **callable on a global endpoint**. When deploying to Blaxel, your workloads are served optimally to dramatically accelerate cold-start and latency while enforcing your [deployment policies](../Model-Governance/Policies). Run the following command to build and deploy a local agent on Blaxel: ```bash theme={null} bl deploy ``` You can alternatively use `bl push` to build and push the agent container image to the Blaxel registry without creating or updating the agent deployment. This is useful for preparing images in advance. When making a deployment using Blaxel CLI (`bl deploy`), the new traffic routing depends on the `--traffic` option. Without this option specified, Blaxel will automatically deploy the new revision with full traffic (100%) if the previous deployment was the latest revision. Otherwise, it will create the revision without deploying it (0% traffic). Specify which sub-directory to deploy with the `--directory` (`-d`) option: ```bash theme={null} bl deploy -d myfolder/mysubfolder ``` This allows for [deploying multiple agents/servers/jobs from the same repository](/Agents/Deploy-multiple) with shared dependencies. ### Customize an agent deployment You can set custom parameters for an agent deployment (e.g. specify the agent name, etc.) in the [`blaxel.toml` file](/deployment-reference) at the root of your directory. For more information on agent deployment settings, refer to the reference section down at the bottom of this guide. ### Deploy with a Dockerfile While Blaxel uses predefined, optimized container images to build and deploy your code, you can also deploy your workload using your own [Dockerfile](https://docs.docker.com/reference/dockerfile/). Deploy resources using a custom Dockerfile. ### Deploy from GitHub You can connect a GitHub repository to Blaxel to automatically deploy updates whenever changes are pushed to the *main* branch. Learn how to synchronize your GitHub repository to automatically deploy updates. ### Deploy multiple resources at once Using a custom Dockerfile allows for [deploying multiple agents & MCPs from the same repository](/Agents/Deploy-multiple) with shared dependencies. Deploy multiple agents & MCP servers with shared context from a single repository. ## Reference for deployment life-cycle ### Deploying an agent Deploying an agent will create the associated agent deployment. At this time: * it is [reachable](/Agents/Query-agents) through a specific endpoint * it does not consume resources [until it is actively being invoked and processing inferences](/Agents/Query-agents) * its status can be monitored either on the console or using the CLI/APIs ### Maximum runtime * Agents deployed on Blaxel Agents Hosting have a maximum runtime of 15 minutes. This limit does not apply to [Sandboxes](../Sandboxes/Overview) or [Batch Jobs](../Jobs/Overview), which have their own runtime limits. ### Managing revisions As you iterate on software development, you will need to update the version of an agent that is currently deployed and used by your consumers. Every time you build a new version of your agent, this creates a **revision**. Blaxel stores the last 5 revisions for each object. image.webp Revisions are atomic builds of your deployment that can be either deployed (accessible via the inference endpoint) or not. This system enables you to: * **rollback a deployment** to its exact state from an earlier date * create a revision without immediate deployment to **prepare for a future release** * implement progressive rollout strategies, such as **canary deployments** Important: Revisions are not the same as versions. You cannot use revisions to return to a previous configuration and branch off from it. For version control, use your preferred system (such as GitHub) alongside Blaxel. Deployment revisions are updated following a **blue-green** paradigm. The Global Inference Network will wait for the new revision to be completely up and ready before routing requests to the new deployment. You can also set up a **canary deployment** to split traffic between two revisions (maximum of two). image.webp When making a deployment using Blaxel CLI (`bl deploy`), the new traffic routing depends on the `--traffic` option. Without this option specified, Blaxel will automatically deploy the new revision with full traffic (100%) if the previous deployment was the latest revision. Otherwise, it will create the revision without deploying it (0% traffic). ### Executions and inference requests **Executions** (a.k.a inference executions) are ephemeral invocations of agent deployments by a [consumer](/Agents/Query-agents). Because Blaxel is serverless, an agent deployment is only materialized onto one of the execution locations when it actively receives and processes requests. Workload placement and request routing is fully managed by the Global Agentics Network, as defined by your [environment policies](../Model-Governance/Policies). Read more about [querying agents in this documentation](/Agents/Query-agents). ### Deactivating an agent deployment Any agent deployment can be deactivated at any time. When deactivated, it will **no longer be reachable** through the inference endpoint and will stop consuming resources. Agents can be deactivated and activated at any time from the Blaxel console, or via [API](https://docs.blaxel.ai/api-reference/agents/update-agent-by-name) or [CLI](https://docs.blaxel.ai/cli-reference/bl_apply). ## Agent deployment reference The agent deployment can be configured via the ***blaxel.toml*** file in your agent directory. This file is not mandatory; if the file is not found or a required option is not set, you will be prompted for the information during deployment. ```toml theme={null} name = "my-agent" workspace = "my-workspace" type = "agent" public = false agents = [] functions = ["blaxel-search"] models = ["gpt-4o-mini"] [env] DEFAULT_CITY = "San Francisco" [runtime] memory = 1024 [[triggers]] id = "trigger-async-my-agent" type = "http-async" [triggers.configuration] path = "agents/my-agent/async" # This will create this endpoint on the following base URL: https://run.blaxel.ai/{YOUR-WORKSPACE} retry = 1 [[triggers]] id = "trigger-my-agent" type = "http" [triggers.configuration] path = "agents/my-agent/sync" retry = 1 ``` * `name`, `workspace`, and `type` fields are optional and serve as default values. Any bl command run in the folder will use these defaults rather than prompting you for input. * `agents`, `functions`, and `models` fields are also optional. They specify which resources to deploy with the agent. These resources are preloaded during build, eliminating runtime dependencies on the Blaxel control plane and dramatically improving performance. * `public` field specifies if the agent is publicly accessible (defaults to `false`). * `region` field pins the agent to a specific [deployment region](../Infrastructure/Regions). This is required when attaching volumes (see below). * `[env]` section defines environment variables that the agent can access via the SDK. Note that these are NOT [secrets](/Agents/Variables-and-secrets). * `[runtime]` section allows to override agent deployment parameters: memory (in MB) to allocate. * `[[volumes]]` section attaches persistent [volumes](../Sandboxes/Volumes) to the agent. See [Attach volumes to an agent](#attach-volumes-to-an-agent) below. * `[[triggers]]` and `[triggers.configuration]` sections defines ways to send requests to the agent. You can create both [synchronous and asynchronous](/Agents/Query-agents) trigger endpoints (respectively `type = "http"` or `type = "http-async"`). A private synchronous HTTP endpoint is always created by default, even if you don’t define any trigger here. ### Pin an agent to a region By default, agents are globally distributed across all regions allowed by your [deployment policies](../Model-Governance/Policies). You can pin an agent to a specific region by adding the `region` field to your `blaxel.toml`: ```toml blaxel.toml theme={null} name = "my-agent" type = "agent" region = "us-pdx-1" ``` See [Regions](../Infrastructure/Regions) for the list of available region codes. Pinning an agent to a region means it will only run in that region. Requests will not be routed to other regions, even if the selected region experiences higher latency for the caller. ### Attach volumes to an agent You can attach persistent [volumes](../Sandboxes/Volumes) to an agent so it can read and write files that persist across executions. This is useful for caching data, storing model artifacts, or sharing files between runs. To attach a volume to an agent, the agent **must be pinned to the same region** as the volume. Volumes are regional resources, and an agent must run in the same region to access them. Add a `region` and `[[volumes]]` section to your `blaxel.toml`: ```toml blaxel.toml theme={null} name = "my-agent" type = "agent" region = "us-pdx-1" [[volumes]] name = "my-volume" mountPath = "/data" ``` Each volume entry requires: | Field | Description | | ----------- | -------------------------------------------------------------------- | | `name` | The name of an existing volume in your workspace | | `mountPath` | The directory path inside the agent where the volume will be mounted | The volume must already exist before deploying. You can create one with the SDK or CLI (see [Volumes](../Sandboxes/Volumes)). ### Deployment manifests (advanced usage) When `bl deploy` runs, it generates a YAML configuration manifest automatically and deploys it to Blaxel's hosting infrastructure. You can also create custom manifest files in the `.blaxel` folder and deploy them using the following command: ```bash theme={null} bl apply -f ./my-deployment.yaml ``` Read our [reference for agent deployments](https://docs.blaxel.ai/api-reference/agents/get-agent-by-name). `DEADLINE_EXCEEDED` or `STARTUP TCP probe failed` errors? Check our [troubleshooting page](/troubleshooting) for possible solutions. See an example of building and deploying an agent on Blaxel with Claude Agent SDK. Learn how to run inference requests on your agent. # Deploy with a Dockerfile Source: https://docs.blaxel.ai/Agents/Deploy-dockerfile Ship your AI agent on Blaxel using a custom Dockerfile. Blaxel allows you to customize your deployments ([agents](Overview), [MCP servers](../Functions/Overview), and [batch jobs](../Jobs/Overview)) using a Dockerfile at the root level of your project. ## Overview By default, Blaxel builds and deploys your application using predefined container images optimized for agent workloads. However, you may need to: * Install additional system dependencies * Configure custom environment settings * Use specific versions of runtime environments * Include proprietary libraries or tools A Dockerfile at the root of your project gives you full control over the container image that will run your workload on Blaxel's infrastructure. 1. Navigate to the root directory of your Blaxel project ([agent](Overview), [MCP server](../Functions/Overview), or [batch job](../Jobs/Overview)) 2. Create a file named `Dockerfile` (case-sensitive) ## Dockerfile Structure Your Dockerfile should follow these guidelines for compatibility with Blaxel's infrastructure: ```Dockerfile Python theme={null} # Start from a base Python image FROM python:3.12-slim # Set working directory WORKDIR /blaxel # Install system dependencies (if needed) RUN apt-get update && apt-get install -y \\ build-essential \\ # Add any other system dependencies here \\ && rm -rf /var/lib/apt/lists/* # Copy requirements first for better caching COPY pyproject.toml uv.lock /blaxel/ RUN pip install uv && uv sync --refresh # Copy application code COPY . . # Set env variable to use the virtual environment ENV PATH="/blaxel/python/.venv/bin:$PATH" # Command to run when container starts, it need to provide a server running on port 80 for agent and MCP server ENTRYPOINT [".venv/bin/python3", "-m", "src"] ``` ```Dockerfile TypeScript/JavaScript theme={null} # Start from a Node.js base image FROM node:22-alpine # Set working directory WORKDIR /blaxel # Copy package files for better caching COPY package.json pnpm-lock.yaml /blaxel/ RUN npx pnpm install # Copy application code COPY . . # Command to run when container starts, it need to provide a server running on port 80 for agent and MCP server ENTRYPOINT ["npx", "pnpm", "start"] ``` ### Entrypoint * The only requirement to deploy an app on Agents Hosting is that it exposes an HTTP API server which is bound on `HOST` (for the host) and `PORT` (for the port). ### Environment variables [Environment variables](/Agents/Variables-and-secrets) configured in the Blaxel platform will be automatically injected into your container at runtime. You do not need to specify them in your Dockerfile. ## Test locally Before deploying to Blaxel, you can test your Dockerfile locally. ```bash theme={null} # Build the Docker image docker build -t my-blaxel-app . # Run the container locally docker run -p 1338:1338 my-blaxel-app ``` ## Deploy When a Dockerfile is present at the root of your project, Blaxel will use it to build a custom container image for your deployment. Deploy your application with the Blaxel CLI as usual. ```bash theme={null} bl deploy ``` You can alternatively use `bl push` to build and push the container image to the Blaxel registry without creating or updating the deployment. ## Deploy multiple resources with shared files Using a custom Dockerfile allows for [deploying multiple agents & MCPs from the same repository](/Agents/Deploy-multiple) with shared dependencies. Deploy multiple agents & MCP servers with shared context from a single repository. # Deploy multiple resources Source: https://docs.blaxel.ai/Agents/Deploy-multiple Deploy multiple agents with shared context from a mono-repo. You can use a **shared context from a same single repository** to deploy multiple resources, mixing [batch jobs](../Jobs/Overview), [agents](Overview), [MCP servers](../Functions/Overview), etc. ## Deploying multiple resources With the `--directory` (`-d`) parameter in `bl deploy` and `bl push`, you can specify a subfolder containing your `blaxel.toml` and `Dockerfile`. The `Dockerfile` defines how your deployment context is built and as such is required if you want to ensure proper mounting of shared dependencies between your different services. This enables such mono-repo structure with shared libraries: ```text theme={null} myrepo |- myjob |- src |- blaxel.toml |- Dockerfile |- myagent |- src |- blaxel.toml |- Dockerfile |- myotheragent |- src |- blaxel.toml |- Dockerfile |- mymcpserver |- src |- blaxel.toml |- Dockerfile |- shared |- sharedfile ``` No changes are required to your `blaxel.toml`. However, in your `Dockerfile`, paths **must be relative** to the root context. For example, replace `COPY src src` with`COPY myagent/src src` This allows you to reference shared resources: ```dockerfile theme={null} COPY myagent/src src COPY shared shared ``` ### Deploy To deploy, run these commands from the root folder: ```bash theme={null} bl deploy -d myjob bl deploy -d myagent bl deploy -d myotheragent bl deploy -d mymcpserver ``` To push without deploying, run these commands from the root folder: ```bash theme={null} bl push -d myjob bl push -d myagent bl push -d myotheragent bl push -d mymcpserver ``` For a complete example, see our [sample repository](https://github.com/drappier-charles/multiagent). # Development guide Source: https://docs.blaxel.ai/Agents/Develop-an-agent Develop custom AI agents in TypeScript or Python using any framework, connect to Blaxel resources via SDK, and deploy as serverless endpoints. You can **develop agents however you want** — either using a framework such as LangChain, Google ADK or AI SDK; or using just custom code — and deploy the agents to Blaxel with our developer tools ([Blaxel CLI](../cli-reference/introduction), [GitHub app](/Agents/Github-integration), GitHub action, etc.). [Blaxel SDK](../sdk-reference/introduction) provides methods to programmatically access and integrate various resources hosted on Blaxel into your agent's code, such as: [model APIs](../Models/Overview), [tool servers](../Functions/Overview), [sandboxes](../Sandboxes/Overview), [batch jobs](../Jobs/Overview), or [other agents](Overview). The SDK handles authentication, secure connection management and telemetry automatically. This packaging makes Blaxel **fully agnostic of the framework** used to develop your agent and doesn’t prevent you from deploying your software on another platform. ## Overview of the development/deployment process Blaxel’s development paradigm is designed to have a minimal footprint on your usual development process. Your custom code remains platform-agnostic: you can deploy it on Blaxel or through traditional methods like Docker containers on VMs or Kubernetes clusters. When you deploy on Blaxel (CLI command `bl deploy`), Blaxel runs a specialized build process that integrates your code with its [Global Agentics Network](../Infrastructure/Global-Inference-Network) features. At this time, Blaxel only supports custom agents developed in TypeScript or Python. Here is a high-level overview of how agents can be built and deployed using Blaxel: 1. **Initialize a new project by creating a local git repository**. This will contain your agent's logic and connections, as well as all required dependencies. For quick setup, use [Blaxel CLI](../cli-reference/introduction) command `bl new agent`, which creates a pre-scaffolded local repository ready for development that you can deploy to Blaxel in one command. 2. **Develop and test your agent iteratively in a local environment**. 1. Develop your agent logic however you want (using an agentic framework or any custom TypeScript/Python code). Write your own functions as needed. Use Blaxel SDK commands to connect to resources from Blaxel such as model APIs and tool servers. 2. Use Blaxel CLI command `bl serve` to serve your agent on your local machine. The execution workflow—including agent logic, functions, and model API calls—is broken down and sandboxed exactly as it would be when served on Blaxel. 3. **Push or deploy your agent**. Use Blaxel CLI command `bl push` to build and push your agent to Blaxel's registry, or `bl deploy` to build and deploy your agent on Blaxel. You can manage a development & production life-cycle by deploying multiple agents, with the according prefix or label. ## Develop an agent on Blaxel Check out the following guide to learn how to develop and deploy an agent using your preferred programming language on Blaxel. Develop your AI agents in TypeScript using the Blaxel SDK. Develop your AI agents in Python using the Blaxel SDK. See an example of building and deploying an agent on Blaxel with Claude Agent SDK. Learn how to deploy your custom AI agents on Blaxel as a serverless endpoint. # Develop agents in Python Source: https://docs.blaxel.ai/Agents/Develop-an-agent-py Use the Blaxel SDK to develop and run a custom agent in Python. You can bring your **custom agents developed in Python** and deploy them to Blaxel with our developer tools ([Blaxel CLI](../cli-reference/introduction), [GitHub app](/Agents/Github-integration), GitHub action, etc.). You can develop agents using frameworks like LangChain, Google ADK, OpenAI Agents SDK; or your own custom code. ## Quickstart It is required to [have *uv* installed](https://docs.astral.sh/uv/getting-started/installation/) to use the following command. You can quickly **initialize a new project from scratch** by using CLI command `bl new`. ```bash theme={null} bl new agent ``` This will create a pre-scaffolded local repo where your entire code can be added. You can choose the base agentic framework for the template. In the generated folder, you'll find a standard server in the entrypoint file `main.py`. While you typically won't need to modify this file, you can add specific logic there if needed. Your main work will focus on the `agent.py` file. Blaxel's development paradigm lets you leverage its hosting capabilities without modifying your agent's core logic. ### Requirements & limitations Agents Hosting have few requirements or limitations: * The only requirement to deploy an app on Agents Hosting is that it exposes an HTTP API server which is bound on `HOST` (for the host) and `PORT` (for the port). **These two environment variables are required for the host+port combo.** * You can use [express](https://expressjs.com/), [fastify](https://fastify.dev/), [FastAPI](https://fastapi.tiangolo.com/), etc. for this. * Agents deployed on Blaxel Agents Hosting have a maximum runtime of 15 minutes. This limit does not apply to [Sandboxes](../Sandboxes/Overview) or [Batch Jobs](../Jobs/Overview), which have their own runtime limits. * The synchronous endpoint closes the connection after **100 seconds** if no data flows through the API. If your agent streams back responses, the connection resets with each chunk streamed. For example, if your agent processes a request for 5 minutes while streaming data, the connection stays open. However, if it goes 100 seconds without sending any data — even while calling external APIs — the connection will close. ## Accessing resources with Blaxel SDK [Blaxel SDK](../sdk-reference/introduction) provides methods to programmatically access and integrate various resources hosted on Blaxel into your agent's code, such as: [model APIs](../Models/Overview), [tool servers](../Functions/Overview), [sandboxes](../Sandboxes/Overview), [batch jobs](../Jobs/Overview), or [other agents](Overview). The SDK handles authentication, secure connection management and telemetry automatically. ### Connect to a model API Blaxel SDK provides a helper to connect to a [model API](../Models/Overview) defined on Blaxel from your code. This allows you to avoid managing a connection with the model API by yourself. Credentials remain stored securely on Blaxel. ```python theme={null} from blaxel.{FRAMEWORK_NAME} import bl_model model = await bl_model("Model-name-on-Blaxel"); ``` The model is automatically converted to your chosen framework's format based on the `FRAMEWORK_NAME` specified in the import. Available frameworks : * [LangGraph/LangChain](https://python.langchain.com/docs/concepts/chat_models/) : `langgraph` * [CrewAI](https://docs.crewai.com/concepts/llms) : `crewai` * [LlamaIndex](https://docs.llamaindex.ai/en/stable/module_guides/models/llms/) : `llamaindex()` * [OpenAI Agents](https://github.com/openai/openai-agents-python): `openai()` * [Pydantic AI Agents](https://github.com/pydantic/pydantic-ai): `pydantic()` * [Google ADK](https://github.com/google/adk-python/blob/main/src/google/adk/models/lite_llm.py): `googleadk()` For example, to connect to model `my-model` in a *LlamaIndex* agent: ```python theme={null} from blaxel.llamaindex import bl_model model = await bl_model("my-model") ``` ### Connect to tools Blaxel SDK provides a helper to connect to [pre-built or custom tool servers (MCP servers)](../Functions/Overview) hosted on Blaxel from your code. This allows you to avoid managing a connection with the server by yourself. Credentials remain stored securely on Blaxel. The following method retrieves all the tools discoverable in the tool server. ```python theme={null} from blaxel.{FRAMEWORK_NAME} import bl_tools await bl_tools(['Tool-Server-name-on-Blaxel']) ``` Like for a model, the retrieved tools are automatically converted to the format of the framework you want to use based on the Blaxel SDK package imported. Available frameworks are `langgraph` ([LangGraph/Langchain](https://python.langchain.com/api_reference/core/tools/langchain_core.tools.structured.StructuredTool.html)), `llamaindex` ([LlamaIndex](https://docs.llamaindex.ai/en/stable/module_guides/deploying/agents/tools/)), `crewai` ([CrewAI](https://docs.crewai.com/concepts/tools)), `openai` ([OpenAI Agents](https://github.com/openai/openai-agents-python)), `pydantic` ([PydanticAI Agents](https://github.com/pydantic/pydantic-ai)) and `googleadk` ([Google ADK](https://github.com/google/adk-python/blob/main/src/google/adk/tools/base_tool.py)). You can develop agents by **mixing tools defined locally in your agents, and tools defined as remote servers**. Using separated tools prevents monolithic designs which make maintenance easier in the long run. Let's look at a practical example combining remote and local tools. The code below uses two tools: 1. `blaxel-search`: A remote tool server on Blaxel providing web search functionality (learn how to create your own MCP servers [here](../Functions/Create-MCP-server)) 2. `weather`: A local tool that accepts a city parameter and returns a mock weather response (always "sunny") ```python agent.py (LangGraph) theme={null} from typing import AsyncGenerator from blaxel.langgraph import bl_model, bl_tools from langchain.tools import tool from langchain_core.messages import AIMessageChunk from langgraph.prebuilt import create_react_agent @tool def weather(city: str) -> str: """Get the weather in a given city""" return f"The weather in {city} is sunny" async def agent(input: str) -> AsyncGenerator[str, None]: prompt = "You are a helpful assistant that can answer questions and help with tasks." ### Load tools dynamically from Blaxel, and adding a tool defined locally: tools = await bl_tools(["blaxel-search"]) + [weather] ### Load model API dynamically from Blaxel: model = await bl_model("gpt-4o-mini") agent = create_react_agent(model=model, tools=tools, prompt=prompt) messages = {"messages": [("user", input)]} async for chunk in agent.astream(messages, stream_mode=["updates", "messages"]): type_, stream_chunk = chunk # This is to stream the response from the agent, filtering response from tools if type_ == "messages" and len(stream_chunk) > 0 and isinstance(stream_chunk[0], AIMessageChunk): msg = stream_chunk[0] if msg.content: if not msg.tool_calls: yield msg.content # This to show a call has been made to a tool, usefull if you want to show the tool call in your interface if type_ == "updates": if "tools" in stream_chunk: for msg in stream_chunk["tools"]["messages"]: yield f"Tool call: {msg.name}\n" ``` ```python agent.py (LlamaIndex) theme={null} from typing import AsyncGenerator from blaxel.llamaindex import bl_model, bl_tools from llama_index.core.agent.workflow import AgentStream, ReActAgent from llama_index.core.tools import FunctionTool async def weather(city: str) -> str: """Get the weather in a given city""" return f"The weather in {city} is sunny" async def agent(input: str) -> AsyncGenerator[str, None]: prompt = "You are a helpful assistant that can answer questions and help with tasks." ### Load tools dynamically from Blaxel, and adding a tool defined locally: tools = await bl_tools(["blaxel-search"]) + [FunctionTool.from_defaults(async_fn=weather)] ### Load model API dynamically from Blaxel: model = await bl_model("gpt-4o-mini") agent = ReActAgent(llm=model, tools=tools, system_prompt=prompt) async for event in agent.run(input).stream_events(): if isinstance(event, AgentStream): yield event.delta ``` ```python agent.py (CrewAI) theme={null} # We have to apply nest_asyncio because crewai is not compatible with async import nest_asyncio nest_asyncio.apply() from typing import AsyncGenerator from blaxel.crewai import bl_model, bl_tools from crewai import Agent, Crew, Task from crewai.tools import tool @tool("Weather") def weather(city: str) -> str: """Get the weather in a given city""" return f"The weather in {city} is sunny" async def agent(input: str) -> AsyncGenerator[str, None]: ### Load tools dynamically from Blaxel, and adding a tool defined locally: tools = await bl_tools(["blaxel-search"]) + [weather] ### Load model API dynamically from Blaxel: model = await bl_model("gpt-4o-mini") agent = Agent( role="Weather Researcher", goal="Find the weather in a city", backstory="You are an experienced weather researcher with attention to detail", llm=model, tools=tools, verbose=True, ) crew = Crew( agents=[agent], tasks=[Task(description="Find weather", expected_output=input, agent=agent)], verbose=True, ) result = crew.kickoff() yield result.raw ``` ```python agent.py (OpenAI Agents) theme={null} from typing import AsyncGenerator from agents import Agent, RawResponsesStreamEvent, Runner, function_tool from blaxel.openai import bl_model, bl_tools from openai.types.responses import ResponseTextDeltaEvent @function_tool() async def weather(city: str) -> str: """Get the weather in a given city""" return f"The weather in {city} is sunny" async def agent(input: str) -> AsyncGenerator[str, None]: ### Load tools dynamically from Blaxel, and adding a tool defined locally: tools = await bl_tools(["blaxel-search"]) + [weather] ### Load model API dynamically from Blaxel: model = await bl_model("gpt-4o-mini") agent = Agent( name="blaxel-agent", model=model, tools=tools, instructions="You are a helpful assistant.", ) result = Runner.run_streamed(agent, input) async for event in result.stream_events(): if isinstance(event, RawResponsesStreamEvent) and isinstance(event.data, ResponseTextDeltaEvent): yield event.data.delta ``` ```python agent.py (Pydantic AI Agents) theme={null} from typing import AsyncGenerator from blaxel.pydantic import bl_model, bl_tools from pydantic_ai import Agent, CallToolsNode, Tool from pydantic_ai.messages import ToolCallPart from pydantic_ai.models import ModelSettings def weather(city: str) -> str: """Get the weather in a given city""" return f"The weather in {city} is sunny" async def agent(input: str) -> AsyncGenerator[str, None]: prompt = "You are a helpful assistant that can answer questions and help with tasks." ### Load tools dynamically from Blaxel, and adding a tool defined locally: tools = await bl_tools(["blaxel-search"]).to_pydantic() + [Tool(weather)] ### Load model API dynamically from Blaxel: model = await bl_model("gpt-4o-mini").to_pydantic() agent = Agent(model=model, tools=tools, model_settings=ModelSettings(temperature=0), system_prompt=prompt) async with agent.iter(input) as agent_run: async for node in agent_run: if isinstance(node, CallToolsNode): for part in node.model_response.parts: if isinstance(part, ToolCallPart): yield(f"Tool call: {part.tool_name}\n") else: yield part.content + "\n" ``` ```python agent.py (Google ADK) theme={null} from logging import getLogger from typing import AsyncGenerator from blaxel.googleadk import bl_model, bl_tools from google.adk.agents import Agent from google.adk.runners import Runner from google.adk.sessions import InMemorySessionService from google.genai import types logger = getLogger(__name__) # @title Define the get_weather Tool def get_weather(city: str) -> dict: """Get the weather in a given city""" return f"The weather in {city} is sunny" APP_NAME = "research_assistant" session_service = InMemorySessionService() async def agent(input: str, user_id: str = "default", session_id: str = "default") -> AsyncGenerator[str, None]: description = "You are a helpful assistant that can answer questions and help with tasks." prompt = """ You are a helpful weather assistant. Your primary goal is to provide current weather reports. " When the user asks for the weather in a specific city, You can also use a research tool to find more information about anything. Analyze the tool's response: if the status is 'error', inform the user politely about the error message. If the status is 'success', present the weather 'report' clearly and concisely to the user. Only use the tool when a city is mentioned for a weather request. """ ### Load tools dynamically from Blaxel, and adding a tool defined locally: tools = await bl_tools(["blaxel-search"]).to_google_adk() + [get_weather] ### Load model API dynamically from Blaxel: model = await bl_model("sandbox-openai").to_google_adk() agent = Agent(model=model, name=APP_NAME, description=description, instruction=prompt, tools=tools) # Create the specific session where the conversation will happen if not session_service.get_session(app_name=APP_NAME, user_id=user_id, session_id=session_id): session_service.create_session( app_name=APP_NAME, user_id=user_id, session_id=session_id ) logger.info(f"Session created: App='{APP_NAME}', User='{user_id}', Session='{session_id}'") runner = Runner( agent=agent, app_name=APP_NAME, session_service=session_service, ) logger.info(f"Runner created for agent '{runner.agent.name}'.") content = types.Content(role="user", parts=[types.Part(text=input)]) async for event in runner.run_async(user_id=user_id, session_id=session_id, new_message=content): # Key Concept: is_final_response() marks the concluding message for the turn. if event.is_final_response(): if event.content and event.content.parts: # Assuming text response in the first part yield event.content.parts[0].text elif event.actions and event.actions.escalate: # Handle potential errors/escalations yield f"Agent escalated: {event.error_message or 'No specific message.'}" ``` ### Connect to another agent (multi-agent chaining) Rather than using a "quick and dirty" approach where you would combine all your agents and capabilities into a single deployment, Blaxel provides a structured development paradigm based on two key principles: * Agents can grow significantly in complexity. Monolithic architectures make long-term maintenance difficult. * Individual agents should be reusable across multiple projects. Blaxel supports a microservice architecture for handoffs, allowing you to call one agent from another using `bl_agent().run()` rather than combining all functionality into a single codebase. ```bash theme={null} from blaxel.core.agents import bl_agent first_agent_response = await bl_agent("first_agent").run(input); second_agent_response = await bl_agent("second_agent").run(first_agent_response); ``` ## Customize the agent deployment You can set custom parameters for an agent deployment (e.g. specify the agent name, etc.) in the [`blaxel.toml` file](/deployment-reference) at the root of your directory. Read the file structure section down below for more details. ## Instrumentation Instrumentation happens automatically when workloads run on Blaxel. To enable telemetry, simply import the SDK in your project's entry point. ```bash theme={null} import blaxel.core ``` When agents and tools are deployed on Blaxel, request logging and tracing happens automatically. To add your own custom logs that you can view in the Blaxel Console, use the Python default logger. ```bash theme={null} import logging logger = getLogger(__name__) logger.info("Hello, world!"); ``` ## Template directory reference ### Overview ```bash theme={null} pyproject.toml # Mandatory. This file is the standard pyproject.toml file, it defines dependencies. blaxel.toml # This file lists configurations dedicated to Blaxel to customize the deployment. It is not mandatory. .blaxel # This folder allows you to define custom resources using the Blaxel API specifications. These resources will be deployed along with your agent. ├── blaxel-search.yaml # Here, blaxel-search is a sandbox Web search tool we provide so you can develop your first agent. It has a low rate limit, so we recommend you use a dedicated MCP server for production. src/ └── main.py # This file is the standard entrypoint of the project. It is used to start the server and create an endpoint bound with agent.py file. ├── agent.py # This file is the main file of your agent. It is loaded from main.py. In the template, all the agent logic is implemented here. ``` ### blaxel.toml The agent deployment can be configured via the `blaxel.toml` file in your agent directory. This file is not mandatory; if the file is not found or a required option is not set, you will be prompted for the information during deployment. ```toml theme={null} name = "my-agent" workspace = "my-workspace" type = "agent" public = false agents = [] functions = ["blaxel-search"] models = ["gpt-4o-mini"] [env] DEFAULT_CITY = "San Francisco" [runtime] memory = 1024 [[triggers]] id = "trigger-async-my-agent" type = "http-async" [triggers.configuration] path = "agents/my-agent/async" # This will create this endpoint on the following base URL: https://run.blaxel.ai/{YOUR-WORKSPACE} retry = 1 [[triggers]] id = "trigger-my-agent" type = "http" [triggers.configuration] path = "agents/my-agent/sync" retry = 1 ``` * `name`, `workspace`, and `type` fields are optional and serve as default values. Any bl command run in the folder will use these defaults rather than prompting you for input. * `agents`, `functions`, and `models` fields are also optional. They specify which resources to deploy with the agent. These resources are preloaded during build, eliminating runtime dependencies on the Blaxel control plane and dramatically improving performance. * `public` field specifies if the agent is publicly accessible (defaults to `false`). * `[env]` section defines environment variables that the agent can access via the SDK. Note that these are NOT [secrets](/Agents/Variables-and-secrets). * `[runtime]` section allows to override agent deployment parameters: memory (in MB) to allocate. * `[[triggers]]` and `[triggers.configuration]` sections defines ways to send requests to the agent. You can create both [synchronous and asynchronous](/Agents/Query-agents) trigger endpoints (respectively `type = "http"` or `type = "http-async"`). A private synchronous HTTP endpoint is always created by default, even if you don’t define any trigger here. Additionally, you can define an `[entrypoint]` section to specify how Blaxel is going to start your server: ```toml theme={null} ... [entrypoint] prod = "python src/main.py" dev = "fastapi dev" ... ``` * `prod`: this is the command that will be used to serve your agent ```bash theme={null} python src/main.py ``` * `dev`: same as prod in dev mode, it will be used with the command `--hotreload`. Example: ```bash theme={null} fastapi dev ``` This `entrypoint` section is optional. If not specified, Blaxel will automatically detect in the agent’s content and configure your agent startup settings. ## Troubleshooting ### Wrong port or host ```text theme={null} Default STARTUP TCP probe failed 1 time consecutively for container "agent" on port 80. The instance was not started. Connection failed with status DEADLINE_EXCEEDED. ``` If you encounter this error when deploying your agent on Blaxel, ensure that your agent properly exposes an API server that binds to a host and port with the **required** environment variables: `HOST` & `PORT`. Blaxel automatically injects these variables during deployment. See an example of building and deploying an agent on Blaxel with Claude Agent SDK. Learn how to deploy your custom AI agents on Blaxel as a serverless endpoint. # Develop agents in TypeScript Source: https://docs.blaxel.ai/Agents/Develop-an-agent-ts Use the Blaxel SDK to develop and run a custom agent in TypeScript. You can bring your **custom agents developed in TypeScript** and deploy them to Blaxel with our developer tools ([Blaxel CLI](../cli-reference/introduction), [GitHub app](/Agents/Github-integration), GitHub action, etc.). You can develop agents using frameworks like LangChain, AI SDK, Mastra; or your own custom code. ## Quickstart It is required to have *npm* installed to use the following command. You can quickly **initialize a new project from scratch** by using CLI command `bl new`. ```bash theme={null} bl new agent ``` This will create a pre-scaffolded local repo where your entire code can be added. You can choose the base agentic framework for the template. In the generated folder, you'll find a standard server in the entrypoint file `index.ts`. While you typically won't need to modify this file, you can add specific logic there if needed. Your main work will focus on the `agent.ts` file. Blaxel's development paradigm lets you leverage its hosting capabilities without modifying your agent's core logic. ### Requirements & limitations Agents Hosting have few requirements or limitations: * The only requirement to deploy an app on Agents Hosting is that it exposes an HTTP API server which is bound on `HOST` (for the host) and `PORT` (for the port). **These two environment variables are required for the host+port combo.** * You can use [express](https://expressjs.com/), [fastify](https://fastify.dev/), [FastAPI](https://fastapi.tiangolo.com/), etc. for this. * Agents deployed on Blaxel Agents Hosting have a maximum runtime of 15 minutes. This limit does not apply to [Sandboxes](../Sandboxes/Overview) or [Batch Jobs](../Jobs/Overview), which have their own runtime limits. * The synchronous endpoint closes the connection after **100 seconds** if no data flows through the API. If your agent streams back responses, the connection resets with each chunk streamed. For example, if your agent processes a request for 5 minutes while streaming data, the connection stays open. However, if it goes 100 seconds without sending any data — even while calling external APIs — the connection will close. ## Accessing resources with Blaxel SDK [Blaxel SDK](../sdk-reference/introduction) provides methods to programmatically access and integrate various resources hosted on Blaxel into your agent's code, such as: [model APIs](../Models/Overview), [tool servers](../Functions/Overview), [sandboxes](../Sandboxes/Overview), [batch jobs](../Jobs/Overview), or [other agents](Overview). The SDK handles authentication, secure connection management and telemetry automatically. ### Connect to a model API Blaxel SDK provides a helper to connect to a [model API](../Models/Overview) defined on Blaxel from your code. This allows you to avoid managing a connection with the model API by yourself. Credentials remain stored securely on Blaxel. ```tsx theme={null} /// Optional: enable automatic telemetry import "@blaxel/telemetry" import { blModel } from "@blaxel/{FRAMEWORK_NAME}"; const model = await blModel("Model-name-on-Blaxel"); ``` The model is automatically converted to your chosen framework's format based on the `FRAMEWORK_NAME` specified in the import. Available frameworks : * [LangChain/LangGraph](https://v03.api.js.langchain.com/classes/_langchain_core.language_models_chat_models.BaseChatModel.html) : `langgraph` * [LlamaIndex](https://ts.llamaindex.ai/docs/llamaindex/modules/tool) : `llamaindex` * [VercelAI](https://sdk.vercel.ai/docs/ai-sdk-core/tools-and-tool-calling) : `vercel` * [Mastra](https://mastra.ai/docs/reference/agents/createTool): `mastra` For example, to connect to model `my-model` in a *LlamaIndex* agent: ```tsx theme={null} import { blModel } from "@blaxel/llamaindex"; const model = await blModel("my-model"); ``` ### Connect to tools Blaxel SDK provides a helper to connect to [pre-built or custom tool servers (MCP servers)](../Functions/Overview) hosted on Blaxel from your code. This allows you to avoid managing a connection with the server by yourself. Credentials remain stored securely on Blaxel. The following method retrieves all the tools discoverable in the tool server. ```tsx theme={null} import { blTools } from "@blaxel/{FRAMEWORK_NAME}"; await blTools(['Tool-Server-name-on-Blaxel']) ``` Like for a model, the retrieved tools are automatically converted to the format of the framework you want to use based on the Blaxel SDK package imported. Available frameworks are `langgraph` ([LangChain/LangGraph](https://v03.api.js.langchain.com/classes/_langchain_core.tools.StructuredTool.html)), `llamaindex` ([LlamaIndex](https://ts.llamaindex.ai/docs/llamaindex/modules/tool)), `vercel` ([Vercel AI](https://sdk.vercel.ai/docs/ai-sdk-core/tools-and-tool-calling)) and `mastra` ([Mastra](https://mastra.ai/docs/reference/agents/createTool)). You can develop agents by **mixing tools defined locally in your agents, and tools defined as remote servers**. Using separated tools prevents monolithic designs which make maintenance easier in the long run. Let's look at a practical example combining remote and local tools. The code below uses two tools: 1. `blaxel-search`: A remote tool server on Blaxel providing web search functionality (learn how to create your own MCP servers [here](../Functions/Create-MCP-server)) 2. `weather`: A local tool that accepts a city parameter and returns a mock weather response (always "sunny") ```typescript agent.ts (Vercel AI) theme={null} import { blModel, blTools } from '@blaxel/vercel'; import { streamText, tool } from 'ai'; import { z } from 'zod'; interface Stream { write: (data: string) => void; end: () => void; } export default async function agent(input: string, stream: Stream): Promise { const response = streamText({ experimental_telemetry: { isEnabled: true }, // Load model API dynamically from Blaxel: model: await blModel("gpt-4o-mini"), tools: { // Load tools dynamically from Blaxel: ...await blTools(['blaxel-search']), // And here's an example of a tool defined locally for Vercel AI: "weather": tool({ description: "Get the weather in a specific city", parameters: z.object({ city: z.string(), }), execute: async (args: { city: string }) => { console.debug("TOOL CALLING: local weather", args); return `The weather in ${args.city} is sunny`; }, }), }, system: "You are an agent that will give the weather when a city is provided, and also do a quick search about this city.", messages: [ { role: 'user', content: input } ], maxSteps: 5, }); for await (const delta of response.textStream) { stream.write(delta); } stream.end(); } ``` ```typescript agent.ts (LlamaIndex) theme={null} import { blModel, blTools } from '@blaxel/llamaindex'; import { agent, AgentStream, tool, ToolCallLLM } from "llamaindex"; import { z } from "zod"; interface Stream { write: (data: string) => void; end: () => void; } export default async function myagent(input: string, stream: Stream): Promise { const streamResponse = agent({ // Load model API dynamically from Blaxel: llm: await blModel("gpt-4o-mini") as unknown as ToolCallLLM, // Load tools dynamically from Blaxel: tools: [...await blTools(['blaxel-search']), // And here's an example of a tool defined locally for LlamaIndex: tool({ name: "weather", description: "Get the weather in a specific city", parameters: z.object({ city: z.string(), }), execute: async (input) => { console.debug("TOOL CALLING: local weather", input) return `The weather in ${input.city} is sunny`; }, }) ], systemPrompt: "If the user asks for the weather, use the weather tool.", }).run(input); for await (const event of streamResponse) { if (event instanceof AgentStream) { for (const chunk of event.data.delta) { stream.write(chunk); } } } stream.end(); } ``` ```typescript agent.ts (LangChain/LangGraph) theme={null} import { blModel, blTools } from '@blaxel/langgraph'; import { HumanMessage } from "@langchain/core/messages"; import { tool } from "@langchain/core/tools"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { z } from "zod"; interface Stream { write: (data: string) => void; end: () => void; } export default async function agent(input: string, stream: Stream): Promise { const streamResponse = await createReactAgent({ // Load model API dynamically from Blaxel: llm: await blModel("gpt-4o-mini"), prompt: "If the user asks for the weather, use the weather tool.", // Load tools dynamically from Blaxel: tools: [ ...await blTools(['blaxel-search']), // And here's an example of a tool defined locally for LangChain: tool(async (input: any) => { console.debug("TOOL CALLING: local weather", input) return `The weather in ${input.city} is sunny`; },{ name: "weather", description: "Get the weather in a specific city", schema: z.object({ city: z.string(), }) }) ], }).stream({ messages: [new HumanMessage(input)], }); for await (const chunk of streamResponse) { if(chunk.agent) for(const message of chunk.agent.messages) { stream.write(message.content) } } stream.end(); } ``` ```typescript agent.ts (Mastra) theme={null} import { blModel, blTools } from "@blaxel/mastra"; import { createTool } from "@mastra/core/tools"; import { Agent } from "@mastra/core/agent"; import { z } from "zod"; interface Stream { write: (data: string) => void; end: () => void; } export default async function agent( input: string, stream: Stream ): Promise { const agent = new Agent({ name: "blaxel-agent-mastra", // Load model API dynamically from Blaxel: model: await blModel("sandbox-openai"), // Load tools dynamically from Blaxel: tools: { ...(await blTools(["blaxel-search"])), // And here's an example of a tool defined locally for Mastra: weatherTool: createTool({ id: "weatherTool", description: "Get the weather in a specific city", inputSchema: z.object({ city: z.string(), }), outputSchema: z.object({ weather: z.string(), }), execute: async ({ context }) => { return { weather: `The weather in ${context.city} is sunny` }; }, }), }, instructions: "If the user asks for the weather, use the weather tool.", }); const response = await agent.stream([{ role: "user", content: input }]); for await (const delta of response.textStream) { stream.write(delta); } stream.end(); } ``` ### Connect to another agent (multi-agent chaining) Rather than using a "quick and dirty" approach where you would combine all your agents and capabilities into a single deployment, Blaxel provides a structured development paradigm based on two key principles: * Agents can grow significantly in complexity. Monolithic architectures make long-term maintenance difficult. * Individual agents should be reusable across multiple projects. Blaxel lets you organize your software with a microservice architecture for handoffs, allowing you to call one agent from another using `blAgent().run()` rather than combining all functionality into a single codebase. ```tsx theme={null} import { blAgent } from "@blaxel/core"; const myFirstAgentResponse = await blAgent("firstAgent").run(input); const mySecondAgentResponse = await blAgent("secondAgent").run(myFirstAgentResponse); ``` ## Customize the agent deployment You can set custom parameters for an agent deployment (e.g. specify the agent name, etc.) in the `blaxel.toml` file at the root of your directory. Read the file structure section down below for more details. Learn how to deploy your custom AI agents on Blaxel as a serverless endpoint. ## Instrumentation Instrumentation happens automatically when workloads run on Blaxel. To enable telemetry, simply import the SDK in your project's entry point. ```tsx theme={null} import "@blaxel/telemetry"; ``` When agents and tools are deployed on Blaxel, request logging and tracing happens automatically. To add your own custom logs that you can view in the Blaxel Console, use the default console logger or any logging library (pino, winston, …). ```tsx theme={null} console.info("my-log") ``` ## Template directory reference ### Overview ```text theme={null} package.json # Mandatory. This file is the standard package.json file, it defines the entrypoint of the project and dependencies. blaxel.toml # This file lists configurations dedicated to Blaxel to customize the deployment. It is not mandatory. tsconfig.json # This file is the standard tsconfig.json file, only needed if you use TypeScript. .blaxel # This folder allows you to define custom resources using the Blaxel API specifications. These resources will be deployed along with your agent. ├── blaxel-search.yaml # Here, blaxel-search is a sandbox Web search tool we provide so you can develop your first agent. It has a low rate limit, so we recommend you use a dedicated MCP server for production. src/ └── index.ts # This file is the standard entrypoint of the project. It is used to start the server and create an endpoint bound with agent.ts file. ├── agent.ts # This file is the main file of your agent. It is loaded from index.ts. In the template, all the agent logic is implemented here. ``` ### package.json Here the most notable imports are the scripts. They are used for the `bl serve` and `bl deploy` commands. ```json theme={null} { "name": "name", "version": "1.0.0", "description": "", "keywords": [], "license": "MIT", "author": "cdrappier", "scripts": { "start": "tsx src/index.ts", "prod": "node dist/index.js", "dev": "tsx watch src/index.ts", "build": "tsc" }, "dependencies": { "@ai-sdk/openai": "^1.2.5", "@blaxel/sdk": "0.1.1-preview.9", "ai": "^4.1.61", "fastify": "^5.2.1", "zod": "^3.24.2" }, "devDependencies": { "@types/express": "^5.0.1", "@types/node": "^22.13.11", "tsx": "^4.19.3", "typescript": "^5.8.2" } } ``` Depending of what you do, all of the `scripts` are not required. With TypeScript, all 4 of them are used. * `start` : start the server locally through the TypeScript command, to avoid having to build the project when developing. * `build` : build the project. It is done automatically when deploying. * `prod` : start the server remotely from the dist folder, the project needs to be have been built before. * `dev` : same as start, but with hotreload. It's useful when developing locally, each file change is reflected immediately. The remaining fields in package.json follow standard JavaScript/TypeScript project conventions. Feel free to add any dependencies you need, but keep in mind that devDependencies are only used during the build process and are removed afterwards. ### blaxel.toml The agent deployment can be configured via the `blaxel.toml` file in your agent directory. This file is not mandatory; if the file is not found or a required option is not set, you will be prompted for the information during deployment. ```toml theme={null} name = "my-agent" workspace = "my-workspace" type = "agent" public = false agents = [] functions = ["blaxel-search"] models = ["gpt-4o-mini"] [env] DEFAULT_CITY = "San Francisco" [runtime] memory = 1024 [[triggers]] id = "trigger-async-my-agent" type = "http-async" [triggers.configuration] path = "agents/my-agent/async" # This will create this endpoint on the following base URL: https://run.blaxel.ai/{YOUR-WORKSPACE} retry = 1 [[triggers]] id = "trigger-my-agent" type = "http" [triggers.configuration] path = "agents/my-agent/sync" retry = 1 ``` * `name`, `workspace`, and `type` fields are optional and serve as default values. Any bl command run in the folder will use these defaults rather than prompting you for input. * `agents`, `functions`, and `models` fields are also optional. They specify which resources to deploy with the agent. These resources are preloaded during build, eliminating runtime dependencies on the Blaxel control plane and dramatically improving performance. * `public` field specifies if the agent is publicly accessible (defaults to `false`). * `[env]` section defines environment variables that the agent can access via the SDK. Note that these are NOT [secrets](/Agents/Variables-and-secrets). * `[runtime]` section allows to override agent deployment parameters: memory (in MB) to allocate. * `[[triggers]]` and `[triggers.configuration]` sections defines ways to send requests to the agent. You can create both [synchronous and asynchronous](/Agents/Query-agents) trigger endpoints (respectively `type = "http"` or `type = "http-async"`). A private synchronous HTTP endpoint is always created by default, even if you don’t define any trigger here. `DEADLINE_EXCEEDED` or `STARTUP TCP probe failed` errors? Check our [troubleshooting page](/troubleshooting) for possible solutions. See an example of building and deploying an agent on Blaxel with Claude Agent SDK. Learn how to deploy your custom AI agents on Blaxel as a serverless endpoint. # Deploy from GitHub Source: https://docs.blaxel.ai/Agents/Github-integration Automatically deploy your GitHub repository with Blaxel. As your project is ready to go to production, a typical way to manage CI/CD for your agents is to synchronize them with a GitHub repo. You can connect a GitHub repository to Blaxel to automatically deploy updates whenever changes are pushed to the *main* branch. This integration is only available to deploy [agents](Overview). ## Set up GitHub integration The simplest way to start is connecting your GitHub repository through the Blaxel Console. github.webp Requirements: * Authenticate with a GitHub account that **shares the same public email address** as your current Blaxel login This creates a GitHub action in your repository that connects to your Blaxel workspace to automatically launch a deployment when a push is made on the *main* branch. ### Deploy from a specific branch At the moment, you can only deploy from *main*. Reach out to Blaxel if you need to deploy from other branches. # Integrate in your apps Source: https://docs.blaxel.ai/Agents/Integrate-in-apps Integrate and use Blaxel agents in your applications and communication platforms. An agent deployed on Blaxel can be consumed through various downstream applications, including web apps and front-end UIs. ## Integrate in your application You’ll need: * An **API key**: generate an [API key for a service account in your workspace](../Security/Service-accounts). Permissions will be scoped to the permissions given to the service account. * The [**inference URL**](/Agents/Query-agents) for the agent. Use these code snippets to integrate your agent in your JavaScript, TypeScript or Python applications. Make sure to not expose your API key publicly. ```javascript JavaScript theme={null} const response = await fetch("https://run.blaxel.ai/YOUR-WORKSPACE/agents/YOUR-AGENT", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ` }, body: JSON.stringify({ inputs: "Hello, world!" }) }); const data = await response.text(); console.log(data); ``` ```typescript TypeScript theme={null} const response = await fetch("https://run.blaxel.ai/YOUR-WORKSPACE/agents/YOUR-AGENT", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ` }, body: JSON.stringify({ inputs: "Hello, world!" }) }); const data: string = await response.text(); console.log(data); ``` ```python Python theme={null} import requests response = requests.post( "https://run.blaxel.ai/YOUR-WORKSPACE/agents/YOUR-AGENT", headers={ "Content-Type": "application/json", "Authorization": "Bearer " }, json={ "inputs": "Hello, world!" } ) data = response.text print(data) ``` ## Downstream integrations Below you'll find examples of tested integrations that show how to use your agents with external services. Orchestrate Blaxel agents using n8n workflows. # Agents Hosting Source: https://docs.blaxel.ai/Agents/Overview Host custom AI agents built with any Python or TypeScript framework as serverless auto-scalable endpoints on Blaxel, with built-in observability and SDK integrations. Blaxel Agents Hosting lets you bring your agent code **and deploys it as a serverless auto-scalable endpoint** — no matter your development framework. An *AI agent* is any application that leverages generative AI models to take autonomous actions in the real world. These agents often require computing power to execute their interactions. ## Essentials Agents Hosting is a **serverless computing service that allows you to host any application** without having to manage infrastructure. It gives you full observability and tracing out of the box. It doesn't force you into any kind of workflow or shaped box — you can host any app on Blaxel as long as it exposes an HTTP API. This makes Blaxel completely agnostic of the framework used to develop your workflow or agent. Blaxel optimizes the experience specifically for agentic AI use cases, delivering a fully serverless experience even for the longer-running tasks typical of AI agents. For example, telemetry focuses on crucial agent metrics like end-to-end latency and time-to-first-token. ### Main features Some features of running workloads on Agents Hosting: * a default invocation endpoint for synchronous requests * an asynchronous invocation endpoint, for agent workloads lasting from dozens of seconds to 10 minutes * full [logging, telemetry and tracing](/Observability/Overview) — out-of-the-box * revisions manage your agents’ lifecycle across iterations. You can ship as a new revision and rollback instantly * an SDK to connect to other Blaxel resources (like [models](../Models/Overview) and [tools](../Functions/Overview)) with adapters to most popular [agent frameworks](../Tutorials/Agents-Overview) ### Requirements & limitations Agents Hosting have few requirements or limitations: * Agents Hosting only supports applications developed in **Python** and in **TypeScript**. * The only requirement to deploy an app on Agents Hosting is that it exposes an HTTP API server which is bound on `HOST` (for the host) and `PORT` (for the port). **These two environment variables are required for the host+port combo.** * You can use [express](https://expressjs.com/), [fastify](https://fastify.dev/), [FastAPI](https://fastapi.tiangolo.com/), etc. for this. * Agents deployed on Blaxel Agents Hosting have a maximum runtime of 15 minutes. This limit does not apply to [Sandboxes](../Sandboxes/Overview) or [Batch Jobs](../Jobs/Overview), which have their own runtime limits. * The synchronous endpoint closes the connection after **100 seconds** if no data flows through the API. If your agent streams back responses, the connection resets with each chunk streamed. For example, if your agent processes a request for 5 minutes while streaming data, the connection stays open. However, if it goes 100 seconds without sending any data — even while calling external APIs — the connection will close. ## Deploy your agent to Blaxel [Blaxel SDK](../sdk-reference/introduction) provides methods to programmatically access and integrate various resources hosted on Blaxel into your agent's code, such as: [model APIs](../Models/Overview), [tool servers](../Functions/Overview), [sandboxes](../Sandboxes/Overview), [batch jobs](../Jobs/Overview), or [other agents](Overview). The SDK handles authentication, secure connection management and telemetry automatically. This packaging makes Blaxel **fully agnostic of the framework** used to develop your agent and doesn’t prevent you from deploying your software on another platform. Quick-start guide to deploy your existing agent code as a serverless API on Blaxel. Read our full guide for developing AI agents leveraging Blaxel developer tools. Read our full guide on deploying your agent to Blaxel. See an example of building and deploying an agent on Blaxel with Claude Agent SDK. Read tutorials on building and deploying agents on Blaxel using popular frameworks. ## Use your agents in your apps Once your agent is deployed on Blaxel, you can start using it in your applications. Whether you need to process individual inference requests or integrate the agent into a larger application workflow, **Blaxel provides flexible options for interaction**. Learn how to authenticate requests, handle responses, and optimize your agent's performance in production environments. Learn how to run inference requests on your agent. Learn how to integrate and use your Blaxel agents in your downstream applications. ## Operational features Manage environment variables and secrets for your agents. Attach Blaxel Volumes or Agent Drive for persistent storage. Run long-running tasks asynchronously with optional callbacks. Set up automatic deployments from your GitHub repository. # Query an agent Source: https://docs.blaxel.ai/Agents/Query-agents Call deployed agents via synchronous or asynchronous inference endpoints on the Global Agentics Network, with streaming support and configurable timeouts. Agent [deployments](Overview) on Blaxel have a default **inference endpoint** which can be used by external consumers to request an inference execution. This inference endpoint is synchronous so the connection remains open until the end of your request is entirely processed by the agent. You can also query an asynchronous endpoint for agents, allowing to send requests that last for longer times without keeping connections open. All inference requests are routed on the [Global Agentics Network](../Infrastructure/Global-Inference-Network) based on the [deployment policies](../Model-Governance/Policies) associated with your agent deployment. ## Inference endpoints ### Default synchronous endpoint When you deploy an agent on Blaxel, an **inference endpoint** is automatically generated on Global Agentics Network. This endpoint operates synchronously—keeping the connection open until your agent sends its complete response. This endpoint supports both batch and streaming responses, which you can implement in your agent's code. The inference URL looks like this: ```http Query agent theme={null} POST https://run.blaxel.ai/{YOUR-WORKSPACE}/agents/{YOUR-AGENT} ``` Connection limit: * The synchronous endpoint closes the connection after **100 seconds** if no data flows through the API. If your agent streams back responses, the connection resets with each chunk streamed. For example, if your agent processes a request for 5 minutes while streaming data, the connection stays open. However, if it goes 100 seconds without sending any data — even while calling external APIs — the connection will close. * If your request processing is expected to take longer than 100 seconds without streaming data, you should use the asynchronous endpoint or [batch jobs](../Jobs/Overview) instead. ### Asynchronous endpoint In addition to the default synchronous endpoint, Blaxel provides the ability to create **asynchronous endpoints** for handling longer-running agent requests. Screenshot 2025-05-18 at 8.53.14 PM.webp This endpoint allows you to initiate requests without maintaining an open connection throughout the entire processing duration, making it particularly useful for complex or time-intensive operations. Blaxel handles queuing and execution behind the scene. You are responsible for implementing your own method for retrieving the agent's results in your code. You can send results to a webhook, a database, an S3 bucket, etc. You can specify an optional callback URL to receive the result when the background job completes. This endpoint supports requests up to 15 minutes. If your request processing is expected to take longer than this, you should use [batch jobs](../Jobs/Overview) instead. The asynchronous endpoint looks like this: ```http Query agent (async) theme={null} POST https://run.blaxel.ai/{YOUR-WORKSPACE}/agents/{YOUR-AGENT}?async=true ``` You can create async endpoints either from the Blaxel Console, or from your code in the `blaxel.toml` file. For more information, read the [documentation on asynchronous triggers](./Asynchronous-triggers). The agent deployment can be configured via the `blaxel.toml` file in your agent directory. This file is not mandatory; if the file is not found or a required option is not set, you will be prompted for the information during deployment. ```toml theme={null} name = "my-agent" workspace = "my-workspace" type = "agent" public = false agents = [] functions = ["blaxel-search"] models = ["gpt-4o-mini"] [env] DEFAULT_CITY = "San Francisco" [runtime] memory = 1024 [[triggers]] id = "trigger-async-my-agent" type = "http-async" [triggers.configuration] path = "agents/my-agent/async" # This will create this endpoint on the following base URL: https://run.blaxel.ai/{YOUR-WORKSPACE} retry = 1 [[triggers]] id = "trigger-my-agent" type = "http" [triggers.configuration] path = "agents/my-agent/sync" retry = 1 ``` * `name`, `workspace`, and `type` fields are optional and serve as default values. Any bl command run in the folder will use these defaults rather than prompting you for input. * `agents`, `functions`, and `models` fields are also optional. They specify which resources to deploy with the agent. These resources are preloaded during build, eliminating runtime dependencies on the Blaxel control plane and dramatically improving performance. * `public` field specifies if the agent is publicly accessible (defaults to `false`). * `[env]` section defines environment variables that the agent can access via the SDK. Note that these are NOT [secrets](/Agents/Variables-and-secrets). * `[runtime]` section allows to override agent deployment parameters: memory (in MB) to allocate. * `[[triggers]]` and `[triggers.configuration]` sections defines ways to send requests to the agent. You can create both [synchronous and asynchronous](/Agents/Query-agents) trigger endpoints (respectively `type = "http"` or `type = "http-async"`). A private synchronous HTTP endpoint is always created by default, even if you don’t define any trigger here. ### Endpoint authentication By default, agents deployed on Blaxel **aren’t public**. It is necessary to authenticate all inference requests, via a [bearer token](../Security/Access-tokens). The evaluation of authentication/authorization for inference requests is managed by the Global Agentics Network based on the [access given in your workspace](../Security/Workspace-access-control). See how to remove authentication on a deployed agent down below. ### Manage sessions To simulate multi-turn conversations, you can pass on request headers. You'll need your client to generate this ID and pass it using any header which you can retrieve via the code (e.g. `Thread-Id`). Without a thread ID, the agent won't maintain nor use any conversation memory when processing the request. ## Make an agent public To make an agent publicly accessible, add the `public` field to the root of the `blaxel.toml` configuration file, as explained above: ```toml blaxel.toml {7} theme={null} public = true [[triggers]] id = "http" type = "http" [triggers.configuration] path = "/" # This will be translated to https://run.blaxel.ai// ``` ## Make an inference request ### Blaxel API Make a **POST** request to the default inference endpoint for the agent deployment you are requesting, making sure to fill in the authentication token: ```bash theme={null} curl 'https://run.blaxel.ai/YOUR-WORKSPACE/agents/YOUR-AGENT?environment=YOUR-ENVIRONMENT' \ -H 'accept: application/json, text/plain, */*' \ -H 'X-Blaxel-Authorization: Bearer YOUR-TOKEN' \ -H 'X-Blaxel-Workspace: YOUR-WORKSPACE' \ --data-raw $'{"inputs":"Enter your input here."}' ``` Read about [the API parameters in the reference](https://docs.blaxel.ai/api-reference/inference). ### Blaxel CLI The following command will make a default POST request to the agent. ```bash theme={null} bl run agent your-agent --data '{"inputs":"Enter your input here."}' ``` Read about [the CLI parameters in the reference](https://docs.blaxel.ai/cli-reference/bl_run). ### Blaxel console Inference requests can be made from the Blaxel console from the agent deployment’s **Playground** page. See an example of building and deploying an agent on Blaxel with Claude Agent SDK. # Quickstart: run an agent on Blaxel Source: https://docs.blaxel.ai/Agents/Quickstart-agent Deploy and run your existing code as a serverless auto-scalable API. Blaxel Agents Hosting lets you bring your agent code **and deploys it as a serverless auto-scalable endpoint** — no matter your development framework. Follow these steps to get your AI agent up and running on Blaxel. ## 1. Create configuration files At the root of your project repository, create a `blaxel.toml` file for configuration, and a `.env` file for your sensitive [environment variables](/Agents/Variables-and-secrets). **Example `blaxel.toml`:** ```toml theme={null} type = "agent" [runtime] generation = "mk3" memory = 4096 [env] MY_NON_SENSITIVE_ENV = "MY_NON_SENSITIVE_ENV" ``` ## 2. Update host and port in your code Ensure your app listens on the host and port provided by Blaxel. Update your code accordingly: ```tsx TypeScript theme={null} const host = process.env.HOST || "0.0.0.0"; const port = parseInt(process.env.PORT || "80"); ``` ```python Python theme={null} import os host = os.getenv("HOST", "0.0.0.0") port = int(os.getenv("PORT", "80")) ``` ## 3. Authenticate via the CLI [Install the Blaxel CLI](../cli-reference/introduction) and log in to Blaxel using this command: ```bash theme={null} bl login ``` ## 4. Deploy your agent When deploying, there are two possible scenarios: ### Option A: You already have a `Dockerfile` Blaxel will automatically use it to build your agent. Just run: ```bash theme={null} bl deploy ``` ### Option B: No `Dockerfile` Blaxel will detect or read configuration to define an entrypoint when building the agent. In TypeScript, entrypoints are managed in the `scripts` in the `package.json` file at the root of the directory. * `start` : start the agent locally through the TypeScript command, to avoid having to build the project when developing. * `build` : build the project. It is done automatically when deploying. * `prod` : start the agent remotely from the dist folder, the project needs to be have been built before. * `dev` : same as start, but with hotreload. It's useful when developing locally, each file change is reflected immediately. The remaining fields in `package.json` follow standard JavaScript/TypeScript project conventions. Feel free to add any dependencies you need, but keep in mind that `devDependencies` are only used during the build process and are removed afterwards. ```json theme={null} { "name": "name", "version": "1.0.0", "description": "", "keywords": [], "license": "MIT", "author": "cdrappier", "scripts": { "start": "tsx src/index.ts", "prod": "node dist/index.js", "dev": "tsx watch src/index.ts", "build": "tsc" }, "dependencies": { "@ai-sdk/openai": "^1.2.5", "@blaxel/sdk": "0.1.1-preview.9", "ai": "^4.1.61", "fastify": "^5.2.1", "zod": "^3.24.2" }, "devDependencies": { "@types/express": "^5.0.1", "@types/node": "^22.13.11", "tsx": "^4.19.3", "typescript": "^5.8.2" } } ``` You can define an optional `[entrypoint]` section to specify how Blaxel will start your agent. ```toml theme={null} [entrypoint] prod = ".venv/bin/python3 src/agent.py" dev = "npx nodemon --exec uv run python src/agent.py" ``` If not specified, Blaxel will auto-detect settings and configure your agent. Then run: ```bash theme={null} bl deploy ``` ## 5. (Optional) Enable telemetry Instrumentation happens automatically when workloads run on Blaxel. To enable telemetry, simply import the SDK in your project's entry point. ```tsx TypeScript theme={null} import "@blaxel/telemetry"; ``` ```python Python theme={null} import blaxel.core ``` ## 6. (Optional) Run locally with Blaxel CLI If you want to run your agent locally and start using the SDK, make sure the `start` and `dev` scripts are defined, then run: ```bash theme={null} bl serve # or bl serve --hotreload ``` ## 7. Test your agent By default, agents deployed on Blaxel are not public. All agent requests must be authenticated via a [bearer token](../Security/Access-tokens). Requests are made to the agent's [inference endpoint](./Query-agents) via the Blaxel API or Blaxel CLI. ### Blaxel API Make a POST request to the inference endpoint for your agent deployment: ```bash theme={null} curl 'https://run.blaxel.ai/YOUR-WORKSPACE/agents/YOUR-AGENT' \ -H 'Content-Type: application/json' \ -H 'X-Blaxel-Authorization: Bearer YOUR-TOKEN' \ -H 'X-Blaxel-Workspace: YOUR-WORKSPACE' \ -d $'{"inputs":"Enter your input here."}' ``` ### Blaxel CLI Run the following command: ```shell theme={null} bl run agent YOUR-AGENT --data '{"inputs":"Enter your input here."}' ``` Althought deployed agents are private by default, it is possible to [make an agent publicly available](./Query-agents#make-an-agent-public). That’s it! You’re ready to start integrating Blaxel features using the Blaxel SDK. ## Resources Want the complete guide on developing and deploying agents on Blaxel? Check out the following resources: See an example of building and deploying an agent on Blaxel with Claude Agent SDK. Complete guide for using the TypeScript SDK to develop an agent using Blaxel services. Complete guide for using the Python SDK to develop an agent using Blaxel services. Complete guide for deploying AI agents on Blaxel. Complete guide for managing variables and secrets when deploying on Blaxel. # Variables and secrets Source: https://docs.blaxel.ai/Agents/Variables-and-secrets Manage variables and secrets in your job/agent/MCP code. Environment variables are retrieved first from your `.env` file (or any other file you specify when deploying, see down below), and if not found there, from the `[env]` section of `blaxel.toml`. This fallback mechanism allows for two kinds of variables: * secrets * simple environment variables ## Secrets Create a file named `.env` at the root of your project to store secrets. Blaxel will retrieve them from this default location upon deployment (see down below to override). Add the `.env` file to your `.gitignore` to prevent committing sensitive variables. ```bash theme={null} MY_SECRET=123456 ``` You can then use secrets in your code as follows: ```typescript TypeScript theme={null} import { env } from "@blaxel/core"; console.info(env.MY_SECRET); // 123456 ``` ```python Python theme={null} import os os.environ.get('MY_SECRET') ``` ### Use secrets from another env file To separate local *.env* from production, specify a different environment file when deploying your resource to Blaxel using the `--env-file` argument in Blaxel CLI: ```bash theme={null} bl deploy --env-file anyenvfile ``` This allows to specify a different environment file for production secrets instead of relying on the default *.env*, e.g.: * Use `.env` for local development * Use `.env.prod` for production deployment ## Variables You can define variables inside your agent or MCP server in the `blaxel.toml` file at root level of your project. These variables are NOT intended to be use as secrets, but as configuration variables. ```toml blaxel.toml {6} theme={null} name = "..." workspace = "..." type = "function" [env] DEFAULT_CITY = "San Francisco" ``` You can then use it in your code as follows: ```typescript TypeScript theme={null} import { env } from "@blaxel/core"; console.info(env.DEFAULT_CITY); // San Francisco ``` ```python Python theme={null} import os os.environ.get('DEFAULT_CITY') ``` ## Reserved variables The following variables are reserved by Blaxel: `PORT`: Reserved by the system. `PORT` : Port of the HTTP server, it need to be set to allow Blaxel platform to configure it `HOST` : Host of the HTTP server, it need to be set to allow Blaxel platform to configure it Internal URL for Blaxel platform, to avoid linking multiple instance through the Internet `BL_AGENT_${envVar}_SERVICE_NAME` `BL_FUNCTION_${envVar}_SERVICE_NAME` `BL_RUN_INTERNAL_HOSTNAME`: internal run url Override URL to link multiple agents and MCP servers together locally `BL_AGENT_${envVar}_URL` `BL_FUNCTION_${envVar}_URL` Metadata automatically set by Blaxel platform in production `BL_WORKSPACE` : workspace name `BL_NAME` : name of the function or the agent `BL_TYPE` : function or agent Authentication environment variables `BL_CLIENT_CREDENTIALS` : client credentials, used by Blaxel in production with a workspaced service account `BL_API_KEY` : can be set in your code to connect with the platform (locally or from a server not on Blaxel platform) `BL_REGION` : default deployment [region](/Infrastructure/Regions) `BL_LOG_LEVEL` : Log level, default to info, can be set to debug,warn,error `BL_DEBUG_TELEMETRY`: Enable telemetry debug mode, will print each interaction with OpenTelemetry `BL_ENABLE_OPENTELEMETRY`: Enable OpenTelemetry, it's set automatically by the platform in production # Volumes Source: https://docs.blaxel.ai/Agents/Volumes Attach Blaxel Volumes to agents for persistent storage that survives redeployments, configured via blaxel.toml or the Blaxel console. Blaxel Volumes provide persistent storage that persists across agent redeployments. For full documentation on creating, deleting, resizing, and listing volumes, see the [Volumes overview](/Volumes/Overview). ## Attach a volume to an agent You must [create a volume](/Volumes/Overview#create-a-volume) before attaching it to an agent. To use a volume with an agent, add a `[[volumes]]` entry to your `blaxel.toml` and pin the agent to a specific region matching the volume's region. ```toml theme={null} # blaxel.toml type = "agent" name = "my-agent" # Required when attaching volumes — the agent must be in the same region as the volume region = "us-pdx-1" [[volumes]] name = "my-volume" # Must match the name of the created volume mountPath = "/data" # Directory inside the agent container ``` Then deploy (or redeploy) your agent: ```bash theme={null} bl deploy ``` The volume will be mounted at the specified path inside your agent's container. Any files written there will persist across redeployments. Learn how to create and manage volumes. Pre-populate volumes with files for faster environment setup. # Example Applications Source: https://docs.blaxel.ai/Examples/Overview Discover sample applications that you can use as reference or deploy to Blaxel. Discover [our templates on Blaxel’s GitHub repository](https://github.com/blaxel-templates): An AI agent that uses secure sandboxes for automated pull request analysis and code review. A code generation agent that builds applications from natural language and previews them live with hot-reload. An intelligent customer support agent that handles customer inquiries across various communication channels. A customer success agent that autonomously handles technical questions via email (inbound and outbound). A powerful agent for automated social media post generation. # Quickstart: Adapt an existing MCP server for Blaxel Source: https://docs.blaxel.ai/Functions/Adapt-Existing-MCP-server Step-by-step guide to convert an existing stdio-based MCP server to streamable HTTP transport and deploy it on Blaxel. MCP ([Model Context Protocol](https://github.com/modelcontextprotocol)) servers provide tools (individual capabilities for accessing specific APIs or databases) that can be used by AI agents. These servers can be hosted on Blaxel's computing platform and used by AI agents via each server's global endpoint. This quickstart walks you through the process of adapting an existing stdio-based MCP server for deployment on Blaxel using the streamable HTTP transport. ## Install the Blaxel CLI Follow the steps below for your platform. To install Blaxel CLI, you must use [Homebrew](https://brew.sh/): make sure it is installed on your machine. We are currently in the process of supporting additional installers. Check out the cURL method down below for general installation. Install Blaxel CLI by running the two following commands successively in a terminal: ```bash theme={null} brew tap blaxel-ai/blaxel ``` ```bash theme={null} brew install blaxel ``` Install Blaxel CLI by running the following command in a terminal (non-sudo alternatives below): ```bash theme={null} curl -fsSL \\ \\ | BINDIR=/usr/local/bin sudo -E sh ``` If you need a non-sudo alternative (**it will ask you questions to configure**): ```bash theme={null} curl -fsSL \\ \\ | sh ``` If you need to install a specific version (e.g. v0.1.21): ```bash theme={null} curl -fsSL \\ \\ | VERSION=v0.1.21 sh ``` Install Blaxel CLI by running the following command in a terminal (non-sudo alternatives below): ```bash theme={null} curl -fsSL \\ \\ | BINDIR=/usr/local/bin sudo -E sh ``` If you need a non-sudo alternative (**it will ask you questions to configure**): ```bash theme={null} curl -fsSL \\ \\ | sh ``` If you need to install a specific version (e.g. v0.1.21): ```bash theme={null} curl -fsSL \\ \\ | VERSION=v0.1.21 sh ``` For the most reliable solution, we recommend adapting the aforementioned Linux commands by using Windows Subsystem for Linux. First install WSL (Windows Subsystem for Linux) if not already installed. This can be done by: * Opening PowerShell as Administrator * Running: `wsl --install -d Ubuntu-20.04` * Restarting the computer * From the Microsoft Store, install the Ubuntu app * Run the command line using the aforementioned Linux installation process. Make sure to install using **sudo**. Once installed, open a terminal and log in to the Blaxel Console using this command: ```bash theme={null} bl login ``` ## Get the example project This quickstart adapts the simple stdio-based MCP weather server from the [official Model Context Protocol GitHub repository](https://github.com/modelcontextprotocol/). Clone the repository and change to the project working directory: ```bash theme={null} git clone cd quickstart-resources/weather-server-typescript ``` Clone the repository and change to the project working directory: ```bash theme={null} git clone cd quickstart-resources/weather-server-python ``` ## Adapt the server If your MCP server is already configured to use streamable HTTP, you may skip this step. Blaxel uses streamable HTTP as the transport layer for MCP servers deployed on its infrastructure. If your MCP server uses stdio (as in this example), you must adapt it to use streamable HTTP instead. The host name and port for the server to bind to are automatically injected by Blaxel during deployment, as `HOST` and `PORT` environment variables. The changes shown below are illustrative only and based on the [Blaxel MCP server template for TypeScript](https://github.com/blaxel-templates/template-mcp-ts). Add Express to handle HTTP requests and responses: ```bash theme={null} npm install express npm install --save-dev @types/express ``` Here is an example of how you could adapt the existing `src/server.ts` file for a streamable HTTP server. ```tsx theme={null} import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import { z } from "zod"; import express from 'express'; // ... code ... const app = express(); app.use(express.json()); app.post('/mcp', async (req, res) => { const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true, }); res.on('close', () => { transport.close(); }); await server.connect(transport); await transport.handleRequest(req, res, req.body); }); const port = parseInt(process.env.PORT || '8000'); const host = process.env.HOST || '0.0.0.0'; app.listen(port, () => { console.log(`MCP Server running on {host}:${port}/mcp`); }).on('error', error => { console.error('Server error:', error); process.exit(1); }); ``` The changes shown below are illustrative only and based on the [Blaxel MCP server template for Python](https://github.com/blaxel-templates/template-mcp-py). Here is an example of how you could adapt the existing `weather.py` file for a streamable HTTP server. ```python theme={null} from typing import Any import httpx, os from mcp.server.fastmcp import FastMCP # Initialize FastMCP server mcp = FastMCP( "weather", stateless_http=True, host=os.getenv('HOST', "0.0.0.0"), port=os.getenv('PORT', "8000") ) # ... code ... def main(): # Initialize and run the server mcp.run(transport='streamable-http') if __name__ == "__main__": main() ``` ## Create the deployment configuration Blaxel looks for a `blaxel.toml` file to configure the deployment of the MCP server on Blaxel. This file is not mandatory; if the file is not found or a required option is not set, you will be prompted for the information during deployment. Create a new `blaxel.toml` file with the following content: ```toml theme={null} type = "function" [runtime] transport = "http-stream" ``` Blaxel also automatically detects a Dockerfile at the root of the project and uses it to create and deploy a container image of your MCP server. This is a very useful feature that allows you to completely customize the deployment environment for your MCP server, including installing additional system dependencies and using specific versions of libraries or tools. Create a new `Dockerfile` with the following content: ```dockerfile theme={null} FROM node:20-alpine WORKDIR /app RUN apk update \\ && apk add build-base curl ca-certificates COPY . . RUN npm install RUN npm run build EXPOSE 8000 CMD [ "node", "build/index.js" ] ``` ```dockerfile theme={null} FROM python:3.12-slim RUN apt-get update && apt-get install -y --no-install-recommends \\ build-essential curl ca-certificates \\ && rm -rf /var/lib/apt/lists/* RUN curl -LsSf | sh \\ && mv /root/.local/bin/uv /usr/local/bin/uv WORKDIR /app COPY . . RUN uv sync --frozen --no-dev EXPOSE 8000 CMD ["uv", "run", "weather.py"] ``` ## Deploy the MCP server on Blaxel Deploy the server on Blaxel by running the following command: ```bash theme={null} bl deploy ``` Blaxel will handle the build and deployment, producing an HTTPS endpoint on Global Agentics Network. The server endpoint looks like this: ```text theme={null} ``` You can now [connect to this endpoint from any MCP-aware client](/Functions/Invoke-functions). # Code mode Source: https://docs.blaxel.ai/Functions/Code-mode Turn any OpenAPI specification into a code mode MCP server on Blaxel Blaxel supports "code mode" natively, enabling a more efficient way to execute tool calls over MCP. For more information on "code mode" or "code execution with MCP", refer to blog posts by [Cloudflare](https://blog.cloudflare.com/code-mode/) and [Anthropic](https://www.anthropic.com/engineering/code-execution-with-mcp). The typical flow is: 1. The agent receives a user prompt (e.g. "List all pets") 2. It calls `search` to discover relevant endpoints in the OpenAPI spec 3. It calls `execute` with a `fetch()` script targeting the right endpoint 4. Blaxel spins up a sandbox, injects credentials, and runs the code 5. The result flows back to the agent Under the hood: * The agent typically does a search first to find the right endpoint, then executes a `fetch` call. * When an agent calls `search`, code mode evaluates a JavaScript function against the in-memory OpenAPI specification. All `$ref` pointers are auto-resolved so the agent sees the complete schema. * When an agent calls `execute`, the code runs inside an auto-scaling sandbox with a 10-minute idle TTL. ## Deployment Use the following code or Blaxel CLI command to deploy an MCP server in code mode. Replace the `OPENAPI_REFERENCE` variable with the URL to the API specification you want to expose. ```typescript TypeScript theme={null} import { createFunction } from "@blaxel/core"; async function main() { await createFunction({ body: { metadata: { name: "my-api-code-mode", displayName: "API Code Mode", }, spec: { runtime: { image: "blaxel/code-mode:latest", memory: 2048, envs: [ { name: "OPENAPI_REFERENCE", value: "https://petstore3.swagger.io/api/v3/openapi.json" }, ], }, }, }, }); } main().catch((err) => { console.error(err); process.exit(1); }); ``` ```python Python theme={null} import asyncio import sys from blaxel.core.client import client from blaxel.core.client.api.functions.create_function import asyncio as create_function from blaxel.core.client.models.env import Env from blaxel.core.client.models.function import Function from blaxel.core.client.models.function_runtime import FunctionRuntime from blaxel.core.client.models.function_spec import FunctionSpec from blaxel.core.client.models.metadata import Metadata async def main(): await create_function( client=client, body=Function( metadata=Metadata( name="my-api-code-mode", display_name="API Code Mode", ), spec=FunctionSpec( runtime=FunctionRuntime( image="blaxel/code-mode:latest", memory=2048, envs=[ Env( name="OPENAPI_REFERENCE", value="https://petstore3.swagger.io/api/v3/openapi.json", ), ], ), ), ), ) asyncio.run(main()) ``` ```bash Blaxel CLI theme={null} bl apply -f - < Check status: ```bash theme={null} bl get mcp my-api-code-mode ``` Retrieve MCP endpoint url: ```bash theme={null} bl get mcp my-api-code-mode -o json | jq -r '.[] | .metadata.url' ``` Once status shows `DEPLOYED`, any agent can use the MCP server as a tool provider. ## Authentication Code mode MCP servers auto-detects security schemes defined in the OpenAPI spec and maps them to environment variables named `AUTH_`. For example, if the spec defines a scheme called `ApiKeyAuth`, define an environment variable in your deployment schema called `AUTH_APIKEYAUTH` with the corresponding secret: ```yaml theme={null} envs: - name: OPENAPI_REFERENCE value: https://api.example.com/openapi.json - name: AUTH_APIKEYAUTH value: ${secrets.AUTH_APIKEYAUTH} ``` ### Supported auth types | OpenAPI scheme type | Env var usage | | -------------------------- | -------------------------------- | | `http` / `bearer` | `Authorization: Bearer ` | | `http` / `basic` | `Authorization: Basic ` | | `apiKey` (header) | Custom header with the key value | | `apiKey` (query) | Appended as query parameter | | `oauth2` / `openIdConnect` | `Authorization: Bearer ` | Build an agent that connects to a Blaxel MCP server running in code mode using Claude Agent SDK. # Quickstart: Develop a custom MCP server Source: https://docs.blaxel.ai/Functions/Create-MCP-server Develop custom MCP servers in TypeScript or Python using Blaxel SDK, with local testing via MCP Inspector and one-command deployment. MCP servers ([Model Context Protocol](https://github.com/modelcontextprotocol)) provide a toolkit of multiple tools—individual capabilities for accessing specific APIs or databases. These servers can be interacted with using HTTP on the server’s global endpoint. You can develop custom [MCP servers](https://modelcontextprotocol.io/introduction) in TypeScript or Python and deploy them on Blaxel by integrating a few lines of the Blaxel SDK and leveraging our other developer tools ([Blaxel CLI](../cli-reference/introduction), GitHub action, etc.). ## Quickstart It is required to have *npm* (TypeScript) or *uv* (Python) installed to use the following command. You can quickly **initialize a new MCP server from scratch** by using CLI command `bl new`. This initializes a new pre-scaffolded local repo where your entire code can be added. ```bash theme={null} bl new mcp ``` You can test it by running the following command which launches **both** the MCP server and a web application to query it ([MCP Inspector](https://github.com/modelcontextprotocol/inspector), managed by MCP) locally. ```shell TypeScript theme={null} pnpm inspect ``` ```shell Python theme={null} BL_DEBUG=true uv run mcp dev src/server.py ``` The web application is accessible at: [http://127.0.0.1:6274](http://127.0.0.1:6274/). Alternatively, you can just simply [serve the server](/Functions/Deploy-a-function) locally by running `bl serve --hotreload`. ## Develop the MCP server logic If you open the `src/server.ts` file, you'll see the complete server implementation. It follows the MCP server standard, using streamable HTTP as the transport mechanism. The main component you'll need to modify is the tool definition: ```typescript server.ts {13-27} theme={null} import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import "@blaxel/telemetry"; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import express from 'express'; import { z } from 'zod'; // Create an MCP server const server = new McpServer({ name: 'GreetingServer', version: '1.0.0', }); server.registerTool( 'greet', { description: 'Greet someone by name', inputSchema: { name: z.string().optional().default('World')}, outputSchema: { result: z.string() } }, async ({ name }) => { const output = { result: `Hello, ${name}!` }; return { content: [{ type: 'text', text: JSON.stringify(output) }], structuredContent: output }; } ); // Set up Express and HTTP transport const app = express(); app.use(express.json()); app.post('/mcp', async (req, res) => { // Create a new transport for each request to prevent request ID collisions const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true }); res.on('close', () => { transport.close(); }); await server.connect(transport); await transport.handleRequest(req, res, req.body); }); const port = parseInt(process.env.PORT || '80'); const host = process.env.HOST || '0.0.0.0'; app.listen(port, () => { console.log(`MCP Server running on {host}:${port}/mcp`); }).on('error', error => { console.error('Server error:', error); process.exit(1); }); ``` Remember that the `name`, `description`, and *parameters* are crucial—they help your agent understand how your tool functions. If you open the `src/server.py` file, you'll see the complete server implementation. It follows the MCP server standard, using streamable HTTP as the transport mechanism. The main component you'll need to modify is the tool definition: ```python server.py {12-16} theme={null} import os from mcp.server.fastmcp import FastMCP mcp = FastMCP( "GreetingServer", stateless_http=True, host=os.getenv('HOST', "0.0.0.0"), port=os.getenv('PORT', "80") ) # Add a simple tool to demonstrate the server @mcp.tool() def greet(name: str = "World") -> str: """Greet someone by name.""" return f"Hello, {name}!" # Run server with streamable_http transport if __name__ == "__main__": mcp.run(transport="streamable-http") ``` Read our complete guide for deploying your custom MCP server on Blaxel. ## Template directory reference ### blaxel.toml The MCP server deployment can be configured via the ***blaxel.toml*** file in your MCP server directory. This file is not mandatory; if the file is not found or a required option is not set, you will be prompted for the information during deployment. ```toml theme={null} name = "my-mcp-server" workspace = "my-workspace" type = "function" [env] DEFAULT_CITY = "San Francisco" [[triggers]] id = "trigger-my-mcp" type = "http" [triggers.configuration] path = "functions/my-mcp" # This will create this endpoint on the following base URL: https://run.blaxel.ai/{YOUR-WORKSPACE}/ authenticationType = "public" ``` * `name`, `workspace`, and `type` fields are optional and serve as default values. Any bl command run in the folder will use these defaults rather than prompting you for input. * `[env]` section defines environment variables that the MCP server can access via the SDK. Note that these are NOT [secrets](../Agents/Variables-and-secrets). * `[[triggers]]` and `[triggers.configuration]` sections defines ways to send requests to the MCP servers. You can also make them either private (default) or public (`authenticationType = "public"`). Additionally, when developing in Python, you can define an `[entrypoint]` section to specify how Blaxel is going to start your server. ```toml theme={null} ... [entrypoint] prod = ".venv/bin/python3 src/server.py" dev = "npx nodemon --exec uv run python src/server.py" ... ``` * `prod`: this is the command that will be used to serve your MCP server ```bash theme={null} .venv/bin/python3 src/server.py ``` * `dev`: same as prod in dev mode, it will be used with the command `--hotreload`. Example: ```bash theme={null} npx nodemon --exec uv run python src/server.py ``` This `entrypoint` section is optional. If not specified, Blaxel will automatically detect in the MCP server’s content and configure your server’s startup settings. In TypeScript, entrypoints are managed in the `scripts` in the `package.json` file at the root of the directory. * `scripts.start` : start the server locally through the TypeScript command, to avoid having to build the project when developing. * `scripts.build` : build the project. It is done automatically when deploying. * `scripts.prod` : start the server remotely on Blaxel from the dist folder, the project needs to be have been built before. * `scripts.dev` : same as start, but with hotreload. It's useful when developing locally, each file change is reflected immediately. The remaining fields in *package.json* follow standard JavaScript/TypeScript project conventions. Feel free to add any dependencies you need, but keep in mind that devDependencies are only used during the build process and are removed afterwards. Read our complete guide for deploying your custom MCP server on Blaxel. # Deploy custom MCP servers Source: https://docs.blaxel.ai/Functions/Deploy-a-function Host your custom MCP Servers on Blaxel as serverless autoscalable endpoints. Blaxel provides a serverless infrastructure to instantly deploy MCP servers. You receive a global inference endpoint for each deployment, and your workloads are served optimally to dramatically accelerate cold-start and latency. The main way to deploy an MCP server on Blaxel is by **using Blaxel CLI.** ## Deploy an MCP server with Blaxel CLI This section assumes you have developed the MCP server locally, as explained [in this documentation](/Functions/Create-MCP-server), and are ready to deploy it. ### Serve locally Blaxel offers you a way to serve locally either: You can test it by running the following command which launches **both** the MCP server and a web application to query it ([MCP Inspector](https://github.com/modelcontextprotocol/inspector), managed by MCP) locally. ```shell TypeScript theme={null} pnpm inspect ``` ```shell Python theme={null} BL_DEBUG=true uv run mcp dev src/server.py ``` The web application is accessible at: [http://127.0.0.1:6274](http://127.0.0.1:6274/). Alternatively, you can just simply [serve the server](/Functions/Deploy-a-function) locally by running `bl serve --hotreload`. You can serve the MCP server locally in order to make the entrypoint function (by default: `server.ts` / `server.py`) available on a local endpoint. Run the following command to serve the MCP server: ```bash theme={null} bl serve ``` You can then create an MCP Client to communicate with your server. When testing locally, communication happens over stdio, but when deployed on Blaxel, your server will use streamable HTTP instead. Add the flag `--hotreload` to get live changes. ```bash theme={null} bl serve --hotreload ``` ### Deploy on production You can deploy the MCP server in order to make the entrypoint function (by default: `server.ts` / `server.py`) **available on a global hosted endpoint**. When deploying to Blaxel, you get a dedicated endpoint that enforces your [deployment policies](../Model-Governance/Policies). Run the following command to build and deploy the MCP server on Blaxel: ```bash theme={null} bl deploy ``` You can alternatively use `bl push` to build and push the MCP container image to the Blaxel registry without creating or updating the deployment. This is useful for preparing images in advance. You can now [connect to the MCP server](/Functions/Invoke-functions) either from an agent on Blaxel (using the Blaxel SDK), or from an external client that supports HTTP. ```typescript In TypeScript theme={null} // Import tool adapter (in whichever framework format): import { blTools } from "@blaxel/langchain"; // or import { blTools } from "@blaxel/llamaindex"; // or import { blTools } from "@blaxel/mastra"; // or import { blTools } from "@blaxel/vercel"; // or // … const tools = blTools(['blaxel-search']) ``` ```python In Python theme={null} # Import tool adapter (in whichever framework format): from blaxel.pydantic import bl_tools # or from blaxel.langgraph import bl_tools # or from blaxel.crewai import bl_tools # or from blaxel.googleadk import bl_tools # or from blaxel.openai import bl_tools #or # … tools = await bl_tools(['blaxel-search']) ``` Learn how to run tool calls through your MCP server. ### Customize an MCP server deployment You can set custom parameters for an MCP server deployment (e.g. specify the server name, etc.) in the `blaxel.toml` file at the root of your directory. For more information on MCP deployment settings, refer to the reference section down at the bottom of this guide. ### Deploy with a Dockerfile While Blaxel uses predefined, optimized container images to build and deploy your code, you can also deploy your workload using your own [Dockerfile](https://docs.docker.com/reference/dockerfile/). Deploy resources using a custom Dockerfile. ### Deploy multiple resources at once Using a custom Dockerfile allows for [deploying multiple agents & MCPs from the same repository](../Agents/Deploy-multiple) with shared dependencies. Deploy multiple agents & MCP servers with shared context from a single repository. ## Reference for deployment life-cycle ### Maximum runtime * Deployed MCP servers have a maximum runtime of 15 minutes. ### Manage revisions As you iterate on your software development, you will need to update the version of a function that is currently deployed and used by your consumers. Every time you build a new version of your function, this creates a **revision**. Blaxel stores the last 5 revisions for each object. image.webp Revisions are atomic builds of your deployment that can be either deployed (accessible via the inference endpoint) or not. This system enables you to: * **rollback a deployment** to its exact state from an earlier date * create a revision without immediate deployment to **prepare for a future release** * implement progressive rollout strategies, such as **canary deployments** Important: Revisions are not the same as versions. You cannot use revisions to return to a previous configuration and branch off from it. For version control, use your preferred system (such as GitHub) alongside Blaxel. Deployment revisions are updated following a **blue-green** paradigm. The Global Inference Network will wait for the new revision to be completely up and ready before routing requests to the new deployment. You can also set up a **canary deployment** to split traffic between two revisions (maximum of two). image.webp When making a deployment using Blaxel CLI (`bl deploy`), the new traffic routing depends on the `--traffic` option. Without this option specified, Blaxel will automatically deploy the new revision with full traffic (100%) if the previous deployment was the latest revision. Otherwise, it will create the revision without deploying it (0% traffic). ### Code mode Blaxel supports ["code mode"](/Functions/Code-mode) natively, enabling a more efficient way to execute tool calls over MCP. ## Deployment reference The MCP server deployment can be configured via the ***blaxel.toml*** file in your MCP server directory. This file is not mandatory; if the file is not found or a required option is not set, you will be prompted for the information during deployment. ```toml theme={null} name = "my-mcp-server" workspace = "my-workspace" type = "function" [env] DEFAULT_CITY = "San Francisco" [[triggers]] id = "trigger-my-mcp" type = "http" [triggers.configuration] path = "functions/my-mcp" # This will create this endpoint on the following base URL: https://run.blaxel.ai/{YOUR-WORKSPACE}/ authenticationType = "public" ``` * `name`, `workspace`, and `type` fields are optional and serve as default values. Any bl command run in the folder will use these defaults rather than prompting you for input. * `[env]` section defines environment variables that the MCP server can access via the SDK. Note that these are NOT [secrets](../Agents/Variables-and-secrets). * `[[triggers]]` and `[triggers.configuration]` sections defines ways to send requests to the MCP servers. You can also make them either private (default) or public (`authenticationType = "public"`). Additionally, when developing in Python, you can define an `[entrypoint]` section to specify how Blaxel is going to start your server. ```toml theme={null} ... [entrypoint] prod = ".venv/bin/python3 src/server.py" dev = "npx nodemon --exec uv run python src/server.py" ... ``` * `prod`: this is the command that will be used to serve your MCP server ```bash theme={null} .venv/bin/python3 src/server.py ``` * `dev`: same as prod in dev mode, it will be used with the command `--hotreload`. Example: ```bash theme={null} npx nodemon --exec uv run python src/server.py ``` This `entrypoint` section is optional. If not specified, Blaxel will automatically detect in the MCP server’s content and configure your server’s startup settings. In TypeScript, entrypoints are managed in the `scripts` in the `package.json` file at the root of the directory. * `scripts.start` : start the server locally through the TypeScript command, to avoid having to build the project when developing. * `scripts.build` : build the project. It is done automatically when deploying. * `scripts.prod` : start the server remotely on Blaxel from the dist folder, the project needs to be have been built before. * `scripts.dev` : same as start, but with hotreload. It's useful when developing locally, each file change is reflected immediately. The remaining fields in *package.json* follow standard JavaScript/TypeScript project conventions. Feel free to add any dependencies you need, but keep in mind that devDependencies are only used during the build process and are removed afterwards. ### Deployment manifests (advanced usage) When `bl deploy` runs, it generates a YAML configuration manifest automatically and deploys it to Blaxel's hosting infrastructure. You can also create custom manifest files in the `.blaxel` folder and deploy them using the following command: ```bash theme={null} bl apply -f ./my-deployment.yaml ``` Read our [reference for MCP server deployments](https://docs.blaxel.ai/api-reference/functions/get-function-by-name). Learn how to run tool calls on your MCP server. Build an agent that connects to a Blaxel MCP server running in code mode using Claude Agent SDK. # Query MCP servers Source: https://docs.blaxel.ai/Functions/Invoke-functions Connect to MCP servers deployed on Blaxel via streamable HTTP endpoints. Covers authentication, public access, and integration with agents and apps. Blaxel uses **streamable HTTP** as its MCP transport mechanism. MCP servers deployed on Blaxel are only hosted server-side and cannot be installed locally. ## MCP server endpoint When you deploy an MCP server on Blaxel, an **HTTP endpoint** is generated on Global Agentics Network to connect to the server. The server endpoint looks like this: ```http Connect to an MCP server theme={null} https://run.blaxel.ai/{YOUR-WORKSPACE}/functions/{YOUR-SERVER-NAME}/mcp ``` ### Endpoint authentication By default, MCP servers deployed on Blaxel aren’t public. It is necessary to authenticate all connections, via a [bearer token](../Security/Access-tokens). The evaluation of authentication/authorization for messages is managed by the Global Agentics Network based on the [access given in your workspace](../Security/Workspace-access-control). You can make an MCP server **public**, meaning it will bypass Blaxel authentication and you will have to implement your own authentication inside the server. This can be done through the `blaxel.toml` configuration file. The MCP server deployment can be configured via the ***blaxel.toml*** file in your MCP server directory. This file is not mandatory; if the file is not found or a required option is not set, you will be prompted for the information during deployment. ```toml theme={null} name = "my-mcp-server" workspace = "my-workspace" type = "function" [env] DEFAULT_CITY = "San Francisco" [[triggers]] id = "trigger-my-mcp" type = "http" [triggers.configuration] path = "functions/my-mcp" # This will create this endpoint on the following base URL: https://run.blaxel.ai/{YOUR-WORKSPACE}/ authenticationType = "public" ``` * `name`, `workspace`, and `type` fields are optional and serve as default values. Any bl command run in the folder will use these defaults rather than prompting you for input. * `[env]` section defines environment variables that the MCP server can access via the SDK. Note that these are NOT [secrets](../Agents/Variables-and-secrets). * `[[triggers]]` and `[triggers.configuration]` sections defines ways to send requests to the MCP servers. You can also make them either private (default) or public (`authenticationType = "public"`). ### Runtime limit MCP server runtime has a hard limit of 15 minutes. ## Call the MCP server You can connect to your MCP server and send requests in several ways (code samples below): * **use the Blaxel SDK to retrieve tools**: best when developing an agent, particularly when running on Blaxel * **integrate with AI tools**: integrate with AI agents and other MCP-aware tools * **connect from your code directly**: suitable for custom implementations requiring server connection to list and call tools * **connect from the Blaxel Console's Playground**: best for testing and validating server functionality ### Use Blaxel SDK to retrieve tools The following code example demonstrates how to use the Blaxel SDK to retrieve and pass an MCP server’s tools when building an agent. ```typescript In TypeScript theme={null} // Import tool adapter (in whichever framework format): import { blTools } from "@blaxel/langchain"; // or import { blTools } from "@blaxel/llamaindex"; // or import { blTools } from "@blaxel/mastra"; // or import { blTools } from "@blaxel/vercel"; // or // … const tools = blTools(['blaxel-search']) ``` ```python In Python theme={null} # Import tool adapter (in whichever framework format): from blaxel.pydantic import bl_tools # or from blaxel.langgraph import bl_tools # or from blaxel.crewai import bl_tools # or from blaxel.googleadk import bl_tools # or from blaxel.openai import bl_tools #or # … tools = await bl_tools(['blaxel-search']) ``` ### Integrate with AI tools Add the MCP server to MCP-aware applications and tools. This section has instructions for some popular applications. You must provide your [Blaxel API key](../Security) in the `Authorization` header. If you have access to multiple workspaces, include the workspace header as well. * Required: `Authorization: Bearer ` * Optional (multi-workspace): `X-Blaxel-Workspace: ` Add the server to `~/.cursor/mcp.json`: ```json theme={null} { "mcpServers": { "blaxel": { "url": "https://run.blaxel.ai//functions/blaxel-search/mcp", "headers": { "Authorization": "Bearer ", "X-Blaxel-Workspace": "" } } } } ``` [Add the remote HTTP server to your Claude Code](https://docs.anthropic.com/en/docs/claude-code/mcp#option-3%3A-add-a-remote-http-server) by running the following command: ```bash theme={null} claude mcp add --transport http blaxel https://run.blaxel.ai//functions/blaxel-search/mcp \\ --header "Authorization: Bearer " \\ --header "X-Blaxel-Workspace: " ``` Add to `~/.codeium/windsurf/mcp_config.json`: ```json theme={null} { "mcpServers": { "blaxel": { "url": "https://run.blaxel.ai//functions/blaxel-search/mcp", "headers": { "Authorization": "Bearer ", "X-Blaxel-Workspace": "" } } } } ``` Add to `~/.config/goose/config.yaml`: ```yaml theme={null} extensions: blaxel: enabled: true type: streamable_http name: blaxel description: Blaxel MCP uri: https://run.blaxel.ai//functions/blaxel-search/mcp envs: {} env_keys: [] headers: Authorization: Bearer X-Blaxel-Workspace: bundled: null available_tools: [] ``` ### Directly connect from your code Below are snippets of code to connect to an MCP server that is deployed on Blaxel. You will need the following information: * `BL_API_KEY`: an [API key](../Security/Access-tokens) to connect to your Blaxel workspace * `BL_WORKSPACE`: the slug ID for your workspace * `MCP_SERVER_NAME`: the slug name for your MCP server ```typescript In TypeScript theme={null} import { settings } from "@blaxel/core"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; import dotenv from 'dotenv'; // Load environment variables from .env file dotenv.config(); // Initialize client const client = new Client({ name: 'streamable-http-client', version: '2.0.0' }); // Initialize transport const baseUrl = `${settings.runUrl}/${settings.workspace}/functions/blaxel-search/mcp` const transport = new StreamableHTTPClientTransport(new URL(baseUrl), { requestInit: { headers: settings.headers } }); // Connect client to transport await client.connect(transport); // List tools const response = await client.listTools(); console.log(`Tools retrieved, number of tools: ${response.tools.length}`); ``` ```python In Python theme={null} import asyncio from mcp.client.session import ClientSession from mcp.client.streamable_http import streamablehttp_client from blaxel import settings async def run(): """Run the completion client example.""" url = f"{settings.run_url}/{settings.workspace}/functions/blaxel-search/mcp" async with streamablehttp_client(url, settings.headers) as (read, write, _): async with ClientSession(read, write) as session: # Initialize the connection await session.initialize() tools = await session.list_tools() print(f"Tools retrieved, number of tools: {len(tools.tools)}") asyncio.run(run()) ``` Requirements are as follows: ```json package.json (In TypeScript) theme={null} "dependencies": {"@blaxel/core": …} ``` ```txt requirements.txt (In Python) theme={null} python-dotenv blaxel ``` ### Connect to pre-built servers Blaxel’s pre-built MCP servers offer two methods: * `tools/list` : method that **lists the available tools** and their schemas, allowing consumers (you or agents) to discover the function’s capabilities. * `tools/call` : method that lets consumers **execute individual tools**. It requires params with two keys: * `name`: the name of the tool to run, obtained from the listing endpoint above * `arguments`: an object with the key and values of input parameters for the execution, obtained from the listing endpoint above Example of `tools/list` outbound message on a Brave Search toolkit (make sure to fill in the authentication token). ```json theme={null} { "method":"tools/list", "jsonrpc":"2.0", "id":1 } ``` This one returns two tools in the function: ***brave\_web\_search*** and ***brave\_local\_search***. ```json theme={null} { "result": { "tools": [ { "name": "blaxel_web_search", "description": "Performs a web search using the Brave Search API, ideal for general queries, news, articles, and online content. Use this for broad information gathering, recent events, or when you need diverse web sources. Supports pagination, content filtering, and freshness controls. Maximum 20 results per request, with offset for pagination. ", "inputSchema": { "type": "object", "properties": { "query": { "type": "string" }, "count": { "type": "number" }, "offset": { "type": "number" } }, "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } }, { "name": "blaxel_local_search", "description": "Searches for local businesses and places using Brave's Local Search API. Best for queries related to physical locations, businesses, restaurants, services, etc. Returns detailed information including:\n- Business names and addresses\n- Ratings and review counts\n- Phone numbers and opening hours\nUse this when the query implies 'near me' or mentions specific locations. Automatically falls back to web search if no local results are found.", "inputSchema": { "type": "object", "properties": { "query": { "type": "string" }, "count": { "type": "number" } }, "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } } ] }, "jsonrpc": "2.0", "id": "1" } ``` Example of `tools/call` outbound message on the ***brave\_web\_search*** tool. ```json theme={null} { "jsonrpc":"2.0", "id":2, "method":"tools/call", "params":{ "name":"blaxel_web_search", "arguments":{ "query":"What is the current weather in NYC?", "count":1, "offset":1 } } } ``` ### Via Blaxel console Requests to an MCP server can be made from the Blaxel console from the server deployment’s **Playground** page. image.webp # MCP servers Source: https://docs.blaxel.ai/Functions/Overview Deploy MCP servers as serverless APIs to equip your agents with tools. MCP servers (called `functions` in Blaxel API) are lightweight programs that expose specific capabilities (accessing databases, APIs, local files, etc.) through the standardized [Model Context Protocol](https://modelcontextprotocol.io/introduction) (MCP). They are designed to equip [agents](/Agents/Overview) with tools to interact with the world. ## Essentials MCP Server Hosting is a **serverless computing service that allows you to host remote MCP servers** without having to manage infrastructure. It gives you full [observability and tracing](/Observability/Overview) out of the box. You only provide the MCP server code, and Blaxel automates its hosting, execution and scaling - providing you with one single global endpoint to access the MCP server. The deployed server uses streamable HTTP as the transport layer. Blaxel SDK allows to **retrieve the tools from an MCP server in your code**. When both an agent and MCP server run on Blaxel, the tool call in the MCP server is execute separately from the agent logic. This ensures not only optimal resource utilization, but also better design practice for your agentic system. ### Requirements & limitations * Your MCP server must implement streamable HTTP as its transport layer. * Deployed MCP servers have a maximum runtime of 15 minutes. ## MCP hosting on Blaxel Blaxel uses **streamable HTTP** as its MCP transport mechanism. MCP servers deployed on Blaxel are only hosted server-side and cannot be installed locally. For developers interested in the technical details, our implementation is available open-source through [Blaxel's Supergateway](https://github.com/blaxel-ai/supergateway) and [Blaxel's SDK](https://github.com/blaxel-ai/toolkit/blob/main/sdk-ts/src/functions/mcp.ts). There are two routes you can take when hosting MCPs on Blaxel: * Use one of the pre-built MCP servers from the Blaxel Store (e.g. [Google Maps](/Integrations/Google-Maps), [Gmail](/Integrations/Gmail)) * Deploy a custom MCP server from your code, or [adapt an existing stdio-based server](/Functions/Adapt-Existing-MCP-server) for Blaxel Convert a stdio MCP server to streamable HTTP and deploy it. Build a new MCP server from scratch with Blaxel SDK. Host your MCP server on Blaxel as a serverless endpoint. Run tool calls through your deployed MCP server. Turn any OpenAPI spec into a code mode MCP server. Manage environment variables and secrets for MCP servers. ## Related products MCP servers integrate with other Blaxel products. [Agents](/Agents/Overview) use MCP servers as tools, [sandboxes](/Sandboxes/Overview) include a [built-in MCP server](/Sandboxes/MCP) for agent-driven operations, and [model APIs](/Models/Overview) provide the LLM backbone for agent reasoning. See the [SDK reference](/sdk-reference/introduction) for programmatic access. # Variables and secrets Source: https://docs.blaxel.ai/Functions/Variables-and-secrets Manage variables and secrets in your job/agent/MCP code. Environment variables are retrieved first from your `.env` file (or any other file you specify when deploying, see down below), and if not found there, from the `[env]` section of `blaxel.toml`. This fallback mechanism allows for two kinds of variables: * secrets * simple environment variables ## Secrets Create a file named `.env` at the root of your project to store secrets. Blaxel will retrieve them from this default location upon deployment (see down below to override). Add the `.env` file to your `.gitignore` to prevent committing sensitive variables. ```bash theme={null} MY_SECRET=123456 ``` You can then use secrets in your code as follows: ```typescript TypeScript theme={null} import { env } from "@blaxel/core"; console.info(env.MY_SECRET); // 123456 ``` ```python Python theme={null} import os os.environ.get('MY_SECRET') ``` ### Use secrets from another env file To separate local *.env* from production, specify a different environment file when deploying your resource to Blaxel using the `--env-file` argument in Blaxel CLI: ```bash theme={null} bl deploy --env-file anyenvfile ``` This allows to specify a different environment file for production secrets instead of relying on the default *.env*, e.g.: * Use `.env` for local development * Use `.env.prod` for production deployment ## Variables You can define variables inside your agent or MCP server in the `blaxel.toml` file at root level of your project. These variables are NOT intended to be use as secrets, but as configuration variables. ```toml blaxel.toml {6} theme={null} name = "..." workspace = "..." type = "function" [env] DEFAULT_CITY = "San Francisco" ``` You can then use it in your code as follows: ```typescript TypeScript theme={null} import { env } from "@blaxel/core"; console.info(env.DEFAULT_CITY); // San Francisco ``` ```python Python theme={null} import os os.environ.get('DEFAULT_CITY') ``` ## Reserved variables The following variables are reserved by Blaxel: `PORT`: Reserved by the system. `PORT` : Port of the HTTP server, it need to be set to allow Blaxel platform to configure it `HOST` : Host of the HTTP server, it need to be set to allow Blaxel platform to configure it Internal URL for Blaxel platform, to avoid linking multiple instance through the Internet `BL_AGENT_${envVar}_SERVICE_NAME` `BL_FUNCTION_${envVar}_SERVICE_NAME` `BL_RUN_INTERNAL_HOSTNAME`: internal run url Override URL to link multiple agents and MCP servers together locally `BL_AGENT_${envVar}_URL` `BL_FUNCTION_${envVar}_URL` Metadata automatically set by Blaxel platform in production `BL_WORKSPACE` : workspace name `BL_NAME` : name of the function or the agent `BL_TYPE` : function or agent Authentication environment variables `BL_CLIENT_CREDENTIALS` : client credentials, used by Blaxel in production with a workspaced service account `BL_API_KEY` : can be set in your code to connect with the platform (locally or from a server not on Blaxel platform) `BL_LOG_LEVEL` : Log level, default to info, can be set to debug,warn,error `BL_DEBUG_TELEMETRY`: Enable telemetry debug mode, will print each interaction with OpenTelemetry `BL_ENABLE_OPENTELEMETRY`: Enable OpenTelemetry, it's set automatically by the platform in production # OAuth flow for MCP integrations Source: https://docs.blaxel.ai/Functions/oauth-flow-mcp Setup a user-facing OAuth flow to create integration connections on Blaxel. Some Blaxel integrations support [OAuth](https://oauth.net/2/)-based authentication. You can automate such a flow to allow multiple users (tenants) to go through an OAuth flow and each have their integration. This approach is particularly useful when you need to automate the creation of dedicated MCP servers for each tenant with customized access permissions. This guide takes the example of creating such a flow for a [Gmail integration](../Integrations/Gmail). Create MCP integrations for your users with OAuth. # Get started Source: https://docs.blaxel.ai/Get-started Step-by-step quickstart guide to install the Blaxel CLI, create a cloud sandbox, run processes, manage files, and deploy your first AI agent. Blaxel is a **perpetual sandbox platform built for AI agents**. Our computing platform lets you keep infinite, secure sandboxes on automatic standby while co-hosting your agents for near instant latency. **Using Cursor, Claude Code, Codex, Goose, or another AI coding agent?** Install the [Blaxel Skill](./skills-mcp) to give your agent the ability to deploy AI agents, create sandboxes for code execution, host MCP servers, run batch jobs, and more...all using simple prompts, zero code required! ```shell theme={null} npx skills add blaxel-ai/agent-skills ``` ## Quickstart Welcome there! 👋 Make sure you have created an account on Blaxel (here → [https://app.blaxel.ai](https://app.blaxel.ai)), and created a first [workspace](Security/Workspace-access-control) (you’ll need the workspace ID). To install Blaxel CLI, you must use [Homebrew](https://brew.sh/): make sure it is installed on your machine. We are currently in the process of supporting additional installers. Check out the cURL method down below for general installation. Install Blaxel CLI by running the two following commands successively in a terminal: ```shell theme={null} brew tap blaxel-ai/blaxel ``` ```shell theme={null} brew install blaxel ``` Install Blaxel CLI by running the following command in a terminal (non-sudo alternatives below): ```shell theme={null} curl -fsSL \ https://raw.githubusercontent.com/blaxel-ai/toolkit/main/install.sh \ | BINDIR=/usr/local/bin sudo -E sh ``` If you need a non-sudo alternative (**it will ask you questions to configure**): ```shell theme={null} curl -fsSL \ https://raw.githubusercontent.com/blaxel-ai/toolkit/main/install.sh \ | sh ``` If you need to install a specific version (e.g. v0.1.21): ```shell theme={null} curl -fsSL \ https://raw.githubusercontent.com/blaxel-ai/toolkit/main/install.sh \ | VERSION=v0.1.21 sh ``` Install Blaxel CLI by running the following command in a terminal (non-sudo alternatives below): ```shell theme={null} curl -fsSL \ https://raw.githubusercontent.com/blaxel-ai/toolkit/main/install.sh \ | BINDIR=/usr/local/bin sudo -E sh ``` If you need a non-sudo alternative (**it will ask you questions to configure**): ```shell theme={null} curl -fsSL \ https://raw.githubusercontent.com/blaxel-ai/toolkit/main/install.sh \ | sh ``` If you need to install a specific version (e.g. v0.1.21): ```shell theme={null} curl -fsSL \ https://raw.githubusercontent.com/blaxel-ai/toolkit/main/install.sh \ | VERSION=v0.1.21 sh ``` For the most reliable solution, we recommend adapting the aforementioned Linux commands by using Windows Subsystem for Linux. First install WSL (Windows Subsystem for Linux) if not already installed. This can be done by: * Opening PowerShell as Administrator * Running: `wsl --install -d Ubuntu-20.04` * Restarting the computer * From the Microsoft Store, install the Ubuntu app * Run the command line using the aforementioned Linux installation process. Make sure to install using **sudo**. Open a terminal and login to Blaxel using this command: ```bash theme={null} bl login ``` The Blaxel SDK requires two environment variables to authenticate: | Variable | Description | | -------------- | -------------------------- | | `BL_WORKSPACE` | Your Blaxel workspace name | | `BL_API_KEY` | Your Blaxel API key | You can create an API key from the [Blaxel console](https://app.blaxel.ai/profile/security). Your workspace name is visible in the URL when you log in to the console (e.g. `app.blaxel.ai/{workspace}`). Set them as environment variables or add them to a `.env` file at the root of your project: ```bash theme={null} export BL_WORKSPACE=my-workspace export BL_API_KEY=my-api-key ``` When developing locally, you can also **log in to your workspace with Blaxel CLI** (as shown above). This allows you to run Blaxel SDK functions that will automatically connect to your workspace without additional setup. When you deploy on Blaxel, authentication is handled automatically — no environment variables needed. Blaxel is the ultimate toolkit for AI agent builders. Our flagship product is the **sandbox**, although we also offer other services for the rest of your agentic workloads on our infrastructure. Sandboxes are secure, instant-launching compute environments that you can use for running AI code. Blaxel lets you keeps sandboxes on automatic standby with optimized agent hosting for near instant latency. With Blaxel sandboxes, you get: * Automatic scale-to-zero after 5s inactivity, resume from standby under 25ms even after weeks. * Micro-VMs with full access to file system, processes and logs — and native support for Zero Data Retention (ZDR). * Preview URLs with your own custom domain. Sandboxes can be created programmatically using Blaxel SDK. Install the SDK: ```shell Python (pip) theme={null} pip install blaxel ``` ```shell Python (uv) theme={null} uv pip install blaxel ``` ```shell TypeScript (pnpm) theme={null} pnpm install @blaxel/core ``` ```shell TypeScript (npm) theme={null} npm install @blaxel/core ``` ```shell TypeScript (yarn) theme={null} yarn add @blaxel/core ``` ```shell TypeScript (bun) theme={null} bun add @blaxel/core ``` Create your first sandbox: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; async function main() { // Create a new sandbox const sandbox = await SandboxInstance.createIfNotExists({ name: "my-sandbox", image: "blaxel/base-image:latest", // public or custom image memory: 4096, // in MB ports: [{ target: 3000, protocol: "HTTP" }], // ports to expose labels: { env: "dev", project: "my-project" }, // labels region: "us-pdx-1" // deployment region }); console.log("Sandbox created: ", {sandbox}); } main().catch(console.error); ``` ```python Python theme={null} import asyncio from blaxel.core import SandboxInstance async def main(): # Create a new sandbox sandbox = await SandboxInstance.create_if_not_exists({ "name": "my-sandbox", "image": "blaxel/base-image:latest", # public or custom image "memory": 4096, # in MB "ports": [{ "target": 3000 }], # ports to expose "labels": {"env": "dev", "project": "my-project"}, # labels "region": "us-pdx-1" # deployment region }) print(f"Sandbox created: {sandbox}") if __name__ == "__main__": asyncio.run(main()) ``` Read the complete guide for creating & connecting to sandboxes using Blaxel SDK. Or deploy another type of resource: Deploy your agent’s components on a purpose-built computing infrastructure for agentics. In Python, you will need to [have pip installed](https://pip.pypa.io/en/stable/installation/); in TypeScript, you will need to [have npm installed](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) for this. Let’s initialize a first app. The following command initializes a new **pre-scaffolded local repository** ready for developing and deploying your agent on Blaxel. ```bash theme={null} bl new agent ``` You can now develop your agent application using any framework you want (or none), and use the [Blaxel](sdk-reference/introduction) [SDK](sdk-reference) to [leverage other Blaxel deployments](Agents/Develop-an-agent). A placeholder HTTP API server is already preconfigured in `/src/main.py` or `/src/main.ts`. In Python, you will need to [have pip installed](https://pip.pypa.io/en/stable/installation/); in TypeScript, you will need to [have npm installed](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) for this. Let’s initialize a first batch job definition. The following command initializes a new **pre-scaffolded local repository** ready for developing and deploying your job on Blaxel. ```bash theme={null} bl new job ``` You can now develop your job and use the [Blaxel](sdk-reference/introduction) [SDK](sdk-reference) to leverage other Blaxel deployments in `/src/index.py` or `/src/index.ts`. In Python, you will need to [have pip installed](https://pip.pypa.io/en/stable/installation/); in TypeScript, you will need to [have npm installed](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) for this. You can quickly **initialize a new MCP server from scratch** by using CLI command `bl new`. This initializes a new pre-scaffolded local repo where your entire code can be added. ```bash theme={null} bl new mcp ``` You can now [develop your MCP server](Functions/Create-MCP-server) using the [Blaxel](sdk-reference/introduction) [SDK](sdk-reference) in `/src/server.py` or `/src/server.ts`. Run the following command to serve your workload locally, replacing `<>` with the name of the workload's root directory: ```bash theme={null} cd <>; bl serve; ``` Query your agent locally by making a **POST** request to this endpoint: [`http://localhost:1338`](http://localhost:1338) with the following payload format: `{"inputs": "Hello world!"}`: ```bash theme={null} curl -X POST -H "Content-Type: application/json" -d '{"inputs": "Hello world!"}' http://localhost:1338 ``` Execute your job locally by making a **POST** request to this endpoint: [`http://localhost:1338`](http://localhost:1338) with the following payload format: `{"tasks": [{"param1": "value1"}]}` ```bash theme={null} curl -X POST -H "Content-Type: application/json" -d '{"tasks": [{"name": "John"}, {"name": "Jane"}]}' http://localhost:1338 ``` You can test it by running the following command which launches **both** the MCP server and a web application to query it ([MCP Inspector](https://github.com/modelcontextprotocol/inspector), managed by MCP) locally. ```shell TypeScript theme={null} pnpm inspect ``` ```shell Python theme={null} BL_DEBUG=true uv run mcp dev src/server.py ``` The web application is accessible at: [http://127.0.0.1:6274](http://127.0.0.1:6274/). Alternatively, you can just simply [serve the server](Functions/Deploy-a-function) locally by running `bl serve --hotreload`. To **push to Blaxel**, run the following command. Blaxel will handle the build and deployment: ```bash theme={null} bl deploy ``` Your workload is made available as a **serverless auto scalable** **global endpoint** 🌎 . Run an inference from a terminal with the following command: ```bash theme={null} bl chat <> ``` This gives you a chat-like interface where you can interact with your agent. To use this when serving locally, just add option `--local` . Alternatively, **just call the** [global endpoint](Agents/Query-agents). Trigger an execution of your batch job from a terminal by running: ```bash theme={null} # Run a job using Blaxel CLI with --data argument bl run job <> --data '{"tasks": [{"name": "John"}, {"name": "Jane"}]}' ``` Alternatively, **just call the** [global endpoint](Jobs/Overview). When you deploy an MCP server on Blaxel, an **HTTP endpoint** is generated on Global Agentics Network to connect to the server. The server endpoint looks like this: ```http Connect to an MCP server theme={null} https://run.blaxel.ai/{YOUR-WORKSPACE}/functions/{YOUR-SERVER-NAME}/mcp ``` Read more about [how to connect to the server here](Functions/Invoke-functions). ## Next steps You are ready to run AI with Blaxel! Here’s a curated list of guides which may be helpful for you to make the most of Blaxel, but feel free to explore the product on your own! Let your AI coding assistant (Cursor, Claude Code, Windsurf…) create and manage Blaxel resources using natural language. Complete guide for spawning sandboxed VMs for your agents to access. Complete guide for creating and running batch jobs from your agents. Complete guide for deploying AI agents on Blaxel. Complete guide for managing deployment and routing policies on the Global Agentics Network. ## Any question? Although we designed this documentation to be as comprehensive as possible, you are welcome to contact [support@blaxel.ai](mailto:support@blaxel.ai) or the community on [Discord](https://discord.gg/zFcGj77VQx) with any questions or feedback you have. # Custom domains Source: https://docs.blaxel.ai/Infrastructure/Custom-domains Expose Blaxel resources using your own custom domains. Blaxel allows you to connect your own domain names to your Blaxel workspace to use when exposing resources. When you register a domain, you also enable the use of wildcard subdomains for that domain. For example: * If you register `mycompany.com`, you can use any `*.mycompany.com` subdomain to create custom URLs. * If you register `preview.mycompany.com`, you can use any `*.preview.mycompany.com` subdomain to create custom URLs. * And so on. Each domain is uniquely assigned to a region. For example, if `preview.mycompany.com` is registered in region `us-pdx-1`, it is not possible to use it in region `eu-lon-1` (for example) or any other region. In the [Blaxel Console](https://app.blaxel.ai/), navigate to **Network** > **Custom Domains** in the sidebar and add a new custom domain. Then, you'll need to configure DNS records with your domain provider. Finally, verify from within Blaxel: after DNS propagation completes, your custom domain will become fully usable. image.webp ## Use a custom domain Custom domains can currently be used for: * [Sandboxes previews](../Sandboxes/Preview-url) * Agents: coming soon! * MCP servers: coming soon! # Dedicated egress gateways Source: https://docs.blaxel.ai/Infrastructure/Dedicated-egress-gateways Attach dedicated egress IP addresses to your workloads. This feature is currently in private preview and is not intended for production use. In private preview, it has the following limitations: * It is only available in the `us-was-1` region. * It is only available for sandboxes. * Egress gateway assignment is only possible at sandbox creation time. * Egress gateway removal is only possible by deleting the corresponding sandbox. For more information, [contact us on Discord](https://discord.com/channels/1333316050330058895/1333319876831612928) or [request access](https://blaxel.ai/contact?message=I%20want%20to%20get%20preview%20access%20to%20dedicated%20egress%20IPs%20for%20the%20following%20use%20case%3A). Dedicated egress gateways enable customers to exclusively attach IP addresses to sandboxes within their workspace. This makes it possible to whitelist outbound traffic from Blaxel's systems for use in downstream providers and eliminates the need for workarounds such as self-hosted proxy servers or VPNs. A single egress IP address supports up to 32,000 sandboxes. It is also possible to group IP addresses into pools to automatically load-balance outbound traffic for high-demand workloads. Sandboxes that do not have a dedicated egress gateway will use the shared [public IP addresses](./Regions#public-ip-addresses) instead. ## Order an egress gateway Egress gateway configuration takes place from the [Blaxel Console](https://app.blaxel.ai). * Navigate to **Network** > **Egress gateways**. * Click the **Order IP** button in the top right corner. List IPs * Select the quantity and egress gateway region. Order IPs Provisioning is automated and typically completes within a few minutes. ## Assign an egress gateway to a sandbox Once provisioning is complete, you can attach the assigned egress gateway when creating one or more sandboxes. All outbound traffic from the attached sandboxes will then originate from this unique address. You can assign an egress gateway to a sandbox at creation time via the Blaxel Console. ### Blaxel Console When creating a new sandbox via the Blaxel Console, use the **Egress IP** drop-down to assign an available egress gateway to that sandbox. Only egress gateways in the same region as the new sandbox are shown for assignment. Assign IP # Generations Source: https://docs.blaxel.ai/Infrastructure/Gens Overview of Blaxel infrastructure generations from Mark 1 through Mark 3, including microVM-based architecture with near-instant cold starts. By default, deployed workloads run on Mark 3 infrastructure. Mark 3 infrastructure leverages microVMs to run with critical-low cold-starts. Mark 3 infrastructure is currently available to run the following workloads: * [sandboxes](../Sandboxes/Overview) * [agents](../Agents/Overview) * [MCP servers](../Functions/Overview) * [batch jobs](../Jobs/Overview) ## What about Mark 1 Mark 1 infrastructure was originally designed for serverless ML model inference but proved inadequate for running agentic workloads. Built on Knative Custom Resource Definitions (CRDs) running atop managed Kubernetes clusters, it leveraged KNative Serving’s scale-to-zero capabilities and Kubernetes’ container orchestration features. The infrastructure utilized pod autoscaling through the Knative Autoscaler (KNA). It also allowed to federate multiple clusters via a Blaxel agent that would offload inference requests from one Knative cluster to another based on a usage metric. While it demonstrated reasonable stability even at 20+ requests per second and achieved somewhat acceptable cold starts through runtime optimization, its architecture wasn’t suited for the more lightweight workloads that make up most of autonomous agents: tool calls, agent orchestration, and external model routing. Mark 1 infrastructure was decommissioned in January 2025. ## What about Mark 2 Mark 2 infrastructure used containers to run workloads, providing emulation of most Linux system calls. Cold starts typically took between 2 and 10 seconds. After a deployment was queried, it stayed warm for a period that varies based on overall infrastructure usage, allowing it to serve subsequent requests instantly. Mark 2 infrastructure was suitable when: * your workload required system calls not supported by Mk 3 infrastructure * boot times of around 5 seconds was suitable for your needs * your deployment received consistent traffic that keeps it running warm * you needed to run workloads in specific regions for sovereignty or regulatory compliance using [deployment policies](../Model-Governance/Policies) * you required revision control for rollbacks or canary deployments Mark 2 infrastructure was deprecated in Q4 2025. # Regions Source: https://docs.blaxel.ai/Infrastructure/Regions Available deployment regions for Blaxel infrastructure including Oregon, Virginia, London, and Frankfurt, with guidance on resource-specific region selection. Blaxel is available in many regions across the globe. Some types of resources can be deployed ‘globally’ over multiple regions (for example: [agents](../Agents/Overview)), while some other types are deployed only in one specific region (for example: [sandboxes](../Sandboxes/Overview)). This guide details the available regions for [Mark 3 infrastructure generation](/Infrastructure/Gens). ## Available regions The following regions are available for [Mark 3 infrastructure generation](/Infrastructure/Gens): | **Region code** | **Location** | **Country** | | --------------- | -------------- | -------------- | | `us-pdx-1` | Oregon | United States | | `us-was-1` | North Virginia | United States | | `eu-lon-1` | London | United Kingdom | | `eu-fra-1` | Frankfurt | Germany | All regions are not necessarily available in self-service by default. Please [contact us](http://blaxel.ai/contact?message=I+would+like+to+get+access+to+region+XYZ+because+\&purpose=regions\&origin=docs) if you would like access to a specific region. ## Selecting a region for deployment When deploying a resource on Blaxel, you sometimes have the option to choose the deployment region. This depends on the type of resource, as explained below. For all resource types, the deployment region **is always subject to the** [deployment policies](../Model-Governance/Policies) applied to the resource or workspace. A resource will never be deployed in a region that is prohibited by an existing deployment policy. ### Resources which are globally distributed over multiple regions This is the case of: * [agents](../Agents/Overview) * [MCP servers](../Functions/Overview) * [batch jobs](../Jobs/Overview) **When deploying** For these types of resources, you don't need to specify a region during deployment. The resource becomes available across all regions allowed by applicable [deployment policies](../Model-Governance/Policies). However, you can optionally **pin an agent or MCP server to a specific region** by setting the `region` field in your [`blaxel.toml`](/deployment-reference). This is required when you want to [attach volumes to an agent](../Agents/Deploy-an-agent#attach-volumes-to-an-agent), since volumes are regional resources and the agent must run in the same region. ```toml blaxel.toml theme={null} region = "us-pdx-1" ``` **When requesting** For these types of resources, you receive a global query endpoint that automatically routes to the optimal region as determined by Blaxel's Global Agentics Network. ### Resources which are deployed in one specific region * [sandboxes](../Sandboxes/Overview) (and their [preview URLs](../Sandboxes/Preview-url)) **When deploying** For these types of resources, you can **optionally specify** a region during deployment, provided it is allowed by applicable [deployment policies](../Model-Governance/Policies). If you do not specify a region, Blaxel will deploy the resource automatically on a default region determined to be optimal. **When requesting** For these types of resources, you receive a regional query endpoint (which contains the name of the region in the domain). ## Public IP addresses If you need to whitelist traffic from your Blaxel deployments, you can retrieve the current [list of public IP addresses](/api-reference/publicips:list/list-public-ips#list-public-ips) used by Blaxel through the Blaxel API. IP addresses are returned as CIDR ranges per region, and the results list can also be filtered by adding a `region` parameter to the API query (only for [Mark 3 infrastructure](/Infrastructure/Gens#mark-3-infrastructure)). Here is an example API request: ```shell theme={null} curl --request GET \ --url https://api.blaxel.ai/v0/publicIps?region=us-was-1 \ --header 'Authorization: Bearer ' ``` # Integrations Source: https://docs.blaxel.ai/Integrations Create agents that connect to private systems, LLMs, SaaS, databases, and APIs. **Blaxel Integrations** enable you to let Blaxel resources access various external APIs, private networks and AI services, and to connect to downstream interfaces such as your applications. With integrations, you can **manage access control, credentials, and observability** across different providers and systems from a single platform. Blaxel supports integration with: * LLM providers like OpenAI or Anthropic * APIs and SaaS for agents’ tools like Slack or GitHub * gateways for tools/agents * downstream applications All integrations must be configured by a [workspace admin](Security/Workspace-access-control) in the Integrations section of the workspace settings before they can be used by team members. [oauth-flow](Integrations/oauth-flow) ## All integrations ### LLM APIs These integrations allow to connect your agents to LLMs from top providers, while controlling access and cost. [OpenAI](Integrations/OpenAI) [Anthropic](Integrations/Anthropic) [MistralAI](Integrations/MistralAI) [Cohere](Integrations/Cohere) [xAI](Integrations/xAI) [DeepSeek](Integrations/DeepSeek) [Azure-AI-Foundry](Integrations/Azure-AI-Foundry) [HuggingFace](Integrations/HuggingFace) **AWS Bedrock** **Gemini** **Google Vertex AI** ### Tools and APIs These integrations allow to equip your agents with tools to access APIs, SaaS and databases. [**AgentMail**](https://agentmail.to/) [**Airweave**](https://airweave.ai/) **AWS S3** **AWS SES** **Brave Search** **Cloudflare** **Dall-E** **Discord** **Exa** **GitHub** **GitLab** [Google-Maps](Integrations/Google-Maps) [Gmail](Integrations/Gmail) **HubSpot** **Linear** **Linkup** [**Nia**](https://app.trynia.ai/sign-in?redirect_url=https://app.trynia.ai/) **Notion** **PostgreSQL** **Qdrant** **Sendgrid** **Shopify** **Slack** **Smartlead** **Snowflake** **Supabase** **Tavily** **Telegram** **Trello** **Twilio** ### Frameworks Blaxel lets you bring agents developed in many of the most popular AI agent frameworks, optimizing how your agent builds and runs no matter how you coded it. [OpenClaw](Tutorials/OpenClaw) [Claude Agent SDK](Tutorials/Claude-Agent-SDK-Index) [CrewAI](Tutorials/CrewAI) [Google ADK](Tutorials/ADK) [LangChain](Tutorials/LangChain) [LlamaIndex](Tutorials/LlamaIndex) [Mastra](Tutorials/Mastra) [n8n](Tutorials/n8n) [OpenAI Agents SDK](Tutorials/OpenAI-Agents) [PydanticAI](Tutorials/PydanticAI) [Vercel AI SDK](Tutorials/Vercel-AI) [Custom agents](Tutorials/Custom-Agents) ### Integrate in your applications These integrations allow to **expose or use Blaxel resources** in downstream applications, gateways and marketplaces. [AgentMail](Integrations/AgentMail) [Rippletide](Integrations/Rippletide) # AgentMail Source: https://docs.blaxel.ai/Integrations/AgentMail Build an intelligent assistant that answers technical queries via email This example shows how to integrate agentic inbox provider [AgentMail](https://agentmail.to/) with Blaxel to create a customer success agent that autonomously handles technical questions via email (inbound and outbound). ## Requirements To use this example, you'll need: * the unique username for your AgentMail inbox * an AgentMail API key ## Create an AgentMail inbox and API key From your AgentMail dashboard, create a new inbox, providing a unique username (by default, the domain is set to `agentmail.to`): inbox.webp From the same dashboard, obtain an API key: api.webp ## Configure the project Clone the [example repository](https://github.com/blaxel-templates/template-agentmail-docbot) and follow the instructions provided. Note that you must configure the following environment variables for your deployment: ```bash theme={null} INBOX_USERNAME= # a unique username for your inbox AGENTMAIL_API_KEY= # your AgentMail API key ``` Create a `.env` file in the project root with these variables, or set them in your deployment environment. ## Deploy the agent [Deploy the agent](../Agents/Deploy-an-agent) on Blaxel. Once the agent is deployed, retrieve its [inference endpoint](../Agents/Query-agents). deployment.webp You will need an API key to query the agent externally. Follow [this guide to create a service account in your workspace and generate an API key](../Security/Service-accounts). Complete documentation for using AgentMail. # Anthropic integration Source: https://docs.blaxel.ai/Integrations/Anthropic Set up the Anthropic integration on Blaxel to call Claude models through a unified endpoint with centralized access control and observability. The Anthropic integration allows Blaxel users to **call Anthropic models using a Blaxel endpoint** in order to unify access control, credentials and observability management. The integration must be set up by an [admin](../Security/Workspace-access-control) in the Integrations section in the [workspace settings](../Security/Workspace-access-control). ## Set up the integration In order to use this integration, you must register an Anthropic access token into your Blaxel workspace settings. The scope of this access token (i.e. the Anthropic workspace it is allowed to access) will be the scope that Blaxel has access to. First, generate an [Anthropic API key](https://docs.anthropic.com/en/api/getting-started) from [your Anthropic organization settings](https://console.anthropic.com/settings/keys). Select the workspace to use for this key. On Blaxel, in Workspace Settings > Anthropic integration, create a new connection and paste this token into the “API key” section. image.webp ## Connect to an Anthropic model Once you’ve set up the integration in the workspace, any workspace member can use it to reference an Anthropic model as an [external model API](../Models/External-model-apis). When creating a model API, select Anthropic. You can search for any model from the Anthropic catalog. image.webp After the model API is created, you will receive a dedicated global Blaxel endpoint to call the model. Blaxel will forward inference requests to Anthropic, using your Anthropic credentials for authentication and authorization. Because your own credentials are used, any inference request on this endpoint will incur potential costs on your Anthropic account, as if you queried the model directly on Anthropic. # Azure AI Foundry integration Source: https://docs.blaxel.ai/Integrations/Azure-AI-Foundry Connect your agents to LLMs deployed in Azure AI Inference, Azure OpenAI Service, and Azure AI Services. The Azure AI Foundry integration allows Blaxel users to **call models deployments from [Azure AI Foundry](https://learn.microsoft.com/en-us/azure/ai-studio/what-is-ai-studio) services** (Azure AI Inference, Azure OpenAI Service, and Azure AI Services) through a Blaxel endpoint that unifies access control, credentials and observability management. There are 2 types of integrations related to this service: * **Azure AI Inference**: connect to a model endpoint deployed as an “Azure AI Services” model on Azure. This typically includes OpenAI models. * **Azure AI Marketplace**: connect to a model deployed from the Azure Marketplace. This typically includes Llama models. The integration must be set up by an [admin](../Security/Workspace-access-control) in the Integrations section in the [workspace settings](../Security/Workspace-access-control). ## Azure AI Inference ### Set up the integration In order to use this integration, you must register an Azure AI Inference endpoint and access key into your Blaxel workspace settings. First, go to the [Azure AI Foundry console](https://ai.azure.com/build/overview), and open your project. Select the “Azure AI Inference” capability, and retrieve both: * the **API key** * the **Azure AI model inference endpoint** azure1.webp On Blaxel, in Workspace Settings > Azure AI Inference integration, create a new connection and paste the endpoint and the Access token there. Screenshot 2025-01-31 at 2.29.05 PM.webp ### Connect to a model Once you’ve set up the integration in the workspace, any workspace member can use it to reference an “Azure AI Services” model as an [external model API](../Models/External-model-apis). When creating a model API, select “Azure AI Inference”. Then, input the **name** of your model just as it is deployed on Azure. azure2.webp azure3.webp After the model API is created, you will receive a dedicated global Blaxel endpoint to call the model. Blaxel will forward inference requests to Azure, using your Azure credentials for authentication and authorization. Because your own credentials are used, any inference request on this endpoint will incur potential costs on your Azure account, as if you queried the model directly on Azure. ## Azure AI Marketplace ### Set up the integration & connect to a model In order to use this integration, you must register an Azure endpoint and access token into your Blaxel workspace settings. The difference with most other model API integrations is that the integration will be tied to your model. First, go to the [Azure AI Foundry console](https://ai.azure.com/build/overview), and open your project. Go to your models, and open the model you want to connect to. Retrieve: * the **API key** * the **Azure AI model inference endpoint** azure4.webp On Blaxel, in Workspace Settings > Azure Marketplace integration, create a new connection and paste this token into the “Access token” section. image.webp Once you’ve set up the integration in the workspace, any workspace member can use it to connect to the model as an [external model API](../Models/External-model-apis). When creating a model API, select Azure Marketplace, input the name of the endpoint as you want it on Blaxel, and finish creating the model. image.webp After the model API is created, you will receive a dedicated global Blaxel endpoint to call the model. Blaxel will forward inference requests to Azure, using your Azure credentials for authentication and authorization. Because your own credentials are used, any inference request on this endpoint will incur potential costs on your Azure account, as if you queried the model directly on Azure. # Cohere integration Source: https://docs.blaxel.ai/Integrations/Cohere Set up the Cohere integration on Blaxel to call Cohere models through a unified endpoint with centralized access control and observability. The Cohere integration allows Blaxel users to **call Cohere models using a Blaxel endpoint** in order to unify access control, credentials and observability management. The integration must be set up by an [admin](../Security/Workspace-access-control) in the Integrations section in the [workspace settings](../Security/Workspace-access-control). ## Set up the integration In order to use this integration, you must register a Cohere access token into your Blaxel workspace settings. First, generate a [Cohere API key](https://docs.cohere.com/v2/docs/rate-limits) from [the Cohere platform](https://dashboard.cohere.com/api-keys). On Blaxel, in Workspace Settings > Cohere integration, create a new connection and paste this token into the “API key” section. Screenshot 2024-12-06 at 2.13.40 PM.webp ## Connect to an Cohere model Once you’ve set up the integration in the workspace, any workspace member can use it to reference a Cohere model as an [external model API](../Models/External-model-apis). When creating a model API, select Cohere. You can search for any model from the Cohere catalog. Screenshot 2024-12-06 at 2.14.58 PM.webp After the model API is created, you will receive a dedicated global Blaxel endpoint to call the model. Blaxel will forward inference requests to Cohere, using your Cohere credentials for authentication and authorization. Because your own credentials are used, any inference request on this endpoint will incur potential costs on your Cohere account, as if you queried the model directly on Cohere. # DeepSeek integration Source: https://docs.blaxel.ai/Integrations/DeepSeek Set up the DeepSeek integration on Blaxel to call DeepSeek models through a unified endpoint with centralized access control and observability. The DeepSeek integration allows Blaxel users to **call DeepSeek models using a Blaxel endpoint** in order to unify access control, credentials and observability management. The integration must be set up by an [admin](../Security/Workspace-access-control) in the Integrations section in the [workspace settings](../Security/Workspace-access-control). ## Set up the integration In order to use this integration, you must register an DeepSeek access token into your Blaxel workspace settings. First, generate an DeepSeek API key from [your DeepSeek console](https://platform.deepseek.com/api_keys). On Blaxel, in Workspace Settings > DeepSeek integration, create a new connection and paste this token into the “API key” section. image.webp ## Connect to an DeepSeek model Once you’ve set up the integration in the workspace, any workspace member can use it to reference an DeepSeek model as an [external model API](../Models/External-model-apis). When creating a model API, select DeepSeek. You can search for any model from the DeepSeek catalog. image.webp After the model API is created, you will receive a dedicated global Blaxel endpoint to call the model. Blaxel will forward inference requests to DeepSeek, using your DeepSeek credentials for authentication and authorization. Because your own credentials are used, any inference request on this endpoint will incur potential costs on your DeepSeek account, as if you queried the model directly on DeepSeek. # Gmail Source: https://docs.blaxel.ai/Integrations/Gmail Integrate Gmail services into your agents for email communication capabilities. The *Gmail integration* allows you to equip your agents with tools to interact with Gmail services, enabling email communication and message processing within your applications. ## Set up the integration In order to use this integration, you must sign-in to your Google account. This will create an integration to Gmail in your workspace settings. ### Single tenant Create the integration yourself from Blaxel Console. image.webp ### Multi-tenant Follow [this guide](/Integrations/oauth-flow) to learn how to automate the creation of dedicated Gmail integrations through a user-facing OAuth flow. Create integrations for your users with OAuth. ## Create a Gmail function Once you’ve set up the integration in the workspace, any workspace member can use it to create a Gmail [function](../Functions/Overview). When creating a function, select Gmail. After the function is created, you will receive a dedicated global Blaxel endpoint to call it. ### Available tools This integration provides the following tools: * `send_email`: Send an email using Gmail. No sender will be needed, it use a default configuration. You just have to set the recipient as an email string address inside the parameter "to", a subject and a body in string format # Google Maps Source: https://docs.blaxel.ai/Integrations/Google-Maps Integrate Google Maps services into your agents for location-based capabilities. The *Google Maps integration* allows to equip your agents with tools to interact with Google Maps services, enabling location-based functionalities and geographic data processing within your applications. ## Set up the integration In order to use this integration, you must register a Google Cloud Platform (GCP) API access token. The scope of this access token will be the scope that Blaxel has access to. First, generate a GCP API key from [your GCP 'API & Services' section](https://console.cloud.google.com/apis/credentials). Then on Blaxel, in the workspace settings, in the *Google Maps* integration, paste this token into the “API key” section. image.webp ## Create a Google Maps function Once you’ve set up the integration in the workspace, any workspace member can use it to create a Google Maps [function](../Functions/Overview). When creating a function, select Google Maps. After the function is created, you will receive a dedicated global Blaxel endpoint to call it. ### Available tools This integration provides the following tools: * `maps_geocode`: Convert an address into geographic coordinates * `maps_reverse_geocode`: Convert coordinates into an address * `maps_search_places`: Search for places using Google Places API * `maps_place_details`: Get detailed information about a specific place * `maps_distance_matrix`: Calculate travel distance and time for multiple origins and destinations * `maps_elevation`: Get elevation data for locations on the earth * `maps_directions`: Get directions between two points # HuggingFace integration Source: https://docs.blaxel.ai/Integrations/HuggingFace Deploy public or private AI models from HuggingFace. The [HuggingFace](https://huggingface.co/) integration enables Blaxel users to **connect to [serverless endpoints](https://huggingface.co/docs/api-inference/en/index) from HuggingFace**—whether public, gated, or private—directly through their agents on Blaxel. The integration is bidirectional, letting you create new [deployments](https://huggingface.co/docs/inference-endpoints/index) on HuggingFace from the Blaxel console to use as [model APIs](../Models/External-model-apis). The integration must be set up by an [admin](../Security/Workspace-access-control) in the Integrations section in the [workspace settings](../Security/Workspace-access-control). ## Set up the integration In order to use this integration, you must register a HuggingFace access token into your Blaxel workspace settings. The scope of this access token (i.e. the HuggingFace resources it is allowed to access) will be the scope that Blaxel has access to. First, generate a [HuggingFace access token](https://huggingface.co/docs/hub/security-tokens) from [your HuggingFace settings](https://huggingface.co/settings/tokens). Give this access token the scope that you want Blaxel to access on HuggingFace (e.g. repositories, etc.). On Blaxel, in the workspace settings, in the *HuggingFace* integration, paste this token into the “API key” section. hf-integration.webp ## Connect to a HuggingFace model Once you’ve set up the integration in the workspace, any workspace member can use it to reference a HuggingFace model as an [external model API](../Models/External-model-apis). ### Public and private models When [creating a model API](../Models/Overview) on Blaxel, select “HuggingFace”. You can search for: * any **public model** from [Inference API (serverless)](https://huggingface.co/docs/api-inference/index) * any **private model** from [Inference Endpoints (dedicated)](https://huggingface.co/docs/inference-endpoints/index) in the organizations & repositories allowed by the integration’s token. image.webp After the model API is created, you will receive a dedicated global Blaxel endpoint to call the model. Blaxel will forward inference requests to HuggingFace, using your HuggingFace credentials for authentication and authorization. ### Gated models If the model you're trying to connected to is [gated](https://huggingface.co/docs/hub/models-gated), you'll **first need to request access on HuggingFace,** and accept their terms and conditions of usage (if applicable). Access to some HuggingFace models is granted immediately after request, while others require manual approval. When the model gets deployed, Blaxel will check if the **integration token is allowed access to the model** on HuggingFace. If you have not been allowed access, the model deployment will fail in error. ## Create a HuggingFace Inference Endpoint You can deploy a model in HuggingFace’s [Inference Endpoints](https://huggingface.co/docs/inference-endpoints/index) directly from the Blaxel console when creating a new [external model API](../Models/External-model-apis). image.webp * **Organization**: select the HuggingFace namespace in which the endpoint will be deployed * **Model**: select the model to deploy * **Instance**: choose the type (GPU) and size of the instance to use for the deployment. Blaxel will trigger a deployment on Google Cloud Platform with default auto-scaling parameters. * **Endpoint**: enter the name for your endpoint on HuggingFace This action will incur costs on your HuggingFace subscription, depending on the choice of instance selected. Once you launch a deployment, it will be available in your HuggingFace console, as well as your Blaxel console. You will receive a dedicated global Blaxel endpoint to call the model which proxies the requests to the HuggingFace endpoint and enforces token usage control and observability. # Mistral AI integration Source: https://docs.blaxel.ai/Integrations/MistralAI Set up the Mistral AI integration on Blaxel to call Mistral models through a unified endpoint with centralized access control and observability. The Mistral AI integration allows Blaxel users to **call Mistral AI models using a Blaxel endpoint** in order to unify access control, credentials and observability management. The integration must be set up by an [admin](../Security/Workspace-access-control) in the Integrations section in the [workspace settings](../Security/Workspace-access-control). ## Set up the integration In order to use this integration, you must register a Mistral AI access token into your Blaxel workspace settings. First, generate a Mistral AI API key from [your Mistral AI La Plateforme settings](https://console.mistral.ai/api-keys/). On Blaxel, in Mistral AI integration, create a new connection and paste this token into the “API key” section. image.webp ## Connect to an Mistral AI model Once you’ve set up the integration in the workspace, any workspace member can use it to reference a Mistral AI model as an [external model API](../Models/External-model-apis). When creating a model API, select Mistral AI. You can search for any model from the Mistral AI catalog. After the model API is created, you will receive a dedicated global Blaxel endpoint to call the model. Blaxel will forward inference requests to Mistral AI, using your Mistral AI credentials for authentication and authorization. Because your own credentials are used, any inference request on this endpoint will incur potential costs on your Mistral AI account, as if you queried the model directly on Mistral AI. # OpenAI integration Source: https://docs.blaxel.ai/Integrations/OpenAI Set up the OpenAI integration on Blaxel to call OpenAI models through a unified endpoint with centralized access control and observability. The OpenAI integration allows Blaxel users to **call OpenAI models using a Blaxel endpoint** in order to unify access control, credentials and observability management. The integration must be set up by an [admin](../Security/Workspace-access-control) in the Integrations section in the [workspace settings](../Security/Workspace-access-control). ## Set up the integration In order to use this integration, you must register an OpenAI access token into your Blaxel workspace settings. The scope of this access token (i.e. the OpenAI resources it is allowed to access) will be the scope that Blaxel has access to. First, generate an [OpenAI API key](https://platform.openai.com/docs/api-reference/authentication) from [your OpenAI Platform settings](https://platform.openai.com/api-keys). Set this API key in `Read-only` mode. On Blaxel, in Workspace Settings > OpenAI integration, create a new connection and paste this token into the “API key” section. Screenshot 2024-12-06 at 10.41.25 AM.webp ## Connect to an OpenAI model Once you’ve set up the integration in the workspace, any workspace member can use it to reference an OpenAI model as an [external model API](../Models/External-model-apis). When creating a model API, select OpenAI. You can search for any model from the OpenAI catalog. Screenshot 2024-12-06 at 10.46.23 AM.webp After the model API is created, you will receive a dedicated global Blaxel endpoint to call the model. Blaxel will forward inference requests to OpenAI, using your OpenAI credentials for authentication and authorization. Because your own credentials are used, any inference request on this endpoint will incur potential costs on your OpenAI account, as if you queried the model directly on OpenAI. # Rippletide Source: https://docs.blaxel.ai/Integrations/Rippletide Ensure agent safety and trust with guardrails and secure execution. This integration combines [Rippletide](https://www.rippletide.com/) with Blaxel to ensure agent safety and trust. Rippletide's hypergraph database ensures agents respect guardrails and prevent hallucinations, while Blaxel provides secure sandboxes for agent code execution, enabling reliable and trusted agent deployments. ## Requirements To use this example, you'll need a Rippletide API key, which you can obtain at [https://eval.rippletide.com](https://eval.rippletide.com). ## Clone the example repository Clone the [example repository](https://github.com/blaxel-templates/template-rippletide-customer-support) and follow the instructions provided to install dependencies. ## Customize the knowledge base Update the files in the `knowledge-base` directory with business- or scenario-specific information and workflows. The agent will use this information to respond to customer enquiries and to transition between workflow states. ## Create an agent Configure the following environment variable in order to obtain an agent ID: ```bash theme={null} RIPPLETIDE_API_KEY= # your Rippletide API key ``` Create an agent: ```bash theme={null} uv run src/setup.py ``` Once your agent is created, the setup process will return an agent ID. Create a `.env` file in the project root with both variables, or set them in your deployment environment. ```bash theme={null} RIPPLETIDE_API_KEY= # your Rippletide API key RIPPLETIDE_AGENT_ID= # your Rippletide agent ID ``` ## Deploy the agent [Deploy the agent](../Agents/Deploy-an-agent) on Blaxel. Once the agent is deployed, retrieve its [inference endpoint](../Agents/Query-agents). You will need an API key to query the agent externally. Follow [this guide to create a service account in your workspace and generate an API key](../Security/Service-accounts). Complete documentation for using Rippletide. # OAuth flow for integrations Source: https://docs.blaxel.ai/Integrations/oauth-flow Setup a user-facing OAuth flow to create integration connections on Blaxel. Some Blaxel integrations support [OAuth](https://oauth.net/2/)-based authentication. You can automate such a flow to allow multiple users (tenants) to go through an OAuth flow and each have their integration. This approach is particularly useful when you need to automate the creation of dedicated MCP servers for each tenant with customized access permissions. This guide takes the example of creating such a flow for a [Gmail integration](/Integrations/Gmail). ## **Prerequisites** * A Google OAuth application configured with the scope [`https://www.googleapis.com/auth/gmail.send`](https://www.googleapis.com/auth/gmail.send) (see below for guide) * Client ID and Client Secret from your OAuth app * A backend server to handle the OAuth flow ### 1. Create the APP * Go to [https://console.cloud.google.com/auth/clients](https://console.cloud.google.com/auth/clients) [](https://lh7-rt.googleusercontent.com/docsz/AD_4nXcFD1le5fn-eMiyTjOee-bHWxp1UjI1AGyCszco9b-mdjaIoN1mnDtOmKbEAW8LsocvYGiroJJwCi_SHFgzKLwYoHoG5UweSDlS3Smm-r0f0RMvr85KCx4Rp_6MdhwweRdRcBpeaQ?key=Pe48uQJwhyRkAD1JsBWU4Q) * Select *Web application* * Choose a name. It will be displayed when your user logins through Google * The redirect URIs will be the URL where your user will be redirected to after Google authorizes the request. It must be server-side as it will need to access secret credentials. Finish creating the application. You’ll be given you a *client\_id* and *client\_secret:* keep them securely. ### 2. Configure scope Scopes are used to request sufficient access on the user’s account. In this example, we want to connect his account to the MCP server to send emails. * Go to Data access [](https://lh7-rt.googleusercontent.com/docsz/AD_4nXcikg83r7fMeZkFl_4JM0evSGUH7oj_EsJtMMjYHwrtiHZrq_1smDrui7kpxbPy-Vqj9-Y6P0pazODg1vPxG5S_Rh5eeqADVjatdfXqukuKc9kx6rGYNbnmnAsnIZfQCOdCxlBmJw?key=Pe48uQJwhyRkAD1JsBWU4Q) * Click on “Add or remove scopes” * Add `gmail.send` [](https://lh7-rt.googleusercontent.com/docsz/AD_4nXeiuINtnWLiOcK94UIMLCoqc7N7L-gQRtvXdKcTmab1yvTpLTwWZ_jvw8fy1ygeONhm8lRsKnTjP_-M6xuzOh-wE0FAm7_qgtgMAAQnP00Y0IVXOvCGt2aT3Inf-tUxvwUclvbi?key=Pe48uQJwhyRkAD1JsBWU4Q) Some scopes (like this one) require an HTTPS callback URL. You won’t be able to test them easily locally without using *ngrok* or a similar tool which allows you to have an HTTPS URL bound to your localhost. By default, it will work with your own account without any review by Google. You can look for the Audience tab on left to add more users. To make it global, you will need to launch a review process from Google with the “Publish app” button. **We recommend creating a separate OAuth flow specifically for the Gmail integration.** Don't simply add the Gmail scope to an existing OAuth flow, as this would require all users to grant email permissions even when they don't need Gmail functionality. ## **Overview of the OAuth flow** The integration follows this redirect pattern: ```text theme={null} UI → Your Backend → Google → Your Backend → UI ``` ## **Step-by-step guide** ### **Step 1: User initiates connection** * In your app’s UI, user clicks a button to “connect with Google” (or equivalent) during integration setup * UI redirects to your backend OAuth endpoint ### **Step 2: Backend initiates Google OAuth** Your backend should redirect to Google's OAuth URL with these parameters: **Required Scopes:** * `https://www.googleapis.com/auth/gmail.send` * `openid` * `profile` * `email` **OAuth URL:** ```text theme={null} https://accounts.google.com/o/oauth2/auth?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope=email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.send+openid+profile&response_type=code&access_type=offline ``` ### **Step 3: Google authorization** * Google prompts user to login and approve requested scopes * Google redirects back to your redirect\_uri with a temporary authorization code ### **Step 4: Exchange Code for Tokens** Your backend exchanges the authorization code for access and refresh tokens: **Example: Token Exchange (Python)** ```python theme={null} import requests import json def exchange_code_for_tokens(auth_code, client_id, client_secret, redirect_uri): """ Exchange authorization code for access and refresh tokens """ token_url = "https://oauth2.googleapis.com/token" data = { 'code': auth_code, 'client_id': client_id, 'client_secret': client_secret, 'redirect_uri': redirect_uri, 'grant_type': 'authorization_code' } try: response = requests.post(token_url, data=data) response.raise_for_status() token_data = response.json() return { 'access_token': token_data['access_token'], 'refresh_token': token_data['refresh_token'], 'expires_in': token_data['expires_in'] } except requests.exceptions.RequestException as e: print(f"Token exchange failed: {e}") if hasattr(e.response, 'json'): print(f"Error details: {e.response.json()}") raise ``` **Example: cURL request** ```bash theme={null} curl -X POST https://oauth2.googleapis.com/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "code=AUTHORIZATION_CODE" \ -d "client_id=YOUR_CLIENT_ID" \ -d "client_secret=YOUR_CLIENT_SECRET" \ -d "redirect_uri=YOUR_REDIRECT_URI" \ -d "grant_type=authorization_code" ``` ### **Step 5: Create integration** Once you have the refresh token, create the integration on Blaxel (for an MCP server in this case) with these parameters: ```bash theme={null} // Create the integration connection on blaxel (store the secrets values) curl -X POST https://api.blaxel.ai/v0/integrations/connections \ -H "Content-Type: application/json" \ -H "X-Blaxel-Workspace: YOUR_WORKSPACE_ID" -H "Authorization: Bearer BL_API_KEY" \ -d '{ "metadata": { "name": "gmail-google-oauth", "displayName": "Gmail Google OAuth Connection" }, "spec": { "integration": "gmail", "secret": { "CLIENT_ID": "your-google-client-id.apps.googleusercontent.com", "CLIENT_SECRET": "your-google-client-secret", "REFRESH_TOKEN": "user-refresh-token-from-oauth" } } }' ``` **Parameters Required:** * `CLIENT_ID`: Your Google OAuth application client ID * `CLIENT_SECRET`: Your Google OAuth application client secret * `REFRESH_TOKEN`: The refresh token obtained from the OAuth flow You can then create the [actual MCP server](../Functions/Overview) that uses this integration connection: ```bash theme={null} // Create the MCP binded to the integration connection curl -X POST https://api.blaxel.ai/v0/functions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer BL_API_KEY" \ -H "X-Blaxel-Workspace: YOUR_WORKSPACE_ID" -d '{ "metadata": { "name": "gmail-mcp-server", "displayName": "Gmail MCP Server" }, "spec": { "type": "mcp", "integrationConnections": ["gmail-google-oauth"], "runtime": { "type": "mcp" } } }' ``` ### **Step 6: Complete Integration** * Save MCP configuration in your system * Redirect user back to frontend with success confirmation * Integration is now ready for use ## **Troubleshooting** * **Invalid scope error**: Ensure Gmail API is enabled in Google Cloud Console * **Redirect URI mismatch**: Verify redirect URI matches exactly in Google OAuth app settings * **Token refresh issues**: Check that `access_type=offline` is included in initial OAuth request # xAI integration Source: https://docs.blaxel.ai/Integrations/xAI Set up the xAI integration on Blaxel to call xAI models through a unified endpoint with centralized access control and observability. The xAI integration allows Blaxel users to **call xAI models using a Blaxel endpoint** in order to unify access control, credentials and observability management. The integration must be set up by an [admin](../Security/Workspace-access-control) in the Integrations section in the [workspace settings](../Security/Workspace-access-control). ## Set up the integration In order to use this integration, you must register an xAI access token into your Blaxel workspace settings. First, generate an [xAI API key](https://docs.x.ai/docs/tutorial#step-2-generate-an-api-key) from [your xAI team console](https://console.x.ai/team/default/api-keys). This key must have access to at least the *Chat* and *Models* endpoints. On Blaxel, in Workspace Settings > xAI integration, create a new connection and paste this token into the “API key” section. Screenshot 2024-12-06 at 2.18.45 PM.webp ## Connect to an xAI model Once you’ve set up the integration in the workspace, any workspace member can use it to reference an xAI model as an [external model API](../Models/External-model-apis). When creating a model API, select xAI. You can search for any model from the xAI catalog. image.webp After the model API is created, you will receive a dedicated global Blaxel endpoint to call the model. Blaxel will forward inference requests to xAI, using your xAI credentials for authentication and authorization. Because your own credentials are used, any inference request on this endpoint will incur potential costs on your xAI account, as if you queried the model directly on xAI. # Deploy jobs Source: https://docs.blaxel.ai/Jobs/Deploy-a-job Deploy your batch jobs on Blaxel as serverless autoscalable endpoints. This guide assumes you have developed a job locally. The [Blaxel SDK](../sdk-reference/introduction) allows you to connect to and orchestrate other resources (such as model APIs, tool servers, multi-agents) during development, and ensures telemetry, secure connections to third-party systems or private networks, smart global placement of workflows, and much more when jobs are deployed. The Blaxel SDK requires two environment variables to authenticate: | Variable | Description | | -------------- | -------------------------- | | `BL_WORKSPACE` | Your Blaxel workspace name | | `BL_API_KEY` | Your Blaxel API key | You can create an API key from the [Blaxel console](https://app.blaxel.ai/profile/security). Your workspace name is visible in the URL when you log in to the console (e.g. `app.blaxel.ai/{workspace}`). Set them as environment variables or add them to a `.env` file at the root of your project: ```bash theme={null} export BL_WORKSPACE=my-workspace export BL_API_KEY=my-api-key ``` When developing locally, you can also **log in to your workspace with Blaxel CLI** (as shown above). This allows you to run Blaxel SDK functions that will automatically connect to your workspace without additional setup. When you deploy on Blaxel, authentication is handled automatically — no environment variables needed. ## Deploy on production You can deploy the job in order to make the entrypoint function (by default: `index.ts` / `server.py`) **callable on a global endpoint**. When deploying to Blaxel, you get a dedicated endpoint that enforces your [deployment policies](../Model-Governance/Policies). Run the following command to build and deploy a local job on Blaxel: ```bash theme={null} bl deploy ``` You can alternatively use `bl push` to build and push the job container image to the Blaxel registry without creating or updating the deployment. This is useful for preparing images in advance. ## Run a job Each deployed job has an HTTP endpoint to trigger a batch execution. You can find this endpoint in the Blaxel console, on the detail page for your deployed job. HTTP endpoints are only available for deployed jobs. You can invoke a job in multiple ways: * using the Blaxel SDK, API, or language-native HTTP client (only for deployed jobs); * using the Blaxel CLI; * scheduling it to run periodically via a cron. ### **SDK** Start batch job execution using the SDK: ```tsx TypeScript theme={null} import { blJob } from "@blaxel/core"; const JOB_NAME = "YOUR_JOB_NAME"; // ex : my-job (not the display name) async function execJob() { const job = blJob(JOB_NAME); let result = await job.run([{"name": "John"}, {"name": "Jane"}]) console.log(result); } execJob().catch(console.error); ``` ```python Python (asynchronous) theme={null} from blaxel.core.jobs import bl_job import asyncio async def exec_job(): try: job = bl_job("YOUR_JOB_NAME"); result = await job.arun([{"name": "John"}, {"name": "Jane"}]) print(result) except Exception as e: print(f"Failed to execute job: {e}") asyncio.run(exec_job()) ``` ```python Python (synchronous) theme={null} from blaxel.core.jobs import bl_job def exec_job(): try: job = bl_job("YOUR-JOB-NAME"); result = job.run([{"name": "John"}, {"name": "Jane"}]) print(result) except Exception as e: print(f"Failed to execute job: {e}") exec_job() ``` ### **API** Start batch job execution by [calling the inference API for your deployed batch job](../api-reference/inference). Here is an example using `curl`: ```http Execute a job theme={null} curl -X POST "https://api.blaxel.ai/$(bl workspace --current)/jobs/{your-job-name}/executions" \ -H "Content-Type: application/json" \ -H "X-Blaxel-Workspace: $(bl workspace --current)" \ -H "X-Blaxel-Authorization: Bearer $(bl token)" \ -d '{"tasks":[{"name":"John"},{"name":"Jane"}]}' ``` Here is an example using a language-native HTTP client: ```tsx TypeScript theme={null} async function execJob() { console.log("Executing job"); const WORKSPACE = "YOUR_WORKSPACE_NAME"; // ex : my-workspace (not the display name) const JOB_NAME = "YOUR_JOB_NAME"; // ex : my-job (not the display name) const response = await fetch(`https://api.blaxel.ai/${WORKSPACE}/jobs/${JOB_NAME}/executions`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Blaxel-Authorization': `Bearer ${process.env.BL_API_KEY}`, 'X-Blaxel-Workspace': WORKSPACE }, body: JSON.stringify({ tasks: [ { "name": "John" }, { "name": "Jane" } ] }) }); if(response.status !== 200) { console.error(`Failed to execute job : ${response.statusText}`); return; } const result = await response.json(); console.log(result); } execJob().catch(console.error); ``` ```python Python theme={null} import os import aiohttp import asyncio async def exec_job(): workspace = "YOUR_WORKSPACE_NAME" # ex : my-workspace (not the display name) job_name = "YOUR_JOB_NAME" # ex : my-job (not the display name) api_key = os.environ.get("BL_API_KEY") try: async with aiohttp.ClientSession() as session: print("Executing job") resp = await session.post( f"https://api.blaxel.ai/{workspace}/jobs/{job_name}/executions", json={ "tasks": [ { "name": "John" }, { "name": "Jane" } ] }, headers={ "Content-Type": "application/json", "X-Blaxel-Authorization": f"Bearer {api_key}", "X-Blaxel-Workspace": workspace } ) data = await resp.text() print(data) except Exception as e: print(f"Failed to execute job: {e}") asyncio.run(exec_job()) ``` ### **CLI** For deployed jobs, you can start a batch job execution by running: ```bash theme={null} # Run a deployed job using Blaxel CLI with --data argument bl run job <> --data '{"tasks": [{"name": "John"}, {"name": "Jane"}]}' # Run a deployed job using Blaxel CLI with --file argument bl run job <> --file batches/sample-batch.json ``` When running a job locally, only JSON file input is currently supported, and you must include the `--local` argument: ```bash theme={null} # Run a job locally using Blaxel CLI with --local and --file argument bl run job <> --local --file batches/sample-batch.json ``` You can cancel a job execution from the Blaxel Console or via API. ### **Cron schedule** Set a job on a cron schedule by adding the following to the `blaxel.toml` configuration file (read full reference on *blaxel.toml* down below): ```toml theme={null} [[triggers]] id = "cron-trigger" type = "cron" [triggers.configuration] schedule = "0 * * * *" ``` ### Retries You can set a maximum number of **retries per task** in the job definition. Check out the reference for `blaxel.toml` configuration file down below. ### Metrics The **Blaxel Console** > **Dashboard** displays detailed job metrics, including the number of active jobs, failures, and requests (both count and requests per second (RPS)) across all deployments. image ## Deploy with a Dockerfile While Blaxel uses predefined, optimized container images to build and deploy your code, you can also deploy your workload using your own [Dockerfile](https://docs.docker.com/reference/dockerfile/). Deploy resources using a custom Dockerfile. ## Deploy multiple jobs at once Using a custom Dockerfile allows for [deploying multiple jobs from the same repository](/Jobs/Deploy-multiple-jobs) with shared dependencies. Deploy multiple jobs with shared context from a single repository. ## Template directory reference ### Overview ```text theme={null} package.json # Mandatory. This file is the standard package.json file, it defines the entrypoint of the project and dependencies. blaxel.toml # This file lists configurations dedicated to Blaxel to customize the deployment. tsconfig.json # This file is the standard tsconfig.json file, only needed if you use TypeScript. src/ └── index.ts # This file is the standard entrypoint of the project. It is where the core logic of the job is implemented. └── steps # This is an example of organization for your sub steps, feel free to change it. ``` ### package.json Here the most notable imports are the scripts. They are used for the `bl serve` and `bl deploy` commands. ```json theme={null} { "name": "job-ts", "version": "1.0.0", "description": "Job using Blaxel Platform", "main": "src/index.ts", "keywords": [], "license": "MIT", "author": "Blaxel", "scripts": { "start": "tsx src/index.ts", "prod": "node dist/index.js", "build": "tsc" }, "dependencies": { "@blaxel/core": "0.2.5", "@blaxel/telemetry": "0.2.5" }, "devDependencies": { "@types/express": "^5.0.1", "@types/node": "^22.13.11", "tsx": "^4.19.3", "typescript": "^5.8.2" } } ``` Depending of what you do, all of the `scripts` are not required. With TypeScript, all 4 of them are used. * `start` : start the job locally through the TypeScript command, to avoid having to build the project when developing. * `prod` : start the job remotely from the dist folder, the project needs to be have been built before. * `build` : build the project. It is done automatically when deploying. The remaining fields in package.json follow standard JavaScript/TypeScript project conventions. Feel free to add any dependencies you need, but keep in mind that devDependencies are only used during the build process and are removed afterwards. ### blaxel.toml The deployment can be configured via the `blaxel.toml` file in your agent directory. This file is not mandatory; if the file is not found or a required option is not set, you will be prompted for the information during deployment. ```toml theme={null} type = "job" name = "my-job" workspace = "my-workspace" policies = ["na"] [env] DEFAULT_CITY = "San Francisco" [runtime] memory = 1024 maxConcurrentTasks = 10 timeout = 900 maxRetries=0 [[triggers]] id = "cron-trigger" type = "cron" [triggers.configuration] schedule = "0 * * * *" tasks = [ { p_id = "1234", arg2 = "foo" }, { p_id = "5678", arg2 = "bar" } ] ``` * `name`, `workspace`, and `type` fields are optional and serve as default values. Any bl command run in the folder will use these defaults rather than prompting you for input. * `policies` fields is also optional. It allow you to specify a Blaxel [policy](../Model-Governance/Policies) to customize the deployment. For example, deploy it only in a specific region of the world. * `[env]` section defines environment variables that the job can access via the SDK. Note that these are NOT secrets. * `[runtime]` section allows to override job execution parameters: maximum number of concurrent tasks, maximum number of retries for each task, timeout (in s), or memory (in MB) to allocate. * `[tasks]` sections allows to specify * `[[triggers]]` and `[triggers.configuration]` sections defines ways to schedule job executions. * `type = "cron"` lets you create a cron schedule for the job to run periodically. The job will be executed without any argument by default. You can override this by passing: * `tasks = [{my_arg="my_value"}]` containing a list of task to execute at each occurence of the cron (default value is one task, without arguments) A private HTTP endpoint to launch job executions is always available by default, even if you don't define a trigger in this file. You can launch a job execution by sending a POST request with the correct job and workspace arguments to `https://api.blaxel.ai/v0/jobs/my-job/executions?workspace=my-workspace`. # Deploy with a Dockerfile Source: https://docs.blaxel.ai/Jobs/Deploy-dockerfile-jobs Ship your AI batch job on Blaxel using a custom Dockerfile. Blaxel allows you to customize your deployments ([agents](../Agents/Overview), [MCP servers](../Functions/Overview), and [batch jobs](Overview)) using a Dockerfile at the root level of your project. ## Overview By default, Blaxel builds and deploys your application using predefined container images optimized for agent workloads. However, you may need to: * Install additional system dependencies * Configure custom environment settings * Use specific versions of runtime environments * Include proprietary libraries or tools A Dockerfile at the root of your project gives you full control over the container image that will run your workload on Blaxel's infrastructure. 1. Navigate to the root directory of your Blaxel project ([agent](../Agents/Overview), [MCP server](../Functions/Overview), or [batch job](Overview)) 2. Create a file named `Dockerfile` (case-sensitive) ## Dockerfile Structure Your Dockerfile should follow these guidelines for compatibility with Blaxel's infrastructure: ```Dockerfile Python theme={null} # Start from a base Python image FROM python:3.12-slim # Set working directory WORKDIR /blaxel # Install system dependencies (if needed) RUN apt-get update && apt-get install -y \\ build-essential \\ # Add any other system dependencies here \\ && rm -rf /var/lib/apt/lists/* # Copy requirements first for better caching COPY pyproject.toml uv.lock /blaxel/ RUN pip install uv && uv sync --refresh # Copy application code COPY . . # Set env variable to use the virtual environment ENV PATH="/blaxel/python/.venv/bin:$PATH" # Command to run when container starts, it need to provide a server running on port 80 for agent and MCP server ENTRYPOINT [".venv/bin/python3", "-m", "src"] ``` ```Dockerfile TypeScript/JavaScript theme={null} # Start from a Node.js base image FROM node:22-alpine # Set working directory WORKDIR /blaxel # Copy package files for better caching COPY package.json pnpm-lock.yaml /blaxel/ RUN npx pnpm install # Copy application code COPY . . # Command to run when container starts, it need to provide a server running on port 80 for agent and MCP server ENTRYPOINT ["npx", "pnpm", "start"] ``` ### Entrypoint The entrypoint must run a function that terminates - if it runs infinitely, your job will continue until it hits the execution timeout. ### Environment variables [Environment variables](../Agents/Variables-and-secrets) configured in the Blaxel platform will be automatically injected into your container at runtime. You do not need to specify them in your Dockerfile. ## Test locally Before deploying to Blaxel, you can test your Dockerfile locally. ```bash theme={null} # Build the Docker image docker build -t my-blaxel-app . # Run the container locally docker run -p 1338:1338 my-blaxel-app ``` ## Deploy When a Dockerfile is present at the root of your project, Blaxel will use it to build a custom container image for your deployment. Deploy your application with the Blaxel CLI as usual. ```bash theme={null} bl deploy ``` ## Deploy multiple resources with shared files Using a custom Dockerfile allows for [deploying multiple jobs from the same repository](/Jobs/Deploy-multiple-jobs) with shared dependencies. Deploy multiple jobs with shared context from a single repository. # Deploy multiple resources Source: https://docs.blaxel.ai/Jobs/Deploy-multiple-jobs Deploy multiple batch jobs with shared context from a mono-repo. You can use a **shared context from a same single repository** to deploy multiple resources, mixing [batch jobs](Overview), [agents](../Agents/Overview), [MCP servers](../Functions/Overview), etc. ## Deploying multiple resources With the `--directory` (`-d`) parameter in `bl deploy`, you can specify a subfolder containing your `blaxel.toml` and `Dockerfile`. The `Dockerfile` defines how your deployment context is built and as such is required if you want to ensure proper mounting of shared dependencies between your different services. This enables such mono-repo structure with shared libraries: ```text theme={null} myrepo |- myjob |- src |- blaxel.toml |- Dockerfile |- myagent |- src |- blaxel.toml |- Dockerfile |- myotheragent |- src |- blaxel.toml |- Dockerfile |- mymcpserver |- src |- blaxel.toml |- Dockerfile |- shared |- sharedfile ``` No changes are required to your `blaxel.toml`. However, in your `Dockerfile`, paths **must be relative** to the root context. For example, replace `COPY src src` with`COPY myagent/src src` This allows you to reference shared resources: ```dockerfile theme={null} COPY myagent/src src COPY shared shared ``` ### Deploy To deploy, run these commands from the root folder: ```bash theme={null} bl deploy -d myjob bl deploy -d myagent bl deploy -d myotheragent bl deploy -d mymcpserver ``` For a complete example, see our [sample repository](https://github.com/drappier-charles/multiagent). # Develop a job Source: https://docs.blaxel.ai/Jobs/Develop-a-job Initialize, develop, and locally test batch processing jobs using the Blaxel CLI and SDK in TypeScript or Python. Jobs allow you to run many AI tasks in parallel using batch processing. Read the [introduction for a lexicon on jobs, tasks, and executions](Overview). ## Quickstart It is required to have *npm* (TypeScript) *or uv* (Python) installed to use the following command. You can quickly **initialize a new job from scratch** by using the CLI command `bl new job`. ```bash theme={null} bl new job ``` This will create a pre-scaffolded local directory where your entire code can be added. In the generated folder, you'll find a boilerplate job with multiple steps in the entrypoint file `src/index.ts` / `src/main.py`. You can update this boilerplate job to your specific requirements, and manage and control job execution using the Blaxel [TypeScript](/Jobs/Manage-job-execution-ts) or [Python](/Jobs/Manage-job-execution-py) SDKs. The template used to generate the boilerplate job is available in Blaxel's public GitHub repository ([TypeScript](https://github.com/blaxel-templates/template-jobs-ts) / [Python](https://github.com/blaxel-templates/template-jobs-py)). Start the job locally: ```bash theme={null} # Run the job with a sample batch file bl run job <> --local --file batches/sample-batch.json # Or directly with --data argument bl run job <> --local --data '{"tasks": [{"name": "John"}]}' # Or without blaxel CLI pnpm start --name John ``` See a sample implementation of a job using Blaxel's TypeScript SDK See a sample implementation of a job using Blaxel's Python SDK Learn how to deploy your AI batch jobs on Blaxel as a serverless auto-scalable endpoint. # Manage job execution in Python Source: https://docs.blaxel.ai/Jobs/Manage-job-execution-py Use the Blaxel SDK to manage batch job execution in Python. You can programmatically execute and manage batch jobs using the Blaxel API and Python SDK. Both synchronous and asynchronous usage is supported: use `method_name` for synchronous operations and `amethod_name()` for asynchronous operations. The code examples in this section assume that your batch job has already been successfully deployed on Blaxel. ### Dispatch job execution Dispatch a job and wait for execution to start: ```python theme={null} from blaxel.core.jobs import bl_job from blaxel.core.client.models.create_job_execution_request import CreateJobExecutionRequest job = bl_job("my-job") request = CreateJobExecutionRequest(tasks=[{"duration": 60}]) execution_id = job.create_execution(request) result = job.wait_for_execution(execution_id, max_wait=180) ``` Time units in the Python SDK are specified in seconds. ### Dispatch job execution with tasks Dispatch a new job with tasks: ```python theme={null} # synchronous request = CreateJobExecutionRequest(tasks=[{"duration": 30}, {"duration": 60}]) execution_id = job.create_execution(request) # asynchronous execution_id = await job.acreate_execution(request) ``` ### Get execution details Get full execution details: ```python theme={null} # synchronous execution = job.get_execution(execution_id) # asynchronous execution = await job.aget_execution(execution_id) ``` ### Get status The possible job states are: ```text theme={null} pending → running → completed ↘ failed ``` Get only the job status (faster than retrieving full execution details): ```python theme={null} # synchronous status = job.get_execution_status(execution_id) # asynchronous status = await job.aget_execution_status(execution_id) ``` ### List executions List all executions for a job: ```python theme={null} # synchronous executions = job.list_executions(limit=50) # asynchronous executions = await job.alist_executions(limit=50) ``` ### Wait for completion Poll until execution completes: ```python theme={null} # synchronous result = job.wait_for_execution( execution_id, max_wait=300, # 5 minutes (seconds) interval=2 # Poll every 2 seconds (seconds) ) # asynchronous result = await job.await_for_execution(execution_id, max_wait=300, interval=2) ``` When polling: * adjust the `interval` based on the expected task duration * set the `max_wait` timeout longer than the expected total task duration ### Override environment and memory for a single job execution Override memory and/or environment variables for a single job execution, without modifying the deployed job configuration: ```python theme={null} from blaxel.core.jobs import bl_job from blaxel.core.client.models.create_job_execution_request import ( CreateJobExecutionRequest, ) from blaxel.core.client.models.create_job_execution_request_env import ( CreateJobExecutionRequestEnv, ) job = bl_job("my-job") env = CreateJobExecutionRequestEnv() env["CUSTOM_ENV"] = "OVERRIDE" env["LOG_LEVEL"] = "debug" request = CreateJobExecutionRequest( tasks=[{"name": "Combined"}], memory=1024, # MB (must be <= deployed job memory) env=env, ) # synchronous execution_id = job.create_execution(request) execution = job.get_execution(execution_id) # asynchronous execution_id = await job.acreate_execution(request) execution = await job.aget_execution(execution_id) print(execution.status) ``` * Memory overrides are expressed in MB and are downward-only: the value must be \<= the memory configured at deployment time. For example, if the job is deployed with 4096 MB, execution overrides must be \<= 4096 MB. * `env` supports multiple environment variables * `memory` and `env` can be set independently or together * Overrides apply only to the current execution ### Complete example Here is a complete example using synchronous operations: ```python theme={null} from blaxel.core.jobs import bl_job from blaxel.core.client.models.create_job_execution_request import CreateJobExecutionRequest job = bl_job("my-job") # create execution request = CreateJobExecutionRequest(tasks=[{"name": "John"}, {"name": "Jane"}]) execution_id = job.create_execution(request) # monitor status = job.get_execution_status(execution_id) print(f"Status: {status}") # wait try: result = job.wait_for_execution(execution_id, max_wait=180, interval=5) print(f"Completed: {result.status}") except Exception as error: print(f"Timeout: {error}") ``` Here is a complete example using asynchronous operations: ```python theme={null} import asyncio from blaxel.core.jobs import bl_job from blaxel.core.client.models.create_job_execution_request import CreateJobExecutionRequest async def main(): job = bl_job("my-job") request = CreateJobExecutionRequest(tasks=[{"name": "John"}, {"name": "Jane"}]) execution_id = await job.acreate_execution(request) status = await job.aget_execution_status(execution_id) print(f"Status: {status}") result = await job.await_for_execution(execution_id, max_wait=180, interval=5) print(f"Completed: {result.status}") asyncio.run(main()) ``` Learn how to deploy your AI batch jobs on Blaxel as a serverless auto-scalable endpoint. # Manage job execution in TypeScript Source: https://docs.blaxel.ai/Jobs/Manage-job-execution-ts Use the Blaxel SDK to manage batch job execution in TypeScript. You can programmatically execute and manage batch jobs using the Blaxel API and TypeScript SDK. The code examples in this section assume that your batch job has already been successfully deployed on Blaxel. ### Dispatch job execution Dispatch a job and wait for execution to start: ```typescript theme={null} import { blJob } from "@blaxel/core"; const job = blJob("my-job"); const executionId = await job.createExecution({ tasks: [{ duration: 60 }] }); const result = await job.waitForExecution(executionId); ``` Time units in the TypeScript SDK are specified in milliseconds. ### Dispatch job execution with tasks Dispatch a new job with tasks: ```typescript theme={null} const executionId = await job.createExecution({ tasks: [ { duration: 30 }, { duration: 60 }, ] }); ``` ### Get execution details Get full execution details: ```typescript theme={null} const execution = await job.getExecution(executionId); console.log(execution.status, execution.metadata); ``` ### Get status The possible job states are: ```text theme={null} pending → running → completed ↘ failed ``` Get only the job status (faster than retrieving full execution details): ```typescript theme={null} const status = await job.getExecutionStatus(executionId); // Returns: "pending" | "running" | "completed" | "failed" ``` ### List executions List all executions for a job: ```typescript theme={null} const executions = await job.listExecutions(); console.log(`Found ${executions.length} executions`); ``` ### Wait for completion Poll until execution completes: ```typescript theme={null} const result = await job.waitForExecution(executionId, { maxWait: 300000, // 5 minutes (milliseconds) interval: 2000, // Poll every 2 seconds (milliseconds) }); ``` When polling: * adjust the `interval` based on the expected task duration * set the `maxWait` timeout longer than the expected total task duration ### Override environment and memory for a single job execution Override memory and/or environment variables for a single job execution, without modifying the deployed job configuration: ```typescript theme={null} import { blJob } from "@blaxel/core" const job = blJob("my-job") const executionId = await job.createExecution({ tasks: [{ name: "Combined" }], memory: 1024, // MB (must be <= deployed job memory) env: { TEST_MODE: "true", LOG_LEVEL: "debug", }, }) const execution = await job.getExecution(executionId) console.log(execution.status) ``` * Memory overrides are expressed in MB and are downward-only: the value must be \<= the memory configured at deployment time. For example, if the job is deployed with 4096 MB, execution overrides must be \<= 4096 MB. * `env` supports multiple environment variables * `memory` and `env` can be set independently or together * Overrides apply only to the current execution ### Complete example Here is a complete example: ```typescript theme={null} import { blJob } from "@blaxel/core"; const job = blJob("data-processing"); // create execution const executionId = await job.createExecution({ tasks: [{"name": "John"}, {"name": "Jane"}] }); // monitor let status = await job.getExecutionStatus(executionId); console.log(`Status: ${status}`); // wait try { const result = await job.waitForExecution(executionId, { maxWait: 180000, interval: 5000, }); console.log(`Completed: ${result.status}`); } catch (error) { console.log(`Timeout: ${error.message}`); } ``` Learn how to deploy your AI batch jobs on Blaxel as a serverless auto-scalable endpoint. # Jobs Source: https://docs.blaxel.ai/Jobs/Overview Scheduled jobs of batch processing tasks for your AI workflows. Jobs allow you to run many AI tasks in parallel using batch processing. image.webp ## Concepts * **Job**: A code definition that specifies a batch processing task. Jobs can run multiple times within a single execution and accept optional input parameters. * **Execution**: A specific instance of running a batch job at a given timestamp. Each execution consists of multiple tasks running in parallel. * **Task**: A single instance of a job definition running as part of an execution. image.webp ## Get started with Batch Jobs Read our guide for developing batch AI jobs leveraging Blaxel developer tools. Learn how to deploy your batch job on Blaxel as a serverless endpoint. Learn how to manage secrets and environment variables for your batch job. # Variables and secrets Source: https://docs.blaxel.ai/Jobs/Variables-and-secrets-jobs Manage variables and secrets in your job/agent/MCP code. Environment variables are retrieved first from your `.env` file (or any other file you specify when deploying, see down below), and if not found there, from the `[env]` section of `blaxel.toml`. This fallback mechanism allows for two kinds of variables: * secrets * simple environment variables ## Secrets Create a file named `.env` at the root of your project to store secrets. Blaxel will retrieve them from this default location upon deployment (see down below to override). Add the `.env` file to your `.gitignore` to prevent committing sensitive variables. ```bash theme={null} MY_SECRET=123456 ``` You can then use secrets in your code as follows: ```typescript TypeScript theme={null} import { env } from "@blaxel/core"; console.info(env.MY_SECRET); // 123456 ``` ```python Python theme={null} import os os.environ.get('MY_SECRET') ``` ### Use secrets from another env file To separate local *.env* from production, specify a different environment file when deploying your resource to Blaxel using the `--env-file` argument in Blaxel CLI: ```bash theme={null} bl deploy --env-file anyenvfile ``` This allows to specify a different environment file for production secrets instead of relying on the default *.env*, e.g.: * Use `.env` for local development * Use `.env.prod` for production deployment ## Variables You can define variables inside your agent or MCP server in the `blaxel.toml` file at root level of your project. These variables are NOT intended to be use as secrets, but as configuration variables. ```toml blaxel.toml {6} theme={null} name = "..." workspace = "..." type = "function" [env] DEFAULT_CITY = "San Francisco" ``` You can then use it in your code as follows: ```typescript TypeScript theme={null} import { env } from "@blaxel/core"; console.info(env.DEFAULT_CITY); // San Francisco ``` ```python Python theme={null} import os os.environ.get('DEFAULT_CITY') ``` ## Reserved variables The following variables are reserved by Blaxel: `PORT`: Reserved by the system. `PORT` : Port of the HTTP server, it need to be set to allow Blaxel platform to configure it `HOST` : Host of the HTTP server, it need to be set to allow Blaxel platform to configure it Internal URL for Blaxel platform, to avoid linking multiple instance through the Internet `BL_AGENT_${envVar}_SERVICE_NAME` `BL_FUNCTION_${envVar}_SERVICE_NAME` `BL_RUN_INTERNAL_HOSTNAME`: internal run url Override URL to link multiple agents and MCP servers together locally `BL_AGENT_${envVar}_URL` `BL_FUNCTION_${envVar}_URL` Metadata automatically set by Blaxel platform in production `BL_WORKSPACE` : workspace name `BL_NAME` : name of the function or the agent `BL_TYPE` : function or agent Authentication environment variables `BL_CLIENT_CREDENTIALS` : client credentials, used by Blaxel in production with a workspaced service account `BL_API_KEY` : can be set in your code to connect with the platform (locally or from a server not on Blaxel platform) `BL_LOG_LEVEL` : Log level, default to info, can be set to debug,warn,error `BL_DEBUG_TELEMETRY`: Enable telemetry debug mode, will print each interaction with OpenTelemetry `BL_ENABLE_OPENTELEMETRY`: Enable OpenTelemetry, it's set automatically by the platform in production # Policies Source: https://docs.blaxel.ai/Model-Governance/Policies Define policies to control where and how workloads execute on the Global Agentics Network, including location constraints, flavor selection, and token usage limits. Policies are used to program how and where your workloads are deployed on Blaxel. Policies can be defined as code, allowing for easy programming and customization of your [Global Agentics Network](../Infrastructure/Global-Inference-Network). Policies apply to the entities they are attached to: [model APIs](../Models/Overview), [functions](../Functions/Overview) and [agent](../Agents/Overview) deployments. ## Policies overview Policies essentially describe rules as to how deployments and executions are made on Blaxel. A policy states all the **allowed options for a specific aspect** (called the *policy type)* of the deployment or execution (for example: the execution location). Example: * Policy `Country: US` means that attached workloads will only be able to run in locations that are in the United States. When no policies are enforced on a type, all options for this type are considered allowed. Workloads are executed using [Global Agentics Network](../Infrastructure/Global-Inference-Network)’s default optimizations. ### Policy types Policies have a **type**, allowing multiple policies to drive various deployment strategies without colliding. Typically, you can easily enforce a policy on the execution location and a policy on the underlying hardware at the same time. There are currently three types of policies: **location,** **flavor,** and **token usage** ### Location policies Location policies give control over which clusters will execute your workloads. They come in two different formats: * policies on **countries** allow to define all [physical locations](/Model-Governance/Policies) inside of one or several countries at once * for example, execute only in the following country: *USA* * policies on **continents** allow to define all [physical locations](/Model-Governance/Policies) inside of one or several continents at once * for example, execute only in *North America* ### Flavor policies Flavor policies give control over which underlying accelerator (GPU) your workloads will be executed on. They come in two different formats: * policies on **cpu** allow to pass a specific list of CPU types * for example, execute only on x86 * policies on **gpu** allow to pass a specific list of GPU types * execute only on NVIDIA A100 * execute only on NVIDIA L4 or NVIDIA T4 ### Token usage policies Token usage policies control the maximum number of tokens your [**model APIs**](../Models/Overview) can handle within a specific time period. You can control the maximum number of input tokens, output tokens, **and/or** total tokens. When a model reaches its maximum token limit, subsequent requests are rejected with a 429 error. The policy only drops complete requests AFTER the maximum limit is reached. The first request that exceeds the threshold will still be processed. However, all subsequent requests within the enforced time period will be dropped. ## Create a policy Policies can be created from the Blaxel console, or from the Blaxel APIs and CLI. Read [our complete reference on policies](https://docs.blaxel.ai/api-reference/policies/create-or-update-policy). ## Attach a policy Attaching a policy to a workload enforces it on the workload. When no policies are enforced on a type, all options for this type are considered allowed. Workloads are executed using [Global Agentics Network](../Infrastructure/Global-Inference-Network)’s default optimizations. ### Attaching multiple policies When attaching **multiple policies** to a resource, it's crucial to understand their combined effect. **If you are attaching multiple policies to the same resource:** Their combined effect is the **UNION** of all of their effects for the same [type](/Model-Governance/Policies) of policy (a.k.a *OR* clause), and **INTERSECTION** across all [types](/Model-Governance/Policies) of policies (a.k.a *AND* clause). For example: * Let’s assume the following policies: * Policy A: Country is: USA * Policy B: Continent is: North America, or Europe * Policy C: GPU is: NVIDIA T4 * if a workload has the following combined policies: * A and B: then the workload will only execute in any location in either North America (including USA) or Europe — on any kind of hardware available there. * B and C: then the workload will only execute in any location in either North America or Europe, only on T4 GPUs. * A and C: then the workload will only execute in any location in the USA, only on T4 GPUs. * A and B and C: then the workload will only execute in any location in either North America (including USA) or Europe — only on T4 GPUs. ## Policy reference Below is the list of official names to build policies. ### Flavors **type**: `flavor` | **Code** | **Type** | **Flavor Name** | | -------- | -------- | --------------- | | CPU x86 | cpu | x86 | | t4 | gpu | NVIDIA T4 | ### Locations **type**: `location` | **Code** | **Type** | **Name** | | -------- | --------- | ------------- | | eu | continent | Europe | | na | continent | North America | | us | country | United States | ### Flavors **type**: `maxToken` * `granularity`: the unit period of time over which the number of tokens is evaluated. One of: `month`, `day`, `hour`, `minute` * `step`: the number of time period units over which the number of tokens is evaluated. It is a number greater than 1. * `input`: threshold for the maximum number of **input** tokens. If 0, this metric is not evaluated. * `output`: threshold for the maximum number of **output** tokens. If 0, this metric is not evaluated. * `total`: threshold for the maximum number of **input and output** tokens. If 0, this metric is not evaluated. # External model APIs Source: https://docs.blaxel.ai/Models/External-model-apis Control & secure access to AI models from top providers behind Blaxel Global Inference Network. You can query any LLM or other generative AI model from top API providers via Blaxel, in order to benefit from a **unified layer of access control and telemetry,** especially when running whole AI agents. ## Creating a model endpoint on Blaxel Adding model endpoints from external providers on Blaxel gives you single endpoints to call the model on the same base URL, rather than calling each provider separately. Blaxel handles the authentication, authorization and monitoring automatically for you. This is done in a two step process: 1. First, you need to create a workspace integration that will contain the credentials to connect to your model API provider. Check out the dedicated documentation for each available integration. 2. Second, you can create a dedicated endpoint for a specific model from this provider. You will need to choose the model from the list of available models for the provider. Screenshot 2024-12-05 at 6.59.49 PM.webp You can then query the model using its [dedicated global inference endpoint](/Models/Query-a-model). Any call to this endpoint will be passed to the underlying provider. ## Provider reference The following providers are available: * [OpenAI](../Integrations/OpenAI) * [Anthropic](../Integrations/Anthropic) * [Mistral AI](../Integrations/MistralAI) * [Cohere](../Integrations/Cohere) * [xAI](../Integrations/xAI) * [DeepSeek](../Integrations/DeepSeek) # Model APIs Source: https://docs.blaxel.ai/Models/Overview Connect external model API providers or deploy custom models on Blaxel for unified gateway access with centralized credentials and observability. AI models are the brain of AI agents, as they are able to reason, talk, and generate payloads for the tools that the agent can use. There are two ways to approach models on Blaxel: * **Using an external model API provider** (e.g. OpenAI, Together, etc.): Blaxel acts as a unified gateway for model APIs, centralizing access credentials, tracing and telemetry. You can achieve this by defining workspace integrations to any major model API provider, and creating gateway endpoints on Blaxel for any of their models. * **Bringing your own model**: Deploy a custom model on Blaxel, allowing you to use fine-tuned SLMs/LLMs or any other kind of AI model. When a model is deployed on Blaxel, you get global API endpoint to call it. This option is part of our Enterprise offering, contact us at [support@blaxel.ai](mailto:support@blaxel.ai) for more information. Complete guide for connecting to an external model provider like Anthropic or OpenAI. # Query a model API Source: https://docs.blaxel.ai/Models/Query-a-model Make inference requests to model APIs via their global endpoints on the Global Agentics Network, with ChatCompletions and custom sub-endpoint support. Model APIs on Blaxel have a unique **inference endpoint** which can be used by external consumers and agents to request an inference execution. Inference requests are then routed on the [Global Agentics Network](../Infrastructure/Global-Inference-Network) based on the [deployment policies](../Model-Governance/Policies) associated with your model API. ## Inference endpoints Whenever you deploy a model API on Blaxel, an **inference endpoint** is generated on Global Agentics Network. The inference URL looks like this: ```http Query model API theme={null} POST https://run.blaxel.ai/{YOUR-WORKSPACE}/models/{YOUR-MODEL} ``` ### Specific API endpoints in your model The URL above calls your model and can be called directly. However your model may **implement additional endpoints.** These sub-endpoints will be hosted on this URL. For example, if you are calling a text generation model that also implements the ChatCompletions API: * calling `run.blaxel.ai/your-workspace/models/your-model` (the base endpoint) will generate text based on a prompt * calling `run.blaxel.ai/your-workspace/models/your-model/v1/chat/completions` (the ChatCompletions API implementation) will generate response based on a list of messages ### Endpoint authentication It is necessary to authenticate all inference requests, via a [bearer token](../Security/Access-tokens). The evaluation of authentication/authorization for inference requests is managed by the Global Agentics Network based on the [access given in your workspace](../Security/Workspace-access-control). Making a workload publicly available is not yet available. Please contact us at [support@blaxel.ai](mailto:support@blaxel.ai) if this is something that you need today. ## Make an inference request ### Blaxel API Make a **POST** request to the [inference endpoint](/Models/Query-a-model) for the model API you are requesting, making sure to fill in the [authentication token](/Models/Query-a-model): ```bash theme={null} curl 'https://run.blaxel.ai/YOUR-WORKSPACE/models/YOUR-MODEL' \ -H 'accept: application/json, text/plain, */*' \ -H 'x-Blaxel-authorization: Bearer YOUR-TOKEN' \ -H 'x-Blaxel-workspace: YOUR-WORKSPACE' \ --data-raw $'{"inputs":"Enter your input here."}' ``` Read about [the API parameters in the reference](https://docs.blaxel.ai/api-reference/inference). ### Blaxel CLI The following command will make a default POST request to the model API. ```bash theme={null} bl run model your-model --data '{"inputs":"Enter your input here."}' ``` You can call [specific API endpoints](/Models/Query-a-model) that your model implements with the option `--path` : ```bash theme={null} bl run model your-model --path /v1/chat/completions --data '{"inputs":"Hello there!"}' ``` Read about [the CLI parameters in the reference](https://docs.blaxel.ai/cli-reference/bl_run). ### Blaxel console Inference requests can be made from the Blaxel console from the model API’s **Playground** page. workbench.webp # Logs & traces Source: https://docs.blaxel.ai/Observability/Overview Get automatic observability for deployed agents with built-in logging, distributed tracing, and real-time metrics including latency, token usage, and request data. Deploying and running agents on Blaxel gives you **total observability by design**, without needing to install any additional library. When you either deploy from the console’s low-code builder or by using the Blaxel SDK to wrap your code for deployment, Blaxel will automatically implement logging & tracing on your requests. ## Monitor from the Blaxel console There are three ways you can observe and monitor your running workloads: * Metrics * Logs * Traces ### Metrics Metrics are aggregated data about workload executions. They include: * Number and rate of requests * End-to-end latency: average, p50, p90, p99 * Number of tokens generated by model APIs: input, output and total * City and country of origin of all requests image.webp image.webp ### Logs Logs are timestamped data about what happens with your agents, functions and model APIs. Such data includes: * Status of all requests on agents, functions and model APIs * Logs generated when building your deployments * Custom logs generated by your agents and functions image.webp ### Traces Tracing helps you understand how your agent works by showing you all its parts in action. When you make a request, it creates a trace that contains multiple *spans*. Think of a span as a building block - it shows when something starts and ends, what went in, what came out, and other useful details. Spans can contain other spans, like when one function calls another. You'll often see spans for things like LLM calls, tool calls, or steps in an agent's process. You can click on any trace to see all its spans laid out clearly. This makes it much easier to follow how your agent works and fix any problems you find. Blaxel collects and saves the traces of a **sampled 10%** of all your executions. In order to force saving the trace on an execution, call the run API and add query parameter `debug:true`. traces.webp ## Opt out This feature is controlled by the `BL_ENABLE_OPENTELEMETRY` environment variable. When you deploy an agent to Blaxel, the platform automatically injects `BL_ENABLE_OPENTELEMETRY=true` into the environment. When developing locally, this environment variable is not set and therefore defaults to `false`. To explicitly disable telemetry: ```bash theme={null} export BL_ENABLE_OPENTELEMETRY=false ``` Setting `DO_NOT_TRACK=1` has no effect on OpenTelemetry. [Read more about SDK and CLI data collection and privacy](/Security/Data-collection-and-privacy). # Blaxel Documentation Source: https://docs.blaxel.ai/Overview Blaxel is a perpetual sandbox platform for AI agents. Explore docs for cloud sandboxes, agent hosting, MCP servers, batch jobs, model gateway, and more. Blaxel is a **perpetual sandbox platform built for AI agents**. Our platform lets you keep infinite, secure sandboxes on automatic standby while co-hosting your agents for near instant latency. **Using Cursor, Claude Code, Codex, Goose, or another AI coding agent?** Install the [Blaxel skill](./skills-mcp) to give your agent the ability to deploy AI agents, create sandboxes for code execution, host MCP servers, run batch jobs, and more...all using simple prompts, zero code required! ```shell theme={null} npx skills add blaxel-ai/agent-skills ``` An *AI agent* is any application that leverages generative AI models to take autonomous actions in the real world. These agents often require computing power to execute their interactions. Some examples of agents include: * **Conversational agents** that are able to take action in the world while keeping a human in the loop for activation or validation: for example code generation agents with real-time previews. * **AI-powered data pipelines**: for example a data transformation pipeline that retrieves unstructured video files and uses an AI model to extract structured data then act on it. * **RAG agents**: for example, a chatbot assistant that can better answer consumers’ queries by autonomously running scripts to access a relevant databases. * **Autonomous system agents** that handle machine-to-machine workflows: like a smart traffic monitoring system that analyzes video feeds, detects accidents in real-time, and automatically dispatches emergency services with AI-generated incident reports. Blaxel’s infrastructure platform gives production-grade agents their own computing environments including code sandboxes, tool servers, and LLMs. It offers infrastructure to run these agents on a global network that makes them run fast and reliably. This website provides comprehensive documentation and API, SDK and CLI references to help you work with Blaxel. ## Essential concepts Blaxel is a perpetual sandbox platform designed for agentic AI. It **doesn't force you into any kind of workflow** or shaped box. While we encourage you to exploit architecture designs that we consider are more reliable, our toolkit gives you all the pieces you need to build reliable agentic systems exactly the way you want. Blaxel consists of modular services that are engineered to work seamlessly together, but you can also just use any one of them independently. Think of it as a purpose-built set of building blocks that you can use to power agents. ### The building blocks At the heart of Blaxel is our flagship **perpetual sandbox** service. Sandboxes are secure, instant-launching compute environments that you can use for running AI code. Blaxel lets you keeps sandboxes on automatic standby with optimized agent hosting for near instant latency. With Blaxel sandboxes, you get: * Automatic scale-to-zero after 5s inactivity, resume from standby under 25ms even after weeks. * microVMs with full access to file system, processes and logs — and native support for Zero Data Retention (ZDR). * Preview URLs with your own custom domain. You can co-locate agent APIs, MCP servers, and batch tasks directly alongside your sandboxes to eliminate network hops and ensure the lowest possible end-to-end latency. For this, Blaxel also offers: * **Agents Hosting** - Deploy your AI agents as serverless auto scalable endpoints. Completely framework agnostic: just bring your code, Blaxel builds it and runs it for you. * **Batch Jobs** - Scalable compute engine designed for agents to schedule and execute many AI processing tasks in parallel in the background * **MCP Servers Hosting** - Deploy custom tool servers on a fast-starting infrastructure to extend your agents' capabilities. * **Model Gateway** - Intelligent routing layer to LLM providers with built-in telemetry, token cost control, and fallbacks capabilities * **Full observability** - out-of-the-box ### A cloud built for agents Agents will transform how we work in the coming years. Traditional cloud providers weren't designed to handle them and their one-size-fits-all architecture holds them back. We built Blaxel to fix that. Blaxel is a cloud where **AI agents themselves are the primary users**. All products are accessible through [MCP servers](skills-mcp), allowing agents to create and manage resources via tool calls. Blaxel provides agents with all the compute they need to scale and perform optimally: products like Sandboxes give them their own dedicated personal computer(s) / computing environments, while Batch Jobs enable them to schedule background tasks at scale. Unlike traditional sandbox providers, Blaxel Sandboxes automatically scale up and down at near-instant speeds. As such, here are some recommended best practices: * If the end-user or agent is expected to continue a session soon, just leave the sandbox be. It will automatically suspend when the connection closes (= you will stop paying for compute runtime) and resume when reconnected. * The definition of "soon" is at your discretion. It's a tradeoff between instant resume times from standby mode (\~25ms) and paying for the [standby snapshot storage cost](https://blaxel.ai/pricing). As a rule of thumb, most customers keep sandboxes in standby for a few hours to a few days. * Blaxel doesn't limit how long a sandbox can stay in standby mode, but doesn't guarantee data persistence. For guaranteed long-term data persistence, use [volumes](Volumes). * If you persist data in a volume, you can delete the sandbox. To resume a session, you'll need to re-create the sandbox (\~2–4 seconds) and restart processes to restore the same state. * For automatic cleanup, set TTLs when creating your sandbox to delete it after a set idle duration or maximum age. * When you delete a sandbox, all data is immediately erased. If the sandbox was never in standby mode, Blaxel guarantees ZDR (zero data retention). We also recommend more general best-practices aiming to provide guardrails and framing when you build your agents - from our experience working with top AI teams. * Break down and distribute your agents whenever possible. A single monolithic agent handling all tool calls, LLM calls, and task workflows can be deployed to Blaxel Agents Hosting - but it will be harder to maintain, monitor, and will use resources inefficiently. Blaxel SDK allows builders to split services and connect them from your code. * Similarly, while direct tool calls are possible, deploying separate MCP servers improves reusability, optimizes resources, and simplifies monitoring. Blaxel also optimizes placement globally when your serverless tool server needs to make multiple backend calls. ### Which component should I use? When building your agentic system, you'll need to make architecture design choices. Blaxel offers several high-perf compute options, summarized below in order of latency performance: * [**Sandboxes**](Sandboxes/Overview): Perfect for maximum workload flexibility. These microVMs provide full access to filesystem, network, and processes, booting from standby in under 25ms. * [**Agents Hosting (sync mode)**](https://docs.blaxel.ai/Agents/Query-agents#default-synchronous-endpoint): Ideal for running HTTP API services that process requests within a few seconds. * [**Agents Hosting (async mode)**](https://docs.blaxel.ai/Agents/Query-agents#async-endpoint): Best for running HTTP API services handling longer requests without maintaining an open connection. * [**Batch Jobs**](Jobs/Overview): Designed for asynchronous tasks that may run for extended periods where boot latency is less critical. These jobs are triggered by providing specific input parameters, unlike Agents that are a fully hosted API. | **Product** | **Typical use** | **Typical workload duration** | **Boot time** | **Input type** | | --------------------------- | ------------------------------------------ | ---------------------------------------- | --------------------- | ------------------------- | | Sandboxes | Giving an agent its own compute runtime | seconds to hours | \~25ms (from standby) | Fully custom | | Agents Hosting (sync mode) | Agent API that answers fast | a few seconds (**maximum 100 s**) | \~25ms | Custom API endpoints | | Agents Hosting (async mode) | Agent API that processes data for a while | a few minutes (**maximum 10 mins**) | \~25ms | Custom API endpoints | | Batch Jobs | Sub-tasks scheduled in an agentic workflow | minutes to hours (**maximum 24 h**) | \~30s | Specific input parameters | | MCP Servers Hosting | Running an MCP server API | seconds to minutes (**maximum 10 mins**) | \~25ms | API following MCP | ## The Blaxel powerhouse When you deploy workloads to Blaxel, they run on a technical backbone called the **Global Agentics Network**. Its natively serverless architecture automatically scales computing resources without any server management on your part. Global Agentics Network serves as the powerhouse for the entire Blaxel platform, from Agents Hosting to Sandboxes. It is natively **distributed** in order to optimize for low-latency or other strategies. It allows for multi-region deployment, enabling AI workloads (such as an AI agent processing inference requests) to run across multiple geographic areas or cloud providers. This is accomplished by decoupling this execution layer from a data layer made of a smart distributed network that federates all those execution locations. Finally, the platform implements advanced security measures, including fine-grained authentication and authorization through Blaxel IAM, ensuring that your AI infrastructure remains protected. It can be interacted with through various methods, including APIs, CLI, web console, and MCP servers. ## Documentation structure You might want to start with any of the following articles: * [**Get started**](Get-started): Deploy your first workload on Blaxel in just 3 minutes. * [**Agent Skill & MCP:**](skills-mcp) Let your coding agent (Cursor, Claude Code, Windsurf…) create and manage Blaxel resources using natural language. * **Product Documentation** * [**Sandboxes**](Sandboxes/Overview): Equip your agents with fast & secure virtual machines to run AI code. * [**Agents Hosting**](Agents/Overview): Host and run AI agents as serverless auto-scalable endpoints. * [**Batch Jobs**](Jobs/Overview): Background tasks for your AI workflows that run in batches. * [**MCP Servers Hosting**](Functions/Overview): Expose capabilities and execute tool calls using MCP. * [**Model APIs**](Models/Overview): Learn about supported model types on our global AI gateway. * [**Agent Drive**](Agent-drive/Overview): Share files across sandboxes and agents with a distributed filesystem. * [**Volumes**](Volumes/Overview): Persist files long-term by attaching volumes to your resources. * [**Integrations**](Integrations): Discover how Blaxel works with other tools, frameworks, and platforms. * [**Observability**](Observability/Overview): Monitor logs, traces and metrics for your agent runs. * [**Governance**](Model-Governance/Policies): Manage your AI deployment strategies with policies and environments. * [**Security**](Security/Workspace-access-control): Implement robust security measures for your AI infrastructure. * [**Regions**](Infrastructure/Regions): Discover where Blaxel is available in the world. * [**Troubleshooting**](troubleshooting): Resolve common issues with Blaxel deployments. * **Tutorials & Examples** * [**Sandbox tutorials**](Tutorials/Sandboxes-Overview): Run web applications in sandboxes with Astro, Expo, and Next.js. * [**Agent tutorials**](Tutorials/Agents-Overview): Deploy agents using popular frameworks like Claude Agent SDK, LangChain, CrewAI, and more. * **References** * [**API reference**](api-reference/introduction): Comprehensive guide to Blaxel's APIs. * [**SDK reference**](sdk-reference/introduction): Manage Blaxel resources programmatically using TypeScript, Python, or Go SDKs. * [**CLI reference**](cli-reference/introduction): Learn how to use Blaxel's command-line interface. * [**Deployment reference**](deployment-reference): Complete reference for the blaxel.toml configuration file. # Code generation tools Source: https://docs.blaxel.ai/Sandboxes/Codegen-tools Tools and functions that are optimized for AI codegen use cases. Blaxel Sandboxes provide tools for managing files and their contents, specialized for code generation ("*codegen*") use cases. These tools are accessible through the sandboxes' [MCP server](https://docs.blaxel.ai/Sandboxes/Overview#mcp-server-for-a-sandbox) and [REST API](https://docs.blaxel.ai/api-reference/root/welcome-message). ## Fast apply of file edits Fast apply of file edits is powered by [Morph](https://morphllm.com/) or [Relace](https://www.relace.ai/) and requires you to bring your own Morph/Relace account. With this tool, you can **apply code changes** suggested by an LLM to your existing code files fast (2000+ tokens/second). Traditional code generation requires generating the entire files every time, which can be slower for large files. With this approach your LLM only generates the specific changes needed, and this tool applies them to the original file. ### Configure environment variables Pass your [Morph API key](https://docs.morphllm.com/api-reference/introduction#authentication) and Morph model (default = *morph-v2*) set as environment variables when creating the sandbox. ```tsx TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; // Create sandbox with Morph API key for fast code edits const sandbox = await SandboxInstance.createIfNotExists({ name: "codegen-sandbox", image: "blaxel/nextjs:latest", memory: 4096, region: "us-pdx-1", ports: [ { name: "preview", target: 3000 } ], envs: [ { name: "MORPH_API_KEY", value: process.env.MORPH_API_KEY || "" }, { name: "MORPH_MODEL", value: process.env.MORPH_MODEL || "morph-v2" } ] }); ``` ```python Python theme={null} import os from blaxel.core import SandboxInstance # Create sandbox with Morph/Relace API key for fast code edits sandbox = await SandboxInstance.create_if_not_exists({ "name": "codegen-sandbox", "image": "blaxel/nextjs:latest", "memory": 4096, "region": "us-pdx-1", "ports": [ { "name": "preview", "target": 3000 } ], "envs": [ { "name": "MORPH_API_KEY", "value": os.getenv("MORPH_API_KEY") }, { "name": "MORPH_MODEL", "value": os.getenv("MORPH_MODEL") or "morph-v2" } ] }) ``` Pass your [Relace API key](https://docs.relace.ai/api-reference/introduction#authentication) as an environment variable when creating the sandbox. ```tsx TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; // Create sandbox with Relace API key for fast code edits const sandbox = await SandboxInstance.createIfNotExists({ name: "codegen-sandbox", image: "blaxel/nextjs:latest", memory: 4096, region: "us-pdx-1", ports: [ { name: "preview", target: 3000 } ], envs: [ { name: "RELACE_API_KEY", value: process.env.RELACE_API_KEY || "" } ] }); ``` ```python Python theme={null} import os from blaxel.core import SandboxInstance # Create sandbox with Relace API key for fast code edits sandbox = await SandboxInstance.create_if_not_exists({ "name": "codegen-sandbox", "image": "blaxel/nextjs:latest", "memory": 4096, "region": "us-pdx-1", "ports": [ { "name": "preview", "target": 3000 } ], "envs": [ { "name": "RELACE_API_KEY", "value": os.getenv("RELACE_API_KEY") }, ] }) ``` ### Use the tool via Blaxel SDK Call the `fastapply` endpoint of the [Sandbox API](https://docs.blaxel.ai/api-reference/fastapply/apply-code-edit) via the Blaxel SDK to fast-apply a targeted edit to a specified file with Morph or Relace, with instructions and partial contents. ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; // Apply code changes await sandbox.codegen.fastapply( "/tmp/test.ts", "// keep existing code // add a typescript function to calculate the area of a circle" ); // Read file with changes let content = await sandbox.fs.read("/tmp/test.ts"); console.log(content) ``` ```python Python theme={null} from blaxel.core import SandboxInstance logger = logging.getLogger(__name__) # Apply code changes await sandbox.codegen.fastapply( "/tmp/test.ts", "// keep existing code // add a typescript function to calculate the area of a circle;" ) # Read file with changes content = await sandbox.fs.read("/tmp/test.ts") logger.info(content) ``` ### Use the tool via MCP Call the `codegenEditFile` tool on the **[MCP server of a sandbox](https://docs.blaxel.ai/Sandboxes/Overview#mcp-server-for-a-sandbox)** to fast-apply a targeted edit to a specified file, with instructions and partial contents. Use Blaxel SDK to retrieve the tool in any [compatible agent framework](../Tutorials/Agents-Overview) (here in AI SDK format): ```typescript TypeScript theme={null} import { blTools } from '@blaxel/vercel'; // Get codegen tools from sandbox MCP const allTools = await blTools([`sandboxes/${sandbox.metadata.name}`]); // Filter for specific codegen tools const codegenTools = Object.fromEntries( Object.entries(allTools).filter(([key]) => key.startsWith('codegen') ) ); ``` ```python Python theme={null} from blaxel.langgraph import bl_tools # Get codegen tools from sandbox MCP all_tools = await bl_tools([f"sandboxes/{sandbox.metadata.name}"]) # Filter for specific codegen tools codegen_tools = [tool for tool in all_tools if tool.name.startswith("codegen")] ``` ## Other tools built for codegen Use the following codegen-optimized functions by making tool calls through the MCP server or REST API of a sandbox. See example above on how to retrieve and execute the tools. | Tool | Description | | ----------------------- | --------------------------------------------------------------- | | `codegenCodebaseSearch` | Semantic search to find relevant code snippets | | `codegenFileSearch` | Fast fuzzy file path search | | `codegenGrepSearch` | Exact regex search using ripgrep engine | | `codegenListDir` | List directory contents (quick discovery) | | `codegenReadFileRange` | Read file contents within a specific line range (max 250 lines) | | `codegenRerank` | Performs semantic search/reranking on code files in a directory | | `codegenParallelApply` | Plan parallel edits across multiple file locations | | `codegenReapply` | Use smarter model to retry a failed edit | Build a Claude Agent SDK agent that connects to a Blaxel sandbox and operates it using the sandbox's MCP server. # Expiration policies Source: https://docs.blaxel.ai/Sandboxes/Expiration Automatically delete sandboxes based on specific conditions. While Blaxel is designed for you to keep your sandboxes in standby perpetually, it also supports automatic deletion of sandboxes based on specific expiration policies. This is useful if you want to avoid keeping snapshot storage for a long tail of sandboxes that will never be reactivated again. Blaxel has a [quota tiering system](https://app.blaxel.ai/account/quotas) that unlocks higher limits and features on the platform as your tier progresses. Some quota tiers enforce expiration dates (Tier 0 and 1, with respectively up to 7 and 30 days). In higher tiers, unlimited persistence is permitted. Automatic deletion differs from the automatic standby (*scale-to-zero*) which happens to **all sandboxes** when inactive and where the memory and filesystem are snapshotted to be resumed instantly. ## Expiration policies The following options are available for sandbox expiry and deletion: * expire after a total maximum lifetime (time-to-live or TTL) using the `ttl` parameter * expire after a period of inactivity using the `lifecycle.expirationPolicies` / `lifecycle.expiration_policies` parameter * expire at a specific date using the `expires` parameter If these parameters are absent, sandboxes will not be deleted. The sandbox metadata includes a read-only parameter, `expiresIn`, that computes the number of seconds until a sandbox is terminated due to its TTL or lifecycle policy. ## Configure sandbox expiry rules at creation You can define a sandbox's time-to-live (TTL) configuration at creation time: ```typescript TypeScript {11,12,13,14,15,16,17,18,19,20,21,22,23} theme={null} import { SandboxInstance } from "@blaxel/core"; // Create a new sandbox const sandbox = await SandboxInstance.create({ name: "my-sandbox", image: "blaxel/base-image:latest", memory: 4096, ports: [{ target: 3000, protocol: "HTTP" }], region: "us-pdx-1", ttl: "24h", // Total duration before auto-deletion. Supported units: h, d, w // OR // expires: new Date(Date.now() + 86400000) // Alternative: set a date at which it will be deleted // OR / AND lifecycle: { expirationPolicies: [ { type: "ttl-idle", value: "24h", // Delete after 24 hours of inactivity. Supported units: h, d, w action: "delete" } ] } }); ``` ```python Python {11,12,13,14,15,16,17,18,19,20,21,22,23} theme={null} from blaxel.core import SandboxInstance, SandboxLifecycle, ExpirationPolicy # Create a new sandbox sandbox = await SandboxInstance.create({ "name": "my-sandbox", "image": "blaxel/base-image:latest", "memory": 4096, "ports": [{ "target": 3000 }], "region": "us-pdx-1", "ttl": "24h", ## Total duration before auto-deletion. Supported units: h, d, w ## OR ## expires: new Date(Date.now() + 86400000) // Alternative: set a date at which it will be deleted ## OR / AND "lifecycle": SandboxLifecycle( expiration_policies=[ ExpirationPolicy( type_="ttl-idle", value="24h", # Delete after 24 hours of inactivity. Supported units: h, d, w action="delete" ) ] ) }) ``` Important notes: * The `ttl` parameter accepts a string with the following time units: `h` (hours), `d` (days), and `w` (weeks). * Lifecycle expirations policies also support types `ttl-max-age` and `date`: check out the [API reference](/api-reference/compute/update-sandbox) for full documentation. * You can combine multiple expiration policies. Whichever condition is met first will trigger the deletion. ## Update sandbox expiry rules You can update a sandbox's time-to-live (TTL) configuration after it has been created: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; // Update sandbox TTL const sandbox = await SandboxInstance.updateTtl("my-sandbox", "30m"); ``` ```python Python theme={null} from blaxel.core import SandboxInstance # Update sandbox TTL sandbox = await SandboxInstance.update_ttl("my-sandbox", "30m") ``` You can also update the expiration policy of a sandbox after it has been created: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; // Update sandbox expiration policy await SandboxInstance.updateLifecycle("my-sandbox", { expirationPolicies: [ { type: "ttl-max-age", value: "30m", action: "delete" } ] }); ``` ```python Python theme={null} from blaxel.core import SandboxInstance # Update sandbox expiration policy await SandboxInstance.update_lifecycle( "my-sandbox", { "expiration_policies": [ { "type": "ttl-max-age", "value": "30m", "action": "delete" } ] }, ) ``` # File system Source: https://docs.blaxel.ai/Sandboxes/Filesystem A simple file system interface for managing files in sandboxes. Manage files and directories within sandboxes through the `fs` module of Blaxel SDK. This module provides essential operations for creating, reading, writing, copying, and deleting files and directories. Complete code examples demonstrating all operations are available on Blaxel's GitHub: [in TypeScript](https://github.com/blaxel-ai/sdk-typescript/tree/main/tests/sandbox), [in Python](https://github.com/blaxel-ai/sdk-python/tree/main/tests/integration/sandbox), and [in Go](https://github.com/blaxel-ai/sdk-go/tree/main/integration_tests). ## Basic file system operations The Blaxel SDK requires two environment variables to authenticate: | Variable | Description | | -------------- | -------------------------- | | `BL_WORKSPACE` | Your Blaxel workspace name | | `BL_API_KEY` | Your Blaxel API key | You can create an API key from the [Blaxel console](https://app.blaxel.ai/profile/security). Your workspace name is visible in the URL when you log in to the console (e.g. `app.blaxel.ai/{workspace}`). Set them as environment variables or add them to a `.env` file at the root of your project: ```bash theme={null} export BL_WORKSPACE=my-workspace export BL_API_KEY=my-api-key ``` When developing locally, you can also **log in to your workspace with Blaxel CLI** (as shown above). This allows you to run Blaxel SDK functions that will automatically connect to your workspace without additional setup. When you deploy on Blaxel, authentication is handled automatically — no environment variables needed. ### Create directory Create a new directory at a specific path in the sandbox: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.get("my-sandbox"); await sandbox.fs.mkdir("/blaxel/app/uploads"); ``` ```python Python theme={null} from blaxel.core import SandboxInstance sandbox = await SandboxInstance.get("my-sandbox") await sandbox.fs.mkdir("/blaxel/app/uploads") ``` ### List files List files in a specific path: ```typescript TypeScript theme={null} const { subdirectories, files } = await sandbox.fs.ls("/blaxel/app"); ``` ```python Python theme={null} result = await sandbox.fs.ls("/blaxel/app") directories = result.subdirectories files = result.files ``` ### Find files and directories Blaxel's Sandbox API uses an optimized `find()` method, which is faster than using the native `find` tool. Find files and directories matching specified patterns: ```typescript TypeScript theme={null} let result = await sandbox.fs.find( "/app", { type: "file", patterns: ["*.md", "*.html"], maxResults: 1000, } ); if (result.matches && result.matches.length > 0) { for (const file of result.matches) { console.log(`Found file: ${file.path}`); } } else { console.log("No files found."); } ``` ```python Python theme={null} result = await sandbox.fs.find( path="/app", type="file", patterns=["*.md", "*.html"], max_results=1000, ) if result.matches: for file in result.matches: logger.info(f"Found file: {file.path}") else: logger.info("No files found.") ``` ### Search for text content within files Blaxel's Sandbox API uses an optimized `grep()` method, which is faster than using the native `grep` tool. Find files containing specified text content: ```typescript TypeScript theme={null} let result = await sandbox.fs.grep( "agentic", "/app", { caseSensitive: true, contextLines: 2, maxResults: 5, filePattern: "*.mdx", excludeDirs: ["images", "node_modules"], } ); if (result.matches && result.matches.length > 0) { for (const match of result.matches) { console.log(`${match.path}:${match.line} -> ${match.text}`); } } else { console.log("No matches found."); } ``` ```python Python theme={null} result = await sandbox.fs.grep( query="agentic", path="/app", case_sensitive=True, context_lines=2, max_results=5, file_pattern="*.mdx", exclude_dirs=["images", "node_modules"], ) if result.matches: for match in result.matches: logger.info( f"{match.path}:{match.line} -> {match.text}" ) else: logger.info("No matches found.") ``` ### Read file Read a file from a specific filepath: ```typescript TypeScript theme={null} const content = await sandbox.fs.read("/blaxel/app/config.json"); ``` ```python Python theme={null} content = await sandbox.fs.read("/blaxel/app/config.json") ``` ### Write file Create a file in a specific path: ```typescript TypeScript theme={null} await sandbox.fs.write("/blaxel/app/config.json", "{}"); ``` ```python Python theme={null} await sandbox.fs.write("/blaxel/app/config.json", "{}") ``` See down below for how to upload/write a binary, or multiple files at once. ### Write multiple files You can write multiple files or directories simultaneously. The second path parameter in `writeTree` specifies the base directory for writing the file tree, eliminating the need to repeat the full path for each file. ```typescript TypeScript theme={null} const files = [ { path: "src/app.js", content: "console.log('Hello');" }, { path: "src/utils.js", content: "export const helper = () => {};" }, { path: "package.json", content: '{"name": "my-app"}' }, { path: "docs/README.md", content: "# My App" } ]; await sandbox.fs.writeTree(files, "/blaxel/app"); ``` ```python Python theme={null} files = [ {"path": "src/app.py", "content": "print('Hello')"}, {"path": "src/utils.py", "content": "def helper(): pass"}, {"path": "requirements.txt", "content": "flask==2.0.1"}, {"path": "docs/README.md", "content": "# My App"} ] await sandbox.fs.write_tree(files, "/blaxel/app") ``` ### Read binary file Read a binary file from the sandbox filesystem: ```typescript TypeScript theme={null} const binaryData = await sandbox.fs.readBinary("/tmp/image.webp"); ``` ```python Python theme={null} binary_data = await sandbox.fs.read_binary("/tmp/image.webp") ``` The binary content is returned as a Web API *Blob* object. ### Write binary file Write binary content to a file in the sandbox filesystem: ```typescript TypeScript theme={null} const binaryData = fs.readFileSync("./image.webp"); await sandbox.fs.writeBinary("/blaxel/app/assets/image.webp", binaryData); ``` ```python Python theme={null} with open("image.webp", "rb") as f: binary_data = f.read() await sandbox.fs.write_binary("/blaxel/app/assets/image.webp", binary_data) ``` The binary content to write can be provided as: * *Buffer*: Node.js Buffer object * *Blob*: Web API Blob object * *File*: Web API File object * *Uint8Array*: Typed array containing binary data ### Download file to host Download a file from the sandbox filesystem to the host: ```typescript TypeScript theme={null} await sandbox.fs.download("/tmp/foo.bin", "foo2.bin"); ``` ```python Python theme={null} await sandbox.fs.download("/tmp/foo.bin", "foo2.bin") ``` ### Copy file Copy a file from a path to another path: ```typescript TypeScript theme={null} await sandbox.fs.cp("/blaxel/app/config.json", "/blaxel/app/config.backup.json"); ``` ```python Python theme={null} await sandbox.fs.cp("/blaxel/app/config.json", "/blaxel/app/config.backup.json") ``` ### Delete file or directory Delete a file or directory by specifying its path: ```typescript TypeScript theme={null} await sandbox.fs.rm(`/blaxel/app/config.json`); ``` ```python Python theme={null} await sandbox.fs.rm(f"/blaxel/app/config.json") ``` ## Watch filesystem for events The `watch` function monitors all file system changes **in the specified directory.** You can also watch subdirectories by passing a `/my/directory/**` pattern. By default (when *withContent: false*), the events will only include metadata about the changes, not the actual file contents. Here's what you'll get in the callback events: 1. For ALL operations (CREATE, WRITE, DELETE, etc.), you'll receive: 1. op: The operation type (e.g., "CREATE", "WRITE", "DELETE") 2. path: The directory path where the change occurred 3. name: The name of the file/directory that changed 2. You will NOT receive: 1. The actual content of the files 2. File contents for CREATE or WRITE operations ```typescript TypeScript theme={null} // You can specify if you want the content of the files or not const handle = sandbox.fs.watch("/", (fileEvent) => { console.log(fileEvent.op, fileEvent.path, fileEvent.content) }, { withContent: true }); // Do file operations // At the end, close the watch handle handle.close(); ``` ```python Python theme={null} def watch_callback(file_event): print(file_event.op, file_event.path, file_event.content) # You can specify if you want the content of the files or not handle = sandbox.fs.watch("/", watch_callback, { "with_content": True }) # Do file operations # At the end, close the watch handle handle["close"]() ``` ### Watch sub-directories Watch all sub-directories recursively with `/**`: ```typescript TypeScript theme={null} const handle = sandbox.fs.watch("/folder/**", (fileEvent) => { console.log(fileEvent.op, fileEvent.path) }); ``` ```python Python theme={null} def watch_callback(file_event): print(file_event.op, file_event.path) # You can specify if you want the content of the files or not handle = sandbox.fs.watch("/folder/**", watch_callback) ``` ### Ignore files or directories You can ignore changes in certain files or directories by providing an array of filepaths to ignore: ```typescript TypeScript theme={null} const handle = sandbox.fs.watch("/", (fileEvent) => { console.log(fileEvent.op, fileEvent.path) }, { ignore: ["/folder", "/folder_two/test2.txt"] }); ``` ```python Python theme={null} def watch_callback(file_event): print(file_event.op, file_event.path) # You can specify if you want the content of the files or not handle = sandbox.fs.watch("/", watch_callback, { "ignore": ["/folder", "/folder_two/test2.txt"] }) ``` Specify `withContent: true` so the events include the actual file contents. # Log streaming Source: https://docs.blaxel.ai/Sandboxes/Log-streaming Retrieve process output logs from sandboxes in batch or real-time streaming mode using the Blaxel SDK in TypeScript, Python, or Go. Logging provides developers with visibility into process outputs within sandboxes. You can retrieve logs either in batch or streaming. Complete code examples demonstrating all operations are available on Blaxel's GitHub: [in TypeScript](https://github.com/blaxel-ai/sdk-typescript/tree/main/tests/sandbox), [in Python](https://github.com/blaxel-ai/sdk-python/tree/main/tests/integration/sandbox), and [in Go](https://github.com/blaxel-ai/sdk-go/tree/main/integration_tests). The Blaxel SDK requires two environment variables to authenticate: | Variable | Description | | -------------- | -------------------------- | | `BL_WORKSPACE` | Your Blaxel workspace name | | `BL_API_KEY` | Your Blaxel API key | You can create an API key from the [Blaxel console](https://app.blaxel.ai/profile/security). Your workspace name is visible in the URL when you log in to the console (e.g. `app.blaxel.ai/{workspace}`). Set them as environment variables or add them to a `.env` file at the root of your project: ```bash theme={null} export BL_WORKSPACE=my-workspace export BL_API_KEY=my-api-key ``` When developing locally, you can also **log in to your workspace with Blaxel CLI** (as shown above). This allows you to run Blaxel SDK functions that will automatically connect to your workspace without additional setup. When you deploy on Blaxel, authentication is handled automatically — no environment variables needed. ## In batch ### Retrieve from the execution object Logs for a [process](/Sandboxes/Processes) are available in the *process execution* object **if** the process is started with the `waitForCompletion: true` / `"wait_for_completion": True` parameter. Both standard output (stdout) and standard error (stderr) are surfaced: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.get("my-sandbox"); const process = await sandbox.process.exec({ name: "hello-process", command: "echo 'Hello, World!'", waitForCompletion: true }); console.log(process.logs); ``` ```python Python theme={null} from blaxel.core import SandboxInstance sandbox = await SandboxInstance.get("my-sandbox") process = await sandbox.process.exec({ "name": "hello-process", "command": "echo 'Hello, World!'", "waitForCompletion": True }) print(process.logs) ``` ### Retrieve from a completed process name or ID Retrieve logs for a specific [process](/Sandboxes/Processes) (using either its name or process ID) after it has completed execution. By default, this retrieves standard output (**stdout**) only: ```typescript TypeScript theme={null} const process = await sandbox.process.exec({ name: "hello-process", command: "echo 'Hello, World!'" }); const logs = await sandbox.process.logs("hello-process"); ``` ```python Python theme={null} process = await sandbox.process.exec({ "name": "hello-process", "command": "echo 'Hello, World!'" }) logs = await sandbox.process.logs("hello-process") ``` To retrieve standard error (**stderr**): ```typescript TypeScript theme={null} const errorLogs = await sandbox.process.logs("hello-process", "stderr"); ``` ```python Python theme={null} error_logs = await sandbox.process.logs("hello-process", "stderr") ``` To retrieve both *stderr* and *stdout*: ```typescript TypeScript theme={null} const allLogs = await sandbox.process.logs("hello-process", "all"); ``` ```python Python theme={null} all_logs = await sandbox.process.logs("hello-process", "all") ``` ## Streaming ### Retrieve via a callback function The callback handlers receive log entries in real-time as they're generated by the process: * **onLog/on\_log**: Receives complete log objects with additional metadata This method ensures you get a full view, as it first **backfills with all past logs** before beginning the real-time stream. This approach is ideal for long-running processes where you need to monitor progress or respond to specific log events during execution. ```typescript TypeScript theme={null} await sandbox.process.exec({ name: "streaming-demo", command: "echo 'Starting process'; sleep 2; echo 'Processing...'; sleep 2; echo 'Completed! onLog: (log) => { console.log(`LOG: ${JSON.stringify(log)}`); } }); ``` ```python Python theme={null} def on_log(log): print(f"LOG: {log}") await sandbox.process.exec({ "name": "streaming-demo", "command": "echo 'Starting process'; sleep 2; echo 'Processing...'; sleep 2; echo 'Completed!'", "on_log": on_log }) ``` ### Retrieve from a process name or ID Stream logs for a specific [process](/Sandboxes/Processes) (using either its name or process ID): ```typescript TypeScript theme={null} // Start a long-running process await sandbox.process.exec({ name: "stream-demo", command: "sh -c 'for i in $(seq 1 5); do echo \"Output $i\"; sleep 1; done'" }); const stream = sandbox.process.streamLogs("stream-demo", { onLog: (log) => console.log("Log:", log), onStdout: (stdout) => console.log("Stdout:", stdout), onStderr: (stderr) => console.log("Stderr:", stderr) }); // Wait for completion and cleanup await sandbox.process.wait("stream-demo"); stream.close(); ``` ```python Python theme={null} # Start a long-running process await sandbox.process.exec({ "name": "stream-demo", "command": "sh -c 'for i in $(seq 1 5); do echo \"Output $i\"; sleep 1; done'" }) stream = sandbox.process.stream_logs("stream-demo", { "on_log": lambda log: print(f"Log: {log}"), "on_stdout": lambda stdout: print(f"Stdout: {stdout}"), "on_stderr": lambda stderr: print(f"Stderr: {stderr}") }) # Wait for completion and cleanup await sandbox.process.wait("stream-demo") stream["close"]() ``` # MCP server Source: https://docs.blaxel.ai/Sandboxes/MCP Built-in MCP server that allows agents to operate a sandbox using tool calls. Every sandbox is exposed via an MCP server that allows agents to **operate it using tool calls.** ## Connect to the MCP server The MCP server operates through streamable HTTP at the sandbox's base URL: ```text theme={null} https:///mcp ``` The base URL of a sandbox can be [retrieved](https://docs.blaxel.ai/api-reference/compute/get-sandbox) via the management API of sandboxes under `metadata.url`. Connect to this MCP server [like any other MCP server](../Functions/Invoke-functions) though the endpoint shown above. Instructions for some popular applications are provided below. You must provide your [Blaxel API key](../Security) in the `Authorization` header. If your user has access to multiple workspaces, include the workspace header as well. * Required: `Authorization: Bearer ` * Optional (multi-workspace): `X-Blaxel-Workspace: ` ### Add to Cursor Add the server to `~/.cursor/mcp.json`: ```json theme={null} { "mcpServers": { "blaxel": { "url": "https:///mcp", "headers": { "Authorization": "Bearer ", "X-Blaxel-Workspace": "" } } } } ``` ### Add to Claude Code [Add the remote HTTP server to your Claude Code](https://docs.anthropic.com/en/docs/claude-code/mcp#option-3%3A-add-a-remote-http-server) by running the following command: ```bash theme={null} claude mcp add --transport http blaxel https:///mcp \\ --header "Authorization: Bearer " \\ --header "X-Blaxel-Workspace: " ``` [Follow this tutorial to build a Claude Agent SDK-powered agent that connects to a Blaxel sandbox and operates it using the sandbox's MCP server](../Tutorials/Claude-Agent-SDK-MCP). ### Add to Windsurf Add to `~/.codeium/windsurf/mcp_config.json`: ```json theme={null} { "mcpServers": { "blaxel": { "url": "https:///mcp", "headers": { "Authorization": "Bearer ", "X-Blaxel-Workspace": "" } } } } ``` ### Add to Goose Add to `~/.config/goose/config.yaml`: ```yaml theme={null} extensions: sandbox-mcp: enabled: true type: streamable_http name: sandbox-mcp description: Sandbox MCP uri: https:///mcp envs: {} env_keys: [] headers: Authorization: Bearer X-Blaxel-Workspace: timeout: 300 bundled: null available_tools: [] ``` ## Tools available in the MCP server ### Process management | Tool | Description | | ---------------- | ------------------------------------------------------------- | | `processExecute` | Execute a command with options for timeout, restart, env vars | | `processGet` | Get info about a process by PID or name | | `processGetLogs` | Get logs for a specific process | | `processesList` | List all running processes | | `processStop` | Stop a specific process | | `processKill` | Kill a specific process | ### Filesystem operations | Tool | Description | | ------------------------- | --------------------------------- | | `fsGetWorkingDirectory` | Get the current working directory | | `fsListDirectory` | List contents of a directory | | `fsReadFile` | Read contents of a file | | `fsWriteFile` | Create or update a file | | `fsDeleteFileOrDirectory` | Delete a file or directory | ### Code search and navigation | Tool | Description | | ----------------------- | --------------------------------------------------------------- | | `codegenCodebaseSearch` | Semantic search to find relevant code snippets | | `codegenFileSearch` | Fast fuzzy file path search | | `codegenGrepSearch` | Exact regex search using ripgrep engine | | `codegenListDir` | List directory contents (quick discovery) | | `codegenReadFileRange` | Read file contents within a specific line range (max 250 lines) | | `codegenRerank` | Performs semantic search/reranking on code files in a directory | ### Code editing | Tool | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------------- | | `codegenEditFile` | Propose and apply a [targeted edit to a file](/Sandboxes/Codegen-tools) (⚠️ requires Morph or Relace API key) | | `codegenParallelApply` | Plan parallel edits across multiple file locations | | `codegenReapply` | Use smarter model to retry a failed edit | Using Blaxel SDK, you can retrieve the tools for a sandbox in any supported framework format by passing the sandbox’s name. For example, in LangGraph: ```typescript TypeScript theme={null} import { blTools } from "@blaxel/vercel"; const tools = await blTools([`sandbox/${sandboxName}`]) ``` ```python Python theme={null} from blaxel.langgraph import bl_tools tools = await bl_tools([f"sandbox/{sandbox_name}"]) ``` [Read more documentation](../Functions/Invoke-functions) on connecting to the MCP server directly from your code. ## Example: Connect to a sandbox from Claude Agent SDK Build a Claude Agent SDK agent that connects to a Blaxel sandbox and operates it using the sandbox's MCP server. # Sandboxes Source: https://docs.blaxel.ai/Sandboxes/Overview Lightweight virtual machines where your agents can run AI code with sub-25ms cold starts. Sandboxes are instant-launching virtual machines serving as **sandboxed compute runtimes for agents**. You can securely run LLM-generated code inside these VMs making them ideal for agents that need access to an operating system to run commands with no risk of escaping. They provide a basic [REST API interface](https://docs.blaxel.ai/api-reference/filesystem) for accessing the file system and processes, along with an [MCP server](./MCP) that makes these capabilities available as tool calls. ## Sandbox lifecycle Unlike traditional sandbox infrastructure, Blaxel's standout feature is fully managed lifecycle. Sandboxes resume from standby in under 25 milliseconds and automatically scale to zero after a few seconds of inactivity. This means that your sandboxes wait on standby indefinitely when not used, eliminating cold starts without complex orchestration. Memory state is maintained even after scaling down, including the running processes and entire filesystem. For cost-effective long-term persistence, you can attach [volumes](Volumes) to sandboxes. For shared filesystems mountable across multiple sandboxes, see [Agent Drive](/Agent-drive/Overview). Lifecycle of Blaxel Sandboxes Lifecycle of Blaxel Sandboxes [Read more about the Blaxel sandbox lifecycle](https://blaxel.ai/blog/understand-the-lifecycle-of-a-blaxel-sandbox). ### Active mode Sandboxes stay in active mode as long as there's an active connection to them. You are charged for memory (based on how much you allocated at sandbox creation) and storage while a sandbox is in active mode. CPU resources are allocated accordingly by Blaxel based on your selected memory allocation and are not charged separately. [Learn more about pricing](https://blaxel.ai/pricing). ### Standby mode If a sandbox does not have an active connection, it automatically transitions to a warm standby mode (also called *scale-to-zero*). This transition happens in approximately 15 seconds. If a sandbox has an ongoing WebSocket/TCP connection, there is a 15-minute idle timeout for such a connection. This means that if the WebSocket/TCP connection remains idle for 15 minutes with no activity, the sandbox will automatically transition to standby mode. When transitioning to standby mode, Blaxel automatically creates a snapshot of the entire state (including the complete file system in memory, preserving both files and running processes) and transitions the sandbox to standby mode within approximately 15 seconds. Reconnecting to the sandbox transitions it back to active mode. Any running processes are included in this snapshot and will be instantly restored when you reconnect to the sandbox. You are not charged for memory while a sandbox is in standby mode. However, you are charged for the storage of the snapshot and/or the volumes. [Learn more about pricing](https://blaxel.ai/pricing). To prevent a sandbox from going into standby, you can use [process keep-alive](./Processes#sandbox-keep-alive), [WebSocket ping/pong messages](./Standby-control) or [other techniques](./Standby-control) to prevent the timeout. ### Deletion In addition to automatic scale-to-zero, Blaxel also supports [automatic sandbox deletion based on expiration policies](./Expiration). Starter quotas enforce time-to-live (TTLs), while higher quota tiers unlock sandboxes with unlimited persistence. Automatic deletion differs from automatic standby (*scale-to-zero*). Deleted sandboxes cannot be recovered, while sandboxes in standby mode can be resumed instantly. ### Sandbox deployment statuses During the deployment process, the possible sandbox statuses are: * `UPLOADING`: A new sandbox version has just been uploaded; the build has not started yet. * `BUILDING`: A new sandbox version has been uploaded and the build is in progress. * `DEPLOYING`: The sandbox deployment is in progress. * `DEPLOYED`: The sandbox is ready to use. It is either in active mode or standby mode. * `FAILED`: An error occurred during the build or deployment of the sandbox. * `TERMINATED`: A TTL was set for the sandbox; it has been deleted and will be removed from the API/UI soon. * `DELETING`: A deletion request has been triggered and the deletion is in progress. `UPLOADING/BUILDING` statuses only appear when using `bl deploy` and `bl push` from a sandbox template folder. ## Use cases Some examples of use cases include: * **Code review agents** that analyze repositories to detect the effects of changes. These agents run fully isolated compute environments for each tenant while keeping them snapshotted in standby between sessions, eliminating the need to clone the repo every time. * **Code generation agents** that iterate in their own compute environments, and instantly render live application previews as human users build, step away, and log back in. * **Data analyst agents** that execute adhoc data analysis workflows, generating scripts on-the-fly and running them securely against private files or data within an isolated, ZDR-compliant environment. * **Background agents** that operate beyond their pre-configured tools. Each agent gets its own "personal computer" where it can autonomously install packages, execute custom scripts, store files, and adapt to new requirements securely. They can parallelize dozens of those personal computers. ## Create a sandbox ### Using the SDKs Create a new sandbox using the [Blaxel SDK](../sdk-reference/introduction) by specifying a name, image to use, [deployment region](../Infrastructure/Regions), optional labels, and the ports to expose. Note that **ports** **80** (system), and **443** & **8080** (sandbox API) are reserved by Blaxel. The Blaxel SDK requires two environment variables to authenticate: | Variable | Description | | -------------- | -------------------------- | | `BL_WORKSPACE` | Your Blaxel workspace name | | `BL_API_KEY` | Your Blaxel API key | You can create an API key from the [Blaxel console](https://app.blaxel.ai/profile/security). Your workspace name is visible in the URL when you log in to the console (e.g. `app.blaxel.ai/{workspace}`). Set them as environment variables or add them to a `.env` file at the root of your project: ```bash theme={null} export BL_WORKSPACE=my-workspace export BL_API_KEY=my-api-key ``` When developing locally, you can also **log in to your workspace with Blaxel CLI** (as shown above). This allows you to run Blaxel SDK functions that will automatically connect to your workspace without additional setup. When you deploy on Blaxel, authentication is handled automatically — no environment variables needed. ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; // Create a new sandbox const sandbox = await SandboxInstance.create({ name: "my-sandbox", image: "blaxel/base-image:latest", // public or custom image memory: 4096, // in MB ports: [{ target: 3000, protocol: "HTTP" }], // optional; ports to expose labels: { env: "dev", project: "my-project" }, // optional; labels region: "us-pdx-1" // deployment region }); ``` ```python Python theme={null} import asyncio from blaxel.core import SandboxInstance async def main(): # Create a new sandbox sandbox = await SandboxInstance.create({ "name": "my-sandbox", "image": "blaxel/base-image:latest", # public or custom image "memory": 4096, # in MB "ports": [{ "target": 3000 }], # optional; ports to expose "labels": {"env": "dev", "project": "my-project"}, # optional; labels "region": "us-pdx-1" # deployment region }) if __name__ == "__main__": asyncio.run(main()) ``` An alternative is to use the helper function `createIfNotExists()` (TypeScript) / `create_if_not_exists()` (Python). This helper function either retrieves an existing sandbox or creates a new one if it doesn't exist. Blaxel first checks for an existing sandbox with the provided `name` and either retrieves it or creates a new one using your specified configuration. ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; // Create sandbox if it doesn't exist const sandbox = await SandboxInstance.createIfNotExists({ name: "my-sandbox", image: "blaxel/base-image:latest", // public or custom image memory: 4096, // in MB ports: [{ target: 3000, protocol: "HTTP" }], // optional; ports to expose labels: { env: "dev", project: "my-project" }, // optional; labels region: "us-pdx-1" // deployment region }); ``` ```python Python theme={null} import asyncio from blaxel.core import SandboxInstance async def main(): # Create sandbox if it doesn't exist sandbox = await SandboxInstance.create_if_not_exists({ "name": "my-sandbox", "image": "blaxel/base-image:latest", # public or custom image "memory": 4096, # in MB "ports": [{ "target": 3000 }], # optional; ports to expose "labels": {"env": "dev", "project": "my-project"}, # optional; labels "region": "us-pdx-1" # deployment region }) if __name__ == "__main__": asyncio.run(main()) ``` ### Using the CLI and Console It is also possible to create a sandbox via the Blaxel CLI or the Blaxel Console. ```shell theme={null} bl new sandbox my-sandbox cd my-sandbox bl deploy ``` This command initializes a new sandbox project and configuration file in the named directory `my-sandbox` and then deploys the sandbox on Blaxel. The project directory contains the Blaxel configuration file `blaxel.toml`, which can be further customized to suit your sandbox deployment requirements, by modifying the base image, memory, environment, etc. [`Learn more about the blaxel.toml file`](/deployment-reference). Running `bl deploy` here also saves the image to be reused later as a template. As an alternative, you can use `bl push` to push the image to Blaxel's registry without deploying it. * Log in to the [Blaxel Console](https://app.blaxel.ai/). * Click **Sandboxes** in the left navigation menu. * Click **+Create sandbox** -> **Deploy from console**. * Select an image template. * On the next page, configure the sandbox resources, including memory, time-to-live and region. * Click **Next** to proceed. * On the next page, reconfirm the sandbox parameters. Click **Create** to create the sandbox. ### Using the API Although less common, it is also possible to [create a sandbox by directly interacting with the Blaxel REST API](/Sandboxes/Templates#blaxel-api). ## Understand sandbox configuration ### Images Blaxel provides [pre-built sandbox images](/Sandboxes/Templates#pre-built-templates) for common needs (e.g. `blaxel/nextjs:latest`, `blaxel/py-app:latest`). It is also possible to build your own [custom images](/Sandboxes/Templates), which serve as *templates* to create sandboxes with a consistent, customized set of tools, configurations, or entrypoint scripts. ### Memory and filesystem For maximum performance, Blaxel sandboxes store part of their filesystem in memory. The base of the filesystem (the user-supplied image) is stored as read-only files on host storage using a highly-efficient format called [EROFS (Extendable Read-Only File System)](https://en.wikipedia.org/wiki/EROFS). On top of the read-only base, a writable layer lives entirely in the sandbox's RAM using `tmpfs`. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) serves as orchestrator, directing reads to the EROFS base and writes to the in-memory `tmpfs` filesystem. Due to this, Blaxel sandboxes reserve, when possible, approximately 50% of the available memory for the `tmpfs` filesystem. More information on our implementation is available in this [blog post](https://blaxel.ai/blog/how-to-slash-sandbox-memory-usage-by-75-using-overlayfs). To avoid out-of-memory errors or if additional storage is required, one option is to add storage using [volumes](/Sandboxes/Volumes). However, this requires deleting and recreating the sandbox first. In addition, volumes are not as fast as the native in-memory filesystem. ### Ports The following ports are reserved by Blaxel's system: * **443**: This port hosts the main [sandbox API](https://docs.blaxel.ai/api-reference/filesystem/get-file-or-directory-information) and is exposed via HTTPS * **80**: Reserved for system operations * **8080**: Reserved for sandbox API functionality You can expose specific non-reserved ports [**when creating a new sandbox**](Overview) by using the `ports` parameter. This allows you to access these ports from outside the sandbox. If you plan to access the sandbox on a specific port, typically using a [preview URL](/Sandboxes/Preview-url), you **must** expose the port at sandbox creation time. It is currently not possible to expose sandbox ports post-creation. ### Regions Select the region where you want to deploy your sandbox. The `region` parameter is optional but recommended, and can reference any of the [supported region codes](/Infrastructure/Regions). It is also possible to set a default region using the `BL_REGION` environment variable (e.g. in your `.env` file) to avoid repeating it in every SDK call. The `region` parameter is currently optional but will become mandatory in future versions of the Blaxel SDK. To ensure compatibility, it is highly recommended to always specify a deployment region, either using the `region` parameter in your SDK call or via the `BL_REGION` environment variable. ### Labels You can also add optional labels for sandboxes. Labels are specified as key-value pairs during sandbox creation. ```typescript TypeScript theme={null} // Create a new sandbox const sandbox = await SandboxInstance.create({ name: "my-sandbox", image: "blaxel/base-image:latest", // public or custom image memory: 4096, // in MB labels: { env: "dev", project: "my-project" }, // optional; labels region: "us-pdx-1" // deployment region }); ``` ```python Python theme={null} # Create a new sandbox sandbox = await SandboxInstance.create({ "name": "my-sandbox", "image": "blaxel/base-image:latest", # public or custom image "memory": 4096, # in MB "labels": {"env": "dev", "project": "my-project"}, # optional; labels "region": "us-pdx-1" # deployment region }) ``` You can use these labels for filtering sandboxes in the Blaxel CLI or Blaxel Console: ```shell theme={null} # Get sandboxes with specific label (e.g., env=dev) bl get sandboxes -o json | jq -r '.[] | select(.metadata.labels.env == "dev") | .metadata.name' ``` ### Expiration Blaxel supports [automatic sandbox deletion](./Expiration) based on specific conditions. ## Retrieve an existing sandbox To reconnect to an existing sandbox, simply provide its name: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; // Connect to existing sandbox const sandbox = await SandboxInstance.get("my-sandbox"); ``` ```python Python theme={null} from blaxel.core import SandboxInstance # Connect to existing sandbox sandbox = await SandboxInstance.get("my-sandbox") ``` Complete code examples demonstrating all operations are available on Blaxel's GitHub: [in TypeScript](https://github.com/blaxel-ai/sdk-typescript/tree/main/tests/sandbox), [in Python](https://github.com/blaxel-ai/sdk-python/tree/main/tests/integration/sandbox), and [in Go](https://github.com/blaxel-ai/sdk-go/tree/main/integration_tests). ## Delete a sandbox When you delete a sandbox, all data is immediately erased. If the sandbox was never in standby mode, Blaxel guarantees ZDR (zero data retention). Delete a sandbox by calling: * the class-level `delete()` method with the sandbox `name` as argument, or ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; // Delete sandbox using class-level method await SandboxInstance.delete("my-sandbox"); ``` ```python Python theme={null} from blaxel.core import SandboxInstance # Delete sandbox using class-level method await SandboxInstance.delete("my-sandbox") ``` * by calling the instance-level `delete()` method: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; // Get existing sandbox const sandbox = await SandboxInstance.get("my-sandbox"); // Delete sandbox using instance-level method await sandbox.delete() ``` ```python Python theme={null} from blaxel.core import SandboxInstance # Get existing sandbox sandbox = await SandboxInstance.get("my-sandbox") # Delete sandbox using instance-level method await sandbox.delete() ``` ## Upgrade a sandbox's API Every Blaxel sandbox includes a [custom API binary](./Templates#how-sandbox-templates-work), which is necessary for sandbox functionality like process management and file operations. It is possible to perform an in-place upgrade of this API without needing to recreate or restart the sandbox. This feature is currently in beta and only available for sandboxes built or created with sandbox API v0.2.0 or later (sandboxes created after 2 Feb 2026). For sandboxes built or created earlier than this date/API version, in-place upgrade is not possible; the sandbox must be recreated to obtain the new API. ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; // Connect to existing sandbox const sandbox = await SandboxInstance.get("my-sandbox") // Upgrade sandbox API to "latest" await sandbox.system.upgrade({ version: "latest" }) ``` ```python Python theme={null} from blaxel.core import SandboxInstance # Connect to existing sandbox sandbox = await SandboxInstance.get("my-sandbox") # Upgrade sandbox API to "latest" await sandbox.system.upgrade(version="latest") ``` You can find a list of available API versions in [Blaxel's public repository](https://github.com/blaxel-ai/sandbox/). ## Connect to a sandbox with an interactive terminal You can explore the contents of a sandbox with an interactive terminal. You can access this terminal in two ways: * From the Blaxel Console, by visiting the detail page for your sandbox in your web browser and selecting the **Terminal** tab: image.webp * From your local host, by running: ```bash theme={null} bl connect sandbox your-sandbox-name ``` image.webp Automatically delete sandboxes based on specific conditions. Interact with a sandbox through its MCP server. Execute and manage processes in sandboxes. Manage directories and files in sandboxes. Manage codebases with tools specifically designed for code generation. Access logs generated in a sandbox. Expose and connect to ports of a sandbox. Render code in real-time via a direct preview URL. Manage temporary sessions to connect to sandboxes from a frontend client. Route outbound traffic through the proxy, configure firewalls, and bind egress IPs. Attach volumes to sandboxes to persist files. Create custom sandbox templates. Recommended practices for using Blaxel sandboxes. Sandboxes work alongside [Agents Hosting](/Agents/Overview), [MCP Servers](/Functions/Overview), and [Batch Jobs](/Jobs/Overview) to form a complete agentic architecture. See [observability](/Observability/Overview) for monitoring sandbox activity. See tutorials and examples: Connect a Claude Agent SDK agent to a Blaxel sandbox and operate it using its MCP server. Read tutorials for running applications built with popular frameworks like Astro, Expo and Next.js on Blaxel. Or explore the Sandbox API reference: Access the your sandbox with an HTTP REST API. # Ports Source: https://docs.blaxel.ai/Sandboxes/Ports Expose specific ports on your sandbox and connect to them. Your sandbox, just like any virtual machine, can **expose ports**. These ports let you connect to a process or app running in the sandbox. ## Reserved ports The following ports are reserved by Blaxel's system: * **443**: This port hosts the main [sandbox API](https://docs.blaxel.ai/api-reference/filesystem/get-file-or-directory-information) and is exposed via HTTPS * **80**: Reserved for system operations * **8080**: Reserved for sandbox API functionality You can expose and use any other port on your sandbox. ## Expose a port To whitelist sandbox traffic in your network, you can [retrieve the public IP addresses](/Infrastructure/Regions#public-ip-addresses) used by Blaxel. You can expose specific non-reserved ports [**when creating a new sandbox**](Overview) by using the `ports` parameter. This allows you to access these ports from outside the sandbox. If you plan to access the sandbox on a specific port, typically using a [preview URL](/Sandboxes/Preview-url), you **must** expose the port at sandbox creation time. It is currently not possible to expose sandbox ports post-creation. ```typescript TypeScript {8} theme={null} import { SandboxInstance } from "@blaxel/core"; // Create a new sandbox const sandbox = await SandboxInstance.create({ name: "my-sandbox", image: "blaxel/base-image:latest", memory: 4096, region: "us-pdx-1", ports: [{ target: 3000 }] }); ``` ```python Python {8} theme={null} from blaxel.core import SandboxInstance # Create a new sandbox sandbox = await SandboxInstance.create({ "name": "my-sandbox", "image": "blaxel/base-image:latest", "memory": 4096, "region": "us-pdx-1", "ports": [{ "target": 3000 }] }) ``` ## Access the sandbox on a specific port ### Via the sandbox API This option requires your request to be [authenticated](../Security/Access-tokens). You can access your sandbox on a specific port through the sandbox API using the following URL format: ```text theme={null} https://sbx-{resource_name}-{workspace_id}.{region_id}.bl.run/port/{port_number} ``` For example to connect to port 3000 on `my-sandbox` in workspace `abc123`: `https://sbx-my-sandbox-abc123.us-pdx-1.bl.run/port/3000` Request paths, if any, can be specified after the port number. For example: `https://sbx-my-sandbox-abc123.us-pdx-1.bl.run/port/3000/my/api/endpoint` ### Via a preview URL [Preview URLs](/Sandboxes/Preview-url) provide a simple URL that maps to an internal port of your sandbox. You can either make this URL fully public or secure it with token-based authentication. Generally speaking: * for file and process management in your sandbox, use the sandbox API or SDK. * to access running applications within the sandbox *(such as a NextJS preview server on port 3000)*, use a preview URL instead. ### Via SDK Available in `@blaxel/core` >= 0.2.79 (Node.js) and `blaxel` >= 0.2.49 (Python). The SDK provides a built-in `fetch` method that handles authentication and proxies requests through the sandbox's `/port/{port}` endpoint. ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.get("my-sandbox"); // Fetch a resource on port 3000 const response = await sandbox.fetch(3000); console.log(await response.text()); // Fetch with a specific path const apiResponse = await sandbox.fetch(3000, "/api/health"); console.log(await apiResponse.json()); ``` ```python Python theme={null} from blaxel.core import SandboxInstance sandbox = await SandboxInstance.get("my-sandbox") # Fetch a resource on port 3000 response = await sandbox.fetch(3000) print(response.text) # Fetch with a specific path api_response = await sandbox.fetch(3000, "/api/health") print(api_response.json()) # Fetch with a custom HTTP method post_response = await sandbox.fetch(3000, "/api/data", method="POST", json={"key": "value"}) print(post_response.json()) ``` For older SDK versions, you can construct the port URL manually. This requires your request to be [authenticated](../Security/Access-tokens). ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; // Connect to existing sandbox const sandbox = await SandboxInstance.get("my-sandbox") // Get URL for port access const url = `${sandbox.metadata.url}/port/3000` // Use the URL with authenticated requests const response = await fetch(url, { headers: { 'Authorization': 'Bearer YOUR_TOKEN' } }) ``` ```python Python theme={null} from blaxel.core import SandboxInstance import requests # Connect to existing sandbox sandbox = await SandboxInstance.get("my-sandbox") # Get URL for port access url = f"{sandbox.metadata.url}/port/3000" # Use the URL with authenticated requests response = requests.get(url, headers={ "Authorization": f"Bearer YOUR_TOKEN" }) ``` Expose applications running within the sandbox via a direct preview URL. # Real-time previews Source: https://docs.blaxel.ai/Sandboxes/Preview-url Render an application in real-time via a direct preview URL for its running sandbox. Sometimes you may need to access a running sandbox application and preview the content in real time in a front-end client. This is useful for example to instantly preview React code generated by a codegen AI agent. You can do this via a **preview URL** that routes to a specific port on your sandbox (e.g. *port 3000* for `npm run dev -- --host 0.0.0.0 --port 3000 &`). This preview URL can be either **public** (does not require you to be authenticated to access it) or **private** (see below). They will look something like this: ```text theme={null} https://tkmu0oj2bf6iuoag6mmlt8.us-pdx-1.preview.bl.run ``` You can have multiple preview URLs per sandbox. If you see a 502 error when accessing the preview URL, the most common cause is that your application server is not reachable externally. To resolve this, configure your server to bind to IP address `0.0.0.0`, so that it listens on all available network interfaces. Sample server startup commands are shown below: ```tsx TypeScript theme={null} npm run dev -- --host 0.0.0.0 # or npm serve -- --host 0.0.0.0 ``` ```python Python theme={null} python main.py --host 0.0.0.0 ``` Read more about this in our [troubleshooting page](/troubleshooting). You can also set a **custom domain** on a preview URL (see down below). ## Current limitations of real-time previews JavaScript module bundlers handle real-time previewing. Here are the key compatibility requirements and limitations: * Module bundler **must implement** [ping-pong](https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.2). * Both [Webpack](https://webpack.js.org/) and [Turbopack](https://nextjs.org/docs/app/api-reference/turbopack) (v16.1.1) have been tested and confirmed to work. * Blaxel has a **15-minute connection timeout**. To maintain previews beyond this limit, ensure your bundler implements automatic reconnection. * You cannot create a preview on **port 80** which is reserved for system. Using a Webpack server but unable to hot reload your previews? Check our [troubleshooting page](/troubleshooting) for possible solutions. ## Private preview URLs When you create a private preview URL a token is required to access the URL. You must include the token as: * a `bl_preview_token` query parameter when accessing the preview URL (e.g. *[https://tkmu0oj2bf6iuoag6mmlt8.preview.bl.run/health?bl\_preview\_token=\{token.value}](https://tkmu0oj2bf6iuoag6mmlt8.preview.bl.run/health?bl_preview_token=\{token.value})*) * a `X-Blaxel-Preview-Token` header ## Manage preview URLs To whitelist sandbox traffic in your network, you can [retrieve the public IP addresses](/Infrastructure/Regions#public-ip-addresses) used by Blaxel. ### Blaxel console You can create a preview URL for a sandbox from the Blaxel Console, on the overview of a sandbox: Screenshot 2025-05-06 at 10.50.49 PM.webp ### Blaxel SDK The Blaxel SDK requires two environment variables to authenticate: | Variable | Description | | -------------- | -------------------------- | | `BL_WORKSPACE` | Your Blaxel workspace name | | `BL_API_KEY` | Your Blaxel API key | You can create an API key from the [Blaxel console](https://app.blaxel.ai/profile/security). Your workspace name is visible in the URL when you log in to the console (e.g. `app.blaxel.ai/{workspace}`). Set them as environment variables or add them to a `.env` file at the root of your project: ```bash theme={null} export BL_WORKSPACE=my-workspace export BL_API_KEY=my-api-key ``` When developing locally, you can also **log in to your workspace with Blaxel CLI** (as shown above). This allows you to run Blaxel SDK functions that will automatically connect to your workspace without additional setup. When you deploy on Blaxel, authentication is handled automatically — no environment variables needed. Create and manage a sandbox’s public preview URL: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.get("my-sandbox"); // Create public preview const preview = await sandbox.previews.create({ metadata: { name: "app-preview" }, spec: { port: 3000, public: true, responseHeaders: { "Access-Control-Allow-Origin": "https://YOUR-DOMAIN", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS, PATCH", "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With, X-Blaxel-Workspace, X-Blaxel-Preview-Token, X-Blaxel-Authorization", "Access-Control-Allow-Credentials": "true", "Access-Control-Expose-Headers": "Content-Length, X-Request-Id", "Access-Control-Max-Age": "86400", "Vary": "Origin" } } }); // Get preview URL const url = preview.spec?.url; ``` ```python Python theme={null} from blaxel.core import SandboxInstance sandbox = await SandboxInstance.get("my-sandbox") # Create public preview preview = await sandbox.previews.create({ "metadata": {"name": "app-preview"}, "spec": { "port": 3000, "public": True, "responseHeaders": { "Access-Control-Allow-Origin": "https://YOUR-DOMAIN", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS, PATCH", "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With, X-Blaxel-Workspace, X-Blaxel-Preview-Token, X-Blaxel-Authorization", "Access-Control-Allow-Credentials": "true", "Access-Control-Expose-Headers": "Content-Length, X-Request-Id", "Access-Control-Max-Age": "86400", "Vary": "Origin" } } }) # Get preview URL url = preview.spec.url ``` Or create a private preview: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.get("my-sandbox"); // Create private preview const preview = await sandbox.previews.create({ metadata: { name: "private-preview" }, spec: { port: 3000, public: false } }); // Create access token (10 minutes expiry) const expiresAt = new Date(Date.now() + 10 * 60 * 1000); const token = await preview.tokens.create(expiresAt); // How to access the preview with the token const url = preview.spec?.url; const response = await fetch(`${url}/health?bl_preview_token=${token.value}`); ``` ```python Python theme={null} import httpx from blaxel.core import SandboxInstance from datetime import datetime, timedelta, UTC sandbox = await SandboxInstance.get("my-sandbox") # Create private preview preview = await sandbox.previews.create({ "metadata": {"name": "private-preview"}, "spec": { "port": 3000, "public": False } }) # Create access token (10 minutes expiry) expires_at = datetime.now(UTC) + timedelta(minutes=10) token = await preview.tokens.create(expires_at) # How to access the preview with the token url = preview.spec.url async with httpx.AsyncClient() as client: response = await client.get(f"{url}/health?bl_preview_token={token.value}") ``` ### URL prefix You can customize the preview URL with a custom string prefix using the `prefixUrl` argument: ```typescript TypeScript theme={null} const sandbox = await SandboxInstance.get("my-sandbox"); const preview = await sandbox.previews.create({ metadata: { name: "app-preview" }, spec: { port: 3000, public: true, prefixUrl: "my-prefix" } }); ``` ```python Python theme={null} sandbox = await SandboxInstance.get("my-sandbox") preview = await sandbox.previews.create({ "metadata": {"name": "app-preview"}, "spec": { "port": 3000, "public": True, "prefixUrl": "my-prefix" } }) ``` When using a prefix URL, the workspace name is automatically added to the prefix and included in the final structure for the preview URL - for example, `https://myprefix-workspace-xxx.preview.bl.run`. ### Create if not exists Just like for sandboxes, this helper function either retrieves an existing preview or creates a new one if it doesn't exist. Blaxel first checks for an existing preview with the provided `name` and either retrieves it or creates a new one using your specified configuration. ```typescript TypeScript theme={null} const preview = await sandbox.previews.createIfNotExists({ metadata: { name: "preview-name" }, spec: { port: 443, public: false } }) ``` ```python Python theme={null} preview = await sandbox.previews.create_if_not_exists({ "metadata": { "name": "preview-name" }, "spec": { "port": 443, "public": False } }) ``` ## Custom domains To set up a custom domain for your sandbox preview: * Register a [custom domain](../Infrastructure/Custom-domains) to your Blaxel workspace and complete the verification process * Use this verified custom domain when creating a new preview: ```typescript TypeScript {8} theme={null} const preview = await sandbox.previews.create({ metadata: { name: "preview-custom-domain" }, spec: { port: 443, public: false, customDomain: ‘your.custom.domain.dev’ } }) ``` ```python Python {8} theme={null} preview = await sandbox.previews.create({ "metadata": { "name": "preview-custom-domain" }, "spec": { "port": 443, "public": True, "customDomain": "your.custom.domain.dev” } }) ``` When you register a custom domain, you also enable the use of wildcard subdomains for that domain. For example, if you register `mycompany.com`, you can configure preview URLs to use any `*.mycompany.com` subdomain. ## Delete a preview When a sandbox is deleted, whether manually or automatically due to a TTL or expiration policy, all of its associated preview URLs are automatically cleaned up as part of that deletion. If you need to remove a preview URL before a sandbox is deleted, you can do so explicitly using the SDKs. ```typescript TypeScript theme={null} const sandbox = await SandboxInstance.get("my-sandbox"); await sandbox.previews.delete("app-preview"); ``` ```python Python theme={null} sandbox = await SandboxInstance.get("my-sandbox") await sandbox.previews.delete("app-preview") ``` # Process execution Source: https://docs.blaxel.ai/Sandboxes/Processes Execute shell commands, retrieve process information, stream output, and control process lifecycle in Blaxel sandboxes using the SDK. Execute and manage processes in your sandboxes with Blaxel SDK. Run shell commands, retrieve process information, and control process execution. Complete code examples demonstrating all operations are available on Blaxel's GitHub: [in TypeScript](https://github.com/blaxel-ai/sdk-typescript/tree/main/tests/sandbox), [in Python](https://github.com/blaxel-ai/sdk-python/tree/main/tests/integration/sandbox), and [in Go](https://github.com/blaxel-ai/sdk-go/tree/main/integration_tests). ## Execute processes and commands The Blaxel SDK requires two environment variables to authenticate: | Variable | Description | | -------------- | -------------------------- | | `BL_WORKSPACE` | Your Blaxel workspace name | | `BL_API_KEY` | Your Blaxel API key | You can create an API key from the [Blaxel console](https://app.blaxel.ai/profile/security). Your workspace name is visible in the URL when you log in to the console (e.g. `app.blaxel.ai/{workspace}`). Set them as environment variables or add them to a `.env` file at the root of your project: ```bash theme={null} export BL_WORKSPACE=my-workspace export BL_API_KEY=my-api-key ``` When developing locally, you can also **log in to your workspace with Blaxel CLI** (as shown above). This allows you to run Blaxel SDK functions that will automatically connect to your workspace without additional setup. When you deploy on Blaxel, authentication is handled automatically — no environment variables needed. ### Execute command Execute shell commands: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.get("my-sandbox"); // Execute command const process = await sandbox.process.exec({ command: "echo 'Hello, World!'" }); ``` ```python Python theme={null} from blaxel.core import SandboxInstance sandbox = await SandboxInstance.get("my-sandbox") # Execute command process = await sandbox.process.exec({ "command": "echo 'Hello, World!'" }) ``` Logs for a [process](/Sandboxes/Processes) are available in the *process execution* object **if** the process is started with the `waitForCompletion: true` / `"wait_for_completion": True` parameter. Process execution logs are also visible in the Blaxel Console. Refer to the **Logs** section of the sandbox detail page, as shown below: process logs ### Set the working directory Set the working directory for subsequent commands: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.get("my-sandbox"); // Execute command const process = await sandbox.process.exec({ workingDir: "/app", command: "ls -al" }); ``` ```python Python theme={null} from blaxel.core import SandboxInstance sandbox = await SandboxInstance.get("my-sandbox") # Execute command process = await sandbox.process.exec({ "working_dir": "/app", "command": "ls -al" }) ``` ### Use process names When starting a process (running a command), you can specify a **process name**. This lets you interact with the process—such as retrieving logs or process information—without needing to store the process ID on your end. ```typescript TypeScript {2} theme={null} const process = await sandbox.process.exec({ name: "hello-process", command: "echo 'Hello, World!'" }); const processInfo = await sandbox.process.get("hello-process"); ``` ```python Python {2} theme={null} process = await sandbox.process.exec({ "name": "hello-process", "command": "echo 'Hello, World!'" }) process_info = await sandbox.process.get("hello-process") ``` You can use either the process name or the process ID to get information about the process: ```typescript TypeScript theme={null} const completedProcess = await sandbox.process.get("hello-process"); if (completedProcess.status === "completed") { // ... } ``` ```python Python theme={null} completed_process = await sandbox.process.get("hello-process") if completed_process.status == "completed": # ... ``` The exit code of the process is available in the `exitCode` parameter of the process execution object returned by the `process.exec` and `process.get` methods. You can also use the process ID or name to [retrieve logs of your processes](/Sandboxes/Log-streaming). ### Kill process Kill a process immediately by running: ```typescript TypeScript theme={null} await sandbox.process.kill("test") ``` ```python Python theme={null} await sandbox.process.kill("test") ``` ## Long-running processes ### Wait for process completion You can wait for process completion when executing it: ```typescript TypeScript theme={null} const process = await sandbox.process.exec({ name: "build-process", command: "npm run build", waitForCompletion: true, timeout: 60000 // 60 seconds }); ``` ```python Python theme={null} process = await sandbox.process.exec({ "name": "build-process", "command": "npm run build", "wait_for_completion": True, "timeout": 60000 # 60 seconds }) ``` When waiting for completion, the process execution object will contain a `.logs` field with the [combined `stdout` and `stderr` output as a string](/Sandboxes/Log-streaming). Also, notice the `timeout` parameter which allows to set a timeout duration on the process. When using `waitForCompletion`, Blaxel enforces a **timeout limit of 60 seconds**. Don't set your timeout longer than this. For longer waiting periods, use the process-watching option described below. You can also wait for a process after it has started: ```typescript TypeScript theme={null} await sandbox.process.exec({ name: "long-task", command: "sleep 10" }); // Wait for completion (max 10 minutes, check every 5 seconds) await sandbox.process.wait("long-task", { maxWait: 600000, interval: 5000 }); ``` ```python Python theme={null} await sandbox.process.exec({ "name": "long-task", "command": "sleep 10" }) # Wait for completion (max 10 minutes, check every 5 seconds) await sandbox.process.wait("long-task", max_wait=600000, interval=5000) ``` Set a long completion duration if your process is expected to take longer. ### Wait for ports In some cases, you may want to wait for a port to be opened while running — for example if you are running `npm run dev` and want to wait for port 3000 to be open. ```typescript TypeScript theme={null} const process = await sandbox.process.exec({ name: "dev-server", command: "npm run dev -- --port 3000 &", waitForPorts: [3000] }); ``` ```python Python theme={null} process = await sandbox.process.exec({ "name": "dev-server", "command": "npm run dev -- --port 3000 &", "wait_for_ports": [3000] }) ``` ## Auto-restart ### Restart process on failure You can restart a process if it fails, up to a maximum number of restart attempts: ```typescript TypeScript theme={null} const process = await sandbox.process.exec({ name: "start-server", command: "npm run dev -- --host 0.0.0.0 --port 8000", restartOnFailure: true, maxRestarts: 5 }); ``` ```python Python theme={null} process = await sandbox.process.exec({ "name": "start-server", "command": "uvicorn main:app --reload --host 0.0.0.0 --port 8000", "restart_on_failure": True, "max_restarts": 5 }) ``` ## Sandbox keep-alive By default, sandboxes automatically switch to standby after a few seconds of inactivity to save resources. However, it is possible to adjust this behaviour and keep the sandbox running when you launch a process, even if there isn't an active connection to it. This is typically used to keep a server running in the sandbox environment even when it is not serving requests. You can include additional keep-alive metadata when launching a new process: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.get("my-sandbox"); // Start a dev server that keeps the sandbox awake await sandbox.process.exec({ name: "dev-server", command: "npm run dev -- --hostname 0.0.0.0 --port 3000", keepAlive: true, // Prevents auto-standby timeout: 3600 // Auto-kill after 1 hour }); ``` ```python Python theme={null} from blaxel.core import SandboxInstance sandbox = await SandboxInstance.get("my-sandbox") # Start a dev server that keeps the sandbox awake await sandbox.process.exec({ "name": "dev-server", "command": "npm run dev -- --hostname 0.0.0.0 --port 3000", "keep_alive": True, # Prevents auto-standby "timeout": 3600 # Auto-kill after 1 hour }) ``` If a `timeout` value is not specified, it defaults to 600 seconds. For processes that should run indefinitely until they complete naturally, set the `timeout` to `0`. You can run multiple processes, and the sandbox will stay active until all of them complete: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.get("my-sandbox"); await sandbox.process.exec({ name: "api-server", command: "npm run start:api", keepAlive: true, timeout: 3600 }); await sandbox.process.exec({ name: "worker", command: "npm run start:worker", keepAlive: true, timeout: 3600 }); ``` ```python Python theme={null} from blaxel.core import SandboxInstance sandbox = await SandboxInstance.get("my-sandbox") await sandbox.process.exec({ "name": "api-server", "command": "npm run start:api", "keep_alive": True, "timeout": 3600 }) await sandbox.process.exec({ "name": "worker", "command": "npm run start:worker", "keep_alive": True, "timeout": 3600 }) ``` ## Process statuses A process can have either of the following status: * `running` * `completed` * `failed` * `killed` * `stopped` # Proxy Source: https://docs.blaxel.ai/Sandboxes/Proxy Route outbound sandbox traffic through Blaxel's platform proxy with man-in-the-middle (MITM) header/body injection and secrets, and configure domain firewalls. This feature is currently in public preview and is not recommended for production use. During the preview, the proxy and network features are only available in the `us-was-1` region. The Blaxel SDK supports two network features when creating sandboxes: * **[Proxy routing with secrets injection](./Proxy-secrets-injection)** - the Blaxel proxy performs man-in-the-middle (MITM) interception on outbound HTTPS traffic and injects headers, body fields, and secrets server-side. * **[Domain filtering](./Proxy-domains)** - the Blaxel proxy controls which external domains the sandbox can reach. Proxy and network configuration is set at sandbox creation time and **cannot be updated after the sandbox has been created**. To change the configuration (e.g. rotate a secret, add a new routing rule, or update the allowlist), you must create a new sandbox. Support for in-place updates is coming soon. ## How it works When a sandbox is created with a proxy config, Blaxel: 1. Sets `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` environment variables inside the sandbox 2. Installs a CA certificate and sets `NODE_EXTRA_CA_CERTS` and `SSL_CERT_FILE` so TLS clients trust the proxy 3. Performs MITM on outbound HTTPS via CONNECT tunneling 4. Matches each request against routing rules by destination domain 5. Injects configured headers and body fields, resolving `{{SECRET:name}}` placeholders server-side 6. Adds an `X-Blaxel-Request-Id` header to every proxied request for tracing Standard HTTP clients work transparently: `curl`, `wget`, `git`, `pip`, `npm`, Node.js `https`, Python `requests`, etc. Localhost (`127.0.0.1`), private ranges (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`), `169.254.169.254`, `.local`, and `.internal` are always bypassed automatically. ## Configuration reference All network settings are passed via the `network` key in the sandbox creation options: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.create({ name: "my-sandbox", image: "blaxel/base-image:latest", region: "us-was-1", network: { // Domain filtering (firewall) allowedDomains: [...], forbiddenDomains: [...], // Proxy with header/body injection proxy: { routing: [...], bypass: [...], }, }, }); ``` ```python Python theme={null} from blaxel.core.sandbox import SandboxInstance sandbox = await SandboxInstance.create({ "name": "my-sandbox", "image": "blaxel/base-image:latest", "region": "us-was-1", "network": { # Domain filtering (firewall) "allowedDomains": [...], "forbiddenDomains": [...], # Proxy with header/body injection "proxy": { "routing": [...], "bypass": [...], }, }, }) ``` ### `SandboxNetwork` | Field | Type | Description | | ------------------ | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | | `allowedDomains` | `string[]` / `list[str]` | Allowlist — only these domains are reachable. Supports wildcards (`*.s3.amazonaws.com`). | | `forbiddenDomains` | `string[]` / `list[str]` | Denylist — all domains except these are reachable. Supports wildcards. If both are set, `forbiddenDomains` takes precedence. | | `proxy` | `ProxyConfig` | Proxy routing and bypass configuration. | ### `ProxyConfig` | Field | Type | Description | | --------- | ------------------------------------- | ----------------------------------------------------------------------------- | | `routing` | `ProxyTarget[]` / `list[ProxyTarget]` | Per-destination routing rules with header/body injection. | | `bypass` | `string[]` / `list[str]` | Domains added to `NO_PROXY` that skip the proxy entirely. Supports wildcards. | ### `ProxyTarget` | Field | Type | Description | | -------------- | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `destinations` | `string[]` / `list[str]` | Domain patterns this rule applies to. Use `["*"]` for a global catch-all rule. Supports wildcards (`*.example.com` matches `sub.example.com` but not `example.com`). | | `headers` | `Record` / `dict` | Headers injected into matching requests. Values may contain `{{SECRET:name}}` references. | | `body` | `Record` / `dict` | JSON body fields injected into matching requests. Values may contain `{{SECRET:name}}` references. | | `secrets` | `Record` / `dict` | Named secret values for this rule. Referenced via `{{SECRET:name}}` in headers and body. Write-only — never returned in API responses. Stored encrypted at rest. | ## Region availability Proxy availability is region-dependent. The `Region` type includes a `proxyAvailable` boolean field. Check region support before relying on proxy features: ```typescript TypeScript theme={null} import { listRegions } from "@blaxel/core"; const { data: regions } = await listRegions({ throwOnError: true }); for (const r of regions) { console.log(`${r.name}: proxy=${r.proxyAvailable}`); } ``` ```python Python theme={null} from blaxel.core import listRegions result = await listRegions() for r in result.data: print(f"{r.name}: proxy={r.proxy_available}") ``` ## Environment variables set inside the sandbox When proxy is configured, the sandbox automatically has: | Variable | Purpose | | --------------------- | ----------------------------------------------------------------------- | | `HTTP_PROXY` | Proxy URL for HTTP traffic | | `HTTPS_PROXY` | Proxy URL for HTTPS traffic | | `NO_PROXY` | Comma-separated bypass list (always includes localhost, private ranges) | | `NODE_EXTRA_CA_CERTS` | Path to CA cert for Node.js TLS verification | | `SSL_CERT_FILE` | Path to CA cert for other TLS clients (`curl`, Python, etc.) | ## CLI tool compatibility When proxy is enabled, the following tools work transparently inside the sandbox with no extra configuration: | Tool | Protocol | Notes | | ----------------- | -------- | ------------------------------------------------------------ | | `curl` | HTTPS | Automatic via `HTTPS_PROXY` env var | | `git` | HTTPS | May need `GIT_SSL_CAINFO=$SSL_CERT_FILE` for some operations | | `pip` / `pip3` | HTTPS | Automatic | | `npm` / `npx` | HTTPS | Automatic | | Python `requests` | HTTPS | Automatic via env vars | | Node.js `https` | HTTPS | Automatic via `HTTPS_PROXY` + `NODE_EXTRA_CA_CERTS` env vars | ## Behavior details * **Wildcard matching**: `*.example.com` matches `sub.example.com` and `a.b.example.com` but not `example.com` itself * **No cross-route leakage**: Headers/secrets from one routing rule are never applied to requests matching a different rule * **User headers preserved**: The proxy adds injected headers alongside any headers the sandbox code sends — it does not overwrite user-sent headers * **Body merge**: Injected body fields are merged into the outbound JSON payload. User-sent fields take precedence if there's a key collision * **Tracing**: Every proxied request gets an `X-Blaxel-Request-Id` header for observability * **Local traffic**: Requests to `localhost` / `127.0.0.1` are never routed through the proxy ## Full example: agent sandbox with proxy + firewall ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.create({ name: "agent-workspace", image: "blaxel/base-image:latest", region: "us-was-1", labels: { team: "ml", env: "staging" }, network: { allowedDomains: [ "api.stripe.com", "api.openai.com", "httpbin.org", "*.s3.amazonaws.com", ], proxy: { routing: [ { destinations: ["api.stripe.com"], headers: { "Authorization": "Bearer {{SECRET:stripe-key}}", "Stripe-Version": "2024-12-18.acacia", }, body: { "api_key": "{{SECRET:stripe-key}}", }, secrets: { "stripe-key": "sk-live-abc123...", }, }, { destinations: ["api.openai.com"], headers: { "Authorization": "Bearer {{SECRET:openai-key}}", "OpenAI-Organization": "org-abc123", }, secrets: { "openai-key": "sk-proj-xyz789...", }, }, ], bypass: ["*.s3.amazonaws.com"], }, }, }); // curl https://api.stripe.com/... -> gets auth header + body injected // curl https://api.openai.com/... -> gets auth header injected // curl https://httpbin.org/... -> allowed, no injection // curl https://evil.com/... -> BLOCKED by allowedDomains firewall const result = await sandbox.process.exec({ command: "curl -s https://api.stripe.com/v1/charges", waitForCompletion: true, }); console.log(result.logs); ``` ```python Python theme={null} from blaxel.core.sandbox import SandboxInstance sandbox = await SandboxInstance.create({ "name": "agent-workspace", "image": "blaxel/base-image:latest", "region": "us-was-1", "labels": {"team": "ml", "env": "staging"}, "network": { "allowedDomains": [ "api.stripe.com", "api.openai.com", "httpbin.org", "*.s3.amazonaws.com", ], "proxy": { "routing": [ { "destinations": ["api.stripe.com"], "headers": { "Authorization": "Bearer {{SECRET:stripe-key}}", "Stripe-Version": "2024-12-18.acacia", }, "body": { "api_key": "{{SECRET:stripe-key}}", }, "secrets": { "stripe-key": "sk-live-abc123...", }, }, { "destinations": ["api.openai.com"], "headers": { "Authorization": "Bearer {{SECRET:openai-key}}", "OpenAI-Organization": "org-abc123", }, "secrets": { "openai-key": "sk-proj-xyz789...", }, }, ], "bypass": ["*.s3.amazonaws.com"], }, }, }) # curl https://api.stripe.com/... -> gets auth header + body injected # curl https://api.openai.com/... -> gets auth header injected # curl https://httpbin.org/... -> allowed, no injection # curl https://evil.com/... -> BLOCKED by allowedDomains firewall result = await sandbox.process.exec({ "command": "curl -s https://api.stripe.com/v1/charges", "wait_for_completion": True, }) print(result.logs) ``` # Domain filtering Source: https://docs.blaxel.ai/Sandboxes/Proxy-domains Restrict which external domains a sandbox can reach using allowlists and denylists. This feature is currently in public preview and is not recommended for production use. During the preview, the proxy and network features are only available in the `us-was-1` region. Domain filtering lets you control which external domains a sandbox can reach. You can define an allowlist (only listed domains are reachable) or a denylist (all domains except listed ones are reachable). Domain filtering and proxy routing are **independent configurations** — you do not need to duplicate domains across both. A domain can appear in the allowlist without having a proxy routing rule, and vice versa. Domain filtering relies on the sandbox's tools and libraries respecting the standard proxy environment variables (`HTTP_PROXY`, `HTTPS_PROXY`). Traffic from tools that ignore these variables will not be filtered. Routing-level enforcement is planned for a future release. ## Allowlist Only the listed domains are reachable: ```typescript TypeScript theme={null} await SandboxInstance.create({ name: "restricted-sandbox", image: "blaxel/base-image:latest", region: "us-was-1", network: { allowedDomains: ["api.stripe.com", "api.openai.com", "*.s3.amazonaws.com"], proxy: { routing: [] }, }, }); ``` ```python Python theme={null} await SandboxInstance.create({ "name": "restricted-sandbox", "image": "blaxel/base-image:latest", "region": "us-was-1", "network": { "allowedDomains": ["api.stripe.com", "api.openai.com", "*.s3.amazonaws.com"], "proxy": {"routing": []}, }, }) ``` ## Denylist All domains except the listed ones are reachable: ```typescript TypeScript theme={null} await SandboxInstance.create({ name: "denylist-sandbox", image: "blaxel/base-image:latest", region: "us-was-1", network: { forbiddenDomains: ["*.malware.com", "evil.example.org"], proxy: { routing: [] }, }, }); ``` ```python Python theme={null} await SandboxInstance.create({ "name": "denylist-sandbox", "image": "blaxel/base-image:latest", "region": "us-was-1", "network": { "forbiddenDomains": ["*.malware.com", "evil.example.org"], "proxy": {"routing": []}, }, }) ``` When both `allowedDomains` and `forbiddenDomains` are set, `forbiddenDomains` takes precedence: a domain that appears in both lists will be blocked. ## Firewall + proxy combined Firewall rules and proxy routing compose naturally: ```typescript TypeScript theme={null} await SandboxInstance.create({ name: "locked-down", network: { allowedDomains: ["api.stripe.com", "api.openai.com"], proxy: { routing: [ { destinations: ["api.stripe.com"], headers: { "Authorization": "Bearer {{SECRET:stripe-key}}" }, secrets: { "stripe-key": "sk_live_..." }, }, ], }, }, }); ``` ```python Python theme={null} await SandboxInstance.create({ "name": "locked-down", "network": { "allowedDomains": ["api.stripe.com", "api.openai.com"], "proxy": { "routing": [ { "destinations": ["api.stripe.com"], "headers": {"Authorization": "Bearer {{SECRET:stripe-key}}"}, "secrets": {"stripe-key": "sk_live_..."}, }, ], }, }, }) ``` Only `api.stripe.com` and `api.openai.com` are reachable. The proxy injects credentials for Stripe requests; OpenAI requests go through unmodified. # Proxy routing with secrets injection Source: https://docs.blaxel.ai/Sandboxes/Proxy-secrets-injection Inject secrets, headers, and body fields into outbound sandbox requests using the Blaxel proxy. This feature is currently in public preview and is not recommended for production use. During the preview, the proxy and network features are only available in the `us-was-1` region. The Blaxel proxy intercepts outbound HTTPS requests from the sandbox and injects headers, body fields, and secrets server-side. ## Header injection ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.create({ name: "my-sandbox", image: "blaxel/base-image:latest", region: "us-was-1", network: { proxy: { routing: [ { destinations: ["api.stripe.com"], headers: { "Authorization": "Bearer {{SECRET:stripe-key}}", "Stripe-Version": "2024-12-18.acacia", }, secrets: { "stripe-key": "sk_live_...", }, }, ], }, }, }); ``` ```python Python theme={null} from blaxel.core.sandbox import SandboxInstance sandbox = await SandboxInstance.create({ "name": "my-sandbox", "image": "blaxel/base-image:latest", "region": "us-was-1", "network": { "proxy": { "routing": [ { "destinations": ["api.stripe.com"], "headers": { "Authorization": "Bearer {{SECRET:stripe-key}}", "Stripe-Version": "2024-12-18.acacia", }, "secrets": { "stripe-key": "sk_live_...", }, }, ], }, }, }) ``` Code inside the sandbox calls `api.stripe.com` normally - the proxy intercepts the request, injects the `Authorization` and `Stripe-Version` headers with the resolved secret, and forwards it. The sandbox never sees the raw API key. ## Body injection (POST requests) ```typescript TypeScript theme={null} await SandboxInstance.create({ name: "body-injection", network: { proxy: { routing: [ { destinations: ["api.stripe.com"], headers: { "Authorization": "Bearer {{SECRET:stripe-key}}", }, body: { "api_key": "{{SECRET:stripe-key}}", }, secrets: { "stripe-key": "sk_live_...", }, }, ], }, }, }); ``` ```python Python theme={null} await SandboxInstance.create({ "name": "body-injection", "network": { "proxy": { "routing": [ { "destinations": ["api.stripe.com"], "headers": { "Authorization": "Bearer {{SECRET:stripe-key}}", }, "body": { "api_key": "{{SECRET:stripe-key}}", }, "secrets": { "stripe-key": "sk_live_...", }, }, ], }, }, }) ``` The proxy merges body fields into outbound POST/PUT/PATCH JSON payloads. User-sent fields are preserved; injected fields are added alongside them. ## Multiple routing rules ```typescript TypeScript theme={null} await SandboxInstance.create({ name: "multi-route", network: { proxy: { routing: [ { destinations: ["api.stripe.com"], headers: { "Authorization": "Bearer {{SECRET:stripe-key}}" }, secrets: { "stripe-key": "sk_live_..." }, }, { destinations: ["api.openai.com"], headers: { "Authorization": "Bearer {{SECRET:openai-key}}" }, secrets: { "openai-key": "sk-proj-..." }, }, ], bypass: ["*.s3.amazonaws.com"], }, }, }); ``` ```python Python theme={null} await SandboxInstance.create({ "name": "multi-route", "network": { "proxy": { "routing": [ { "destinations": ["api.stripe.com"], "headers": {"Authorization": "Bearer {{SECRET:stripe-key}}"}, "secrets": {"stripe-key": "sk_live_..."}, }, { "destinations": ["api.openai.com"], "headers": {"Authorization": "Bearer {{SECRET:openai-key}}"}, "secrets": {"openai-key": "sk-proj-..."}, }, ], "bypass": ["*.s3.amazonaws.com"], }, }, }) ``` Secrets are scoped per rule — the Stripe key is never injected into OpenAI requests and vice versa. ## Global catch-all rule ```typescript TypeScript theme={null} await SandboxInstance.create({ name: "global-auth", network: { proxy: { routing: [ { destinations: ["*"], headers: { "X-Global-Auth": "Bearer {{SECRET:global-key}}", }, secrets: { "global-key": "token-xyz", }, }, ], }, }, }); ``` ```python Python theme={null} await SandboxInstance.create({ "name": "global-auth", "network": { "proxy": { "routing": [ { "destinations": ["*"], "headers": {"X-Global-Auth": "Bearer {{SECRET:global-key}}"}, "secrets": {"global-key": "token-xyz"}, }, ], }, }, }) ``` The `["*"]` destination matches all proxied traffic. ## Proxy bypass Domains listed in `bypass` skip the proxy tunnel entirely (direct connection): ```typescript TypeScript theme={null} await SandboxInstance.create({ name: "bypass-only", network: { proxy: { bypass: ["*.s3.amazonaws.com", "169.254.169.254"], }, }, }); ``` ```python Python theme={null} await SandboxInstance.create({ "name": "bypass-only", "network": { "proxy": { "bypass": ["*.s3.amazonaws.com", "169.254.169.254"], }, }, }) ``` S3 and metadata endpoint traffic goes direct; everything else routes through the proxy. ## Secret interpolation Secrets are referenced in headers and body values using the `{{SECRET:name}}` syntax: ```text theme={null} "Authorization": "Bearer {{SECRET:api-token}}" → "Bearer tok_live_abc123" "X-Multi": "{{SECRET:part-a}}-{{SECRET:part-b}}" → "ALPHA-BETA" "X-Plain": "no-secret-here" → "no-secret-here" (unchanged) ``` * Multiple `{{SECRET:...}}` placeholders can appear in a single value * Secrets are resolved server-side by the proxy — the sandbox runtime never sees raw secret values * Secrets are write-only: the `secrets` field is stripped from API responses * Secrets are scoped per routing rule: a secret defined on route A cannot be resolved by route B * User code inside the sandbox can also send `{{SECRET:name}}` in its own request headers or body — the proxy will resolve them if the secret exists on the matching route ## Reading proxy config from an existing sandbox After creation or retrieval, network config is available as typed model attributes: ```typescript TypeScript theme={null} import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.get("my-sandbox"); const network = sandbox.spec.network; if (network?.proxy?.routing) { for (const route of network.proxy.routing) { console.log(route.destinations); console.log(route.headers["Authorization"]); } if (network.proxy.bypass) { console.log(network.proxy.bypass); } } if (network?.allowedDomains) { console.log(network.allowedDomains); } ``` ```python Python theme={null} from blaxel.core.sandbox import SandboxInstance from blaxel.core.client.types import Unset sandbox = await SandboxInstance.get("my-sandbox") network = sandbox.spec.network # SandboxNetwork (or Unset) if not isinstance(network, Unset) and not isinstance(network.proxy, Unset): for route in network.proxy.routing: print(route.destinations) print(route.headers["Authorization"]) if not isinstance(network.proxy.bypass, Unset): print(network.proxy.bypass) if not isinstance(network, Unset) and not isinstance(network.allowed_domains, Unset): print(network.allowed_domains) ``` # Client-side sessions Source: https://docs.blaxel.ai/Sandboxes/Sessions Operate sandboxes from a frontend client using sessions. In many situations, you’ll need to operate a sandbox from a frontend client. When doing so, you cannot share the Blaxel credentials needed to access the sandbox. The solution is to use **sessions.** Sessions are created for a sandbox from a backend server (using Blaxel credentials) and then shared with the frontend client, allowing the browser to connect to the sandbox. From a session, you can: * only interact with the [sandbox API](https://docs.blaxel.ai/api-reference/filesystem/get-file-or-directory-information) (i.e. manage the sandbox filesystem, processes and logs). From a session, you cannot: * interact with Blaxel API to create other preview URLs or sessions. These operations must be done server-side. ## Basic example Create a temporary backend session to access a sandbox instance from your client application. Main parameter for this is `expiresAt`, a `Date()` corresponding to the expiration date. ```typescript TypeScript theme={null} // From your backend import { SandboxInstance } from "@blaxel/core"; const sandbox = await SandboxInstance.get("my-sandbox"); const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours const session = await sandbox.sessions.create({ expiresAt }); ``` ```python Python theme={null} # From your backend from datetime import datetime, timedelta, UTC from blaxel.core import SandboxInstance sandbox = await SandboxInstance.get("my-sandbox") expires_at = datetime.now(UTC) + timedelta(hours=24) session = await sandbox.sessions.create({"expires_at": expires_at}) ``` ```tsx theme={null} /// From your frontend: import { SandboxInstance } from "@blaxel/core"; const sandboxWithSession = await SandboxInstance.fromSession(session) ``` ### Create if expired This helper function either retrieves an existing session or creates a new one if it expired. You can optionally pass `delta` (default: 1 hour), the time window in milliseconds before actual expiration when a session should still be recreated. ```typescript TypeScript theme={null} const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours const session = await sandbox.sessions.createIfExpired( { expiresAt }, 60000 // delta in milliseconds ); ``` ```python Python theme={null} expires_at = datetime.now(UTC) + timedelta(hours=24) session = await sandbox.sessions.create_if_expired( {"expiresAt": expires_at}, delta_seconds=60000 ) ``` ## Example (NextJS) The following example demonstrates a full implementation of sessions in a backend server and frontend client using NextJS. ### Server code (backend) ```typescript expandable theme={null} import { NextResponse } from 'next/server'; import { SandboxInstance } from "@blaxel/core"; const SANDBOX_NAME = 'my-sandbox'; const responseHeaders = { "Access-Control-Allow-Origin": "http://localhost:3000", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS, PATCH", "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With, X-Blaxel-Workspace, X-Blaxel-Preview-Token, X-Blaxel-Authorization", "Access-Control-Allow-Credentials": "true", "Access-Control-Expose-Headers": "Content-Length, X-Request-Id", "Access-Control-Max-Age": "86400", "Vary": "Origin" } export async function GET() { // Get or create sandbox const sandbox = await SandboxInstance.createIfNotExists({ name: SANDBOX_NAME, image: "blaxel/base-image:latest", memory: 4096, region: "us-pdx-1", ports: [ { name: "preview", target: 3000 } ] }); // Create session (24 hours expiry) const session = await sandbox.sessions.create({ expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000) }); // Create preview for port 3000 const preview = await sandbox.previews.create({ metadata: { name: "app-preview" }, spec: { port: 3000, public: true, responseHeaders: responseHeaders } }); return NextResponse.json({ session, preview_url: preview.spec?.url }); } ``` ### Client code (frontend) ```typescript expandable theme={null} 'use client' import { SandboxInstance } from "@blaxel/core"; import { useState, useEffect } from "react"; export default function SandboxClient() { const [sandbox, setSandbox] = useState(null); const [previewUrl, setPreviewUrl] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { initializeSandbox(); }, []); async function initializeSandbox() { // Get session from backend const response = await fetch('/api/sandbox'); const { session, preview_url } = await response.json(); // Create sandbox from session const sandboxInstance = await SandboxInstance.fromSession(session); setSandbox(sandboxInstance); setPreviewUrl(preview_url); // Start development server await sandboxInstance.process.exec({ name: "dev-server", command: "npm run dev", workingDir: "/app", waitForPorts: [3000] }); setLoading(false); } if (loading) return
Loading sandbox...
; return (

Sandbox Demo

{previewUrl && (