Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

FissionPlane Python SDK

Use FissionPlane to create and control isolated sandboxes on your own infrastructure. This package connects Python applications to an FissionPlane installation.

The SDK can:

  • create, list, pause, resume, and delete sandboxes;
  • run commands, stream process output, and use PTYs;
  • read, write, and watch sandbox files;
  • make a sandbox port private or public;
  • build templates from OCI images; and
  • use synchronous or asynchronous Python.

FissionPlane requires an existing on-premises installation. See the FissionPlane repository for the platform source and deployment information.

Requirements

  • Python 3.10 or later
  • An FissionPlane control plane URL
  • An API key or OIDC bearer token
  • A template alias or template artifact ID

Install

Install the package with pip:

pip install fissionplane

You can also use uv:

uv add fissionplane

Configure the client

Set the control plane URL and API key:

export FISSIONPLANE_API_URL="https://api.sandbox.example.com"
export FISSIONPLANE_API_KEY="your-api-key"

FissionPlane() reads both variables. You can also pass the values directly:

from fissionplane import FissionPlane

client = FissionPlane(
    base_url="https://api.sandbox.example.com",
    api_key="your-api-key",
)

Use access_token instead of api_key for an OIDC bearer token. An explicit API key takes precedence over an access token. The client rejects an empty credential, or one containing whitespace, when you construct it.

Timeouts, retries, and logging

The client applies a 60 second timeout to every request. Change the default with request_timeout. Pass 0 or None to disable the timeout.

client = FissionPlane(request_timeout=30)

Every operation also accepts request_timeout for one call:

sandbox = client.sandboxes.get("sbx-123", request_timeout=5)
result = sandbox.commands.run("make", args=["build"], request_timeout=0)

The client retries a failed request twice by default, with exponential backoff and jitter. Set max_retries=0 to disable retries. The SDK only retries a request that is safe to send again:

  • reads, such as get(), list(), and files.read();
  • sandboxes.create() when you pass an idempotency_key; and
  • responses the server marks retryable, or status 429 and 5xx responses that the server does not mark retryable: false.
client = FissionPlane(max_retries=4)
sandbox = client.sandboxes.create("base", idempotency_key="example-job-1")

Pass headers to add or replace headers on one call:

client.sandboxes.list(headers={"X-Request-Source": "nightly-job"})

The SDK reports retries, capability token re-mints, and page fetches at debug level on the fissionplane logger. Pass your own logger to redirect them:

import logging

logging.basicConfig(level=logging.DEBUG)
client = FissionPlane(logger=logging.getLogger("my-app.sandboxes"))

Anything you pass in httpx_args wins over the SDK defaults, including timeout and headers.

Create a sandbox and run a command

Sandbox creation is synchronous. The call returns after a node acknowledges the sandbox.

from fissionplane import FissionPlane

client = FissionPlane()
sandbox = client.sandboxes.create(
    "base",
    name="example-job",
    deadline_seconds=600,
    idempotency_key="example-job-1",
)

try:
    result = sandbox.commands.run(
        "python",
        args=["-c", "print('hello from FissionPlane')"],
        timeout_seconds=30,
    )
    print(result.stdout)
    print(result.exit_code)
finally:
    sandbox.delete()

commands.run() waits for the command to exit. It returns the exit code, standard output, standard error, and an optional truncation flag.

Use sandbox.commands.list_processes() to list supervised processes. Use sandbox.commands.kill(pid, "SIGTERM") to signal one process.

Start a background process when output must be followed or stdin stays open:

from fissionplane import PtySize

process = sandbox.commands.start("bash", pty=PtySize(cols=120, rows=40))
attachment = process.attach()
attachment.send_input("pwd\n")

for event in attachment:
    if event.type == "stdout":
        print(event.data, end="")
    elif event.type == "exit":
        break

Filesystem operations use the sandbox data plane directly:

sandbox.files.make_dir("/workspace")
sandbox.files.write("/workspace/input.txt", b"hello")
entries = sandbox.files.list("/workspace")
watch = sandbox.files.watch("/workspace", recursive=True)

Manage the sandbox lifecycle

A sandbox has one of four visible states: running, paused, terminated, or failed.

sandbox.pause()
sandbox.resume(deadline_seconds=600)
sandbox.extend_deadline(900)
sandbox.delete()

pause() saves a snapshot and releases node capacity. resume() restores the snapshot on a node. A resumed sandbox has a new epoch.

Capability tokens belong to one sandbox epoch. The SDK replaces the token on the handle after resume(). A handle returned by sandboxes.get() or sandboxes.iterate() has no token. Call sandbox.mint_token() before you use commands on such a handle.

A capability token also expires on its own schedule. When the sandbox data plane rejects one, the handle mints a replacement and sends the request again. This applies to command, file, and streaming calls alike, so long-lived handles keep working without your code refreshing anything.

Use an idempotency key when your application can retry sandbox creation. The same key returns the sandbox from the first successful request.

