Functions and Scaling Groups
Define a Chalk Function with the @chalkcompute.function decorator, call it, and ship the helpers it imports.
To define a Chalk Function, decorate a Python callable with @chalkcompute.function:
import chalkcompute
@chalkcompute.function
def add(x: int, y: int) -> int:
return x + y
if __name__ == "__main__":
result = add.remote(3, 5)
print(result) # 8
Deploy by running the script: the decorator registers the function with
Chalk as soon as it runs, and .remote(...) waits for that deployment to be
ready before invoking it. add(3, 5) runs the Python body locally instead;
use .remote(...) to call the deployed version.
To call an already-deployed function from a different script — without
redeploying — attach to it by name with RemoteFunction.from_name:
import chalkcompute
fn = chalkcompute.RemoteFunction.from_name("add")
result = fn.remote(3, 5)
print(result) # 8
A deployed function often calls helpers defined in other files. Whether a
helper resolves remotely depends on where it lives relative to the decorated
function (the function under @chalkcompute.function):
Image.add_local_python_source.
The same applies to all file-external helpers when the decorated function is
defined in a standalone script rather than a package.If the decorated function’s module runs as part of a package (imported from
an entrypoint, or executed directly with python -m), Chalk ships the whole
top-level package in the deploy image:
# mypkg/helpers.py
def normalize(text: str) -> str:
return text.strip().lower()
# mypkg/pipeline.py
import chalkcompute
from mypkg.helpers import normalize
@chalkcompute.function
def clean(text: str) -> str:
return normalize(text)
# main.py (outside mypkg/)
from mypkg.pipeline import clean
print(clean.remote(" Hello "))
uv run python main.py
Running the entrypoint (or the function’s own module with
uv run python -m mypkg.pipeline) deploys clean with all of mypkg, so
normalize is importable remotely exactly as it is locally.
Running the file by path (uv run python mypkg/pipeline.py) ships only that one file
because Python doesn’t know that it belongs to a package. In this scenario, Chalk will
raise an error at deploy time.
Every run of an entrypoint that imports the decorated function deploys the
function. If the function has changed since its last deploy, the run creates a
new function version; otherwise Chalk keeps the current version. To call an
existing deployment without redeploying, attach to it by name with
RemoteFunction.from_name instead.
# call_clean.py: call the deployed function without triggering a redeploy
import chalkcompute
fn = chalkcompute.RemoteFunction.from_name("clean")
print(fn.remote(" Hello "))
uv run python call_clean.py
add_local_python_sourceWhen the decorated function is defined in a standalone script, or imports helpers from outside its own top-level package, list those local modules or packages on the image:
# helpers.py (next to deploy.py)
def normalize(text: str) -> str:
return text.strip().lower()
# deploy.py
import chalkcompute
from helpers import normalize
@chalkcompute.function(
image=chalkcompute.Image.debian_slim().add_local_python_source("helpers"),
)
def clean(text: str) -> str:
return normalize(text)
uv run python deploy.py
add_local_python_source accepts any number of top-level module or package
names. Each must be importable on your local Python path; packages are copied
whole (excluding __pycache__). Dotted names, namespace packages spanning
multiple directories, and compiled extensions are rejected with a
ValueError.
This ships your own source code only. Third-party dependencies still need to
be installed in the image with pip_install or run_commands.