Skip to content

Quickstart

This quickstart uses one scenario: creating a container image that prints a required message. You will package that scenario either as a scored SkillCred item or as a guided lab.

What you will build

A sandbox around one container-image task:

Path Outcome
SkillCred Score whether a candidate can create linux-foundation-education/hello:1.0.
Lab Guide a learner through creating linux-foundation-education/hello:1.0.

The image must print:

hello tux

Before you begin, set up your Codespace.

Follow your cartridge workflow

Step 1: Scaffold the environment

Run the initializer from the items/ directory:

@codespace-author ➜ .../quickstart (main)
cd items
sandbox init

When prompted: select Exam task → name it hello-image → accept all other defaults → Create → validate.

bash ×

Enter the item directory (named after what you entered above):

@codespace-author ➜ .../items (main)
cd hello-image

You now have a bootable sandbox with one Debian-based virtual machine. Drop into the VM to see what the candidate will see:

@codespace-author ➜ .../items/hello-image (main)
sandbox shell

bash ×

You can now exit the virtual machine by using Ctrl+C

You have successfully used sandbox init to scaffold out a sandbox environment, started the virtual machine, and stopped it.

You may want to take some time to review the file structure created in step 1.

Generated file structure
hello-image/
├── .gitignore
├── metadata.yaml
├── sandbox.yaml
├── task.en.md
└── host1/
    ├── assets/
    │   └── .gitkeep
    └── scripts/
        ├── build.sh
        ├── setup.sh
        ├── answer.sh
        └── score.sh

Checkpoint

You have a scaffolded SkillCred item in items/hello-image.

Step 2: Write the candidate task

task.en.md is what the candidate reads. The sandbox renders it as a MkDocs site in the instructions tool, always visible in the left panel.

You may preview the instructions as they will be rendered by the instructions tool in your development environment using the sandbox CLI. It's helpful to keep this running in a Codespace terminal while you author because the preview auto-updates.

@codespace-author ➜ .../items/hello-image (main)
sandbox instructions

Preview server started

The port may differ in your environment. Open the localhost URL shown in your terminal.

terminal output
ghcr.io/lf-certification/p3-sandbox-instructions-generator:latest
Building instructions...
Starting preview server at http://127.0.0.1:<port>

The preview tab shows the instructions exactly as the platform will render them to the end user of your environment.

Keep preview running

Leave sandbox instructions running while you edit. The preview reloads automatically when task.en.md changes.

Open task.en.md in your editor and save the contents to the following:

Copy into task.en.md

task.en.md
# Task

Create a container image tagged `linux-foundation-education/hello:1.0`.

When the image is run, it must print exactly:

```text
hello tux
```

You may use `podman build` and a `Dockerfile`.

Checkpoint

The preview tab now shows the candidate-facing task.

Step 3: Add item metadata

Open metadata.yaml and fill in the required fields:

Copy into metadata.yaml

metadata.yaml
competency: <blueprint-competency-id>
difficulty: easy # easy, medium, or hard
title: "Build a greeting container image"
total_check_count: 2
revision: 1

Tip

competency must match an id in blueprint.yaml. total_check_count must match the number of checks in score.sh.

Checkpoint

The metadata expects two scoring checks, matching the two scoring::check calls you will add next.

Step 4: Implement the sandbox

Open sandbox.yaml and configure the tools. Each tool name becomes a tab the candidate sees. Then implement the lifecycle scripts in host1/scripts/.

Lifecycle map for this task
Script Role in this scenario
build.sh Installs podman and caches the base image before the candidate starts.
setup.sh Creates the candidate workspace each time the sandbox starts.
answer.sh Builds the correct image during local testing.
score.sh Verifies the image exists and prints the required message.

In host1/scripts/build.sh, install the container tooling and pre-pull the base image:

Copy into host1/scripts/build.sh

host1/scripts/build.sh
#!/usr/bin/env bashp
set -euxo pipefail

install::apt_packages podman
podman pull docker.io/library/alpine:3.20

In host1/scripts/setup.sh, prepare a workspace for the candidate:

Copy into host1/scripts/setup.sh

host1/scripts/setup.sh
#!/usr/bin/env bashp
set -euxo pipefail

mkdir -p /home/tux/container-image
chown -R tux:tux /home/tux/container-image

In host1/scripts/answer.sh, write the reference solution:

Copy into host1/scripts/answer.sh

host1/scripts/answer.sh
#!/usr/bin/env bashp
set -euxo pipefail

cat > /home/tux/container-image/Dockerfile <<'EOF'
FROM docker.io/library/alpine:3.20
CMD ["echo", "hello tux"]
EOF

