This reference documents the chalkcompute Python SDK for building and deploying containers, sandboxes, volumes, remote functions, and scaling groups on Chalk's managed compute infrastructure. Use it to spin up isolated environments, stash files in persistent volumes, and deploy versioned Python functions and classes that scale on demand.
New to Chalk Compute? Start with the Compute overview for a conceptual tour of sandboxes, containers, scaling groups, and the deployment model. Then dive into Images, Functions, Volumes, and Sandbox design for task-oriented guides. The sections below document every public class and function in the SDK.
A full end-to-end sandbox: build an image with your code baked in, create the sandbox, exec a command inside it, read the output, and tear it down.
from chalkcompute import SandboxClient, Image
client = SandboxClient(target="sandboxes.example.com:443")
img = (
Image.debian_slim()
.pip_install(["pandas", "requests"])
.add_local_file(
"./analyze.py",
"/app/analyze.py",
)
.workdir("/app")
)
sandbox = client.create(
image=img,
name="analysis-scratchpad",
cpu="2",
memory="4Gi",
)
result = sandbox.exec(
"python",
"/app/analyze.py",
"--input", "/data/in.csv",
)
print(result.stdout_text)
sandbox.terminate()
Declarative, composable container image builder using a fluent API.
Each builder method returns a new Image instance so intermediate images
can be shared and extended. Use class methods like Image.debian_slim()
or Image.base() to start, then chain pip_install, run_commands,
add_local_file, etc.
Declarative, composable container image builder.
Uses a fluent (method-chaining) API. Each method returns a new Image
instance so that intermediate images can be shared and extended.
from chalkcompute import Image
img = (
Image.debian_slim()
.pip_install(["requests", "pandas"])
.workdir("/home/user/app")
)
Install packages from a requirements.txt file via uv pip install.
The file is read locally and its contents are inlined into the image
spec so that the file does not need to be accessible at build time.
Uses the uv resolver for significantly faster installs than
pip_install_from_requirements. Requires a base image that
has uv available.
from chalkcompute import Image
img = (
Image.base("ghcr.io/astral-sh/uv:python3.14-trixie-slim")
.uv_pip_install_from_requirements("./requirements.txt")
)
Add a local file into the image.
Each call is additive — the file is appended to the set of
files (or build steps) already registered on the image, not
replacing them — so add_local_file can be chained many times
to bring in several files.
Optional POSIX file permission mode. Written in octal with a
0o prefix; if omitted, the file is created with the image's
default permissions. Common values:
0o755 (rwxr-xr-x) — executable scripts and binaries;
owner can read/write/execute, everyone else read/execute.0o644 (rw-r--r--) — regular data files; owner can
read/write, everyone else read-only.0o600 (rw-------) — private files (credentials,
secrets, SSH keys); owner read/write, no access for others.0o700 (rwx------) — owner-only directories or
private executables.0o400 (r--------) — immutable/read-only files the
workload must not mutate.from chalkcompute import Image
img = (
Image.debian_slim()
.add_local_file(
"./config.yaml",
"/app/config.yaml",
)
.add_local_file(
"./entrypoint.sh",
"/app/entrypoint.sh",
mode=0o755,
)
)
Add an entire local directory into the image.
Each call is additive — the directory's files are appended to
the set already registered on the image, so add_local_dir can
be chained with other add_local_dir / add_local_file calls
to merge sources from multiple locations.
Automatically respects .gitignore and .chalkignore files found
at any level within src (each scoped to its directory subtree,
matching go-git's behavior). The .git/ directory is always
excluded. Negation patterns (!) are supported.
"copy" inlines all file contents into the image spec.
"volume" (default) defers each file as a lazy reference
to be mounted at sandbox start.
from chalkcompute import Image
img = (
Image.debian_slim()
.add_local_dir(
"./src",
"/app/src",
exclude=["*.pyc", "__pycache__"],
)
)
Add raw Dockerfile instructions.
These are injected verbatim into the generated Dockerfile. Each call
is additive — instructions are appended to any previous build
steps (including prior dockerfile_commands calls), not replacing
them — so you can split a Dockerfile across multiple calls and
interleave with other builder methods.
from chalkcompute import Image
img = (
Image.debian_slim()
.dockerfile_commands([
"USER root",
"EXPOSE 8080",
])
)
Set the container entrypoint.
The ENTRYPOINT is the executable that always runs when the
container starts. Unlike cmd — which provides default
arguments that callers can override at run time — the entrypoint
is fixed: callers can't swap it out by passing a different command
to Container.run or kubectl exec, only append to it.
Together, ENTRYPOINT and CMD form the full command that
runs in the container:
ENTRYPOINT runs with no args.CMD is treated as the
executable and the rest as its arguments.ENTRYPOINT + CMD, where
CMD supplies the default (overridable) arguments.Each call replaces any previously set entrypoint.
Use exec-form (["python", "-m", "my_app"]) rather than
shell-form ("python -m my_app") — exec-form skips the shell
wrapper and makes signals (SIGTERM, SIGINT) reach your process
directly, which matters for graceful shutdown.
from chalkcompute import Image
img = (
Image.debian_slim()
.entrypoint(["python", "-m", "my_app"])
)
Set the container CMD.
The CMD is the default argument list passed to the container's
entrypoint when the container starts. Unlike entrypoint — which
sets the executable that always runs — CMD defines the default
arguments that can be overridden at run time (for example, by a
Container.run(command=[...]) call or a Kubernetes pod spec).
If no entrypoint is set, the first element of CMD is treated as
the executable. If an entrypoint is set, CMD is appended to it.
Run python -m my_app by default, but allow the caller to override
the module at run time:
from chalkcompute import Image
img = (
Image.debian_slim()
.entrypoint(["python"])
.cmd(["-m", "my_app"])
)
High-level container abstraction backed by the Chalk ContainerService.
Orchestrates image building, local file upload via volumes, and container
lifecycle in a single API. Use Container(image=...).run() to start,
.exec() to run commands, and .stop() to clean up.
A managed container backed by the Chalk ContainerService.
Orchestrates image building, local file upload via volumes, and container lifecycle in a single high-level API.
Build an image, run a container, and exec a command inside it:
from chalkcompute import Container, Image
c = Container(
image=(
Image.debian_slim()
.pip_install(["requests"])
.add_local_file("./script.py", "/app/script.py")
),
cpu="1",
memory="2Gi",
env={"LOG_LEVEL": "INFO"},
).run()
result = c.exec("python", "/app/script.py")
result.stdout_text
'hello\n'
c.stop()
Opaque container identifier assigned by the service.
None until run (or from_id / from_name)
has resolved the container against the service.
The most recently fetched ContainerInfo snapshot.
None until the container has been started or attached to.
Populated by run, from_id, and from_name.
Call refresh_info to fetch the latest state from the service.
Build the image, upload local files, and start the container.
Walks through three phases and blocks until the container is ready
(or raises): (1) build the image via CustomImageService, (2) if
the Image has add_local_file / add_local_dir entries
registered with strategy="volume", upload them to a managed
volume and attach it, (3) start the container and poll until it
reaches the Running state.
self, to allow chaining.
If the container fails to start or times out.
If the image build fails.
Build an image from scratch, start a container, inspect it, and tear it down:
from chalkcompute import Container, Image
img = (
Image.debian_slim()
.pip_install(["requests"])
.add_local_file(
"./app.py",
"/app/app.py",
)
.workdir("/app")
)
c = Container(
image=img,
cpu="1",
memory="2Gi",
env={"LOG_LEVEL": "INFO"},
)
c.run()
c.info.status
'Running'
c.stop()
Execute a command in the running container.
The command runs as a one-shot process inside the already-started
container (equivalent to docker exec). Output is captured in
full and returned at once; use exec if you need a
streaming interface.
The stdout, stderr, and exit code of the executed command.
If the container is not running or the exec fails.
Build an image, start a container, run a few commands against it, and clean up:
from chalkcompute import Container, Image
c = Container(
image=(
Image.debian_slim()
.pip_install(["requests"])
.add_local_file(
"./fetch.py",
"/app/fetch.py",
)
),
cpu="1",
memory="1Gi",
).run()
hello = c.exec(
"python",
"/app/fetch.py",
"https://example.com",
)
hello.exit_code
0
hello.stdout_text.splitlines()[0]
'<!doctype html>'
err = c.exec("ls", "/does-not-exist")
err.exit_code
2
err.stderr_text
"ls: cannot access '/does-not-exist': No such file or directory\n"
c.stop()
Result of a one-shot command executed inside a container.
Returned by exec. All three fields are populated once
the command has finished — ExecResult does not stream.
POSIX exit status of the command (0 on success, non-zero on
error; signals are encoded as 128 + signum where applicable).
stdout decoded as UTF-8 (with errors="replace").
Convenience for the common case where the command emits text.
Invalid UTF-8 bytes are replaced with U+FFFD rather than
raising.
Low-level sandbox management backed by the Chalk SandboxService (gRPC).
Provides bidirectional streaming exec, interactive stdin/signal control, and fine-grained process lifecycle management.
Initialize the gRPC client.
Optional TLS/SSL channel credentials. If None, uses insecure
channel.
Container image to use — either a string reference
(e.g. "ubuntu:latest") or a declarative Image builder.
A sandbox handle.
A handle to a sandbox instance.
Obtain instances from create or
get. Use exec to run commands and
terminate to shut the sandbox down when you're done.
from chalkcompute import SandboxClient, Image
sandbox = SandboxClient().create(
image=Image.debian_slim().pip_install(["numpy"]),
)
result = sandbox.exec(
"python",
"-c",
"import numpy; print(numpy.__version__)",
)
result.stdout_text.strip()
'1.26.4'
sandbox.terminate()
Start a command and return an ExecProcess handle for interactive use.
The caller can write to stdin, send signals, and iterate output.
Handle for interacting with the running process.
Persistent named volumes backed by object storage.
VolumeClient manages volume lifecycle; Volume provides file
operations (read, write, list, delete, batch upload).
Initialize the gRPC client.
Optional TLS/SSL channel credentials. If None, uses insecure
channel.
Create a VolumeClient from an already-authenticated ConnectClient.
An authenticated ConnectClient instance. Auth is
ensured automatically if not already done.
A new client with TLS credentials and metadata derived
from the ConnectClient's token and environment.
A handle to a named volume, providing file operations.
Volumes are persistent storage backed by object storage. Obtain an
instance via create or get.
Create a volume, upload files, and read them back:
from chalkcompute import VolumeClient
client = VolumeClient(target="volumes.example.com:443")
vol = client.create("models")
vol.put_file("config.yaml", b"learning_rate: 0.01\n")
vol.read_file("config.yaml")
b'learning_rate: 0.01\n'
[f.path for f in vol.listdir()]
['config.yaml']
Batch-upload multiple files atomically:
with vol.batch_upload() as batch:
batch.put("a.txt", b"hello")
batch.put("b.txt", b"world")
Metadata about a volume.
name Name of the volume. created_at Timestamp when the volume was created.
Deploy Python functions as versioned, autoscaling remote functions.
Remote functions turn an ordinary Python callable into a managed service. Chalk packages the function into a container image, deploys it as a ScalingGroup, routes incoming calls over gRPC, and handles replica autoscaling, warm-pool management, batching, and retries. Input and output Arrow schemas are inferred from the function's type hints so callers can invoke it with native Python values and the transport layer stays hidden.
The decorator form, function, is the common entrypoint: annotate
any callable with @chalkcompute.function(image=..., cpu=..., memory=...)
and call .deploy() to publish a new version. For the imperative API —
useful when wrapping functions defined elsewhere or deploying
programmatically — construct a RemoteFunction directly.
Use RetryPolicy to configure automatic retries, and catch the
FunctionError / FunctionBuildError hierarchy for
deploy-time and runtime failures.
Decorator that deploys a function as a versioned remote function.
Locally (at decoration time):
ExternalFunctionCatalogServiceCHALK_FUNCTION_LOCAL_SDK_COPY=1, includes local SDK source in
the deploy image for unreleased feature iteration.Remotely (inside the container): The decorator is a no-op — returns the raw function unchanged.
GPU resource request (e.g. "nvidia-l4", "2:nvidia-a100").
Format is "<count>:<type>" or just "<type>" for a single GPU.
Graceful termination period in seconds before replicas are forcibly killed during scale-down. Defaults to 30s on the server.
How often (in seconds) the autoscaler scrapes metrics to make scaling decisions. Defaults to 60s on the server.
Target pending-request queue depth per replica. When set, the autoscaler scales on the function's own queue depth.
Maximum time in milliseconds to buffer incoming items before invoking the handler. Defaults to 1000 ms when batching is enabled. When batching is enabled, handler args are lists.
Maximum number of items to accumulate before invoking the handler. Defaults to 10 when batching is enabled.
Retry policy for handler invocations. Pass an int for simple
max-attempts with default exponential backoff, or a
RetryPolicy for full control. Enforced
before each outbound RPC, not in the handler.
Rate limit policy for outbound calls. Pass an int for a simple
"N per second" cap with a per-function key, or a
RateLimitPolicy for full control (rate,
per, key). Multiple functions sharing the same key share
one bucket — used when a downstream service imposes a throughput
limit across callers.
Concurrency policy: cap on in-flight handler invocations. Pass an
int for a simple max_concurrent cap with a per-function key,
or a ConcurrencyPolicy for full control
(max_concurrent, key). Multiple functions sharing the same
key share one gate — independent of rate_limit (which caps
rate, not in-flight count).
Queue quota: cap on the number of pending items that may be enqueued
for this function at once. Pass an int for the cap, or a
QueuePolicy (currently equivalent —
QueuePolicy(max_items=N)). Defaults to 500,000 items when unset.
Submitting past the cap raises a gRPC RESOURCE_EXHAUSTED error —
clients should back off or call purge() on the function to drain
the queue if items were erroneously added.
import chalkcompute
@chalkcompute.function
def add(x: int, y: int) -> int:
return x + y
add(1, 2)
A versioned remote function backed by ExternalFunctionCatalogService.
Deploys a Python function as a ScalingGroup and registers it with input/output Arrow schemas derived from the function's type hints.
Most users should prefer the function decorator; use
RemoteFunction directly when you need the imperative API (for
example, when wrapping a function defined elsewhere, or when
constructing deployments programmatically).
Decorator form — the most common entrypoint:
import chalkcompute
from chalkcompute import Image
@chalkcompute.function(
image=(
Image.debian_slim()
.pip_install(["numpy"])
),
cpu="1",
memory="2Gi",
min_replicas=1,
max_replicas=4,
)
def embed(text: str) -> list[float]:
import numpy as np
return np.ones(8).tolist()
embed.deploy()
embed("hello world")
[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
Imperative form, for constructing a RemoteFunction from an existing
callable:
from chalkcompute import RemoteFunction, Image
def square(x: int) -> int:
return x * x
fn = RemoteFunction(
square,
image=Image.debian_slim(),
min_replicas=1,
max_replicas=2,
)
fn.deploy()
fn(7)
49
Retry configuration for handler invocations.
Construct via the named constructors rather than instantiating directly.
With exponential backoff, wait times grow geometrically
(initial, initial * multiplier, initial * multiplier^2, ...)
capped at max_wait. With linear, wait times are constant between
retries. A plain int passed to function(retries=3) is shorthand
for RetryPolicy.exponential(attempts=3). By default all Exception
subclasses trigger a retry; pass a tuple of exception classes to
retry_on to narrow the set.
RetryPolicy.exponential(attempts=5, initial=1.0, max_wait=30.0)
RetryPolicy.linear(attempts=3, delay=2.0)
RetryPolicy.exponential(
attempts=3,
retry_on=(ConnectionError, TimeoutError, OSError),
)
RetryPolicy.exponential(attempts=5, initial=0.5, max_wait=30.0)
RetryPolicy.exponential(attempts=3, retry_on=(TimeoutError,))
RetryPolicy.linear(attempts=3, delay=2.0)
RetryPolicy.linear(
attempts=5,
delay=0.5,
retry_on=(ConnectionError, TimeoutError),
)
Decorator that deploys a class as versioned remote functions.
Locally (at decoration time):
@method, @before, @afterExternalFunctionCatalogServiceCHALK_FUNCTION_LOCAL_SDK_COPY=1, includes local SDK source in
the deploy image for unreleased feature iteration.Remotely (inside the container): The decorator is a no-op — returns an instance of the class.
Graceful termination period in seconds before replicas are forcibly killed during scale-down. Defaults to 30s on the server.
How often (in seconds) the autoscaler scrapes metrics to make scaling decisions. Defaults to 60s on the server.
Target pending-request queue depth per replica. When set, the autoscaler scales on each method's own queue depth.
Maximum time in milliseconds to buffer incoming items before invoking the handler. Defaults to 1000 ms when batching is enabled. When batching is enabled, handler args are lists.
Maximum number of items to accumulate before invoking the handler. Defaults to 10 when batching is enabled.
Retry policy for handler invocations. Pass an int for simple
max-attempts with default exponential backoff, or a
RetryPolicy for full control. Enforced
before each outbound RPC, not in the handler.
Rate limit policy for outbound calls. Pass an int for a simple
"N per second" cap with a per-method key, or a
RateLimitPolicy for full control (rate,
per, key). Multiple methods sharing the same key share
one bucket — used when a downstream service imposes a throughput
limit across callers.
Concurrency policy: cap on in-flight handler invocations. Pass an
int for a simple max_concurrent cap with a per-method key,
or a ConcurrencyPolicy for full control
(max_concurrent, key). Multiple methods sharing the same
key share one gate — independent of rate_limit (which caps
rate, not in-flight count).
Queue quota policy: cap on queued calls per key. Pass an int
for a simple max_queue_depth cap with a per-method key, or a
QueuePolicy for full control.
A managed class backed by ExternalFunctionCatalogService.
Deploys each @method as a separate function version with its own
scaling group, sharing a single container image. Lifecycle hooks
(@before / @after) run in every method's container.
Most users should prefer the cls decorator.
Deploy a stateful class with an expensive warm-up step, then call individual methods remotely:
import chalkcompute
from chalkcompute import Image
img = (
Image.debian_slim()
.pip_install(["sentence-transformers"])
)
@chalkcompute.cls(
image=img,
cpu="2",
memory="4Gi",
min_replicas=1,
max_replicas=2,
)
class Embedder:
@chalkcompute.before
def load(self):
from sentence_transformers import SentenceTransformer
self.model = SentenceTransformer("all-MiniLM-L6-v2")
@chalkcompute.method
def embed(self, text: str) -> list[float]:
return self.model.encode(text).tolist()
@chalkcompute.method
def embed_batch(self, texts: list[str]) -> list[list[float]]:
return self.model.encode(texts).tolist()
@chalkcompute.after
def shutdown(self):
del self.model
Embedder.deploy()
e = Embedder()
vec = e.embed("hello world")
batch = e.embed_batch(["a", "b", "c"])
Attach to an existing remote class by name.
Discovers all function versions whose functionName starts with
{name}. and rebuilds a RemoteClass with callable methods.
A handle bound to the existing versions.
If no function versions are found for the given name.
Fetch latest info for all methods from the server.
Mapping of method name to updated FunctionVersionInfo.
Managed scaling groups for deploying HTTP/gRPC services.
Orchestrates image building, local file upload, and scaling group
lifecycle. Use .call() to make HTTP requests to the deployed service.
A managed scaling group backed by ScalingGroupManagerService.
Orchestrates image building, local file upload via volumes, and scaling-group lifecycle in a single high-level API.
from chalkcompute import ScalingGroup, Image
img = (
Image.debian_slim()
.pip_install(["flask"])
.add_local_file("./app.py", "/app/app.py")
.entrypoint(["python", "/app/app.py"])
)
sg = ScalingGroup(image=img, port=8080).deploy().wait_ready()
resp = sg.call("/health", method="GET")
sg.delete()
Attach to an existing scaling group by ID.
A ScalingGroup handle bound to the existing resource.
If the scaling group cannot be found.
Attach to an existing scaling group by name.
A ScalingGroup handle bound to the existing resource.
If the scaling group cannot be found.
References to secrets available to a sandbox, container, or remote function.
Use Secret.from_name(...) to reference a secret by name; the secret
value is resolved at runtime from the Chalk secret store and injected
as an environment variable.
A reference to a Chalk secret or integration to inject as env vars.
Construct instances via the factory methods rather than instantiating directly.
Secret.from_env("OPENAI_API_TOKEN")
Secret.from_integration("prod_postgres")
Secret.from_local_env("OPENAI_API_KEY")
Secret.from_local_env("OPENAI_API_KEY", env_var_name="API_KEY")
Secret.from_local_env_file(".env")
Inject a local environment variable as a secret into the container.
Reads os.environ[local_env_var] at container start time, upserts it
as a Chalk secret, and injects it as an env var in the container.
A lazy secret reference resolved at Container.run() time.
Inject all variables from a local .env file as secrets.
Reads the file at container start time, upserts each KEY=VALUE
pair as a Chalk secret, and injects them as env vars in the container.
Lines starting with # and blank lines are ignored.
A lazy secret reference resolved at Container.run() time.