Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .agents/skills/add-mission/references/mission-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Every mission supplies:
- An effective learning `track` and `environment`; omitted values preserve the legacy `linux` and `simulated` defaults.
- Teaching content: `story`, `objective`, one or more unique base names in `suggested_commands`, `hints`, and `explanation`.
- Simulated labs: an absolute clean `start_dir` plus declarative `setup` containing `directories`, `files`, `processes`, `environment`, and `archives` as needed.
- Docker labs: `track: docker`, `environment: docker`, and a declarative `docker` setup containing digest-pinned image references and logical `running` or `stopped` container fixtures. Fixtures may select fixed Go-implemented behaviors: an optional startup `log`, a `health` probe (`healthy` or `unhealthy`), a stopped one-shot job (`log` + `exit_code`), or a running bounded crash loop (`log` + non-zero `exit_code` + `restart: on-failure`). They do not define simulated setup or a start directory.
- Docker labs: `track: docker`, `environment: docker`, and a declarative `docker` setup containing digest-pinned image references and logical `running` or `stopped` container fixtures. Fixtures may select fixed Go-implemented behaviors: an optional startup `log`, a `health` probe (`healthy` or `unhealthy`), a stopped one-shot job (`log` + `exit_code`), or a running bounded crash loop (`log` + non-zero `exit_code` + `restart: on-failure`). A setup may declare internal `networks` by logical name, and fixtures join them through `networks`; a fixture without networks runs with networking disabled. They do not define simulated setup or a start directory.
- Declarative `validation.all`: one or more observable conditions.
- `rewards`: positive `xp` and non-negative `hint_penalty`.

Expand All @@ -26,7 +26,7 @@ Use the smallest combination that proves the outcome without encoding a command
- Virtual file state: `file_content_equals`, `file_content_contains`, `file_lines_equal`, `file_mode_equals`, `file_owner_equals`.
- Virtual processes: `process_stopped`, `process_running`.
- Virtual environment: `env_equals` with `NAME=value`.
- Docker state: `docker_container_running`, `docker_container_stopped`, or `docker_container_absent` with a declared logical container alias, and `docker_container_count_equals` with a non-negative count. Running and stopped both require the container to still exist.
- Docker state: `docker_container_running`, `docker_container_stopped`, or `docker_container_absent` with a declared logical container alias, and `docker_container_count_equals` with a non-negative count. Running and stopped both require the container to still exist. Network state: `docker_containers_share_network` and `docker_containers_isolated` with exactly two declared `containers` (both must exist), and `docker_network_absent` with a declared `network`.

Output-only validation is appropriate when producing the exact useful output is the lesson. Prefer filesystem, process, or environment state when the operational result should survive the final command. Combine positive and negative conditions when distractors could otherwise produce a false completion.

Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# OpsQuest agent guide

OpsQuest is a Go 1.26 CLI game with 23 in-memory Linux missions and 11 optional Docker labs across two worlds. Linux player commands stay inside the teaching shell. Docker input is parsed into a deliberately small command subset that can affect only disposable, OpsQuest-labeled resources. Kubernetes remains future scope unless a task explicitly adds it.
OpsQuest is a Go 1.26 CLI game with 23 in-memory Linux missions and 16 optional Docker labs across three worlds. Linux player commands stay inside the teaching shell. Docker input is parsed into a deliberately small command subset that can affect only disposable, OpsQuest-labeled resources. Kubernetes remains future scope unless a task explicitly adds it.

## Repository map

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ OpsQuest validates the result, not a prescribed command. Equivalent supported so
## What is included

- 23 Linux missions across four ordered learning worlds
- 11 optional, disposable Docker missions across two worlds: Foundations and Container Triage
- 16 optional, disposable Docker missions across three worlds: Foundations, Container Triage, and Network Plumbing
- An isolated in-memory filesystem, environment, process table, and archives
- Quote-aware globs and variables, pipelines, redirection, and command history
- A compact virtual `vi` and bounded virtual shell scripts
Expand Down Expand Up @@ -97,7 +97,7 @@ boundary.

Player-entered Linux commands—including virtual scripts—are parsed and executed by OpsQuest. They never reach a host shell, host process, or host path. The teaching shell operates only on bounded in-memory state.

Docker input is parsed into a small set of typed teaching actions. OpsQuest constructs Docker arguments itself, uses only exact resources labeled for the current attempt, applies resource restrictions, and verifies ownership again during cleanup. Fixture processes live at most 24 hours, and leftovers from a crashed process are removed only when every ownership label matches and the recorded owner process is gone. It does not expose arbitrary Docker passthrough, privileged mode, host mounts, host networking, devices, or the Docker socket.
Docker input is parsed into a small set of typed teaching actions. OpsQuest constructs Docker arguments itself, uses only exact resources labeled for the current attempt, applies resource restrictions, and verifies ownership again during cleanup. Fixture processes live at most 24 hours, and leftovers from a crashed process are removed only when every ownership label matches and the recorded owner process is gone. Lab networks are always internal, attempt-owned, and labeled; players cannot run commands inside containers. It does not expose arbitrary Docker passthrough, privileged mode, host mounts, host networking, devices, or the Docker socket.

The optional web companion binds only to an ephemeral `127.0.0.1` port, uses a one-time pairing URL, and exposes a read-only mission projection. It cannot submit commands, mutate the profile or attempt, address Docker resources, or approve completion.

Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ The game describes an observable objective, gives you a disposable environment,
## Current scope

