TaskAppConfig to Modal. This page captures what the tooling expects so you can ship a working Modal app on the first try.
Required configuration objects
ModalTaskAppConfig
Instances of ModalTaskAppConfig (defined in synth_ai/task_app_cfgs.py) describe how to call the Modal CLI:
synth_ai/cli/deploy.py and synth_ai/cli/task_apps.py) validates these fields before dispatching to deploy_modal_app.
TaskAppEntry.modal
When registering a task app, set TaskAppEntry.modal to a ModalDeploymentConfig so discoverable apps automatically inherit default resources (CPU, memory, mounts, secrets) (synth_ai/task/apps/__init__.py).
Modal app module requirements
deploy_modal_app loads your Modal script and enforces the following invariants (synth_ai/utils/modal.py:134):
- The file must define
modal.App(...)(or exposemodal_app). Ifmodal.Appcannot be found, deployment aborts (ensure_py_file_defines_modal_app). - The module must expose an ASGI entrypoint decorated with
@modal.asgi_app()that returns the FastAPI object produced bycreate_task_app(...). Typical pattern:
- When the deploy helper loads your module it automatically:
- Mounts the Modal script’s directory and the repo root into
/root/...so intra-repo imports resolve (synth_ai/utils/modal.py:162). - Attempts to wrap
image = modal.Image(...)definitions withadd_local_dirfor the same mounts (synth_ai/utils/modal.py:171). - Injects an inline
ENVIRONMENT_API_KEYsecret onto each function decorator when an inline secret is supported (synth_ai/utils/modal.py:200).
- Mounts the Modal script’s directory and the repo root into
Mount your task app
Add amodal.Mount for the task app module (or directory) so Modal sees the same files the CLI uses locally. Without an explicit mount the container only receives the Modal script, and imports such as from task_app import config fail.
modal.Mount.from_local_file(...)) when you prefer a tighter scope; the important part is ensuring the task app code is listed in mounts=[...].
Deployment flow
- Invoke
synth-ai task-app deploy <APP_ID> --runtime modal(oruvx synth-ai deploy --runtime modal). The CLI:- Resolves the task app entry and its
ModalTaskAppConfig. - Locates the Modal CLI (
modal) unless you override--modal-cli. - Loads optional
.envfiles, ensuringENVIRONMENT_API_KEYis present. - Generates a temporary wrapper module that imports your Modal script, adds repo mounts, and exposes the resolved
app.
- Resolves the task app entry and its
- The wrapper calls the Modal CLI with
modal <cmd_arg> <wrapper_path> [--name ...]. - All stdout is streamed to the terminal. When Modal prints a
*.modal.runURL, the helper writes it to.envasTASK_APP_URL(synth_ai/utils/modal.py:218).
Inline secrets and environment variables
- Inline secret injection is best-effort. If your Modal function already lists secrets, the helper appends
Secret.from_dict({"ENVIRONMENT_API_KEY": ...})when possible. - For long-lived deployments, create a Modal Secret (
modal secret create ...) and reference it directly in your app script; the helper won’t override existingsecrets=[...]definitions. - Use Modal volume mounts or
extra_local_dirsinModalDeploymentConfigwhen you need additional files beyond the repo snapshot.
Local testing tips
modal serve <modal_app.py>runs the ASGI app locally via Modal. Ensure your script installssynth-aiin editable mode inside the Modal container if the app relies on the repo (seeexamples/task_apps/pokemon_battle/modal_app.py).- If you see import errors, verify the repo path is mounted and
pip install -eis executed inside the Modal function (the example does this before callingcreate_task_app).
synth-ai task-app deploy --runtime modal can package, deploy, and record the Modal URL for any registered task app.