Install
$ agentstack add skill-blaxel-ai-agent-skills-blaxel-sdk ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ● Filesystem access Used
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Blaxel Skill Reference
What is Blaxel
Blaxel (https://blaxel.ai) is a cloud platform that gives AI agents their own compute environments. Its flagship product is perpetual sandboxes: instant-launching microVMs that resume from standby in under 25ms and scale to zero after a few seconds of inactivity.
You use Blaxel primarily to:
- Spin up a sandbox, install dependencies, run a dev server, and expose a live preview URL
- Build and deploy sandbox templates (custom Docker images) for reusable environments
- Deploy AI agents, MCP servers, and batch jobs as serverless endpoints
SDKs: TypeScript (@blaxel/core) and Python (blaxel) CLI: bl (install from https://docs.blaxel.ai/cli-reference/introduction) Docs: https://docs.blaxel.ai
Authentication
The SDK authenticates using these sources in priority order:
- Blaxel CLI, when logged in
- Environment variables in
.envfile (BL_WORKSPACE,BL_API_KEY) - System environment variables
- Blaxel configuration file (
~/.blaxel/config.yaml)
Log in locally (recommended for development):
bl login YOUR-WORKSPACE
Or set environment variables (for remote/CI environments):
export BL_WORKSPACE=your-workspace
export BL_API_KEY=your-api-key
When running on Blaxel itself, authentication is automatic.
Sandbox workflow (primary use case)
This is the most common workflow: create a sandbox, run commands in it, and get a preview URL.
Step 1: Create a sandbox
Use a public image from the Blaxel Hub (https://github.com/blaxel-ai/sandbox/tree/main/hub):
blaxel/base-image:latest— minimal Linuxblaxel/node:latest— Node.jsblaxel/nextjs:latest— Next.jsblaxel/vite:latest— Viteblaxel/expo:latest— Expo (React Native)blaxel/py-app:latest— Python
Or use a custom template image you deployed yourself.
Declare the ports you need at creation time. Ports cannot be added after creation. Ports 80, 443, and 8080 are reserved.
import { SandboxInstance } from "@blaxel/core";
const sandbox = await SandboxInstance.createIfNotExists({
name: "my-sandbox",
image: "blaxel/base-image:latest",
memory: 4096,
ports: [{ target: 3000, protocol: "HTTP" }],
});
from blaxel.core import SandboxInstance
sandbox = await SandboxInstance.create_if_not_exists({
"name": "my-sandbox",
"image": "blaxel/base-image:latest",
"memory": 4096,
"ports": [{"target": 3000, "protocol": "HTTP"}],
})
Use createIfNotExists / create_if_not_exists to reuse an existing sandbox by name or create a new one.
Always prefer this over a get-then-create fallback. Deleted sandboxes are kept in TERMINATED state for a few minutes (so their logs stay accessible), which means a plain get can return a dead sandbox whose gateway and preview URLs fail with workload-not-found. createIfNotExists checks the status for you and recreates the sandbox when the existing record is FAILED, TERMINATED, TERMINATING, or DELETING. As of @blaxel/core 0.2.88 / blaxel 0.2.55, it also waits out the brief DELETING window right after a delete, so delete-then-recreate works directly. On older SDK versions that window can throw "Unable to create sandbox after 3 attempts" — wait a moment and retry, or upgrade. If you must use get, check sandbox.status before reusing the instance.
Step 2: Write files and run commands
// Write files
await sandbox.fs.write("/app/package.json", JSON.stringify({
name: "my-app",
scripts: { dev: "astro dev --host 0.0.0.0 --port 3000" },
dependencies: { "astro": "latest" }
}));
// Or write multiple files at once
await sandbox.fs.writeTree([
{ path: "src/pages/index.astro", content: "Hello" },
{ path: "astro.config.mjs", content: "import { defineConfig } from 'astro/config';\nexport default defineConfig({});" },
], "/app");
// Execute a command and wait for it to finish
const install = await sandbox.process.exec({
name: "install",
command: "npm install",
workingDir: "/app",
waitForCompletion: true,
timeout: 60, // seconds (default 600; 0 = no auto-kill with keepAlive)
});
// Start a long-running dev server (don't wait for completion)
const devServer = await sandbox.process.exec({
name: "dev-server",
command: "npm run dev",
workingDir: "/app",
waitForPorts: [3000], // returns once port 3000 is open
});
await sandbox.fs.write("/app/package.json", '{"name":"my-app","scripts":{"dev":"astro dev --host 0.0.0.0 --port 3000"},"dependencies":{"astro":"latest"}}')
await sandbox.fs.write_tree([
{"path": "src/pages/index.astro", "content": "Hello"},
{"path": "astro.config.mjs", "content": "import { defineConfig } from 'astro/config';\nexport default defineConfig({});"},
], "/app")
install = await sandbox.process.exec({
"name": "install",
"command": "npm install",
"working_dir": "/app",
"wait_for_completion": True,
"timeout": 60, # seconds (default 600; 0 = no auto-kill with keep_alive)
})
dev_server = await sandbox.process.exec({
"name": "dev-server",
"command": "npm run dev",
"working_dir": "/app",
"wait_for_ports": [3000],
})
IMPORTANT: Dev servers must bind to 0.0.0.0 (not localhost) to be reachable through preview URLs. Use --host 0.0.0.0 or the HOST env variable.
Step 3: Create a preview URL
const preview = await sandbox.previews.createIfNotExists({
metadata: { name: "app-preview" },
spec: { port: 3000, public: true },
});
const url = preview.spec?.url;
// url => https://xxxx.us-pdx-1.preview.bl.run
preview = await sandbox.previews.create_if_not_exists({
"metadata": {"name": "app-preview"},
"spec": {"port": 3000, "public": True},
})
url = preview.spec.url
For private previews, set public: false and create a token:
const preview = await sandbox.previews.createIfNotExists({
metadata: { name: "private-preview" },
spec: { port: 3000, public: false },
});
const token = await preview.tokens.create(new Date(Date.now() + 10 * 60 * 1000));
// Access: preview.spec?.url + "?bl_preview_token=" + token.value
Step 4: Manage the sandbox
// Reconnect to an existing sandbox. Careful: get can return a recently
// deleted sandbox still in TERMINATED state — check status before reuse,
// or use createIfNotExists which handles this for you.
const sandbox = await SandboxInstance.get("my-sandbox");
// List files
const { subdirectories, files } = await sandbox.fs.ls("/app");
// Read a file
const content = await sandbox.fs.read("/app/src/pages/index.astro");
// Get process info / logs
const proc = await sandbox.process.get("dev-server");
const logs = proc.logs; // available if waitForCompletion was true
// Kill a process
await sandbox.process.kill("dev-server");
// Delete the sandbox (all data is erased)
await sandbox.delete();
sandbox = await SandboxInstance.get("my-sandbox")
result = await sandbox.fs.ls("/app")
content = await sandbox.fs.read("/app/src/pages/index.astro")
proc = await sandbox.process.get("dev-server")
# proc.logs available if wait_for_completion was True
await sandbox.process.kill("dev-server")
await sandbox.delete()
Sandbox templates (custom images)
When you need a reusable environment (e.g. an Astro project with all deps pre-installed), create a template:
bl new sandbox my-astro-template
cd my-astro-template
This creates: blaxel.toml, Dockerfile, entrypoint.sh, Makefile.
Customize the Dockerfile. Always include the sandbox-api binary:
FROM node:22-alpine
WORKDIR /app
COPY --from=ghcr.io/blaxel-ai/sandbox:latest /sandbox-api /usr/local/bin/sandbox-api
RUN npm install -g astro
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
The entrypoint.sh must start the sandbox-api:
#!/bin/sh
/usr/local/bin/sandbox-api &
while ! nc -z 127.0.0.1 8080; do sleep 0.1; done
echo "Sandbox API ready"
# Optionally start a process via the sandbox API:
# curl http://127.0.0.1:8080/process -X POST -d '{"workingDir":"/app","command":"npm run dev","waitForCompletion":false}' -H "Content-Type: application/json"
wait
Deploy the template:
bl deploy
Then retrieve the IMAGE_ID and use it to create sandboxes:
bl get sandboxes my-astro-template -ojson | jq -r '.[0].spec.runtime.image'
const sandbox = await SandboxInstance.createIfNotExists({
name: "project-sandbox",
image: "IMAGE_ID",
memory: 4096,
ports: [{ target: 3000, protocol: "HTTP" }],
});
Tutorials and Examples
Sandboxes
Astro: https://docs.blaxel.ai/Tutorials/Astro Expo: https://docs.blaxel.ai/Tutorials/Expo Next.js: https://docs.blaxel.ai/Tutorials/Nextjs
Agents
Overview: https://docs.blaxel.ai/Tutorials/Agents-Overview
Core CLI commands
For CLI commands that may prompt for input (like confirmations), add -y to auto-confirm when running in non-interactive / no-TTY environments (e.g. scripts, CI, agents).
| Command | Purpose | |---------|---------| | bl login | Authenticate to workspace | | bl new sandbox\|agent\|job\|mcp NAME | Initialize new resource from template | | bl deploy | Build and deploy resource to Blaxel | | bl deploy -d DIR | Deploy from a specific directory | | bl serve | Run resource locally for testing | | bl serve --hotreload | Run locally with hot reload | | bl get sandboxes\|agents\|jobs\|functions | List resources | | bl get sandbox NAME --watch | Watch a sandbox deployment status | | bl delete sandbox\|agent\|job\|function NAME | Remove resource | | bl connect sandbox NAME | Open interactive terminal in sandbox | | bl chat AGENT-NAME | Interactive chat with deployed agent | | bl run job NAME --data JSON | Execute a deployed batch job |
blaxel.toml structure
name = "my-resource"
type = "sandbox" # sandbox, agent, function, job, volume-template
[env]
NODE_ENV = "development" # NOT for secrets — use Variables-and-secrets
[runtime]
memory = 4096 # MB
generation = "mk3"
# timeout = 900 # seconds (agents max 900, jobs max 86400)
# Ports (sandbox only)
[[runtime.ports]]
name = "dev-server"
target = 3000
protocol = "tcp"
Important gotchas
- Ports must be declared at sandbox creation time — they cannot be added later
- Ports 80, 443, 8080 are reserved by Blaxel
- Dev servers must bind to
0.0.0.0, notlocalhost, for preview URLs to work - ~50% of sandbox memory is reserved for the in-memory filesystem (tmpfs). Use volumes for extra storage
- Sandboxes auto-scale to zero after ~5s of inactivity. State is preserved in standby and resumes in Workspace settings.
You lose the process logs in the Blaxel Console; reading logs through the SDK/API (process.get, log streaming) still works.
Common antipatterns to flag when reviewing integrations
| Antipattern | Symptom | Fix | |---|---|---| | get-then-create instead of createIfNotExists | workload-not-found on gateway/preview URL after a delete + quick recreate (sandbox returned in TERMINATED state) | createIfNotExists, or check sandbox.status after get | | Re-pulling repo + reinstalling deps on every cold boot | minutes of startup on every session | volume or Agent Drive for the workspace; template image for deps | | One fs.write per file for many files | restore takes minutes (N network round trips) | zip + writeBinary + unzip (2 calls); writeTree for small sets | | Verbose stdout with log export left on | CPU spikes during compiles/heavy output | SANDBOX_DISABLE_PROCESS_LOGGING=true or workspace toggle; also lower app verbosity | | Deleting sandboxes on idle | cold rebuild on every return visit | let standby handle idleness; use ttl for cleanup |
Agent Drive (shared filesystem)
Agent Drive is a distributed filesystem backed by SeaweedFS that can be mounted to multiple sandboxes or agents at any time, including while they are already running. Unlike volumes (block storage attached only at sandbox creation), drives support concurrent read-write access from multiple sandboxes and can be attached/detached dynamically.
> This feature is currently in private preview. During the preview, Agent Drive is only available in the us-was-1 region. Both drive and sandbox must be in this region.
Use cases:
- Passing data between sandboxes without intermediary services
- Storing tool outputs and context histories for other agents
- Sharing datasets across multiple agents
- Creating a shared filesystem cache of package dependencies
Create a drive
import { DriveInstance } from "@blaxel/core";
const drive = await DriveInstance.createIfNotExists({
name: "my-drive",
region: "us-was-1",
displayName: "My Project Drive", // optional; defaults to name
labels: { env: "dev", project: "x" }, // optional
});
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",
"labels": {"env": "dev", "project": "x"},
}
)
Mount a drive to a sandbox
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
});
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="/",
)
Once mounted, any file written to the mount path inside the sandbox is stored on the drive and persists even after the sandbox is deleted.
Mount a subdirectory
await sandbox.drives.mount({
driveName: "my-drive",
mountPath: "/app/project",
drivePath: "/projects/alpha",
});
await sandbox.drives.mount(
drive_name="my-drive",
mount_path="/app/project",
drive_path="/projects/alpha",
)
List, unmount, and delete drives
// List mounted drives on a sandbox
const mounts = await sandbox.drives.list();
// List all drives
const drives = await DriveInstance.list();
// Unmount
await sandbox.drives.unmount("/mnt/data");
// Delete a drive
await DriveInstance.delete("my-drive");
// or instance-level:
const drive = await DriveInstance.get("my-drive");
await drive.delete();
mounts = await sandbox.drives.list()
drives = await DriveInstance.list()
await sandbox.drives.unmount("/mnt/data")
await DriveInstance.delete("my-drive")
# or instance-level:
drive = await DriveInstance.get("my-drive")
await drive.delete()
CLI: bl get drives
Full Agent Drive example
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 image ID from custom 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
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);
import asyncio
from blaxel.core.drive import DriveInstance
from blaxel.core import SandboxInstance
async def main():
drive = await DriveInstance.create_if_not_exists(
{"name": "agent-storage", "region": "us-was-1"}
)
sandbox = await SandboxInstance.crea
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [blaxel-ai](https://github.com/blaxel-ai)
- **Source:** [blaxel-ai/agent-skills](https://github.com/blaxel-ai/agent-skills)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.