Multi-Modal Account Profiles in .env and Native Sandbox Provisioning¶
Status: Accepted (Amends ADR 0003, ADR 0024, and ADR 0053)
We introduce multi-account Modal credential configuration via MODAL_TOKENS in .env as a JSON array of profile objects, purge legacy single-account variables (MODAL_TOKEN_ID and MODAL_TOKEN_SECRET) with zero backward compatibility, and provision all configured workspace profiles directly into the sandbox container filesystem (/root/.modal.toml).
Context¶
In ADR 0024, we introduced multi-profile workspace discovery in sandbox/profiles.py by parsing the host's ~/.modal.toml. In ADR 0053, we consolidated secrets into a single root .env configuration file, injecting credentials into containers and the hosted control plane via native modal.Secret.
However, Modal cloud credentials in .env remained constrained to a single account pair: MODAL_TOKEN_ID and MODAL_TOKEN_SECRET. Consequently:
1. Developers and operators managing multiple Modal workspaces (e.g. personal, work, client, or team organizations) could not declare multiple Modal accounts in .env.
2. When launching sandboxes with --modal, scripts/setup.sh generated only a single [default] profile in /root/.modal.toml. Multi-tenant tools, cross-account sandboxes, and agent tasks requiring multi-workspace operations could not switch accounts from inside the sandbox.
3. In headless CI/CD and containerized control planes lacking ~/.modal.toml, only a single fallback profile was available.
4. Staging host ~/.modal.toml into the control plane image (sandbox/function.py) risked leaking local host configuration and violated the zero-credential-at-rest invariant from ADR 0053.
Decisions¶
- Multi-Profile Credential Configuration (
MODAL_TOKENS): - Parameterize Modal account credentials via
MODAL_TOKENSin.env(templated in.env.example) as a JSON array of profile objects: -
Each profile object supports
name(orprofile),token_id,token_secret, optionalactive: bool, and optionalenvironment: str(defaults to"main"). -
Zero Backward Compatibility Purge:
- Completely remove
MODAL_TOKEN_IDandMODAL_TOKEN_SECRETacross the codebase (.env.example,sandbox/launcher.py,sandbox/profiles.py,scripts/setup.sh,readme.md,GLOSSARY.md). -
If
--modalis requested without validMODAL_TOKENS, fail fast immediately during launcher preflight validation. -
Authoritative Precedence over Host
~/.modal.toml: - When
MODAL_TOKENSis defined in.envor the process environment,sandbox/profiles.pyuses it as the authoritative source of truth for workspace profiles. Host~/.modal.tomlis used only as a secondary fallback whenMODAL_TOKENSis completely absent. -
Retire legacy file-staging in
sandbox/function.py(image.add_local_file(str(modal_toml), "/root/.modal.toml")), ensuring the control plane discovers profiles dynamically fromMODAL_TOKENSpassed viamodal.Secret. -
In-Sandbox Multi-Profile Provisioning (
scripts/setup.sh): - When
--modalis passed (ENABLE_MODAL=1),scripts/setup.shparsesMODAL_TOKENSand generates/root/.modal.toml(mode0600) containing TOML tables for every profile in the array. -
If a specific profile is targeted via
--profile <name>(passed asMODAL_PROFILE), that profile is markedactive = truein the sandbox; otherwise, the profile with"active": trueinMODAL_TOKENS(or the first profile) is set as active. -
Sandbox Launcher Profile Alignment (
sandbox/launcher.py&sandbox/cli.py): - Support
--profile <name>insandbox/cli.pyandLaunchRequest.profileinsandbox/core.py. sandbox/launcher.pyresolves the Modal client for the specified profile viaget_client_for_profile(), launches the sandbox in that account, and exportsMODAL_PROFILEinto the sandbox container environment.
Consequences¶
- Full parity with
ANTIGRAVITY_TOKENSfor multi-account management in.env. - Sandboxes launched with
--modalhave complete multi-account tooling (modal profile list,modal profile switch <name>) pre-configured in/root/.modal.toml. - Zero credentials or host configuration files are baked into container image layers.
- Strict preflight schema validation prevents launching broken containers when Modal tooling is requested with invalid or missing credentials.