Modal Provider
Read when:
- choosing
provider: modal; - configuring Modal apps, images, or sandbox workdirs;
- changing
internal/providers/modal.
Modal is a delegated run provider. Crabbox shells out to the local Modal Python client for Sandbox lifecycle, file upload, status/list, and command execution. Modal owns sandbox state and process transport; Crabbox owns local config, repo claims, sync manifests and guardrails, slugs, timing summaries, and normalized list/status rendering.
#When To Use
Use Modal when commands should run in Modal Sandboxes and you do not need a Crabbox SSH target. Use AWS, Hetzner, Static SSH, Namespace Devbox, Semaphore, Sprites, or Daytona when you need crabbox ssh, VNC, code-server, or Actions hydration.
#Prerequisites
- Install the Modal Python client:
pip install modal. - Authenticate with Modal:
python3 -m modal setupor set
MODAL_TOKEN_ID / MODAL_TOKEN_SECRET in the environment. Do not pass Modal tokens as command-line flags.
#Commands
crabbox warmup --provider modal --modal-app crabbox --modal-image python:3.13-slim
crabbox run --provider modal -- pnpm test
crabbox run --provider modal --id blue-lobster --shell 'pnpm install && pnpm test'
crabbox status --provider modal --id blue-lobster
crabbox stop --provider modal blue-lobster
#Auth
Crabbox does not accept Modal token flags. The local Python client reads normal Modal auth state from python3 -m modal setup or from:
export MODAL_TOKEN_ID=...
export MODAL_TOKEN_SECRET=...
Rotate these values if they were pasted into a chat, shell history, issue, or log.
#Config
provider: modal
target: linux
modal:
app: crabbox
image: python:3.13-slim
workdir: /workspace/crabbox
python: python3
Provider flags:
--modal-app
--modal-image
--modal-workdir
--modal-python
Environment overrides:
CRABBOX_MODAL_APP
CRABBOX_MODAL_IMAGE
CRABBOX_MODAL_WORKDIR
CRABBOX_MODAL_PYTHON
#Lifecycle
warmup/runwithout--idcreates a Modal Sandbox inmodal.appwith- Crabbox stores a local claim with a normal
cbx_...lease ID and friendly - By default
runarchive-syncs the working tree: Git manifest → local - The user command runs through
Sandbox.execin abash -lcwrapper that - Non-kept one-shot sandboxes are terminated after the run.
--keepand
modal.image, the configured timeout, and Crabbox ownership tags.
slug.
tar -czf → Modal process-stdin upload to /tmp/crabbox-modal-sync-*.tgz → in-sandbox tar -xzf into modal.workdir.
changes into modal.workdir, streaming stdout/stderr back through Crabbox.
--keep-on-failure retain the sandbox until crabbox stop.
#Capabilities
- SSH: no.
- Crabbox sync: yes, archive sync through Modal Sandbox exec/upload.
- Provider sync: no separate Modal sync command.
- Desktop/browser/code: no Crabbox VNC/code surface.
- Actions hydration: no.
- Coordinator: no.
#Gotchas
- IDs can be Crabbox slugs,
cbx_...lease IDs, or Modal sandbox IDs when the --classand--typeare rejected; the configured Modal image owns runtimemodal.workdirmust be an absolute, dedicated directory. Broad roots such as--checksumis rejected because Modal does not expose Crabbox's SSH/rsync- Use
--sync-onlyto pre-upload the archive into a kept sandbox before a --script,--script-stdin,--fresh-pr, local stdout/stderr captures,- Forwarded environment values are written to a temporary shell profile, uploaded
sandbox carries Crabbox tags.
contents and resources for this first implementation.
/, /tmp, /home, and /workspace are rejected before sync or command execution.
target. Large-sync guardrails still apply, and --force-sync-large is honored for intentional large archive syncs.
later command.
--capture-on-fail, and --download are rejected because Modal owns command transport and Crabbox has no SSH target for those paths.
into /tmp, sourced for the command, and removed best-effort. They are not placed on the local Python process argv.
Related docs: