Skip to content

SandboxProvider

A sandbox provider creates sandboxes on one platform, such as this machine or Daytona, and resumes sandboxes it created before. The settings a platform needs, such as credentials or a root directory, go to the provider’s layer, so code that creates sandboxes does not depend on which provider it uses.

Since v0.1.0

The service over a provider’s create and resume, with createScoped derived from them, as ChildProcessSpawner.make derives the rest of that service from spawn.

Example (A sandbox for one piece of work)

import { SandboxProvider } from "@amends-dev/sandbox"
import { Effect } from "effect"
declare const create: SandboxProvider.SandboxProvider["Service"]["create"]
declare const resume: SandboxProvider.SandboxProvider["Service"]["resume"]
const sandboxProvider = SandboxProvider.make({ create, resume })
// The sandbox is destroyed when the scope closes, however it closes.
const program = Effect.scoped(
Effect.gen(function* () {
const sandbox = yield* sandboxProvider.createScoped()
return sandbox.workingDirectory
})
)

Signature

declare const make: (provider: Pick<SandboxProvider["Service"], "create" | "resume">) => SandboxProvider["Service"]

Source

Since v0.1.0

What a sandbox is created with: its id, the ports it exposes, the template that prepares it, the network policy it starts under, and what only its provider takes. Each has a default.

Signature

export interface CreateOptions<E> {
/**
* Names the new sandbox. Creating never looks a sandbox up, so an id already in use fails with
* `AlreadyExistsError`. When omitted, the provider picks one.
*/
readonly id?: Sandbox.SandboxId
/** The ports to expose from the start; `Sandbox.exposePorts` exposes more later. */
readonly ports?: ReadonlyArray<Network.Port>
/**
* Prepares the sandbox before `create` returns it. It may be given as `undefined`, as an agent's
* `template` is when the agent needs no sandbox.
*/
readonly template?: Template.Template<E> | undefined
/**
* The outbound network policy the sandbox starts under, `AllowAll` when omitted. It is in force
* before `create` returns, so nothing run in the sandbox afterwards reaches further than it
* allows; the template prepares the sandbox before it applies, as preparing may download what it
* installs. Fails with `UnsupportedError`, creating nothing, when the provider cannot enforce the
* policy, as `Sandbox.setNetworkPolicy` does.
*/
readonly networkPolicy?: Network.NetworkPolicy
/** What only one platform takes, under its provider's id, as `ProviderOptions` describes. */
readonly providerOptions?: ProviderOptions
}

Source

Since v0.1.0

What only one platform takes on a create, keyed by the provider’s id, as SandboxError.provider names it, with JSON values: such as the snapshot a sandbox on Daytona starts from.

Details

A provider decodes its own entry and ignores the others, so one value can name several providers; an entry that is not what the provider takes fails with InvalidOptionsError, creating nothing.

Example (The snapshot a sandbox on Daytona starts from)

import { SandboxProvider } from "@amends-dev/sandbox"
import { Effect } from "effect"
const program = Effect.gen(function* () {
const sandboxProvider = yield* SandboxProvider.SandboxProvider
return yield* sandboxProvider.create({
providerOptions: { daytona: { snapshot: "python-3.13" } }
})
})

Signature

declare const ProviderOptions: Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>

Source

Since v0.1.0

Signature

type ProviderOptions = typeof ProviderOptions.Type

Source

Since v0.1.0

Creates sandboxes on one platform and resumes the ones it created before.

Details

A program asks for the service and gets whichever provider’s layer it runs under. make builds the service from a provider’s create and resume.

Example (Creating a sandbox, stopping it, and resuming it later)

import { Network, Sandbox, SandboxProvider } from "@amends-dev/sandbox"
import { Effect, FileSystem, Path } from "effect"
const id = Sandbox.SandboxId.make("review-42")
const port = Network.Port.make(3000)
const program = Effect.gen(function* () {
const sandboxProvider = yield* SandboxProvider.SandboxProvider
const sandbox = yield* sandboxProvider.create({ id, ports: [port] })
yield* Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem
const path = yield* Path.Path
yield* fs.writeFileString(path.join(sandbox.workingDirectory, "notes.md"), "# Review")
}).pipe(Effect.provide(Sandbox.layerServices(sandbox)))
yield* sandbox.stop
// Later, in this process or another: the files are still there, and so is the port.
const resumed = yield* sandboxProvider.resume(id)
const endpoint = yield* resumed.endpoint(port, "http")
return endpoint.url
})

Signature

declare class SandboxProvider

Source

Since v0.1.0