# C3 Docs

> C3 is a GPU compute marketplace for academics. Users configure projects with a .c3 YAML file and run c3 deploy to provision cloud GPUs, run jobs, and return results.

- [C3 Docs](https://docs.cthree.cloud/index.md)

## artifacts

- [Artifact Output](https://docs.cthree.cloud/artifacts.md): The output of a job is its artifacts. These are things like plots produced by your job, trained neural network weights, or saved checkpoints.

## dashboard

- [Web Dashboard](https://docs.cthree.cloud/dashboard.md): The C3 web dashboard at cthree.cloud/dashboard provides a visual interface for managing your GPU compute jobs, billing, and data.

## data-mounting

- [Data Mounting](https://docs.cthree.cloud/data-mounting.md): How C3 stores data

## environment

- [Environment](https://docs.cthree.cloud/environment.md): When you run code locally, you manage your own Python environment. On C3, you declare your dependencies in your .c3 config and C3 builds the environment on the GPU automatically.

## marketplace

- [Marketplace](https://docs.cthree.cloud/marketplace.md): C3 aggregates GPU capacity from multiple data centers. When you submit a job, we find available compute at competitive rates—no need to manage cloud accounts or hunt for capacity yourself.

## submission

- [Project Configuration](https://docs.cthree.cloud/submission.md): C3 projects are configured with a .c3 YAML file at the project root. Run c3 deploy from anywhere in the project to submit a job.

## warm-pool

- [Warm Pool](https://docs.cthree.cloud/warm-pool.md): C3's warm pool is the key to achieving a "mounted-like" GPU development experience. Instead of waiting minutes for a VM to provision, your code starts running in seconds.


---

# Full Documentation Content

# Artifact Output

The output of a job is its artifacts. These are things like plots produced by your job, trained neural network weights, or saved checkpoints.

Only files written to configured output directories are collected. By default this is `$C3_ARTIFACTS_DIR` (an `artifacts/` directory pre-created for every job). You can add more directories with the `output:` field in your `.c3` config. Files written elsewhere in the working directory are not collected.

## Configuring output[​](#configuring-output "Direct link to Configuring output")

Every job automatically collects files written to `$C3_ARTIFACTS_DIR`:

```
import os

output_dir = os.environ["C3_ARTIFACTS_DIR"]  # always set, pre-created
with open(os.path.join(output_dir, "metrics.json"), "w") as f:
    json.dump(results, f)
```

You can collect files from additional directories too:

```
output:
  - results
  - checkpoints
```

Both `$C3_ARTIFACTS_DIR` contents and `output:` directories end up in the same artifact manifest, downloadable with `c3 pull`.

## Storage quota[​](#storage-quota "Direct link to Storage quota")

Artifact bytes count toward your account's tracked storage usage. When the agent registers an artifact after upload, the control plane records the byte delta against your storage balance. This means your displayed storage usage may increase after artifact uploads.

The quota check is currently **soft-fail** — uploads are never rejected due to quota, but a warning is logged when usage exceeds the quota. You can check your current usage with `c3 balance`.

## Artifact lifecycle[​](#artifact-lifecycle "Direct link to Artifact lifecycle")

1. Your script writes files to `$C3_ARTIFACTS_DIR` and/or directories listed in `output:`
2. After the script finishes, the agent collects all output files and uploads them as content-addressed blobs
3. An artifact manifest is created at `/jobs/<jobId>/`
4. Artifact bytes are charged to your storage usage quota
5. You can download, browse, or reuse artifacts in another job

**Important:** If your script exits successfully (exit code 0) but artifact upload fails, the job is marked `FAILED` with reason `UPLOAD_ERROR`. This is non-retryable — the GPU work completed, but the output could not be saved. Check your storage configuration and job logs if you encounter this status. When the script itself fails (non-zero exit), artifact upload is best-effort: upload errors are logged but the job status reflects the script failure.

## Browsing artifacts[​](#browsing-artifacts "Direct link to Browsing artifacts")

Artifacts are stored the same way as uploaded datasets, using the same content-addressed storage. You can browse them with the same `c3 data` commands, just at a different path.

You can reach a job's artifacts in two ways:

```
c3 data ls /jobs/job_abc123/                              # By job ID (resolves project automatically)
c3 data ls /projects/my-project/jobs/job_abc123/          # By project + job ID
```

Both paths point to the same data. Having two paths does not mean the data is stored twice.

To list all jobs with artifacts in a project:

```
c3 data ls /projects/my-project/jobs/
```

## Downloading artifacts[​](#downloading-artifacts "Direct link to Downloading artifacts")

Download artifacts to your local machine with `c3 pull`:

```
c3 pull job_abc123          # Download a specific job's artifacts
c3 pull                     # Download all new completed jobs
```

Or use `c3 data cp` for more control:

```
c3 data cp /jobs/job_abc123/ ./local-output/
```

## Reusing artifacts in another job[​](#reusing-artifacts-in-another-job "Direct link to Reusing artifacts in another job")

Because artifacts live in C3's centralised storage, you can mount them directly into a new job without downloading to your local machine first. This avoids the slow local-machine bottleneck entirely:

```
datasets:
  - ref: /jobs/job_abc123
    mount: /data/prev_weights
```

This mounts the output from `job_abc123` at `/data/prev_weights` in your new job. The data transfers server-to-server at full speed.

## Job chaining[​](#job-chaining "Direct link to Job chaining")

Job chaining is mounting a previous job's artifacts directly into a new job. This lets you build multi-stage pipelines where each stage feeds into the next, with all data staying in C3's storage network:

```
# Stage 1: Preprocess data
c3 deploy -f
# Job completes, producing job_preprocess

# Stage 2: Train model (mount preprocessed data)
# Update .c3:
#   datasets:
#     - ref: /jobs/job_preprocess
#       mount: /data/preprocessed
c3 deploy -f
# Job completes, producing job_train

# Stage 3: Evaluate (mount trained model)
# Update .c3:
#   datasets:
#     - ref: /jobs/job_train
#       mount: /data/model
c3 deploy -f
```

Each stage mounts the previous stage's output directly. Data stays in C3's storage network and never needs to touch your local machine.


---

# Web Dashboard

The C3 web dashboard at [cthree.cloud/dashboard](https://cthree.cloud/dashboard) provides a visual interface for managing your GPU compute jobs, billing, and data.

**Everything available in the dashboard is also available via the CLI.** The CLI is the primary interface for C3 — the dashboard is a convenience layer that mirrors CLI functionality.

## Dashboard Pages[​](#dashboard-pages "Direct link to Dashboard Pages")

| Dashboard                                                   | CLI Equivalent            | Description                                                                             |
| ----------------------------------------------------------- | ------------------------- | --------------------------------------------------------------------------------------- |
| [Jobs](https://cthree.cloud/dashboard/squeue)               | `c3 squeue`               | View all jobs with status, GPU, runtime. Click any job to see details.                  |
| [Billing](https://cthree.cloud/dashboard/billing)           | `c3 balance` / `c3 topup` | View credit balance, transaction history, and top up via Stripe.                        |
| [Subscription](https://cthree.cloud/dashboard/subscription) | `c3 upgrade`              | View current plan, upgrade/downgrade between tiers, cancel or resume your subscription. |
| [Data](https://cthree.cloud/dashboard/data)                 | `c3 data ls`              | Browse your datasets and storage usage.                                                 |
| [Settings](https://cthree.cloud/dashboard/settings)         | `c3 apikey`               | Create and manage API keys for programmatic access.                                     |

## Login[​](#login "Direct link to Login")

The dashboard uses the same Auth0 authentication as the CLI. Click "Login" in the header at cthree.cloud, or navigate directly to `/dashboard` to be prompted to sign in.

Once logged in, the dashboard uses the same API and credentials as `c3 login` — you'll see the same jobs, balance, and data in both.

## Key Differences from CLI[​](#key-differences-from-cli "Direct link to Key Differences from CLI")

* **No job submission**: Jobs are submitted via `c3 deploy` from the CLI. The dashboard shows and manages existing jobs.
* **No data upload/download**: Data transfers use `c3 data cp`. The dashboard browses data that's already uploaded.
* **Stripe redirect**: Topping up with credits, or subscribing to a paid plan from free, opens the same Stripe checkout page the CLI opens. Tier switches (pro ↔ max), downgrades, and cancellations happen inline without redirecting to Stripe.


---

# Data Mounting

## How C3 stores data[​](#how-c3-stores-data "Direct link to How C3 stores data")

C3 keeps all data (datasets you upload and artifacts your jobs produce) on a centralised storage server with high-bandwidth connections to GPU nodes around the world. Think of it like a warehouse on a motorway network: the links between the warehouse and the GPUs are fast, high-bandwidth connections. Uploading from your local machine is the bottleneck, since home and office network connections to remote servers are much slower than server-to-server transfers. The good news is you only need to upload once. After that, C3 moves data between its storage and GPUs at full speed.

## Paths[​](#paths "Direct link to Paths")

Data in C3 can be organised by project, by job, or both:

| Path                                | What it contains                  |
| ----------------------------------- | --------------------------------- |
| `/datasets/{name}/`                 | Uploaded datasets                 |
| `/jobs/{jobId}/`                    | Job output artifacts              |
| `/projects/{project}/data/{name}/`  | Datasets scoped to a project      |
| `/projects/{project}/jobs/{jobId}/` | Job artifacts scoped to a project |

You can use whichever path style suits your workflow. `/jobs/{jobId}/` resolves the project automatically.

## Upload a dataset[​](#upload-a-dataset "Direct link to Upload a dataset")

```
c3 data cp ./local-data/ /datasets/my-dataset/
```

This uploads your data to C3's centralised storage. You only need to do this once. After the initial upload, every `c3 deploy` that references this dataset gets rapid access to it directly from the storage network, with no re-upload needed.

C3 uses content-addressed deduplication: each file is hashed (SHA256) before upload, and if the content already exists, the upload is skipped. This means re-uploading a dataset with minor changes only transfers the files that actually changed, and overall storage usage can be lower than standard methods since identical files are never stored twice (see [How deduplication works](#how-deduplication-works) below).

## Browse data[​](#browse-data "Direct link to Browse data")

Use `c3 data ls` to browse datasets, versions, and files:

```
c3 data ls /datasets/                          # List all datasets
c3 data ls /datasets/my-dataset/               # List versions
c3 data ls -l /datasets/my-dataset/@latest/     # List files in latest version
```

## Mount a dataset in a job[​](#mount-a-dataset-in-a-job "Direct link to Mount a dataset in a job")

Reference the dataset in your `.c3` config:

```
datasets:
  - ref: /datasets/my-dataset
    mount: /data/my-dataset
```

Once referenced, C3 handles moving the data to whichever GPU your job lands on. From your script's perspective, the files are simply local at the mount path. You read them like any other files:

```
import numpy as np

data = np.loadtxt("/data/my-dataset/measurements.csv", delimiter=",")
```

### Mount path rules[​](#mount-path-rules "Direct link to Mount path rules")

* Mount paths must be **absolute** (start with `/`). Relative paths are rejected at submission time with a clear error.
* If `mount` is omitted, it is auto-derived as `/data/<dataset-name>` (e.g., `/datasets/cifar10` becomes `/data/cifar10`).
* In `.c3` YAML, a relative mount like `mydata` is auto-prefixed to `/data/mydata`.

### Local directories[​](#local-directories "Direct link to Local directories")

You can reference a local directory as a dataset. C3 auto-uploads it before submitting the job:

```
datasets:
  - ref: ./local-data
    mount: /data/train
```

This is equivalent to running `c3 data cp ./local-data/ /datasets/...` yourself, but handled automatically.

## Versioning[​](#versioning "Direct link to Versioning")

Every upload creates a new version. Your jobs always get exactly the data they expect:

```
c3 data log /datasets/my-dataset/
```

```
VERSION   CREATED              FILES   SIZE
v3        2024-01-15 10:00:00  1000    2.5GB
v2        2024-01-10 09:00:00  1000    2.4GB
v1        2024-01-05 08:00:00  500     1.2GB
```

Jobs reference the latest version by default, or you can pin to a specific version for reproducibility.

## How deduplication works[​](#how-deduplication-works "Direct link to How deduplication works")

All data in C3 (datasets, workspaces, and job artifacts) uses the same content-addressed storage. Every file is stored as a **blob** keyed by its SHA256 hash, and a **manifest** lists which blobs make up each dataset, workspace, or set of job artifacts.

This means:

* **Cross-job dedup**: If two jobs produce identical output files, the data is stored once
* **Workspace dedup**: Re-deploying the same code skips uploading unchanged files
* **Cross-dataset dedup**: Identical files shared across datasets use the same storage
* **Instant re-uploads**: `c3 data cp` only uploads files that have actually changed

Deduplication is automatic and transparent. Artifacts still appear per-job (each job has its own listing), but identical files across jobs share storage behind the scenes.

## Data commands[​](#data-commands "Direct link to Data commands")

| Command                | Description                                   |
| ---------------------- | --------------------------------------------- |
| `c3 data ls /path/`    | List files, datasets, or job artifacts        |
| `c3 data cp SRC DST`   | Copy files (upload or download)               |
| `c3 data rm -r /path/` | Delete a dataset (requires `-r` for datasets) |
| `c3 data du /path/`    | Show disk usage                               |
| `c3 data log /path/`   | Show version history                          |


---

# Environment

When you run code locally, you manage your own Python environment. On C3, you declare your dependencies in your `.c3` config and C3 builds the environment on the GPU automatically.

## Python projects[​](#python-projects "Direct link to Python projects")

Point `python.project` at a directory containing `pyproject.toml` and `uv.lock`:

```
python:
  project: ./
```

C3 uses [uv](https://github.com/astral-sh/uv) for fast, reproducible installs. When your job starts, C3 runs `uv sync` on the GPU to create the virtual environment before executing your script.

### Generate a lock file[​](#generate-a-lock-file "Direct link to Generate a lock file")

If you don't have a `uv.lock` yet:

```
uv lock
```

This creates a lock file that pins exact dependency versions, ensuring your job gets the same environment every time.

### Subdirectory projects[​](#subdirectory-projects "Direct link to Subdirectory projects")

If your Python project is in a subdirectory:

```
python:
  project: ./my_project
```

The path is relative to the `.c3` file.

## Environment caching[​](#environment-caching "Direct link to Environment caching")

C3 caches built environments based on the hash of your `uv.lock` file. If your dependencies haven't changed since the last job, the cached environment is reused instantly with no rebuild. This means:

* **First job**: Full `uv sync` (typically 10-30 seconds depending on dependencies)
* **Subsequent jobs with same lock file**: Cached environment, near-instant setup
* **After changing dependencies**: Run `uv lock` locally, then deploy. First job with the new lock file rebuilds, then it is cached again.

Use `python.project` instead of `pip install` in your script

Always declare dependencies via `python.project` rather than running `pip install` in your bash script. C3 caches the environment across jobs based on your `uv.lock` hash — unchanged dependencies are reused instantly. Running `pip install` in the script would reinstall everything from scratch on every job.

## What gets installed[​](#what-gets-installed "Direct link to What gets installed")

C3 GPU VMs come with:

* Python (via uv)
* CUDA drivers and toolkit
* Standard system libraries

Your `pyproject.toml` + `uv.lock` define everything else. This keeps environments reproducible: the same lock file always produces the same environment, regardless of which GPU or data center runs your job.

## Full example[​](#full-example "Direct link to Full example")

```
# .c3
project: my-experiment
script: run.sh
gpu: l40
time: "02:00:00"

python:
  project: ./

datasets:
  - ref: /datasets/imagenet
    mount: /data/imagenet

output:
  - ./results
```

```
# run.sh
#!/bin/bash
python3 train.py
```

```
# pyproject.toml
[project]
name = "my-experiment"
requires-python = ">=3.11"
dependencies = [
    "jax[cuda12]",
    "flax",
    "optax",
    "numpy",
]
```


---

# Marketplace

C3 aggregates GPU capacity from multiple data centers. When you submit a job, we find available compute at competitive rates—no need to manage cloud accounts or hunt for capacity yourself.

## Available GPUs[​](#available-gpus "Direct link to Available GPUs")

| GPU       | VRAM | Best for                                           |
| --------- | ---- | -------------------------------------------------- |
| L40       | 48GB | Training, inference, general-purpose GPU workloads |
| H100 80GB | 80GB | Large model training, high-performance compute     |
| A100 80GB | 80GB | Training, mixed-precision workloads                |
| RTX A4000 | 16GB | Light training, testing, development               |

Set `gpu:` in your `.c3` config to select a GPU. Run `c3 list` to see current availability and pricing.

## Pricing[​](#pricing "Direct link to Pricing")

### Compute[​](#compute "Direct link to Compute")

You're billed per second of actual compute time—not for time spent queuing or provisioning. New accounts receive £10 in free credits. Check your balance:

```
c3 balance
```

### Plans[​](#plans "Direct link to Plans")

Every new account starts with a **14-day Pro trial** — 100 GB of storage and £10 in compute credits.

| Plan | Storage | Price     | Best for                        |
| ---- | ------- | --------- | ------------------------------- |
| Free | 1 GB    | £0/month  | Trying C3, small experiments    |
| Pro  | 100 GB  | £9/month  | Regular research, datasets      |
| Max  | 1 TB    | £15/month | Large datasets, heavy workloads |

Manage your plan anytime:

```
c3 upgrade              # Interactive picker
c3 upgrade pro          # Subscribe to or switch to Pro
c3 upgrade max          # Subscribe to or switch to Max
c3 upgrade free         # Cancel subscription (takes effect at period end)
c3 upgrade free --yes   # Non-interactive cancel (for scripts)
c3 upgrade free -y      # Short form of --yes
```

Upgrades (e.g. Pro → Max) are immediate: you get the new features right away and your card is charged the prorated difference for the remainder of the current billing period. Downgrades (e.g. Max → Pro) and cancellations take effect at the **end of your current billing period** — you keep the features you paid for until then. To reverse a pending downgrade or cancellation before it takes effect, run `c3 upgrade <current-tier>`.

When your trial ends, you're moved to the Free plan. Existing data is preserved — you just can't upload more until you upgrade or free up space.

## How jobs run[​](#how-jobs-run "Direct link to How jobs run")

1. **PENDING** — Job submitted, waiting for a GPU
2. **SCHEDULING** — Assigning to a machine
3. **RUNNING** — Your script is executing
4. **COMPLETED** — Done. Download results with `c3 pull`
5. **SYNCED** — Results downloaded locally

Failed or cancelled jobs show as **FAILED**, **CANCELED**, or **TIMED\_OUT**.

## Warm pool[​](#warm-pool "Direct link to Warm pool")

C3 maintains a pool of pre-provisioned GPUs. Jobs hitting the warm pool start running in **\~5-15 seconds** instead of waiting 2-5 minutes for cold provisioning.

| Path           | Allocation    | Total Startup  |
| -------------- | ------------- | -------------- |
| **Warm pool**  | < 1 second    | \~5-15 seconds |
| Cold provision | \~2-5 minutes | \~2-5 minutes  |

This enables rapid iteration: edit locally, submit, see results quickly, repeat.

**[Learn more about the warm pool →](https://docs.cthree.cloud/warm-pool.md)**

## Providers[​](#providers "Direct link to Providers")

Jobs currently run on **Hyperstack**. We're onboarding additional providers to increase capacity and reduce prices.


---

# Project Configuration

C3 projects are configured with a `.c3` YAML file at the project root. Run `c3 deploy` from anywhere in the project to submit a job.

Key differences from running locally

**Environment:** You declare dependencies via `python.project` pointing to a directory with `pyproject.toml` + `uv.lock`. C3 builds the environment on the GPU automatically. See [Environment](https://docs.cthree.cloud/environment.md).

**Data mounting:** Your data lives in C3's centralised storage. You tell C3 which datasets to mount and where using `datasets:`. Your script reads from that path as if the files were local. See [Data Mounting](https://docs.cthree.cloud/data-mounting.md).

**Artifact output:** Files on the GPU are discarded when the job ends. Write results to `$C3_ARTIFACTS_DIR` or a directory listed in `output:`. Only these are collected. See [Artifact Output](https://docs.cthree.cloud/artifacts.md).

## Configuration reference[​](#configuration-reference "Direct link to Configuration reference")

| Field            | Type   | Description                                                                                                   |
| ---------------- | ------ | ------------------------------------------------------------------------------------------------------------- |
| `project`        | string | Project name (auto-generated if not set). Lowercase alphanumeric + hyphens.                                   |
| `script`         | string | **Required.** Path to a bash script with your execution commands (e.g. `run.sh`), relative to `.c3`           |
| `gpu`            | string | GPU profile (e.g. `l40`, `h100-80gb`, `a100-80gb-pcie`). See `c3 list`                                        |
| `time`           | string | Maximum runtime in `HH:MM:SS` format. You're only charged for actual usage                                    |
| `job_name`       | string | Job display name                                                                                              |
| `python.project` | string | Path to Python project dir (must contain `pyproject.toml` + `uv.lock`)                                        |
| `datasets`       | list   | Datasets to mount (`ref` + optional `mount`). See [Data Mounting](https://docs.cthree.cloud/data-mounting.md) |
| `output`         | list   | Directories to collect as artifacts. See [Artifact Output](https://docs.cthree.cloud/artifacts.md)            |

## Full example[​](#full-example "Direct link to Full example")

All job configuration goes in `.c3`. The `script` field points to a bash script containing your execution commands — no `#SBATCH` or `#C3` directives needed.

```
# .c3
project: my-experiment
script: run.sh
gpu: l40
time: "04:00:00"
job_name: train-model

python:
  project: ./

datasets:
  - ref: /datasets/imagenet
    mount: /data/imagenet

output:
  - ./checkpoints
  - ./results
```

```
# run.sh
#!/bin/bash
python3 train.py
```

## Creating a new project[​](#creating-a-new-project "Direct link to Creating a new project")

```
cd my-project
c3 init
```

This creates a `.c3` file with sensible defaults. Edit it and deploy with `c3 deploy`.

## API keys[​](#api-keys "Direct link to API keys")

For team billing or CI/CD, add an API key to `.c3.local` (keep this file out of version control):

```
# .c3.local — secrets (add to .gitignore)
api_key: c3_key_abc123def456...
```

Create keys with `c3 apikey create my-team-key`. The API key takes priority over `c3 login` credentials.


---

# Warm Pool

C3's warm pool is the key to achieving a **"mounted-like" GPU development experience**. Instead of waiting minutes for a VM to provision, your code starts running in seconds.

## The Problem with Cold Provisioning[​](#the-problem-with-cold-provisioning "Direct link to The Problem with Cold Provisioning")

Traditional cloud GPU workflows require spinning up a fresh VM for every job:

1. **Request VM** from cloud provider
2. **Wait for allocation** (30-60s)
3. **Boot the VM** (30-60s)
4. **Initialize GPU drivers** (30-60s)
5. **Download your code** (10-30s)
6. **Finally run your job**

This adds up to **2-5 minutes of waiting** before your code even starts. For iterative development—tuning hyperparameters, debugging training loops, testing model changes—this latency kills productivity.

## How the Warm Pool Works[​](#how-the-warm-pool-works "Direct link to How the Warm Pool Works")

C3 maintains a fleet of **pre-provisioned GPUs**. These VMs are:

* Already booted and initialized
* GPU drivers loaded and ready
* C3 agent running and polling for work
* Network configured with fast access to our control plane

When you submit a job, the scheduler finds an idle warm GPU and assigns it inline—**allocation takes under a second**, with total startup of \~5-15 seconds (agent heartbeat + code download):

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                           C3 WARM POOL ARCHITECTURE                         │
└─────────────────────────────────────────────────────────────────────────────┘

                                    ┌─────────────┐
                                    │   Your Job  │
                                    │  c3 deploy  │
                                    └──────┬──────┘
                                           │
                                           ▼
┌──────────┐                      ┌─────────────────┐
│          │    Job submitted     │                 │
│   You    │ ──────────────────▶  │  C3 Control     │
│          │   allocation < 1s    │  Plane          │
└──────────┘                      └────────┬────────┘
                                           │
                                           ▼
                              ┌──────────────────────┐
                              │   GPU PROVIDER(S)    │
                              │  ┌────┐ ┌────┐       │
                              │  │GPU │ │GPU │  ...  │
                              │  │ ✓  │ │ ✓  │       │
                              │  └────┘ └────┘       │
                              │    Warm Pool         │
                              └──────────┬───────────┘
                                         │
                                         ▼
                              ┌───────────────────┐
                              │  Job runs on      │
                              │  first available  │
                              │  warm GPU         │
                              └───────────────────┘
```

### Warm Path vs Cold Path[​](#warm-path-vs-cold-path "Direct link to Warm Path vs Cold Path")

| Metric              | Warm Pool      | Cold Provision                  |
| ------------------- | -------------- | ------------------------------- |
| **Allocation time** | < 1 second     | \~2-5 minutes                   |
| **Total startup**   | \~5-15 seconds | \~2-5 minutes                   |
| **When used**       | Most jobs      | Pool exhausted / rare GPU types |

## Sub-Second Allocation[​](#sub-second-allocation "Direct link to Sub-Second Allocation")

When a warm GPU is available, job allocation is **nearly instantaneous**:

1. **You submit** → Job hits the C3 control plane
2. **Sub-second allocation** → Scheduler finds an idle warm GPU and assigns your job
3. **Agent pickup (\~5s)** → Agent picks up the job on its next heartbeat
4. **Code download** → Bundle is fetched and extracted
5. **Your code runs** → Execution begins, logs stream back immediately

This transforms GPU development from a **batch workflow** into an **interactive one**. It feels like having a GPU mounted to your local machine.

## Pool Scaling[​](#pool-scaling "Direct link to Pool Scaling")

The warm pool scales with demand. C3 uses a baseline target per GPU profile plus demand-based scaling:

* **Low demand**: Pool holds a baseline number of warm GPUs
* **High demand**: Pool scales up to meet job volume (with a configurable cap)
* **Burst load**: Overflow goes to cold provisioning (still works, just slower)

## When Cold Provisioning Happens[​](#when-cold-provisioning-happens "Direct link to When Cold Provisioning Happens")

Sometimes jobs use cold provisioning instead:

* **Pool exhausted**: All warm GPUs are busy during high demand
* **Rare GPU type**: Specialized hardware not kept warm
* **Unusual demand patterns**: Spikes beyond the baseline pool capacity

Cold provisioning still works—your job will run, it just takes longer to start. C3 automatically falls back to cold provisioning when needed.

## Best Practices[​](#best-practices "Direct link to Best Practices")

### Maximize Warm Pool Benefits[​](#maximize-warm-pool-benefits "Direct link to Maximize Warm Pool Benefits")

1. **Use L40 GPUs** — Currently the available warm pool GPU
2. **Keep jobs small** — Finish faster, return GPU to pool for others
3. **Use `--follow`** — See real-time logs as your job runs
4. **Submit during active hours** — Pool is warmest when others are using it too

### Understand the Timing[​](#understand-the-timing "Direct link to Understand the Timing")

* **Allocation time**: How long from submission until a GPU is assigned (sub-second for warm, minutes for cold)
* **Total startup**: Time from submission until your code starts running (\~5-15 seconds for warm, minutes for cold)
* **Runtime**: Your actual code execution
* **Total time**: Everything from submit to completion

## The Development Experience[​](#the-development-experience "Direct link to The Development Experience")

With the warm pool, your workflow becomes:

```
┌─────────────────────────────────────────────────────────────────┐
│                    ITERATIVE GPU DEVELOPMENT                    │
└─────────────────────────────────────────────────────────────────┘

    ┌──────────┐      ┌──────────┐      ┌──────────┐
    │  Edit    │      │  Submit  │      │   See    │
    │  Code    │ ───▶ │   Job    │ ───▶ │ Results  │
    │ Locally  │      │ c3 deploy│      │  quickly │
    └──────────┘      └──────────┘      └──────────┘
          ▲                                   │
          │                                   │
          └───────────────────────────────────┘
                    Iterate rapidly
```

This is especially powerful for:

* **ML experimentation** — Try different hyperparameters quickly
* **Debugging** — Add print statements, see output fast
* **Prototyping** — Test ideas without provisioning overhead
* **Education** — Learn GPU programming interactively

The warm pool makes cloud GPUs feel local.


---

