# Choose code and dependencies

Pick the right packaging mode for standalone scripts, Python packages, native profiles and containers.

Choose how your job's code and Python dependencies are packaged and executed on a worker.

## 1. Pick how to supply your code

| What you are running     | How to submit it                          | Best for                                                 |
| ------------------------ | ----------------------------------------- | -------------------------------------------------------- |
| **Single `.py` script**  | `ct-cli submit script.py`                 | Quick experiments, one-off analysis, or testing          |
| **Local Python project** | `ct-cli program publish ./my-pkg ...`     | Reusable functions with a `pyproject.toml` and `uv.lock` |
| **Git repository**       | `--git-url ... --git-ref main`            | Pinning a calculation to an exact Git commit             |
| **Published Program**    | `ct-cli submit my-program@1 --params ...` | Production workflows called repeatedly with new inputs   |

When you reference a Git repository, the platform resolves the branch or tag to an exact commit SHA at submission time so future pushes never alter an already-submitted job.

## 2. Choose how dependencies are installed

There are three ways a worker can provide Python libraries for your job:

### Managed `uv` environment (default for scripts and small packages)

The worker automatically creates or reuses a cached `uv` environment matching your script's inline PEP 723 metadata or your project's `pyproject.toml` and `uv.lock`.

### Shared native profile (`compute/runtime`)

Our scientific packages (DFT, MD, TS search, and benchmarks) share a single locked Python 3.13 environment (`compute/runtime`, with CUDA 13 on Linux GPU workers). Using a native profile skips per-job installation for heavy scientific libraries:

```bash
uv sync --project compute/runtime --frozen
```

> **Important:** Native profiles verify the installed environment fingerprint before running a job. Always stop the worker before modifying or syncing packages in `compute/runtime`.

### Docker container execution

Container jobs run inside a fresh Docker container per attempt, combining prebuilt system/C++ dependencies from the base image with your pinned Python source. Both native and container runs use the exact same [Program](/start/reusable-programs/) input validation and artifact collection.

## 3. Separate code versions from placement

Your code/dependencies and your target hardware are configured independently:

- **Program version (`name@1` → `name@2`):** Captures code, Pydantic schemas, and dependency lock.
- **Pool & resources (`--pool`, `--cpus`, `--gpus`, `--memory`):** Selects which [registered workers](/operate/workers/) can pick up the job.

## 4. Keep working directories stateless

Workers run each job attempt in a fresh temporary scratch directory:

- Never hardcode paths to files outside the job workspace.
- Stage input files explicitly and write any file you want to keep under `results/` (see [Work with files and results](/operate/files/)).
