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 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 Image, Sandbox
img = (
Image.debian_slim()
.pip_install(["pandas", "requests"])
.add_local_file(
"./analyze.py",
"/app/analyze.py",
)
.workdir("/app")
)
sandbox = Sandbox(
image=img,
name="analysis-scratchpad",
cpu="2",
memory="4Gi",
).run()
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.
Call build to capture a reusable image with pinned file contents.
Built images work with every image= parameter and can be transferred
between processes using to_json and from_json.
from chalkcompute import Image
img = (
Image.debian_slim()
.pip_install(["requests", "pandas"])
.workdir("/home/user/app")
)
Return pinned volumes retained by this image.
tuple of VolumeMount Pinned volumes retained independently of worker cleanup.
With no additional volumes, building an already built image returns an equivalent copy without network calls. Authentication, polling, and timeout settings only apply when a build or volume lookup is needed.
Backing volumes persist independently of workers. Keep them while built images remain in use. Pins do not enforce runtime read-only access.
Optional retained source volume name for local volume files. Defaults to a stable name derived from the build recipe and file layout, excluding local source paths and volume file contents. Pass a name to share source volumes across recipes or make cleanup discoverable. Requires local volume files to upload.
A new built image with pinned volumes, leaving this recipe unchanged.
If a name is supplied without local volume files, or mounts conflict.
Install Debian/Ubuntu system packages during the image build.
Like pip_install, accepts a sequence and returns a new image.
Requires apt-get and a root build user. Updates package indexes,
installs noninteractively without recommended packages, and removes
indexes in one build layer. Package versions can be pinned with
name=version. Other distributions can use run_commands
with their package manager.
image = Image.sandbox().apt_install(["tmux"])
sandbox = Sandbox(image=image).run()
sandbox.exec("tmux", "new-session", "-d", "-s", "work")
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, strategy="volume" preserves the
source file's on-disk permissions and strategy="copy" uses
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.If strategy="copy" exceeds the per-file or total copied-content
limit.
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,
strategy="copy",
)
)
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 and
rejects files larger than 32 KiB or additions that would make
the image's total copied content exceed 32 KiB.
"volume" (default) defers each file as a lazy reference
to be mounted at sandbox start.
If strategy="copy" exceeds the per-file or total copied-content
limit.
from chalkcompute import Image
img = (
Image.debian_slim()
.add_local_dir(
"./src",
"/app/src",
exclude=["*.pyc", "__pycache__"],
)
)
Add local Python modules or packages to /app in the image.
Wraps add_local_dir and add_local_file with sanity checking.
Raises ValueError if a name is dotted, cannot be found on the local Python path, or does not resolve to a pure-Python module or package.
from chalkcompute import Image
img = Image.debian_slim().add_local_python_source("helpers", "mypkg")
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"])
)
Reconstruct an Image from an ImageSpec (inverse of to_proto; volume files excluded).
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.
from chalkcompute import Container, Image
c = (
Container(image=Image.debian_slim())
.mount_volume("my-data", "/data")
.run()
)
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="2Gi",
).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()
Start a persistent command session in the running container.
The returned ContainerSession can stream output, accept stdin,
detach, and later be reattached with attach_session.
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 RPC client.
Whether to use HTTPS for the ConnectRPC transport. When omitted,
this remains compatible with the old behavior: passing any
credentials object enables TLS.
Container image to use — either a string reference
(e.g. "ubuntu:latest") or a declarative Image builder.
If omitted, uses sandbox.
Environment variables as strings or single-value Secret references. The mapping key sets the injected name.
Optional Volume handles, VolumeMount specifications, or
(name_or_volume, mount_path) pairs to mount into the sandbox.
Volume handles preserve their selected ref or pinned version.
Optional network egress policy. Reuses the same NetworkPolicy
type accepted by containers.
Whether to give the sandbox a platform-managed Chalk identity.
The identity is exposed inside the sandbox through the standard
CHALK_WEB_IDENTITY_TOKEN_FILE environment variable.
A sandbox handle.
A managed sandbox backed by the Chalk SandboxService.
create constructs and immediately runs a sandbox. To
configure a Sandbox before running it, construct one and pass it
to run. Use exec to run commands and
terminate to shut the sandbox down when you're done.
from chalkcompute import Image, SandboxClient
with SandboxClient.from_env() as client:
sandbox = client.create(
Image.debian_slim().pip_install(["numpy"]),
)
result = sandbox.exec(
"python",
"-c",
"import numpy; print(numpy.__version__)",
)
sandbox.terminate()
result.stdout_text.strip()
'2.5.1'
Opaque sandbox identifier assigned by the service.
None until run has created the sandbox.
The most recently fetched SandboxInfo snapshot.
None until the sandbox has been started or attached to.
The fully qualified registry URI of the image the sandbox uses.
Set after run finishes the image build (or, if the sandbox
was constructed with a string image reference, equal to that
reference). None before the sandbox has been started.
Access Git operations inside this running sandbox.
SandboxGit Helpers for cloning, staging, committing, branches, remotes, and repository-local configuration. Paths refer to the sandbox filesystem, relative to the image working directory or absolute. Custom images must include Git; the default sandbox image already includes it.
sandbox.git.clone("https://github.com/octocat/Hello-World.git", "repo")
status = sandbox.git.status("repo")
Configure a sandbox to be created by run.sandbox_id
Existing sandbox ID. With no client, authentication is resolved lazily
from the receiver's environment on the first operation. This form
never creates a sandbox and cannot be mixed with image configuration.
Calling run without a client creates one from the environment.
Prefer using an explicit SandboxClient. Its
create method is a shortcut for constructing and
immediately running a sandbox. For other setup, construct a Sandbox
and pass it to run.
Container image to use, either a string reference such as
"ubuntu:latest" or a declarative Image. If omitted,
uses sandbox (Python, Git, SSH, and /workspace).
Environment variables as strings or single-value Secret references. The mapping key sets the injected name, overriding aliases and prefixes.
Optional Volume handles, VolumeMount specifications, or
(name_or_volume, mount_path) pairs to mount into the sandbox.
Volume handles preserve their selected ref or pinned version.
Each volume must already exist; run fails if one is missing.
Optional network egress policy. Reuses the same
NetworkPolicy type accepted by Container.
Whether to give the sandbox a platform-managed Chalk identity.
The identity is exposed inside the sandbox through the standard
CHALK_WEB_IDENTITY_TOKEN_FILE environment variable.
Optional SSH aliases mapped to SSHDest instances. Managed
SSH sandboxes run on host compute.
sandbox = Sandbox(image="ubuntu:latest")
with SandboxClient.from_env() as client:
client.run(sandbox)
Mount a named volume or volume handle into the sandbox.
Must be called before the sandbox is run. Returns self for chaining.
from chalkcompute import Sandbox, SandboxClient
sandbox = Sandbox(image="ubuntu:latest")
sandbox.mount_volume("my-data", "/data")
with SandboxClient.from_env() as client:
client.run(sandbox)
Expose credentials to requests bound for specific hosts.
String credentials name existing Chalk secrets. Use
from_local_env to read a credential from the local
environment when the sandbox starts.
The sandbox receives a placeholder in each credential's environment variable. Its network policy replaces that placeholder when it appears in headers on requests to the supplied hosts.
Must be called before the sandbox is run. Returns self for chaining.
sandbox = (
Sandbox(image="ubuntu:latest")
.add_credentials("api.openai.com", "OPENAI_API_KEY")
.add_credentials(
["api.slack.com", "*.slack.com"],
Secret.from_local_env("SLACK_BOT_TOKEN"),
)
)
with SandboxClient.from_env() as client:
client.run(sandbox)
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.
Run Python source in the sandbox with structured output capture.
The server wraps source in a capture harness that injects a
save_artifact(obj, *, name=None, kind=None, content_type=None)
helper into the namespace and, after the source finishes, inspects the
namespace for plotly/altair figures bound to variables. Everything
saved or captured is persisted to the Chalk artifact store
server-side — the sandbox itself never receives credentials — and
returned as Artifact handles.
Python source to execute. Bare final expressions do not print; charts are captured regardless of printing.
Inspect the namespace for plotly/altair figures after execution
(default True).
Buffered stdout/stderr, exit status, and persisted artifacts.
Consume all output and return the final result.
If the response stream is interrupted after the session starts,
reconnect and replay buffered events by default. Set
auto_reattach=False to handle transport disconnects yourself.
Aggregated stdout, stderr, exit code, and signal information.
Persistent named volumes backed by object storage.
VolumeClient manages volume lifecycle; Volume provides file
operations (read, write, list, delete, batch upload).
Initialize the typed volume control plane and native data plane.
Volume service endpoint. Values without a scheme are converted
to http:// or https:// depending on credentials.
Create a client from an authenticated ConnectClient.
An authenticated ConnectClient. Auth is ensured
automatically if not already done.
A new client with endpoint, token, and environment settings
derived from the ConnectClient.
Return whether a volume with name exists.
Probes GetVolume with the default version selector. A not-found
response maps to False; any other client error propagates so a
transient failure is never mistaken for "absent".
Upload an image's lazy local files into volumes.
Creates one volume per destination directory and commits files in batches. Returned mounts follow the default mutable ref.
One VolumeMount per created volume.
Stage an image's lazy local files into source-code volumes.
Reuses (or creates, source_code-kind) one stable volume
per destination directory — named from volume_name — and uploads
the file bytes, but does not commit. Each staged upload is
returned as a typed chalk.volume.v2.CommitIntent for
ExternalFunctionVersionSpec.volume_commits: the server
commits the intent and stamps the resulting version_id onto the spec
volume with the matching name, so every replica is pinned to that
immutable snapshot.
On reused volumes the intent carries a recursive remove of root, which the server applies as "replace the base tree": the committed version is exactly the staged files, so redeploys never leak stale files into new versions.
One mount and one commit-intent dict per volume.
A handle to a volume using the v2 volume service.
Volumes expose immutable snapshots behind mutable refs. The
Python API supports direct file writes, reads, listing, and version
lookup. Each write produces a new immutable version; the main ref
(or a caller-provided ref) advances to point at the latest committed
version.
Write a file, advance the ref, and read the result back:
from chalkcompute import Volume
with Volume("models") as vol:
vol.put_file("config.yaml", b"lr: 0.01\n")
vol.read_file("config.yaml")
b'lr: 0.01\n'
Pin a handle to a previous version and read from it:
previous = vol.at_version(vol.versions()[-2].id)
_ = previous.read_file("config.yaml")
Initialize a volume handle.
Optional VolumeClient. If None, one is
constructed from a default ConnectClient.
If set, pin this handle to a specific immutable version. Such
handles are read-only; mutating operations raise
VolumeError.
If True (the default), the volume is created on first
access if it does not already exist. Ignored when
version_id is set.
Empty directories are omitted. Uploads may make multiple commits. A failed upload can leave earlier commits visible.
self, with its cached version updated after commits complete.
If paths are invalid or the directory contains symlinks or special files.
If the volume is closed, pinned, or an upload fails.
Copy a Chalk Dataset revision into a volume.
Only the revision's output parquet files are ingested with matching partitioning.
The newly committed volume version.
Return a read-only handle pinned to a specific version.
Mutating operations on the returned handle raise
VolumeError.
A new handle pointing at version_id.
Metadata about a volume.
name Name of the volume. created_at Timestamp when the volume was created.
Metadata about a file inside a volume.
path File path within the volume. size File size in bytes. updated_at Timestamp when the file was last updated.
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.
Prefer @cc.function or @cc.function(image=...) without name=.
The registered name defaults to the Python function's name, including
underscores, and can be used with RemoteFunction.from_name(...).
Locally, decoration validates the function, starts deployment in a background worker, and returns. The worker:
ExternalFunctionCatalogServiceCHALK_FUNCTION_LOCAL_SDK_COPY=1, includes local SDK source in
the deploy image for unreleased feature iteration.Deployments of consecutive, distinctly named functions overlap. Remote calls and lifecycle operations wait for their function's deployment before proceeding. A script containing only decorated definitions also waits for all queued deployments before interpreter shutdown.
Remotely (inside the container):
Lifecycle methods become no-ops. Calling the symbol runs the local Python
body in-process; .remote() / .defer() dispatch to the deployed
function (resolved lazily by name), so a function can invoke a sibling
without RemoteFunction.from_name(...).
GPU resource request (e.g. "nvidia-l4", "2:nvidia-a100").
Format is "<count>:<type>" or just "<type>" for a single GPU.
Optional registered-name override. Omit this in normal usage to use
the function's __name__. Set it only when a different registered
name is intentional, such as preserving an existing deployment's name
after renaming the Python function. Changing or removing an override
changes the target function; it does not rename an existing deployment.
Environment variables as strings or single-value Secret references. The mapping key sets the injected name, overriding aliases and prefixes.
List of Volume handles, VolumeMount specifications, or
(name_or_volume, mount_path) tuples for persistent storage.
Volume handles preserve their selected ref or pinned version.
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 GPU utilization percentage (1-100) that drives autoscaling, read
from DCGM. Requires gpu and min_replicas >= 1: the utilization
series exists only while replicas do, so this trigger cannot scale a
group up from zero.
Target pending-request queue depth per replica. When set, the autoscaler scales on the function's own queue depth.
Sets a replica floor during specified cron-defined time windows, independent of the other autoscaling triggers.
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 configuration, including the pending-item cap and asynchronous
result retention. Pass a QueuePolicy and set
result_ttl_seconds to retain terminal results for a custom period;
the default is one day. Submitting past max_items
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.
Optional crontab or Chalk duration string for invoking a no-input
function on a schedule (e.g. "0 * * * *" or "1h").
Mapping of model_name -> output_type for Chalk models that should
be auto-bound into the local chalkdf catalog before the function body
runs. Each entry becomes a bind_model call
invoked by the handler shim on import, so
F.catalog_call("model.<name>", ..., output_type=<type>) resolves
without any explicit setup in the function body. For advanced overrides
(version, method_name, qualified_name) call
bind_model directly inside the function.
Server-side remote-function tracing is enabled by default. Use
TracingPolicy for sampling. Set False to
explicitly turn tracing off.
Maximum seconds to wait on a single .remote()/.defer()/
.poll() call before raising FunctionError — including
while the scaling group is Unhealthy (e.g. replicas stuck in
CrashLoopBackOff), where the error includes the scaling group's
status message. Defaults to 60s. Pass None to disable the
deadline and wait indefinitely (previous behavior).
import chalkcompute
@chalkcompute.function
def add(x: int, y: int) -> int:
return x + y
add.remote(1, 2) # wire call to the deployed function
add(1, 2) # runs the Python body in-process
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.remote("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.remote(7)
49
fn(7) # runs the local Python body in-process
49
Attach through an immutable version ID.
Maximum seconds to wait on a single .remote()/.defer()/
.poll() call before raising. None disables the deadline.
A handle bound to the existing version.
Attach to an external function's currently selected version.
Maximum seconds to wait on a single .remote()/.defer()/
.poll() call before raising. None disables the deadline.
A handle bound to the existing version.
Invoke the deployed remote function over the wire.
Bounded by call_timeout (set on the constructor / @function
decorator / from_name — 60s by default): if the scaling group is
Unhealthy (e.g. replicas stuck in CrashLoopBackOff) or
otherwise never responds, this raises TimeoutError instead of
blocking forever, including the scaling group's status message when
available.
Scalar result for single-row calls, or a list of results otherwise. For generator functions, returns an iterator of result batches.
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):
Lifecycle methods become no-ops. Accessing a @method runs the local
method body in-process when called; .remote() / .defer() dispatch to
the deployed method (resolved lazily by name), so a method can invoke a
sibling without RemoteClass.from_name(...).
Optional registered-name override. Omit this in normal usage to use
the class's __name__. Set it only when a different registered name
is intentional, such as preserving existing deployments after renaming
the Python class. Changing or removing an override changes the target
functions; it does not rename existing deployments.
Environment variables as strings or single-value Secret references. The mapping key sets the injected name, overriding aliases and prefixes.
List of Volume handles, VolumeMount specifications, or
(name_or_volume, mount_path) tuples for persistent storage.
Volume handles preserve their selected ref or pinned version.
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 GPU utilization percentage (1-100) that drives autoscaling, read
from DCGM. Requires gpu and min_replicas >= 1: the utilization
series exists only while replicas do, so this trigger cannot scale a
group up from zero.
Target pending-request queue depth per replica. When set, the autoscaler scales on each method's own queue depth.
Sets a replica floor during specified cron-defined time windows, independent of the other autoscaling triggers.
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 configuration shared by the class's methods, including the
pending-item cap and asynchronous result retention. Pass a
QueuePolicy; terminal results are retained for
one day by default or for result_ttl_seconds when configured.
Optional crontab or Chalk duration string applied to every no-input
@method in the class (e.g. "0 * * * *" or "1h").
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,
authenticated=True,
).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.
Make an HTTP request to the scaling group's endpoint.
A buffered HTTP response satisfying the SDK's structural response protocol.
If the scaling group has no web_url yet.
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_chalk_env("OPENAI_API_TOKEN")
Secret.from_chalk_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.
Offline evaluation of a task function against a pinned dataset revision.
An evaluation pairs one dataset revision, one task version and one or more
scorer versions, and is immutable once created. Running it queues an
EvaluationRun that calls the task per row, passes each output to every
scorer, and writes the scores to a result dataset.
Create an evaluation from deployed function handles.
task and every function scorer must already be deployed. Handles
returned by @chalkcompute.function meet this requirement because
resolving their version waits for the decorator's background deployment.
A SqlExpression deploys nothing and is sent as its expression.
A queued or completed execution of an evaluation.
Wait for this run to finish and return its final representation.
Raise EvaluationRunFailedError for failed or canceled
runs. Set to False to inspect the terminal handle directly.
The score and optional row-level metadata returned by a scorer function.
Annotating a @chalkcompute.function with this return type installs its
Arrow struct contract automatically. Scorer functions must return an
EvaluationScorerResult instance rather than an untyped dictionary.
Structural type accepted for references to the latest dataset revision.
Built-in scorers for evaluations, in chalkcompute.scorers.
Calling a built-in deploys it and returns a handle to pass to
Evaluation.create. sql is the exception: it builds a SqlExpression
evaluated in the run's query, so nothing is deployed.
Deploy a scorer that looks for expected substrings in a column.
The reference column holds one substring, or a JSON array of them. mode
scores them together: "all" demands every one, "any" one of them,
and "fraction" gives the share that appeared. Which ones matched and
which were missing are recorded as metadata.
Deploy a scorer that grades two columns by how close their meanings are.
Both columns are embedded with model and scored by cosine similarity,
clipped into [0, 1], with the raw cosine recorded as metadata. This
catches an answer that is right but worded differently, which the string
scorers mark wrong. base_url and api_key name the endpoint and the
Secret holding its key, as they do for llm_judge.
Deploy a scorer that gives 1.0 when two columns hold the same text.
inputs names the candidate column and then the column it is compared
against. strip trims each side, normalize_whitespace collapses runs
of whitespace instead, and case_insensitive folds case. The metadata
records whether the two matched.
Deploy a scorer that compares two columns as JSON documents.
Without paths the whole documents must be equal, so object key order
does not matter but list order does. With paths (dotted, as in
"user.id" or "items.0.sku") the score is the share of those paths
whose values agree. Either way the paths or keys that differed are recorded
as metadata, and a column that does not parse scores 0.0. Values are
compared as JSON, so true never passes for 1.
Deploy an LLM judge described by a pydantic model.
response_model needs a score field, which becomes the scorer's
score; its other fields are recorded as row metadata. A reply that fails
validation fails the row.
inputs are the dataset columns to grade (output is the task's).
prompt_fn(response_model, **inputs) replaces the prompt; parse_fn
replaces structured outputs. With neither base_url nor api_key the
judge calls Chalk's AI router as the environment itself, so no provider key
is needed; base_url takes any other OpenAI-compatible URL and
api_key a Secret read in the pod. completion_kwargs (say
{"temperature": 0, "max_tokens": 400}) are sent with every request.
name defaults to the model class in kebab case; other keywords go to
function.
Deploy a scorer that compares two columns as numbers.
With a tolerance the score is 1.0 or 0.0 depending on whether the two
are within it, taken as a share of the larger value when relative.
Without one the score falls off with the gap between them, as
1 - gap / max(abs(a), abs(b)). The signed difference is recorded as
metadata. A column that does not parse as a finite number scores 0.0,
which covers inf and nan as well as ordinary text.
Deploy a scorer that gives 1.0 when a column matches pattern.
full_match requires the pattern to cover the whole column instead of
appearing anywhere in it. The matched text and any named groups are
recorded as metadata, so a pattern can also pull a value out of the row.
An unusable pattern is rejected here rather than on every row.
Score rows with a ChalkSQL expression you write yourself.
expression is a select item over the evaluation's own columns: every
dataset column by name, plus output, the task's result for the row. It
must yield a number. Nothing is deployed; name labels the result column
and the row in the compare table.
Deploy a scorer that grades two columns by string similarity.
method picks the measure: "jaro_winkler", "jaccard",
"token_set", "token_sort", "partial", or "sequence". Each
is the same quantity as the chalk.functions of that name, expressed as
a similarity in [0, 1], and the raw value is recorded as metadata.
Two empty columns score 1.0.
A scorer whose score is a ChalkSQL expression, evaluated in the run's query.
The expression is a select item over the evaluation's own columns: every
dataset column by name, plus output, the task's result for the row. It
must yield a number, and unlike a function scorer it deploys nothing and
carries no metadata.
A session's worth of telemetry: every trace and span under one call.
Declaring a @chalkcompute.function parameter as Trace installs its
Arrow contract, so the value arrives as the large_utf8 session id Chalk
bound to that argument.
.. _trace-waiting:
Every read waits for ingest to settle. Spans reach Chalk asynchronously
— through a batching span processor, an OTLP collector, and finally
ClickHouse — so a scorer running immediately after the task it scores can
observe an incomplete session. That is worse than an error: a partial read
produces a plausible wrong number. So get_spans, summary,
and traces all poll until the number of spans they can see stops
growing, and all take the same four arguments:
wait
Poll until the span count holds steady across two consecutive reads.
Pass False to read once, for a session that finished long ago.
timeout
Seconds to wait for that. Exceeding it raises TimeoutError
rather than returning a knowingly incomplete result.
poll_interval
Seconds between polls.
expect_min
Minimum span count to wait for. Defaults to 1, so an empty result is
treated as "not ingested yet" rather than "nothing to see". Pass 0 to
accept an empty session.
A steady count is a pragmatic signal, not a proof: it cannot tell "complete"
from "quiet", so a long pause between agent turns can settle early. Pass
expect_min when the caller knows better.
Return this session's spans, waiting for span ingest to settle.
Span attributes that must match. A None value matches any span
carrying the key.
If the span count does not reach expect_min and hold steady
within timeout.
Return this session's aggregate: turn count, span count, wall clock.
Settles on the same signal as get_spans, so trace_count and
span_count do not undercount a session whose spans are still
arriving.
The session's aggregate.
If the session never appears — it received no spans at all.
If it appears but its span count never holds steady.
Return a summary per trace in this session — typically one per turn.
Settles on the same signal as get_spans: a turn that is still
recording grows this session's span count without adding a trace, so
waiting on the traces alone would return stale per-trace counts.
One summary per trace, newest first.
If the session's span count does not reach expect_min and hold
steady within timeout.
Return an attribute parsed as a float, or None if absent or unparseable.
Span attributes arrive as strings — ChalkSpan.attributes is a
map<string, string> — so summing span.attributes["llm.cost"]
directly concatenates text instead of adding numbers. Use this instead.