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

​
Function dependencies in external files

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):

  • Helper in the decorated function’s own package: the function’s entire top-level package is shipped automatically, so imports of sibling modules resolve remotely with no extra configuration.
  • Helper anywhere else (a standalone module, or a different package): must be declared on the image with 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.

​
Same package: automatic

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

​
Everything else: add_local_python_source

When 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.