Files
Abhinav Sinha 124e5276d4 refactor(scenarios): split monolithic configuration into individual files
- Split `scenarios/scenarios.json` into individual JSON files under `scenarios/data/` named `<scenario-id>.json`
- Split `scenarios/bundles.json` into individual JSON files under `scenarios/bundles/` named `<bundle-id>.json`
- Updated `backend/server.js` to dynamically load scenario and bundle files from their respective directories
- Updated documentation in `scenarios/SCHEMA.md` and `README.md` to reflect the new repository layout and contributor workflow

Signed-off-by: Abhinav Sinha <[email protected]>
2026-06-15 07:52:47 +05:30

8.3 KiB

KubeKosh Configuration Schema Reference

KubeKosh uses two primary directories to define its curriculum, learning paths, and exam configurations:

  1. Bundles (scenarios/bundles): Each file defines one high-level study bundle (e.g., CKA, CKAD, CKS), including active highlights, exam duration, ordered list of included scenarios, and other fields.
  2. Scenarios (scenarios/data): Each file defines one individual exercise — a hands-on task or multiple-choice question (MCQ). Each scenario contains an environment setup script, cleanup script, hints, problem statement, automated validation script, and other fields.

1. Bundles Schema (scenarios/bundles)

Each file contains a single bundle object. The filename must match the bundle's id field (e.g., k8s-basics.json).

Schema Fields

  • id (string, required): A unique, kebab-case identifier for the bundle (e.g., k8s-basics).
  • name (string, required): The human-readable name of the bundle shown in navigation (e.g., Kubernetes Basics).
  • icon (string, required): An emoji or glyph representing the bundle (e.g., 🌱).
  • tagline (string, required): A short summary of the bundle's objectives.
  • color (string, required): Hex color code representing the bundle's UI identity/accent color (e.g., #3fb950).
  • colorDim (string, required): Translucent RGBA color matching the accent color at low opacity, used for UI row highlighting (e.g., rgba(63,185,80,0.12)).
  • exam_minutes (number, required): The time limit allocated for the mock exam in minutes (e.g., 60).
  • scenario_ids (array of strings, required): List of scenario IDs belonging to this bundle in the order they should appear.

Example Bundle

{
  "id": "k8s-basics",
  "name": "Kubernetes Basics",
  "icon": "🌱",
  "tagline": "Core concepts for beginners",
  "color": "#3fb950",
  "colorDim": "rgba(63,185,80,0.12)",
  "exam_minutes": 60,
  "scenario_ids": [
    "pod-basics-mcq",
    "kubectl-essentials-mcq",
    "namespaces-basics",
    "deploy-nginx"
  ]
}

2. Scenarios Schema (scenarios/data)

Each file contains a single scenario object. The filename must match the scenario's id field (e.g., k8s-basics.json).

Scenarios are defined as JSON objects. A scenario can be either a hands-on console challenge ("task") or a multiple-choice question ("mcq").

Common Fields (All Types)

{
  "id": "unique-kebab-case-id",        // string — unique scenario identifier
  "title": "Human-readable Title",      // string — shown in sidebar list
  "category": "Workloads",             // string — groups scenarios in sidebar accordion
  "difficulty": "Easy",                // "Easy" | "Medium" | "Hard"
  "type": "task",                      // "task" | "mcq"
  "weight": 7,                         // number — points value (used for final grade scoring)
  "description": "## Markdown...",     // string — problem statement supporting GitHub-flavored Markdown
  "hints": [...],                      // array — see Hints schema below
  "setup_commands": [...],             // array<object> — commands run on environment preparation
  "teardown_commands": [...],           // array<object> — optional — cleanup commands run after scenario completes
  "default_namespace": "default"       // string — optional — default active namespace for the terminal
}

Hints Schema

Each hint is rendered as a collapsible card inside the Hints tab of the UI:

{
  "title": "Short title for the hint card",
  "body":  "Explanation text (plain text, no markdown format).",
  "command": "kubectl run nginx --image=nginx" // optional — renders a copyable code block
}

