# Contribute a Lab Exercise

You will contribute one lab exercise through two pull requests: first the learner instructions, then the implemented sandbox environment.

Two reviewed pull requests

| Pull request | Outcome | Merge gate |
| --- | --- | --- |
| **1. Learner instructions** | A complete `instructions.md` and the generated item scaffold. | Another author approves the learner flow and technical content. |
| **2. Sandbox environment** | A working environment that implements and validates the merged instructions. | Another author approves the implementation and its local proof. |

Keep each branch and pull request scoped to one `items/<item-name>/` directory. Start the second branch only after the first pull request merges.

[A linear flow with ten steps. Create a branch. Initialize the lab with sandbox init. Write the instructions. Open PR 1. Merge PR 1 after another author approves. Create a new branch. Build the sandbox. Test the sandbox. Open PR 2. Merge PR 2 after another author approves.](https://skills.staging.lf-cert.cloud/docs/assets/lab-author-workflow.svg)

## Before you start

You need:

- GitHub and Codespaces access to the assigned lab repository.
- One assigned lab exercise and item name.
- The learning objectives and technical source material for that exercise.
- Enough domain knowledge to execute and verify every command you teach.

Complete [Setting Up](https://skills.staging.lf-cert.cloud/docs/setting-up/index.md) before you edit the repository. Complete the [Quickstart](https://skills.staging.lf-cert.cloud/docs/quickstart/index.md) first when the sandbox CLI is new to you.

Read the [Lab instruction style and voice](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/index.md) reference before you draft `instructions.md`.

Both pull requests stay inside the assigned item directory. Leave shared files, other items, and release selection unchanged unless a repository maintainer assigns that work separately.

## Pull request 1: approve the learner instructions

Treat the learner instructions as the contract for the environment implementation. Finish and review that contract before you write the environment behavior.

### Create one branch and scaffold one item

Update `main`, then create the instruction branch.

**@codespace-author ➜ .../LFSXXXX (main)**

```
git switch main
git pull --ff-only
git switch -c instructions/<item-name>
```

You now have one branch for one lab exercise. The prefix names the stage the branch carries, so the pull request's purpose is visible wherever the branch appears: `instructions/<item-name>` for this review, `env/<item-name>` for the environment review that follows. Keep the required convention when your repository defines a different one.

Run the initializer from `items/`.

**@codespace-author ➜ .../LFSXXXX (instructions/<item-name>)**

```
cd items
sandbox init
```

Select Lab exercise → enter the assigned item name → choose the required VM topology → Create → validate.

The initializer creates `instructions.md`, `sandbox.yaml`, and one lifecycle-script directory for each VM.

The scaffold is not a finished environment

The generated lifecycle scripts are placeholders in this pull request. Do not present `sandbox build && sandbox test` as proof until you implement them in pull request 2.

### Choose the instruction layout

Decide whether the lab is one page or several before you draft. The style guide's [Structure section](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/#structure) owns this decision: most labs fit a single `instructions.md`; a long lab, or one that pairs a high-level walk-through with detailed steps, uses a directory with an `index.md` landing page.

Set `sourcePath` in `sandbox.yaml` to the file or directory you choose.

### Complete the learner instructions

Enter the generated item directory and edit `instructions.md`.

Draft in the order the [instruction style guide](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/index.md) teaches; its sections follow the order you work in:

- **[Headings and the opening](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/#headings-and-the-opening)** — the `# <section>.<subsection> <Title>` H1 and the short framing that orients the learner.
- **[Writing steps](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/#writing-steps)** — one command or one logical move per numbered step, in execution order.
- **[Commands and prompts](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/#commands-and-prompts)** — titled bash blocks whose labels mirror the exact prompt the environment provides.
- **[Expected output](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/#expected-output)** — comparison output where the learner verifies progress, with a note on what will differ.
- **[File contents](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/#file-contents), [paths](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/#paths-and-ownership), and [admonitions](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/#admonitions)** — as the steps need them.
- **[Collapsible hints](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/#collapsible-hints)** — optional `??? tip "Hint: <topic>"` nudges where learners benefit from trying a step on their own first.
- **[Labs that span machines or pages](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/#labs-that-span-machines-or-pages)** — tab transitions and directory mode when the lab moves between them.
- **[Closing the lab](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/#closing-the-lab)** — one cleanup step, one verification command, or one pointer at further experiments.

Configure the learner-visible VM and tool names in `sandbox.yaml` while you draft. Prompt titles such as `student@cp:~$` must match the terminals the learner will receive. Defer packages, starter assets, runtime behavior, reference answers, and scoring logic to pull request 2.

### Preview and statically validate

Run the static checks from the item directory.

**@codespace-author ➜ .../items/<item-name> (instructions/<item-name>)**

```
sandbox validate
```

This checks the sandbox schema, tool targets, required script files, and instruction source path without building a VM image.

Open the lab as the [instructions tool](https://skills.staging.lf-cert.cloud/docs/sandbox/tools/#instructions) renders it.

**@codespace-author ➜ .../items/<item-name> (instructions/<item-name>)**

```
sandbox instructions -o
```

Leave the preview running while you edit. It reloads when `instructions.md` changes.

Read the rendered lab from beginning to end before you request review:

- Scan the [Common pitfalls](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/#common-pitfalls) checklist; it gathers the patterns reviewers reject.
- Confirm every step names a host, user, and path the planned topology provides.
- Confirm no step depends on knowledge or an artifact the instructions never introduce.
- Confirm the sequence teaches one coherent exercise.

### Open the instruction pull request

Push the branch after the instructions are complete.

**@codespace-author ➜ .../LFSXXXX (instructions/<item-name>)**

```
git push -u origin HEAD
```

Open pull request 1 and state:

- The assigned exercise and item directory.
- That `instructions.md` is complete and ready for instruction review.
- That the remaining environment files are generated scaffolds.
- How you previewed and statically validated the instructions.
- Any host, version, or technical assumption the reviewer must examine closely.

Keep the pull request scoped to `items/<item-name>/`. Do not combine a second exercise or environment implementation with this review.

Pull request 1 shape

One item directory containing a complete `instructions.md`, the configured `sandbox.yaml`, and placeholder lifecycle scripts for each VM. Nothing outside `items/<item-name>/` changes.

### Complete instruction review and merge

Request review from another author. The reviewer checks:

- Alignment with the assigned learning objectives.
- Technical accuracy and safe execution order.
- A complete learner path with no hidden prerequisites.
- Consistent VM, terminal, user, path, and version assumptions.
- Compliance with the [lab instruction style](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/index.md), scanned against its [Common pitfalls](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/#common-pitfalls).
- Hints that nudge without handing over the solution, where the lab uses them.
- Correct rendering in `sandbox instructions`.

Respond to review feedback on the same branch. Request another review after substantial changes.

Merge pull request 1 only after another author approves it. The merged instructions now define the environment contract.

Instruction contract merged

`main` contains one reviewed lab scaffold with complete learner instructions. The environment remains intentionally incomplete and is not ready for release.

## Pull request 2: implement the sandbox environment

Start this work from the reviewed instructions on `main`. Implement exactly the learner experience that pull request 1 established.

### Create a new branch from updated main

Update `main` after pull request 1 merges, then create a distinct environment branch.

**@codespace-author ➜ .../LFSXXXX (main)**

```
git switch main
git pull --ff-only
git switch -c env/<item-name>
```

The branch now contains the approved `instructions.md` and its generated scaffold.

### Implement the item environment

Work only inside `items/<item-name>/`.

Implement each artifact against the merged instructions:

| Artifact | Required outcome |
| --- | --- |
| `sandbox.yaml` | Declares the final VMs, base images, resources, tools, users, ports, and instruction source. |
| `<vm>/assets/` | Contains the starter files and other build-time inputs the learner needs. |
| `<vm>/scripts/build.sh` | Builds static machine state into the VM image. |
| `<vm>/scripts/setup.sh` | Waits for required runtime readiness; otherwise remains empty. |
| `<vm>/scripts/answer.sh` | Completes the taught outcome with learner-available tools and actions. |
| `<vm>/scripts/score.sh` | Checks the observable outcome and ends with `scoring::report`. |
| `metadata.yaml` | Matches the assigned title, competency, difficulty, revision, and final check count. |

Use the [lifecycle scripts reference](https://skills.staging.lf-cert.cloud/docs/sandbox/lifecycle-scripts/index.md) to place work in the correct phase. Use the [`sandbox.yaml` reference](https://skills.staging.lf-cert.cloud/docs/sandbox/sandbox-yaml/index.md) for multi-VM, resource, port, tool, and UI configuration.

For a multi-VM lab, implement every generated VM directory. A two-host item generates both `cp/` and `worker/`; the implementation must prepare and validate both machines where the instructions depend on them.

For iterative work on both hosts, use the [background multi-VM workflow](https://skills.staging.lf-cert.cloud/docs/sandbox/cli/#sandbox-start-and-stop): build, run `sandbox start --vms cp,worker`, then open separate `sandbox attach --target cp` and `sandbox attach --target worker` terminals. CLI v1.27 watches both VMs' scripts, assets, and local libraries even after those terminals close.

Saving a helper in `libs/` recompiles lifecycle scripts that use it without requiring edits to those scripts. This updates mounted files, not the running environment's state; execute the regenerated script when needed. See the [library-only reload example](https://skills.staging.lf-cert.cloud/docs/sandbox/lifecycle-scripts/#verify-library-only-reload).

### Follow the learner path manually

If background development VMs are still running, stop them with `sandbox stop` first. Then build the image and enter a fresh configured starting state:

**@codespace-author ➜ .../items/<item-name> (env/<item-name>)**

```
sandbox build
sandbox setup
```

Follow the rendered instructions from beginning to end. Use only the terminals, users, files, and tools available to the learner. Record and fix every mismatch between the written steps and the environment.

Exit the shell when the walkthrough is complete.

### Run the lifecycle acceptance test

An owning `sandbox setup` shell deletes its VMs when you exit. If you instead left background VMs running, stop them with `sandbox stop`. Then test the untouched and answered states:

**@codespace-author ➜ .../items/<item-name> (env/<item-name>)**

```
sandbox test
```

`sandbox test` passes only when the untouched sandbox earns zero checks and the reference answer earns every check.

Rebuild before testing again whenever you change `build.sh` or a build-time asset.

Local implementation proof

You have followed the learner instructions manually and `sandbox test` ends with `Test successful!`.

### Cross-check instructions and implementation

Compare every learner-facing requirement with the implemented environment:

- Each referenced host, tab, user, path, package, command, service, and file exists at the point the learner needs it.
- The starting state does not already satisfy the final checks.
- `setup.sh` performs runtime readiness work only.
- `answer.sh` follows the outcome taught in `instructions.md` with learner-available tools.
- `score.sh` checks the taught outcome rather than incidental implementation details.
- Every host reports the expected initial and answered result.
- `metadata.yaml` matches the final number of scoring checks.

Keep `instructions.md` unchanged when the implementation matches the contract. If implementation exposes an instruction defect, mark the pull request as draft, correct the instructions, and request explicit instruction re-review before approval.

### Open the environment pull request

Push the environment branch after both proof paths pass.

**@codespace-author ➜ .../LFSXXXX (env/<item-name>)**

```
git push -u origin HEAD
```

Open pull request 2 and include:

- The item directory and link to the merged instruction pull request.
- A summary of the VM topology and implemented lifecycle behavior.
- Confirmation that you followed the instructions manually.
- The exact `sandbox build` and `sandbox test` commands you ran.
- The final check counts for the untouched and answered states.
- Any learner-facing instruction changes that require renewed instruction review.

Keep this pull request scoped to the same `items/<item-name>/` directory.

### Complete environment review and merge

Request review from another author. The reviewer checks the implementation against the merged instructions and runs the local proof.

The environment review covers:

- Sandbox topology, resources, tools, ports, and learner access.
- Build-time and runtime lifecycle ownership.
- Manual completion of the written learner path.
- A candidate-like reference answer.
- Checks that fail before learner work and pass after the answer.
- Reproducible `sandbox build && sandbox test` results.
- Explicit re-review of any learner-facing instruction change.

Respond to feedback on the same branch. Merge pull request 2 only after another author approves it.

Lab implementation merged

`main` contains one reviewed lab exercise with approved instructions and a proven sandbox environment.

## Done checklist

You are done when:

- Pull request 1 contains one item directory and complete learner instructions.
- Another author approves and merges the instruction pull request.
- Pull request 2 starts from updated `main` after that merge.
- The environment implements every host, tool, file, and state named in the instructions.
- You complete the rendered learner path manually.
- `sandbox build && sandbox test` passes.
- The untouched environment earns zero checks.
- The reference answer earns every check.
- Another author approves and merges the environment pull request.
- Neither pull request modifies another exercise or unrelated shared files.

## Related pages

- **[Quickstart](https://skills.staging.lf-cert.cloud/docs/quickstart/index.md)**

Practice the full lab sandbox authoring loop before assigned work.

- **[Lab instruction style and voice](https://skills.staging.lf-cert.cloud/docs/labs/instruction-style/index.md)**

Write the learner instructions reviewed in pull request 1.

- **[Lifecycle scripts](https://skills.staging.lf-cert.cloud/docs/sandbox/lifecycle-scripts/index.md)**

Implement build, runtime setup, reference answers, and scoring in pull request 2.

- **[`sandbox.yaml` reference](https://skills.staging.lf-cert.cloud/docs/sandbox/sandbox-yaml/index.md)**

Configure the VM topology and learner tools shared by both reviews.
