modal
A Sandbox on Modal.
Pass it as agent({sandbox: modal(image_id="im-...")}). Each sandbox starts with no environment and its network blocked. TypeScript: always refuses (Modal's JS SDK runs commands over a transport threads can't fence); use Python.
Import from @threads/modal (TypeScript) or threads.modal (Python).
function modal(): SandboxParameters
image_idstrrequiredPython only. A built Modal image (im-..., for example modal.Image.debian_slim().build(app) once at setup). It needs /bin/sh, sed, find, sha256sum and stat. Empty is invalid_config.
token_idstr | SecretPython only. The Modal token id: a secret() or a string. Omitted: secret("MODAL_TOKEN_ID"). Resolved on the host at setup with token_secret; either unset is missing_secret. It goes only to Modal's control plane.
token_secretstr | SecretPython only. The Modal token secret: a secret() or a string. Omitted: secret("MODAL_TOKEN_SECRET"). Resolved with token_id.
app_namestrdefault threadsPython only. The Modal app sandboxes are created under.
environmentstrPython only. The Modal environment. Empty: the workspace's default.
lifetime_msintdefault 3600000Python only. How long a sandbox lives, in milliseconds, before Modal ends it (the declared expiry). 1000 to 86400000; anything else is invalid_config.
allow_internetbooldefault falsePython only. Lifts Modal's network block. Egress is then unenforced, so the agent must also set egress: "unenforced".
namestrdefault modalPython only. The provider name in SandboxInfo and the sandbox ledger; rows under another name are never touched.
server_urlstrdefault https://api.modal.comPython only. Seam: the Modal API URL (tests point it at a fake).
connectthreads.adapters.sandboxes.modal.channel.ConnectPython only. Seam: opens a gRPC channel to a URL (tests). Omitted: a TLS channel; the fence checks every request on it either way.
Returns
Throws ConfigError with one of these codes: invalid_config (Python only), missing_secret (Python only), transport_fence_unsupported (TypeScript only).