Expose a port

Every port is private by default. Private access requires a capability token. Make one port public only when anonymous access is required.

exposure = sandbox.ports.expose(3000, "public")
print(exposure.url)

records = sandbox.ports.list()
sandbox.ports.unexpose(3000)

unexpose() removes the exposure record. The port then returns to private access.

Build and use a template

Template builds run asynchronously on the FissionPlane installation.

from fissionplane import BuildStep

build = client.templates.build(
    "python:3.12",
    alias="python-tools",
    steps=[BuildStep(command="pip install httpx")],
)
template = build.wait(timeout=600)

sandbox = client.sandboxes.create("python-tools")

Use build.logs(offset) to read build output. Pass the returned offset to the next call. Use client.templates.get_build(build_id) to reconnect to an existing build.

Use the asynchronous client

AsyncFissionPlane has the same operations as the synchronous client. Await each network operation.

import asyncio

from fissionplane import AsyncFissionPlane


async def main() -> None:
    client = AsyncFissionPlane()
    sandbox = await client.sandboxes.create("base")
    try:
        result = await sandbox.commands.run("python", args=["-V"])
        print(result.stdout)
    finally:
        await sandbox.delete()


asyncio.run(main())

Use async for with client.sandboxes.iterate() to read all matching pages.

Read every page

sandboxes.list() returns one page and its next_cursor. Use iterate() when you want every match instead. It fetches one page at a time and follows the cursor until the collection ends.

for sandbox in client.sandboxes.iterate(state=SandboxState.RUNNING, limit=50):
    print(sandbox.sandbox_id)

The asynchronous client returns an async generator:

async for sandbox in client.sandboxes.iterate(metadata={"run": "42"}):
    print(sandbox.sandbox_id)

Handle errors

All SDK errors inherit from FissionPlaneError. HTTP errors include status, code, retryable, and request_id when the server returns those fields.

from fissionplane import FissionPlaneError, RateLimitError

try:
    sandbox = client.sandboxes.create("base")
except RateLimitError as error:
    if error.retryable:
        print(f"retry later; request ID: {error.request_id}")
except FissionPlaneError as error:
    print(error.code, error)

The package also exports errors for authentication, authorization, missing resources, lifecycle conflicts, expired snapshots, command timeouts, and failed template builds.

Control plane and data plane

The control plane manages sandboxes, ports, tokens, and templates. The sandbox data plane runs commands, streams process I/O, and accesses files.

The SDK sends your API key or OIDC token to the control plane. It sends a short-lived capability token to the sandbox data plane. The SDK stores that token on the sandbox handle.

The data-plane agent uses port 50000 by default. Pass agent_port to the client only when your installation uses a different port.

Build the API reference

The package documents its public surface with pdoc. Run it from src/sdks/python:

uv run pdoc fissionplane -o docs

The command writes browsable HTML to docs/, which is not committed. Add module names to document them on their own pages, for example uv run pdoc fissionplane fissionplane.sandboxes -o docs. Do not point pdoc at fissionplane._api or fissionplane._dataplane: those are generated cores, and the OpenAPI files below are their reference.

Use uv run pdoc fissionplane without -o to preview the reference on a local web server.

API status

This package is version 0.0.1. Treat its public API as unstable until the project publishes a stable release.

The control-plane and data-plane OpenAPI files define the HTTP contracts:

License

FissionPlane uses the Apache License 2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fissionplane-0.0.1b0.tar.gz (102.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fissionplane-0.0.1b0-py3-none-any.whl (129.0 kB view details)

Uploaded Python 3

File details

Details for the file fissionplane-0.0.1b0.tar.gz.

File metadata

  • Download URL: fissionplane-0.0.1b0.tar.gz
  • Upload date:
  • Size: 102.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.24 {"installer":{"name":"uv","version":"0.9.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for fissionplane-0.0.1b0.tar.gz
Algorithm Hash digest
SHA256 6b0e5bc150bb802b3c9f8aeb50fb79630748ce26d5f9bb7c8d8d91df5b91e79d
MD5 e1894bd7d0b25bc6f9361eb567b87ce8
BLAKE2b-256 692adea481f4bf67a1385ca6c66ddc41c55c7a545168c1eb33f21a522babc63b

See more details on using hashes here.

File details

Details for the file fissionplane-0.0.1b0-py3-none-any.whl.

File metadata

  • Download URL: fissionplane-0.0.1b0-py3-none-any.whl
  • Upload date:
  • Size: 129.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.24 {"installer":{"name":"uv","version":"0.9.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for fissionplane-0.0.1b0-py3-none-any.whl
Algorithm Hash digest
SHA256 53fdab5f0aeb7cef0c7aedbd93611a7a3b936e1e5bde79a1fb333ceda883451b
MD5 6d21de61bc1908699a6ef2e0657055d6
BLAKE2b-256 45ee49b2e31b34b5856dadc87d3c931aa54c2ea99435c072cf66cbe7ad0d082b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page