Skip to main content

Mainbrella Python SDK

Local package, not published to PyPI yet. Python 3.10+; standard-library runtime.

python -m pip install /absolute/path/to/backend/sdk/python
import os
from mainbrella import Mainbrella

client = Mainbrella(os.environ["MAINBRELLA_API_KEY"])
print(client.capabilities())
with client.create(catalog_id="python") as sandbox:
    result = sandbox.commands.run("python --version")
    sandbox.files.write("/tmp/probe.bin", bytes([0, 128, 255]))
    assert sandbox.files.read("/tmp/probe.bin") == bytes([0, 128, 255])

The context manager cleans up only its returned generation. connect(id, created_at) uses an existing generation without provisioning. Creation retries one idempotency key; ambiguous errors expose idempotency_key for reconciliation. Commands and writes are never retried automatically. API errors expose sanitized code and status. Nonzero shell exit codes remain normal command results.

The richer filesystem helpers require the corresponding client.capabilities()["files"] flags. They operate on absolute UTF-8 guest paths:

sandbox.files.mkdir("/workspace/output", recursive=True, mode="0700")
page = sandbox.files.list("/workspace", limit=100)
# Pass page["nextOffset"] as offset for the next page, if it is not None.
metadata = sandbox.files.stat("/workspace/output")
sandbox.files.move("/tmp/probe.bin", "/workspace/output/probe.bin")
sandbox.files.chmod("/workspace/output/probe.bin", "0640")
sandbox.files.remove("/workspace/output", recursive=True)

Lists contain one level, sorted by UTF-8 filename bytes, with up to 1,000 entries per page. Pagination rescans; directory changes can duplicate or omit entries. Metadata includes type, size, mode, uid/gid, second-precision modification time and symlink target. stat inspects a symlink itself unless follow_symlinks=True. Moves never overwrite an existing destination. Removal defaults to files or empty directories and removes a symlink itself. Mutation paths cannot be root. These operations share the four-operation pool and 30-second file deadline. Recursive deletion and moves across filesystems may partly complete before interruption; inspect state before retrying a mutation. Watchers remain unsupported.

Versioned local archives can be built and checked with backend npm run sdk:qualify. Install its wheel with python -m pip install /path/to/mainbrella-0.1.0-py3-none-any.whl; this remains an archive installation, not a PyPI release. See the backend SDK release runbook for artifact and deployed-workflow gates.

Credentials belong in your environment or secret manager. HTTPS is required except loopback development URLs. HTTP redirects are refused.

sandbox.commands.start(command, timeout_ms=300000) returns a managed job with get(), wait(), cancel() and events(). events() yields stdout/stderr chunks and status updates, reconnects on normal stream rotation and tracks job.cursor. Closing the iterator detaches; cancellation is explicit. Execution(sandbox, id) reconnects to a retained job. Preserve idempotency_key on start errors and retry the same options within one hour. Runtime restart interrupts unfinished managed jobs and stops their matching container generation.

Check client.capabilities()["execution"] for argv, stdin, signals, managedProcessListing, programmaticPty and ptyResize before using richer process control:

job = sandbox.commands.start(["cat"], stdin=True, cwd="/tmp", env={"TASK": "probe"})
job.stdin.write(b"hello\n")
job.stdin.close()  # Pipe EOF; no automatic input retry.
result = job.wait()
attached = sandbox.commands.attach(job.id)
executions = sandbox.commands.list()["executions"]  # Retained managed jobs.
terminal = sandbox.commands.start(["/bin/sh"], stdin=True, pty={"cols": 80, "rows": 24})
terminal.resize(132, 40)
terminal.stdin.write(b"exit\n")
terminal.wait()
# terminal.signal("SIGTERM")  # Delivery request; inspect state afterward.

A list starts argv directly; a string uses /bin/sh -lc. Environment values go into the guest and are not protected secrets. Input caps are 64 KiB per write, 1 MiB accepted per job and 256 KiB pending. Ambiguous writes stay counted and are never retried. PTY output combines stderr on stdout with terminal line discipline; input closure may hang up the terminal. Cancellation targets the operation process group; deliberately detached processes remain bounded by the machine lease. Local helpers require corresponding deployed capabilities. Guest-wide process listing and filesystem watching remain unsupported.

Protected application previews require client.capabilities()["previews"]["supported"] to be true. Start your application's HTTP server in the sandbox first, then create a link for its listening port:

preview = sandbox.previews.create(3000, ttl_seconds=900)
# Give preview["url"] to the intended recipient through a private channel.
previews = sandbox.previews.list()["previews"]  # Metadata only, no URLs.
sandbox.previews.revoke(preview["id"])