- 23 Linux missions across four ordered learning worlds
- 11 optional Docker missions across two worlds
- 16 optional Docker missions across three worlds
- Outcome-based validation rather than one required command transcript
- An in-memory filesystem, process table, environment, archives, editor, and shell scripts
- Persistent XP, ranks, command practice, hints, completions, and achievements
Expand Down
4 changes: 2 additions & 2 deletions docs/play/diagrams/learning-journey.excalidraw
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
{"id":"docker-lane","type":"rectangle","x":40,"y":545,"width":1410,"height":215,"angle":0,"strokeColor":"#8b5cf6","backgroundColor":"#f5f3ff","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"roundness":{"type":3},"seed":214,"version":1,"versionNonce":2014,"isDeleted":false,"boundElements":null,"updated":1784505600000,"link":null,"locked":false},
{"id":"docker-label","type":"text","x":70,"y":565,"width":370,"height":20,"angle":0,"strokeColor":"#6d28d9","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":1,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"roundness":null,"seed":215,"version":1,"versionNonce":2015,"isDeleted":false,"boundElements":null,"updated":1784505600000,"link":null,"locked":false,"fontSize":16,"fontFamily":2,"text":"DOCKER TRACK · OPTIONAL · INDEPENDENT WORLD NUMBERING","textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"DOCKER TRACK · OPTIONAL · INDEPENDENT WORLD NUMBERING","autoResize":true,"lineHeight":1.25},
{"id":"docker-world","type":"rectangle","x":85,"y":610,"width":390,"height":115,"angle":0,"strokeColor":"#7c3aed","backgroundColor":"#ffffff","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"roundness":{"type":3},"seed":216,"version":1,"versionNonce":2016,"isDeleted":false,"boundElements":null,"updated":1784505600000,"link":null,"locked":false},
{"id":"docker-world-text","type":"text","x":115,"y":630,"width":330,"height":75,"angle":0,"strokeColor":"#4c1d95","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":1,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"roundness":null,"seed":217,"version":1,"versionNonce":2017,"isDeleted":false,"boundElements":null,"updated":1784505600000,"link":null,"locked":false,"fontSize":18,"fontFamily":2,"text":"DOCKER WORLDS 1–2\nIt Works on My Machine → Container Triage\nMissions 20–34 · lifecycle, diagnostics, triage","textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"DOCKER WORLDS 1–2\nIt Works on My Machine → Container Triage\nMissions 20–34 · lifecycle, diagnostics, triage","autoResize":true,"lineHeight":1.25},
{"id":"docker-world-text","type":"text","x":115,"y":630,"width":330,"height":75,"angle":0,"strokeColor":"#4c1d95","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":1,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"roundness":null,"seed":217,"version":1,"versionNonce":2017,"isDeleted":false,"boundElements":null,"updated":1784505600000,"link":null,"locked":false,"fontSize":18,"fontFamily":2,"text":"DOCKER WORLDS 1–3\nFoundations → Triage → Networks\nMissions 20–39 · lifecycle, triage, networks","textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"DOCKER WORLDS 1–3\nFoundations → Triage → Networks\nMissions 20–39 · lifecycle, triage, networks","autoResize":true,"lineHeight":1.25},
{"id":"docker-note","type":"rectangle","x":650,"y":610,"width":700,"height":115,"angle":0,"strokeColor":"#a78bfa","backgroundColor":"#ede9fe","fillStyle":"solid","strokeWidth":2,"strokeStyle":"dashed","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"roundness":{"type":3},"seed":218,"version":1,"versionNonce":2018,"isDeleted":false,"boundElements":null,"updated":1784505600000,"link":null,"locked":false},
{"id":"docker-note-text","type":"text","x":685,"y":630,"width":630,"height":75,"angle":0,"strokeColor":"#4c1d95","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":1,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"roundness":null,"seed":219,"version":1,"versionNonce":2019,"isDeleted":false,"boundElements":null,"updated":1784505600000,"link":null,"locked":false,"fontSize":18,"fontFamily":2,"text":"Separate readiness and progress\nPinned local fixture · no automatic pull · Linux never blocked\n11 bounded lifecycle and diagnostic missions","textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"Separate readiness and progress\nPinned local fixture · no automatic pull · Linux never blocked\n11 bounded lifecycle and diagnostic missions","autoResize":true,"lineHeight":1.25},
{"id":"docker-note-text","type":"text","x":685,"y":630,"width":630,"height":75,"angle":0,"strokeColor":"#4c1d95","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":1,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"roundness":null,"seed":219,"version":1,"versionNonce":2019,"isDeleted":false,"boundElements":null,"updated":1784505600000,"link":null,"locked":false,"fontSize":18,"fontFamily":2,"text":"Separate readiness and progress\nPinned local fixture · no automatic pull · Linux never blocked\n16 bounded lifecycle and diagnostic missions","textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"Separate readiness and progress\nPinned local fixture · no automatic pull · Linux never blocked\n16 bounded lifecycle and diagnostic missions","autoResize":true,"lineHeight":1.25},
{"id":"a-docker","type":"arrow","x":475,"y":668,"width":175,"height":0,"angle":0,"strokeColor":"#7c3aed","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":3,"strokeStyle":"dashed","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"roundness":{"type":2},"seed":220,"version":1,"versionNonce":2020,"isDeleted":false,"boundElements":null,"updated":1784505600000,"link":null,"locked":false,"points":[[0,0],[175,0]],"lastCommittedPoint":null,"startBinding":null,"endBinding":null,"startArrowhead":null,"endArrowhead":"arrow","elbowed":false}
],
"appState": {"gridSize": null, "viewBackgroundColor": "#f8fafc"},
Expand Down
10 changes: 5 additions & 5 deletions docs/play/diagrams/learning-journey.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading