> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tuneplane.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Mount a governed folder

> Give a job read-only access to material nobody is allowed to download.

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
tp volume create acme/support-transcripts -d "Tier-2 tickets, redacted"
tp volume push ./transcripts --name acme/support-transcripts
tp submit my-sft --profile h200:8 --volume acme/support-transcripts
```

The job reads the files at `$VOLUMES_DIR/support-transcripts`, read-only. Nobody can download
them unless the owner turns that on.

## A Volume is not a dataset

|            | Volume                                                          | Dataset                                             |
| ---------- | --------------------------------------------------------------- | --------------------------------------------------- |
| Versions   | None. Its current contents are its contents                     | Immutable versions                                  |
| Reference  | `<owner>/<name>`                                                | `<owner>/<name>[@version]`                          |
| Changes    | Files added and removed in place                                | A new version each time                             |
| Use it for | Internal documents, reference PDFs, material that keeps growing | Training data a finished run has to be able to name |
| Download   | Off until the owner turns it on                                 | Available to anyone who can reference it            |

A version suffix on a volume reference is refused when the spec is parsed. So is a malformed
id, and two volumes whose leaf names would collide at the same mount path.

## Create and fill one

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
tp volume create acme/support-transcripts -d "Tier-2 tickets, redacted"
tp volume create acme/refs --public                    # any signed-in user may reference it
tp volume push ./transcripts --name acme/support-transcripts
tp volume ls
```

`tp volume push` uploads everything under the directory, minus OS and Office noise. Raise
`--concurrency` on a fast link.

Removing files, or the whole volume:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
tp volume rm acme/support-transcripts -p old/2024 -p drafts
tp volume rm acme/support-transcripts --yes
```

## Reference it from a job

Declare it in the experiment config, which is the durable form:

```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
data:
  volumes:
    - acme/support-transcripts
    - bob/reference-pdfs
```

Or override for one submission:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
tp submit my-sft --profile h200:8 \
  --volume acme/support-transcripts --volume bob/reference-pdfs
```

Each one appears at `$VOLUMES_DIR/<leaf name>`. Read the path from the environment; never
hard-code it.

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import os, pathlib

root = pathlib.Path(os.environ["VOLUMES_DIR"]) / "support-transcripts"
for path in root.rglob("*.txt"):
    ...
```

A job that cannot see a referenced volume is refused at submission. That is deliberate: an
empty directory would make a permission problem look like a modelling problem.

## Which backends can mount one

| Fleet kind | Mounts a volume                      | How                                                 |
| ---------- | ------------------------------------ | --------------------------------------------------- |
| `local`    | Yes                                  | A bind mount                                        |
| `node`     | Yes                                  | One filesystem at the same path on every node       |
| `kuberay`  | Only with `TUNEPLANE_K8S_VOLUME_PVC` | A read-only claim at `/volumes`                     |
| `slurm`    | No                                   | The platform does not control the image's bind list |

On a backend that cannot, submission is refused naming the setting, rather than starting a job
whose mount would be empty.

## Turn one file into something people can read

Two permissions, both the owner's, both off by default:

| Permission       | What it allows                                                          |
| ---------------- | ----------------------------------------------------------------------- |
| `allow_download` | Fetching the bytes back out. The only way material leaves by design     |
| `allow_preview`  | The console rendering one file at a time, inline. Every read is audited |

They are independent. Listing the structure — file names, sizes — is always available to anyone
who can reference the volume; content is not.

## Produce a dataset from a volume

Reading a volume and publishing the result is a **Processing Run**: your code, on the platform,
with provenance.

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
tp submit my-prep --profile h200:1 \
  --volume acme/support-transcripts \
  --output-dataset acme/support-sft@v1
```

The job writes into `$TUNEPLANE_DATASET_OUT_DIR` and the platform publishes when the run
succeeds. The job never holds a registry credential, and the published dataset inherits the
classification of the material it read.

This is also how you clean a volume: read, treat, publish. The platform never rewrites what you
uploaded.

## Check it worked

`tp volume ls` shows the volume with its file count. In a running job:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
ls -la "$VOLUMES_DIR"
```

The mount is read-only, so a write there fails — that is the mount working, not a bug.

<Accordion title="What a Volume does not protect against">
  If your code can read the plaintext, no storage control stops exfiltration. A script that can
  open a PDF can base64 it into its own stdout.

  What a Volume does enforce: no download route while `allow_download` is off, no preview route
  while `allow_preview` is off, one audited read per file when it is on, a read-only mount, an
  audited reference, and no bulk log download. Every way out is a decision somebody made and a
  record somebody can find.

  Keeping material off the cluster entirely is the deployment's egress policy, not this feature.
</Accordion>

## Next

[Datasets](/en/guides/datasets) · [Submitting a job](/en/guides/submit) ·
[The Data page](/en/console/data)
