Build a New Adventure#
Ready to turn an approved idea into a full adventure? This guide walks you through the implementation process.
Before You Start#
- Pick an approved idea. Browse open implementation issues to find unclaimed ideas. Once you pick one, comment on its issue to claim it.
- Read the idea thoroughly. Understand the story, objectives, and learning outcomes.
- Have your own idea? Propose it — ideas go through review before they're available for implementation.
- Ready to build? Once an idea is approved and merged into
ideas/, it's available viamake new-adventure.
What You'll Build#
An adventure consists of:
| Component | Purpose |
|---|---|
| Challenge files | The "broken" state participants will fix |
| Documentation | Story, objectives, hints, and solution walkthroughs |
| Devcontainer | Pre-configured environment with all required infrastructure |
| Verification script | Validates solutions and generates completion certificate |
Adventure Structure#
Use 00 as the adventure number during development. When your adventure is scheduled for release, maintainers will assign the final number and move it out of planned/.
adventures/planned/00-adventure-name/
├── README.md # Brief intro + link to docs
├── mkdocs.yaml # Navigation for this adventure
├── docs/
│ ├── index.md # Adventure introduction
│ ├── beginner.md # Level guide
│ ├── intermediate.md
│ ├── expert.md
│ └── solutions/
│ ├── beginner.md # Solution walkthrough
│ ├── intermediate.md
│ └── expert.md
├── beginner/
│ ├── verify.sh # Verification script
│ └── [challenge files]
├── intermediate/
│ └── ...
└── expert/
└── ...
.devcontainer/00-adventure-name_01-beginner/
├── devcontainer.json
├── post-create.sh # Runs once (install tools)
└── post-start.sh # Runs every start (start services)
Step-by-Step#
1. Scaffold the Files#
Run the scaffolding script to generate the skeleton for your adventure level:
make new-adventure
This will prompt you to select an adventure and level, then generate:
adventures/planned/00-adventure-name/— adventure base withREADME.md,mkdocs.yaml, anddocs/index.mdadventures/planned/00-adventure-name/docs/<level>.md— level guideadventures/planned/00-adventure-name/<level>/verify.sh— verification script skeleton.devcontainer/00-adventure-name_NN-level/—devcontainer.json,post-create.sh,post-start.sh
Search for TODO in the generated files to find everything that needs filling in.
2. Configure the Devcontainer#
Open the generated .devcontainer/00-adventure-name_NN-level/ files and fill in the TODOs.
For Kubernetes-based adventures, Adventure 01 is a good reference for what features and setup scripts to use.
post-create.sh runs once when the container is created:
- Install CLI tools using setup scripts from lib/ — every script accepts a --version flag to pin a specific version. Run any script with --help to see available flags and defaults.
- Pull container images
- Set up one-time configurations
Example calls in post-create.sh:
"$REPO_ROOT/lib/kubernetes/init.sh" # use default versions
"$REPO_ROOT/lib/argocd/init.sh" --version v3.5.0 # pin a version
"$REPO_ROOT/lib/argocd/init.sh" --read-only --version v3.5.0 # combine flags
"$REPO_ROOT/lib/kubernetes/init.sh" --kubectl-version v1.35.0 --helm-version v4.1.0 # per-tool versions
post-start.sh runs every time the container starts: - Start services (databases, clusters, etc.) - Apply initial state
Infrastructure constraints:
Codespaces run on 2 cores and 8 GB RAM by default. Design your adventure within these limits — avoid memory-hungry workloads running in parallel and prefer lightweight images where possible.
Post-create should finish in under 15 minutes, but aim for well under that.
3. Build the Working Solution#
Implement the fully working version first. This is what the solved challenge looks like where everything works correctly.
This approach helps you: - Understand the problem space before designing the challenge - Ensure the challenge is actually solvable - Have a reference implementation for the solution walkthrough
4. Introduce the Challenges#
Work backwards from your working solution to create the "broken" state participants will fix.
Good challenges are: - Realistic. Introduce issues that could happen in real-world scenarios. - Discoverable. Problems should be findable using standard tools and techniques. - Focused. Each issue should teach something from the learning objectives. - Solvable. Don't require knowledge outside what's being taught.
Not sure if a challenge belongs at Beginner, Intermediate, or Expert? See Calibrating Difficulty for concrete signals and time expectations.
5. Write the Documentation#
Fill in the generated docs/<level>.md — it already contains the story, objectives, and learning outcomes from the idea file. Add:
- Architecture overview (how the level is set up)
- UI access instructions with port numbers
- Where to start investigating
- Helpful links to external docs
No spoilers — save those for a solutions/<level>.md file.
See Adventure 01's beginner level for a good example.
6. Create the Verification Script#
Fill in the generated <level>/verify.sh. It already has the boilerplate wired up — add your checks between the print_sub_header and the summary block.
A good verification script: - Passes when the challenge is solved correctly - Fails with helpful error messages when not solved - Generates a certificate users can copy to claim completion
Check outcomes, not implementation. Verify the state the participant should have reached — a service is healthy, traces are present in Jaeger, a metric is being collected — not how they got there. File content checks (check_file_contains) are a last resort: they break for valid alternative solutions and reward copy-pasting over understanding. If your objective says "see traces in Jaeger", your verification should check that traces exist, not that a specific import was added.
Browse lib/scripts/ to see the available helper functions.
7. Final Test Run#
Before submitting:
- Start fresh. Open a new Codespace to test the full experience.
- Solve the challenge. Complete it as a participant would.
- Run verification. Ensure
verify.shpasses when solved and fails when not. - Check all links. Documentation should be complete and accurate.
Tips#
- Open a draft PR early. Get feedback on structure before completing everything.
- Ship one level at a time. Each level gets its own PR — start with one, get it working, then build the next. Use
Part of #<tracking-issue>on all but the last PR, andCloses #<tracking-issue>on the final one so the tracking issue closes automatically. - Test on slow connections. Codespace startup time matters.
- Write clear error messages. Help participants understand what went wrong without giving away the solution.