Kubeasy Registry
The registry is the source of truth for all Kubeasy challenges. It serves challenge metadata, objectives, and manifests to the CLI and the web app via a simple HTTP API.
What's in here
challenges/ # All challenge definitions (Git = source of truth)
pod-evicted/
challenge.yaml # Metadata + objectives
manifests/ # Kubernetes manifests (broken state)
policies/ # Kyverno policies (bypass prevention)
...
pkg/challenges/ # Shared Go library — imported by the CLI
types.go # Challenge, Objective, all spec types
parse.go # YAML → typed structs
validate.go # Structural validation
loader.go # Scan a directory and load all challenges
internal/
server/server.go # HTTP handlers (chi router)
store/store.go # In-memory challenge store
cmd/
root.go # --challenges-dir flag
serve.go # registry serve
validate.go # registry validate [slug]
main.go # Entrypoint
API
| Endpoint |
Description |
GET /challenges |
List all challenges |
GET /challenges/{slug} |
Full challenge JSON (metadata + objectives) |
GET /challenges/{slug}/yaml |
Raw challenge.yaml (used by CLI) |
GET /challenges/{slug}/manifests |
.tar.gz of manifests/ + policies/ |
Running locally
mise install
go run . serve
# CHALLENGES_DIR defaults to ./challenges
Override the challenges directory:
go run . serve --challenges-dir /path/to/challenges
Validate challenges
go run . validate # all challenges
go run . validate pod-evicted # single challenge
Adding a challenge
- Create a folder under
challenges/ (folder name = slug)
- Add
challenge.yaml, manifests/, and optionally policies/
- Push — Railway redeploys automatically, CI validates on PR
See CHALLENGE_GUIDELINES.md for the full spec.
Architecture
The registry is consumed by:
- kubeasy-cli — imports
pkg/challenges for types, calls /challenges/{slug}/yaml for runtime data
- monorepo API — calls the registry HTTP API and fan-outs challenge data alongside user progress
See the Kubeasy CLAUDE.md for the full system architecture.