Runs vs Tasks
Tasks are TypeScript handlers with durable execution (queues, retries, step.run, step.sleep) — ideal for API-triggered work like sending emails or processing webhooks.
Runs are ephemeral containers that run to exit — ideal for ML training, ETL pipelines, and batch workloads where you bring your own image (Python, Go, Rust, etc.).
Runs are ephemeral containers that run to exit — ideal for ML training, ETL pipelines, and batch workloads where you bring your own image (Python, Go, Rust, etc.).
Parallel Execution
Spawn N runs simultaneously with Promise.all() — fan-out workloads made simple
Run to Completion
Container runs until exit — no idle timeouts, no heartbeats needed
Shared Volume Mounts
Mount shared volumes for feature caches across parallel runs
Machine Profiles
Pick a managed machine size for predictable cost and performance
Log Capture
Full stdout + stderr captured and stored on completion (1 MiB each)
Quick Start
train.ts
import { RunsClient, createClient } from '@sylphx/sdk'
// Connection URL bundles credential + slug — no separate ref env var needed
const config = createClient(process.env.SYLPHX_URL!)
// Single run — wait for completion
const result = await RunsClient.runAndWait(config, {
image: 'ghcr.io/acme/trainer:sha-abc123',
command: ['python', 'train.py', '--fold', '0'],
machine: 'large',
timeoutSeconds: 3600,
})
if (result.exitCode !== 0) {
throw new Error(`Training failed: ${result.stderr}`)
}
console.log('Accuracy:', JSON.parse(result.stdout).accuracy)Parallel Walk-Forward Training
Spawn multiple runs in parallel, each processing a different data fold:
train-parallel.ts
import { RunsClient, createClient } from '@sylphx/sdk'
const config = createClient(process.env.SYLPHX_URL!)
const folds = [0, 1, 2, 3, 4, 5, 6, 7, 8]
// Spawn all runs in parallel
const handles = await Promise.all(
folds.map((fold) =>
RunsClient.run(config, {
image: 'ghcr.io/acme/trainer:sha-abc123',
command: ['python', 'train.py', '--fold', String(fold)],
env: { FOLD_ID: String(fold), DATABASE_URL: process.env.DATABASE_URL! },
machine: 'large',
// Shared feature cache volume for concurrent access.
volumeMounts: [{ volumeId: process.env.CACHE_VOLUME_ID!, mountPath: '/cache' }],
timeoutSeconds: 7200,
}),
),
)
// Wait for all to complete
const results = await Promise.all(handles.map((h) => h.wait()))
const failures = results.filter((r) => r.exitCode !== 0)
if (failures.length > 0) {
console.error(`${failures.length}/${folds.length} folds failed`)
}
const avgAccuracy = results
.filter((r) => r.exitCode === 0)
.map((r) => JSON.parse(r.stdout).accuracy)
.reduce((a, b) => a + b, 0) / folds.length
console.log('Average accuracy:', avgAccuracy)Configuration Reference
| Property | Type | Description |
|---|---|---|
imagerequired | string | OCI image from a connected registry. |
commandrequired | string[] | Command and arguments to run inside the container. |
env | Record<string, string> | Environment variables injected into the container. |
machine | 'nano' | 'micro' | 'small' | 'standard' | 'large' | 'xlarge' | Managed machine size. Defaults to standard; the platform owns scheduling and isolation. |
volumeMounts | RunVolumeMount[] | Volumes to mount. Use shared volumes for cross-run sharing. |
timeoutSeconds | number | Hard deadline. Run is killed if exceeded. Default: 3600 (1h), max: 86400 (24h). |
RunHandle API
| Property | Type | Description |
|---|---|---|
handle.id | string | Run ID (run_xxxxx). Store this to poll later. |
handle.wait(options?) | Promise<RunResult> | Polls until terminal state. Returns RunResult with exitCode, stdout, stderr. |
handle.status | RunStatus | Current status at time of creation: pending | running | succeeded | failed | cancelled | timeout |
Pricing
Billed per compute-second based on the selected machine and actual runtime. Runs that exit early are billed for actual duration only.
| Property | Type | Description |
|---|---|---|
Free tier | All plans | 100K standard compute-seconds per month |
Beyond free tier | Usage-based | Usage-based by machine size and duration |
Cost example
9 parallel large runs × 600s each bill as 5,400 large compute-seconds. Free tier credits apply automatically before usage-based billing.