chown tux:tux /home/tux/container-image/Dockerfile
sudo -iu tux podman build -t linux-foundation-education/hello:1.0 /home/tux/container-image

In host1/scripts/score.sh, check that the image exists and prints the expected message:

Copy into host1/scripts/score.sh

host1/scripts/score.sh
#!/usr/bin/env bashp
set -euo pipefail

IMAGE_TAG="linux-foundation-education/hello:1.0"
EXPECTED_OUTPUT="hello tux"

image_exists() {
    sudo -iu tux podman image exists "${IMAGE_TAG}"
}

image_prints_expected_message() {
    output="$(sudo -iu tux podman run --rm "${IMAGE_TAG}")"
    test "${output}" = "${EXPECTED_OUTPUT}"
}

scoring::check image_exists
scoring::check image_prints_expected_message
scoring::report

Checkpoint

The sandbox now has setup, reference answer, and scoring logic for the container image task.

Step 5: Validate

Test the full lifecycle, build, setup, answer, and score, in one command:

@codespace-author ➜ .../items/hello-image (main)
sandbox test

This passes when scoring returns zero checks before the answer is applied, and full marks after.

Preview the candidate instructions:

@codespace-author ➜ .../items/hello-image (main)
sandbox instructions

Run the full SkillCred checks:

@codespace-author ➜ .../items/hello-image (main)
cd ../..
skills validate --full .

You are done when

  • sandbox test passes.
  • skills validate --full . passes.
  • The instructions preview renders the candidate task correctly.

Step 1: Scaffold the lab

  • Name the lab

    Lab sandboxes live under labs/<lab-name>. This example uses foo-bar.

  • Create the lab

    @codespace-author ➜ .../quickstart (main)
    mkdir -p labs
    cd labs
    sandbox init foo-bar
    cd foo-bar
    
Generated file structure
foo-bar/
├── .gitignore
├── instructions.md
├── sandbox.yaml
└── host1/
    ├── assets/
    │   └── .gitkeep
    └── scripts/
        ├── build.sh
        ├── setup.sh
        ├── answer.sh
        └── score.sh

Checkpoint

You have a scaffolded lab sandbox in labs/foo-bar.

Step 2: Register the lab

Add the lab to lab-configuration.yaml at the cartridge root:

Copy into lab-configuration.yaml

lab-configuration.yaml
search_locations:
  - labs/foo-bar

Checkpoint

The lab cartridge now knows where to find labs/foo-bar.

Step 3: Write the lab instructions

instructions.md is what the learner reads. The sandbox renders it as a MkDocs site in the instructions tool, always visible in the left panel.

Open instructions.md and write the guided steps:

Copy into instructions.md

instructions.md
# Lab

In this lab, you will create a container image tagged `linux-foundation-education/hello:1.0`.

Create a working directory:

```shell
mkdir -p ~/container-image
cd ~/container-image
```

Create a `Dockerfile`:

```dockerfile
FROM docker.io/library/alpine:3.20
CMD ["echo", "hello tux"]
```

Build and run the image:

```shell
podman build -t linux-foundation-education/hello:1.0 .
podman run --rm linux-foundation-education/hello:1.0
```

Preview it at any time:

@codespace-author ➜ .../labs/foo-bar (main)
sandbox instructions

Keep preview running

Leave sandbox instructions running while you edit. The preview reloads automatically when instructions.md changes.

Checkpoint

The learner instructions now walk through the same container image scenario.

Step 4: Implement the sandbox

Open sandbox.yaml and configure the tools. Each tool name becomes a tab the learner sees. Set spec.ui.showTimer: true, then implement the lifecycle scripts in host1/scripts/.

Reuse the same implementation

The lab sandbox can use the same build.sh, setup.sh, answer.sh, and score.sh pattern from the SkillCred path. The difference is the learner sees guided instructions instead of a scored exam prompt.

Step 5: Validate

Test the full lifecycle, build, setup, answer, and score, in one command:

@codespace-author ➜ .../labs/foo-bar (main)
sandbox test

This passes when scoring returns zero checks before the answer is applied, and full marks after.

Preview the learner instructions:

@codespace-author ➜ .../labs/foo-bar (main)
sandbox instructions

Run the lab checks:

@codespace-author ➜ .../labs/foo-bar (main)
cd ../..
skills validate --product lab .

You are done when

  • sandbox test passes.
  • skills validate --product lab . passes.
  • The instructions preview renders the guided lab correctly.

Key Resources

Configure virtual machines, tools, base images, resources, and multi-VM layouts.

Learn when build.sh, setup.sh, answer.sh, and score.sh run and how to write scoring checks.

Understand the sandbox model, configuration flow, and authoring building blocks.

Prepare your Codespace and local authoring tools before building cartridges.