Setup & Teardown Commands

  • setup_commands: Executed sequentially on the Kubernetes cluster when the user starts a scenario or clicks "Prepare Environment". Useful for pre-deploying resources or injecting bugs.
  • teardown_commands: Optional cleanup commands run when moving away from or resetting a scenario.
  • Commands must be objects with a command key:
    "setup_commands": [
      { "command": "kubectl create namespace debug" },
      { "command": "kubectl create deployment broken-app --image=nginx:1.25 -n debug" }
    ]
    
  • Note: Non-zero exit codes are tolerated (e.g., "namespace already exists" errors won't halt the pipeline). All commands execute as root.

Type: "task" — Hands-On Scenario

Requires the user to run shell commands in the interactive terminal. The system runs an automated validation sequence to check the cluster state.

{
  "type": "task",
  "validation": {
    "description": "Check that deployment has been correctly configured",
    "commands": [
      {
        "description": "Checks the running pods count",
        "command": "kubectl get deploy nginx -o jsonpath='{.status.readyReplicas}'",
        "expected_output": "3",
        "match": "exact" // "exact" | "contains" | "regex"
      }
    ]
  }
}

Match Modes

Mode Behaviour
exact Trimmed stdout must exactly equal expected_output.
contains stdout must contain expected_output as a substring.
not_contains stdout must not contain expected_output as a substring.
regex stdout must match the regular expression in expected_output.

Type: "mcq" — Multiple Choice Question

Renders a questionnaire block. No terminal is shown. The user answers by selecting an option.

{
  "type": "mcq",
  "options": [
    { "id": "a", "text": "Option A explanation" },
    { "id": "b", "text": "Option B explanation" },
    { "id": "c", "text": "Option C explanation" },
    { "id": "d", "text": "Option D explanation" }
  ],
  "correct_option": "c",               // must match one of the option IDs
  "explanation": "Detailed explanation of why C is the correct answer." // shown after submitting
}

3. Full Examples

Full Example — Hands-On Task Scenario

{
  "id": "scale-deployment",
  "title": "Scale a Deployment",
  "category": "Workloads",
  "difficulty": "Easy",
  "type": "task",
  "weight": 4,
  "description": "## Scale the Deployment\n\nA deployment named `myapp` exists in the `default` namespace.\n\n**Scale it to 5 replicas.**",
  "hints": [
    {
      "title": "Using kubectl scale",
      "body": "The scale subcommand lets you change the replica count imperatively.",
      "command": "kubectl scale deployment myapp --replicas=5"
    }
  ],
  "setup_commands": [
    { "command": "kubectl create deployment myapp --image=nginx:1.25 --replicas=1" }
  ],
  "teardown_commands": [
    { "command": "kubectl delete deployment myapp --ignore-not-found" }
  ],
  "default_namespace": "default",
  "validation": {
    "description": "Checks that myapp has 5 ready replicas.",
    "commands": [
      {
        "description": "myapp has 5 ready replicas",
        "command": "kubectl get deployment myapp -o jsonpath='{.status.readyReplicas}'",
        "expected_output": "5",
        "match": "exact"
      }
    ]
  }
}

Full Example — MCQ Scenario

{
  "id": "service-types-mcq",
  "title": "Kubernetes Service Types",
  "category": "Networking",
  "difficulty": "Easy",
  "type": "mcq",
  "weight": 3,
  "description": "## Kubernetes Service Types\n\nWhich `kubectl` command creates a ClusterIP service named `my-svc` exposing port 80 for a deployment named `my-app`?",
  "options": [
    { "id": "a", "text": "kubectl expose deployment my-app --name=my-svc --port=80 --type=ClusterIP" },
    { "id": "b", "text": "kubectl create service my-svc --port=80" },
    { "id": "c", "text": "kubectl apply service my-app --port=80" },
    { "id": "d", "text": "kubectl expose pod my-app --name=my-svc --port=80 --type=NodePort" }
  ],
  "correct_option": "a",
  "explanation": "`kubectl expose deployment` is the correct imperative command. It creates a Service targeting the deployment's pods. `--type=ClusterIP` is the default but explicit here for clarity.",
  "hints": [
    {
      "title": "kubectl expose syntax",
      "body": "Use kubectl expose to create a Service from an existing resource. Specify the resource type, name, port, and service type.",
      "command": "kubectl expose deployment my-app --name=my-svc --port=80 --type=ClusterIP"
    }
  ],
  "setup_commands": [],
  "teardown_commands": [],
  "default_namespace": "default"
}