Modal Function Sync
Overview
Use this skill to add or modify Modal functions in modal_functions, register them, and locally sync the generated client into win.
Auto-generation rules
modal_functionsis the source of truth; never implement Modal entrypoints directly inwin.services/modal/client_generated.pyis generated from themodal_functionsregistry; do not edit it by hand.- Sync is local-first from the sibling checkout with
scripts/local/sync_win_modal_client.sh. - Check drift without mutating
winwithscripts/local/check_win_modal_client_drift.sh. - CI validates and deploys Modal functions; it does not commit generated client files into
win. - Generate locally to
tmp/client_generated.pyfor fast validation without dirtyingwin. - Generate into
../win/services/modal/client_generated.pythrough the local sync wrapper before testingwinwrappers/call sites. - Stable Modal runtime secrets should default to the local canonical store -> manifest -> Modal sync flow, not one-off manual Modal secret updates.
Workflow
1) Gather context
- Ask for the new function or pipeline intent, inputs/outputs, storage/caching expectations, and where win will call it.
- Confirm whether the change is new functionality or a behavior update.
2) Read local guidance
- Open
AGENTS.mdin both repos (seereferences/paths.md) and follow nested rules.
3) Implement in modal_functions (source of truth)
- Add or modify code under
src/functions/.... - Update
src/registry.pyto expose the function. - Update
src/deploy.pyso Modal actually ships the symbol. - Update shared helpers in
src/common/if needed. - Run
python tools/validate_registry.pywhen changing the registry. - Keep the Modal app name consistent with
src/common/containers.py.
4) Handle secrets and config deliberately
- Use
references/modal-secrets.mdas the checklist for secret ownership and manifest updates. - If the change adds or modifies
modal.Secret.from_name(...), decide whether the secret is:- a stable runtime secret that should be managed from the local canonical store, or
- an intentional exception owned by a separate system.
- Default rule: if it is a stable runtime secret, add it to
scripts/local/secrets/modal_secrets_manifest.json. - Ensure the backing local canonical secret exists before relying on the manifest entry.
- If you are adopting an older Modal-only secret, write it once through
~/GitHub/scripts/bin/local-secrets set; do not print the value or add another canonical owner. - Update
docs/rules/environment-variables.mdwhen the secret shape or expected env keys change. - Do not leave a new code-level
modal.Secret.from_name(...)reference unmanaged unless the exception is explicitly documented.
5) Client sync (local generated output)
- Run the local sync wrapper from
modal_functions:scripts/local/sync_win_modal_client.sh - The wrapper validates the registry, generates
../win/services/modal/client_generated.py, and formats it with WIN's Ruff config. - Do not hand-edit
services/modal/client_generated.py. - Use
python tools/generate_modal_client.py --output tmp/client_generated.pyfor local validation without touchingwin. - Use
scripts/local/check_win_modal_client_drift.shwhen you need a check-only stale-client guardrail. - Include generated client changes in the
winworktree when the registry output changed.
6) Win integration
- Use
ModalClientGeneratedfromservices/modal/client_generated.py. - Add wrapper/helper methods in
services/modal/client.pyif needed for ergonomics. - Update tests in
tests/services/modal/test_client.pyand any call sites.
7) Deploy + verify
- Push to
main, watch CI: lint/tests/deploy. - In the deploy job, confirm the secret-refresh step passes when the change touches managed Modal secrets.
- Verify critical flows or run targeted tests in
win.
Common pitfalls
- Docs-only changes won't trigger Modal deploy (workflow ignores
docs/**and*.md). - Missing registry entries means the client will not include the function.
- Adding
modal.Secret.from_name(...)in code without updating the manifest reintroduces secret drift. - Adding a manifest entry without a real local backing secret will make deploy-time secret sync fail.
- Direct edits to generated client output will be overwritten by the local sync wrapper.
References
- See
references/paths.mdfor key files and repo entry points. - See
references/modal-secrets.mdfor the secret-management checklist.