Write up a plan for this:
We need to migrate our current “agent worker over a 1TB dataset” setup from a DigitalOcean volume to Modal.
Current setup:
- Data currently lives on a DigitalOcean volume.
- We want to run many ephemeral Codex CLI workers against that shared dataset.
- The dataset should be treated as read-only by agent workers.
- Each worker should have its own writable scratch directory.
- Outputs should be written to per-job result directories, not back into the shared dataset.
- We are using Codex CLI, not Claude Code.
Goal: Build a Modal-based worker system that can:
- Store/mount the dataset using a Modal Volume.
- Spin up Modal workers/sandboxes/functions that run Codex CLI.
- Mount the shared dataset at
/data. - Use
/workspaceas local writable scratch. - Write final outputs to
/results/<job_id>/. - Inject secrets via Modal Secrets, especially
OPENAI_API_KEY. - Avoid putting secrets in files, prompts, logs, or mounted volumes.
- Make it easy to submit jobs programmatically.
Please inspect the current repo first and adapt to the existing structure. Do not rewrite everything unnecessarily. Prefer a small, clean integration.
Implementation requirements:
- Add Modal as a dependency if not already present.
- Create a Modal app, probably in something like
modal_workers/agent_worker.pyor an equivalent location that fits this repo. - Define a Modal image that installs:
- Node.js / npm if needed
- Codex CLI
- git
- ripgrep
- fd/findutils if useful
- jq
- Python utilities already needed by the repo
- Define or reference a Modal Volume for the dataset, e.g.
agent-dataset. - Define or reference a Modal Volume for results if useful, e.g.
agent-results. - Mount dataset Volume at
/data. - Mount results Volume at
/results. - Ensure workers run from
/workspace, not/data. - Ensure the prompt tells Codex that
/datais read-only and/workspaceis writable. - Use
OPENAI_API_KEYfrom a Modal Secret, e.g.agent-keys.
The core worker should look conceptually like:
@app.function(
image=image,
volumes={
"/data": dataset_volume,
"/results": results_volume,
},
secrets=[modal.Secret.from_name("agent-keys")],
cpu=4,
memory=8192,
timeout=3600,
)
def run_codex_job(job_id: str, prompt: str, extra_context: dict | None = None):
this is a full migration off digital ocean (too expensive , doesnt really work , not secure) onto modal (scalable , secure , etc).
I want to store all our public datasets on one modal volume. We should be able to spin up arbitrary codex workers with that volume mounted , etc.