Ports are 1024–65535, TTL is 60–3600 seconds (default 900), and at most eight grants are active per generation. expiresAt is Unix milliseconds, clipped to the container deadline. The URL is a bearer credential returned once; keep it out of logs and analytics. Listing and revocation work when new issuance is disabled. Creation is never retried automatically. After a lost response, list and revoke the unwanted grant before creating another link. A preview_reconciliation_required error exposes error.preview_id; retry sandbox.previews.revoke(error.preview_id). Revocation closes active connections. Stopping or replacing the generation invalidates its links. Application cookies are stripped; cookie sessions and absolute redirect rewriting are unsupported. Host and forwarded host/protocol reflect the validated HTTPS preview origin; the caller's Origin is preserved. Protected previews are enabled on mainbrella.dev after live qualification; check previews.supported in /capabilities before using them.

Workload observations and webhooks

Check observability.lifecycleEvents, metrics and webhooks first. Lifecycle history belongs to one generation, survives stop, and is bounded to seven days/256 events per slot. Deduplicate stable IDs and order by sequence. Metrics are provider workload observations, separate from billing allocations and public service health; missing evidence remains unobserved/null. Metrics and webhook delivery remain disabled until operator configuration and live qualification.

page = sandbox.events(cursor=0, limit=100)
if page["hasMore"]:
    page = sandbox.events(cursor=page["nextCursor"])
capabilities = client.capabilities()
if capabilities["observability"]["metrics"]:
    observations = sandbox.metrics()
if capabilities["observability"]["webhooks"]:
    configured = sandbox.webhook.configure("https://trusted-relay.example/callback", replay_from_cursor=0)
    # Store configured["signingSecret"] securely, outside guest files/env and logs.
    deliveries = sandbox.webhook.deliveries()["deliveries"]
    # sandbox.webhook.retry(exhausted_event_id)
    sandbox.webhook.remove()

Receiving servers import verify_webhook_signature and call verify_webhook_signature(raw_body, signature_header, signing_secret) before JSON parsing. It authenticates exact bytes and a five-minute timestamp window. Persist received IDs to reject duplicates; delivery can arrive out of order.

Targets must be operator-controlled trusted HTTPS relay hosts; arbitrary customer domains, IPs, credentials, ports and redirects are unsupported. Configuration is per generation and expires after seven days. PUT rotates the secret and clears old attempts; it is never retried automatically. Reconcile lost responses, then rotate explicitly if the one-time secret is unavailable. Eight automatic attempts use bounded backoff; exhausted deliveries allow at most three manual retry cycles. Removing configuration cancels future attempts but cannot undo requests a receiver already accepted. See API.md for retention and signature details. OTLP remains unsupported.

Outbound internet selection

Internet defaults to enabled. Offline creation is immutable for that generation and requires the advertised networking.internetControl capability. The SDK checks discovery before admission, fails if a runtime cannot enforce the policy, and confirms the returned selection. Keep the same creation key on ambiguous transport failure. This does not configure allowlists or secrets; live provider isolation remains a release gate.

offline = client.create(internet=False, idempotency_key="offline-workspace")

Saved workspaces

Check client.capabilities()["persistence"]["snapshots"] before save/restore. Ordinary stop discards changes; save explicitly.

import uuid
save_key = str(uuid.uuid4())  # Persist the key and request body before sending.
saved = sandbox.save_workspace("Project files", stop=True, idempotency_key=save_key)
restored = client.workspaces.restore(saved["id"], idempotency_key=str(uuid.uuid4()))
archive = restored.export_workspace()  # /workspace gzip tar, at most 16 MiB compressed.
restored.kill()
client.workspaces.delete(saved["id"])

client.workspaces.list(), .get(id) and .update(id, name=…, archived=True) manage metadata. Retry an ambiguous save with the original body and key (error.idempotency_key). Restore consumes one start and requires the saved image digest, size and internet policy. Filesystem bytes return in a fresh generation; RAM, processes and previews do not resume. Quotas and expiry apply. Archive retains quota; deletion revokes future restores without immediately erasing provider-held bytes.

Metadata

Release files for mainbrella 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mainbrella 0.1.0
File Size Uploaded
mainbrella-0.1.0.tar.gz 26.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mainbrella 0.1.0
File Interpreter ABI Platform
mainbrella-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 50.2 kB

Release files / mainbrella-0.1.0.tar.gz

Download URL mainbrella-0.1.0.tar.gz
Size 26.9 kB
Tags Source
SHA-256 checksum
How to use checksums
130a9f1522e886af13fbc061746e18ac8f873b9bc342dc29541e402d83ddb5d3
BLAKE2b-256 checksum
How to use checksums
b18d0d58a8104dead2c1ba650a4cace58e225bc75431913564201e0c2c8b33cb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.7

Release files / mainbrella-0.1.0-py3-none-any.whl

Download URL mainbrella-0.1.0-py3-none-any.whl
Size 23.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d3f674a4630fea3e226682ff0309cfb21f367e02695ab6ef3e623798e7f329b3
BLAKE2b-256 checksum
How to use checksums
9765ef97b844e6179fc35fce1791854bb51c2604aed626cf88b6efcc42e8d920
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.7

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page