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

# What sf init creates

> What sf init creates, what the CLI uploads, and what never leaves your laptop

A StarForge **lab** is a normal git repository on your machine. The console never clones it. `sf submit` packs a subset of files, uploads that bundle, and the server injects the Job Capsule on top.

## After `sf init my-lab --yes`

```text theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
my-lab/
├── starforge.yaml      # repo marker + project name (only signal `sf` uses to find the root)
├── experiments/        # sf new creates directories here
├── configs/            # official bases + model fragments; yours to edit or pin
├── common/             # shared code: data scripts, environments, rewards
├── .gitignore
└── README.md
```

`starforge.yaml` currently needs a `name` whose characters match `[A-Za-z0-9._-]`. That name is the console project. Do not pass `--project` on submit.

```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
name: my-lab
```

Commands that need a project (`sf new`, `submit`, `ls`, `validate`) walk up from the current directory looking for this file. CI can set `SF_REPO_ROOT` instead of `cd`. `sf login` / `logout` / `status` are global and do not need it.

## One experiment directory

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
sf new my-grpo --method nemo-rl/grpo
```

```text theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
experiments/my-grpo/
├── config.yaml           # your diffs; inherits via defaults
├── README.md             # scaffold notes, not executed
└── recipe.lock.json      # method + framework pin
```

`custom/custom` also gets `train.sh` (the only entrypoint). You can add `train.py` next to it. Plugins add `plugins.lock.json` after `sf plugin install … --exp`.

Do not put a `framework` file in the experiment and expect the platform to notice. The lock file is the method.

## What gets uploaded

The CLI packs the experiment, `common/`, and `configs/`. The same exclude list is shared with the server (`PACKAGE_EXCLUDES` in `starforge.contract.env`):

| Pattern                                     | Why it is dropped                                                               |
| ------------------------------------------- | ------------------------------------------------------------------------------- |
| `.forge/**`                                 | Local credentials. Putting this in the bundle would ship tokens to the cluster. |
| `.git/**`                                   | History is recorded as commit SHA in provenance, not as a clone.                |
| `**/outputs/**`                             | Local leftover artifacts. Cluster output is `$FORGE_OUT_DIR`.                   |
| `datasets/**/raw/**`, `datasets/**/data/**` | Raw data volume. Use a [platform dataset](/en/guides/datasets) or an HF id.     |
| `**/__pycache__/**`                         | Bytecode.                                                                       |
| `**/*.key`, `**/secrets.env`                | Secrets belong on the server, not in the job package.                           |

The JobSpec lands in the bundle at `.starforge/jobspec.json`. That path is inside `.starforge/`, not `.forge/`. Mixing the two directories is a real footgun: `.forge` is excluded, so a spec written there never reaches the cluster.

## What does not live in the lab

* Cluster kubeconfig, Slurm JWT, object-storage keys
* The Job Capsule (`runner.pex`). The server injects it after admit.
* Hardware parallelism. That comes from `--profile` and the registry.

## Git

Submit records `NRL_GIT_COMMIT` and `NRL_GIT_DIRTY`. A dirty tree is rejected unless you pass `--allow-dirty`. Untracked files are listed as warnings either way. Initialize git at `sf init` (the default) so the first commit is not an afterthought.

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
git add -A && git commit -m "first grpo config"
sf submit my-grpo --profile h200:8
```
