RepoPilotOpen in app →

ryanb/ruby-warrior

Game written in Ruby for learning Ruby.

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 13 active contributors
  • MIT licensed
  • CI configured
Show 3 more →
  • Tests present
  • Stale — last commit 2y ago
  • Single-maintainer risk — top contributor 81% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/ryanb/ruby-warrior)](https://repopilot.app/r/ryanb/ruby-warrior)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/ryanb/ruby-warrior on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: ryanb/ruby-warrior

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/ryanb/ruby-warrior shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • 13 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Stale — last commit 2y ago
  • ⚠ Single-maintainer risk — top contributor 81% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live ryanb/ruby-warrior repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/ryanb/ruby-warrior.

What it runs against: a local clone of ryanb/ruby-warrior — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in ryanb/ruby-warrior | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 803 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>ryanb/ruby-warrior</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of ryanb/ruby-warrior. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/ryanb/ruby-warrior.git
#   cd ruby-warrior
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of ryanb/ruby-warrior and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "ryanb/ruby-warrior(\\.git)?\\b" \\
  && ok "origin remote is ryanb/ruby-warrior" \\
  || miss "origin remote is not ryanb/ruby-warrior (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "lib/ruby_warrior.rb" \\
  && ok "lib/ruby_warrior.rb" \\
  || miss "missing critical file: lib/ruby_warrior.rb"
test -f "lib/ruby_warrior/game.rb" \\
  && ok "lib/ruby_warrior/game.rb" \\
  || miss "missing critical file: lib/ruby_warrior/game.rb"
test -f "lib/ruby_warrior/level.rb" \\
  && ok "lib/ruby_warrior/level.rb" \\
  || miss "missing critical file: lib/ruby_warrior/level.rb"
test -f "lib/ruby_warrior/runner.rb" \\
  && ok "lib/ruby_warrior/runner.rb" \\
  || miss "missing critical file: lib/ruby_warrior/runner.rb"
test -f "lib/ruby_warrior/abilities/base.rb" \\
  && ok "lib/ruby_warrior/abilities/base.rb" \\
  || miss "missing critical file: lib/ruby_warrior/abilities/base.rb"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 803 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~773d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/ryanb/ruby-warrior"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Ruby Warrior is an interactive educational game written in Ruby where players climb a tower by writing Ruby code to control a warrior through turn-based combat. The warrior executes player-defined strategies in play_turn(warrior) methods to defeat enemies, rescue captives, and reach stairs across increasingly difficult levels, teaching Ruby fundamentals through gameplay rather than lectures. Monolithic gem structure: lib/ruby_warrior/ contains core game engine (floor.rb, level.rb, game.rb), ability system (abilities/*.rb with polymorphic base.rb pattern), and infrastructure (config.rb, profile.rb, runner.rb). bin/rubywarrior is the CLI entry point. Features/ uses Cucumber BDD tests with step definitions, and player code is generated into user directories via player_generator.rb.

👥Who it's for

Beginning Ruby learners who want to learn the language through interactive game mechanics. Players write real Ruby code to solve puzzles, debug their logic, and iterate on solutions without needing external tutorials or mentorship.

🌱Maturity & risk

Actively maintained and production-ready. The project has 111KB of Ruby code across a well-organized codebase with Cucumber feature tests (7.6KB), RSpec test configuration (.rspec), and GitHub Actions CI/CD (.github/workflows/ci.yml). Updated recently to support Ruby 3.3+ as noted in the README. This is a stable, proven educational tool.

Low risk—single maintainer (ryanb, Ryan Bates) is a known Ruby community figure. The dependency surface is minimal (Gemfile present but slim, indicating few external dependencies). No apparent breaking changes in recent history. Main concern: slow commit frequency may mean bug fixes take time, but the scope is contained and well-tested.

Active areas of work

Repository is in maintenance mode—no active development milestones visible in the file list, but CI/CD pipeline is active (.github/workflows/ci.yml) and README mentions Ruby 3.3 support, indicating recent compatibility updates. The project appears stable rather than rapidly evolving.

🚀Get running

git clone https://github.com/ryanb/ruby-warrior.git
cd ruby-warrior
bundle install
bundle exec bin/rubywarrior

Then follow the interactive setup to create a profile directory with your player.rb file.

Daily commands:

bundle exec bin/rubywarrior

Follows the interactive prompts to select a profile or create one. To run tests: ```bash bundle exec rspec bundle exec cucumber

🗺️Map of the codebase

  • lib/ruby_warrior.rb — Main entry point that loads the entire gem and exposes the public API for Ruby Warrior game initialization.
  • lib/ruby_warrior/game.rb — Core game loop orchestrator that manages tower progression, level execution, and turn-based combat resolution.
  • lib/ruby_warrior/level.rb — Level abstraction that manages floor state, unit interactions, and turn resolution logic for each game level.
  • lib/ruby_warrior/runner.rb — Entry point for game execution that handles CLI interactions, profile loading, and game lifecycle management.
  • lib/ruby_warrior/abilities/base.rb — Base class for all warrior abilities; defines the common interface and validation pattern all actions inherit from.
  • lib/ruby_warrior/units/warrior.rb — Player-controlled unit that receives abilities and executes the player-provided strategy via the play_turn method.
  • lib/ruby_warrior/profile.rb — Player profile management that persists progress, tracks completed levels, and stores generated player code.

🛠️How to make changes

Add a New Enemy Unit Type

  1. Create a new unit class in lib/ruby_warrior/units/ that inherits from lib/ruby_warrior/units/base.rb and define health, attack_power, and turn behavior (lib/ruby_warrior/units/base.rb)
  2. Implement the take_damage and act methods to define unit-specific behavior and combat rules (lib/ruby_warrior/units/[new_unit].rb)
  3. Register the unit in level definition files (e.g., spec/fixtures/short-tower/level_001.rb) by instantiating it in the @floor.add_unit calls (spec/fixtures/short-tower/level_001.rb)
  4. Add a spec file at spec/ruby_warrior/units/[new_unit]_spec.rb to test health, damage, and turn behavior (spec/ruby_warrior/units/[new_unit]_spec.rb)

Add a New Warrior Ability

  1. Create a new ability class in lib/ruby_warrior/abilities/ inheriting from lib/ruby_warrior/abilities/base.rb (lib/ruby_warrior/abilities/base.rb)
  2. Implement the perform method to define the action logic, and validate method to check preconditions (direction validity, range, unit state) (lib/ruby_warrior/abilities/[new_ability].rb)
  3. Register the ability in lib/ruby_warrior/units/warrior.rb by calling add_ability with a symbol key and the new ability class (lib/ruby_warrior/units/warrior.rb)
  4. Create a spec file at spec/ruby_warrior/abilities/[new_ability]_spec.rb covering success cases, validation failures, and edge cases (spec/ruby_warrior/abilities/[new_ability]_spec.rb)
  5. Update level player.rb templates in lib/ruby_warrior/player_generator.rb to document the new ability for players (lib/ruby_warrior/player_generator.rb)

Create a New Tower

  1. Create a new directory under towers/ (or in test fixtures) with tower metadata in a config or manifest file (lib/ruby_warrior/tower.rb)
  2. Create level definition files (level_001.rb, level_002.rb, etc.) that define enemy placement, floor layout, and level description using lib/ruby_warrior/level_loader.rb conventions (lib/ruby_warrior/level_loader.rb)
  3. Each level file should set @description, @floor.width, @floor.height, and call @floor.add_unit for enemies and captives (spec/fixtures/short-tower/level_001.rb)
  4. Add a test in features/towers.feature to verify the tower loads and progresses through levels correctly (features/towers.feature)

Modify Game Difficulty or Balance

  1. Adjust unit health, attack power, or behavior by editing the target unit class (e.g., lib/ruby_warrior/units/sludge.rb) (lib/ruby_warrior/units/sludge.rb)
  2. Modify level layouts and enemy counts in the tower's level definition files (spec/fixtures/short-tower/level_001.rb)
  3. Update ability costs or validation rules in lib/ruby_warrior/abilities/base.rb or individual ability files (lib/ruby_warrior/abilities/base.rb)
  4. Run tests (spec/ruby_warrior/units/_spec.rb and spec/ruby_warrior/abilities/_spec.rb) to ensure changes don't break unit and ability contracts (spec/ruby_warrior/units/base_spec.rb)

🔧Why these technologies

  • Ruby — The entire project is a teaching tool for Ruby itself; the game mechanics deliberately expose and reinforce Ruby syntax and idioms.
  • RSpec + Cucumber — Comprehensive test coverage (unit specs + acceptance tests) ensures game logic is reliable and regressions are caught early.
  • File-based persistence (YAML/JSON in ~/.rubywarrior) — Simple, human-readable storage for profiles and progress; no database dependency keeps setup minimal for learning environment.

⚖️Trade-offs already made

  • Turn-based synchronous game loop instead of real-time or event-driven

    • Why: Synchronous execution makes the game logic deterministic and easier to understand for learners; predictable turn order.
    • Consequence: No true concurrency; actions are sequential, limiting realism but improving clarity and testability.
  • Player code is executed directly via eval() in a controlled context

    • Why: Allows players to write arbitrary Ruby code without compilation or deployment overhead.
    • Consequence: Security risk in production (arbitrary code execution); acceptable for local educational tool.
  • Grid

    • Why: undefined
    • Consequence: undefined

🪤Traps & gotchas

No external service dependencies or env vars required (fully self-contained). Gotchas: (1) Player code in user directories is NOT part of this repo—changes are isolated per installation, (2) Level design is hardcoded in lib/ruby_warrior/level.rb (no data files), so adding levels requires Ruby code, not config, (3) The play_turn method receives a warrior proxy object, not raw state—direct access to internal game objects is blocked by design, (4) No undo/save-state within a level—failure requires restarting with improved code.

🏗️Architecture

💡Concepts to learn

  • Turn-based game simulation — The core of Ruby Warrior's game loop (game.rb) executes discrete turns where each actor (warrior, enemies) calls a play method sequentially; understanding this pattern is essential for modifying level progression or AI behavior.
  • Proxy/Wrapper object pattern — The warrior object passed to play_turn(warrior) is a proxy limiting player access to internal game state; understanding why this design exists teaches API boundaries and security through encapsulation.
  • Polymorphism via class hierarchy — All abilities (attack.rb, walk.rb, feel.rb, etc.) inherit from abilities/base.rb, allowing the game to invoke them uniformly; this is Ruby's core OOP pattern and learners see it in action.
  • State machine (implicit) — A warrior progresses through discrete states: alive → dead (fail level), or alive → stairs reached (pass level); implicit state transitions drive the game loop logic in game.rb.
  • Profile persistence & game saves — profile.rb serializes player progress (current level, total score) to disk so learners can resume later; understanding serialization and file I/O is a practical Ruby skill.
  • Domain-Specific Language (DSL) via method_missing — Ruby Warrior likely uses meta-programming (e.g., method_missing or method_added) to dynamically expose warrior abilities; learners encountering player.rb examples see magic method calls (warrior.attack!, warrior.feel()) that are generated at runtime.
  • Behavior-Driven Development (BDD) with Gherkin — The 7.6KB of Gherkin files (features/*.feature) define game rules in English-like syntax; learners can read features/levels.feature to understand what each level should do before reading Ruby code.
  • thoughtbot/ruby-science — Complementary tutorial repo on Ruby best practices and refactoring patterns; learners graduating from Ruby Warrior often move here.
  • ruby/ruby — Official Ruby source—referenced by Ruby Warrior's documentation and critical for understanding edge cases in Ruby 3.3 compatibility.
  • ryanb/railscasts-episodes — Ryan Bates' Rails/Ruby tutorial series—Ruby Warrior is his educational philosophy applied to a game; same author, same teaching approach.
  • codecombat/codecombat — Closest alternative: game-based coding education, but multi-language (Python, JavaScript, Lua) and web-based; shows the broader landscape of gamified learning.
  • exercism/exercism — Parallel approach to Ruby learning via exercises + mentorship; both teach Ruby fundamentals but Ruby Warrior emphasizes game engagement while Exercism emphasizes code review.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for lib/ruby_warrior/abilities directory

The abilities directory contains 14 ability classes (attack.rb, feel.rb, look.rb, listen.rb, etc.) but there's no corresponding spec/ruby_warrior/abilities directory visible in the file structure. These are core game mechanics that players interact with directly. Adding unit tests for each ability class would improve maintainability, catch regressions, and serve as documentation for new contributors.

  • [ ] Create spec/ruby_warrior/abilities/ directory
  • [ ] Add unit tests for each ability in lib/ruby_warrior/abilities/ (base.rb, attack.rb, feel.rb, look.rb, listen.rb, walk.rb, rest.rb, rescue.rb, shoot.rb, etc.)
  • [ ] Test ability initialization, validation, and execution with mocked units and floors
  • [ ] Ensure coverage of edge cases (e.g., attacking in invalid directions, feeling outside floor bounds)

Add unit tests for lib/ruby_warrior/units directory and base unit mechanics

The units directory defines game entities (warrior.rb, archer.rb, sludge.rb, captive.rb, etc.) that are core to gameplay, but there's no visible spec/ruby_warrior/units test directory. Testing unit health, damage, positioning, and interactions is critical for game correctness and would help new contributors understand the entity system.

  • [ ] Create spec/ruby_warrior/units/ directory
  • [ ] Add tests for lib/ruby_warrior/units/base.rb covering unit attributes, damage/healing, and state management
  • [ ] Add specific tests for each unit type (warrior.rb, archer.rb, sludge.rb, etc.) covering their unique behaviors
  • [ ] Test unit interactions like damage application, death conditions, and captive rescue mechanics

Add integration tests for level loading and floor generation (spec/ruby_warrior/level* and spec/ruby_warrior/floor*)

The lib/ruby_warrior/level.rb, lib/ruby_warrior/level_loader.rb, and lib/ruby_warrior/floor.rb files handle critical game setup logic, but spec/ruby_warrior appears to lack tests for these modules. The spec/fixtures/short-tower directory exists with sample levels, making it ideal for integration testing. This would validate that levels load correctly, floors initialize with proper units, and the progression system works end-to-end.

  • [ ] Create unit tests in spec/ruby_warrior/level_spec.rb testing level initialization, completion detection, and progression
  • [ ] Create unit tests in spec/ruby_warrior/level_loader_spec.rb validating level file parsing and script loading using spec/fixtures/short-tower
  • [ ] Create unit tests in spec/ruby_warrior/floor_spec.rb covering floor layout, unit placement, pathfinding, and space management
  • [ ] Add integration tests verifying a complete level progression using the fixture tower

🌿Good first issues

  • Add test coverage for lib/ruby_warrior/space.rb—it manages tile state (enemy, captive, stairs) but has no visible unit tests in the file list; write RSpec specs covering all occupation types and transitions.
  • Document the abilities system architecture in docs/ABILITIES.md—the file structure (lib/ruby_warrior/abilities/*.rb) is clear, but no guide exists for contributors extending it; create a template showing base.rb inheritance, method signatures (perform, description), and a worked example.
  • Implement a --dry-run flag in bin/rubywarrior to simulate level execution without persisting progress—useful for learners testing theories; touches runner.rb, game.rb, and CLI argument parsing in the bin script.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • a062c16 — Merge pull request #105 from ryanb/syntax-tree-format (ryanb)
  • 6758e98 — Add cucumber.yml config which quiets publish message (ryanb)
  • bd8cf92 — Clean up script/console and move to bin/console (ryanb)
  • 34d7a33 — Format all Ruby code using Syntax Tree (ryanb)
  • f64a6e1 — Add bin/format script to format Ruby code with syntax tree (ryanb)
  • aa20971 — Add syntax_tree gem (ryanb)
  • b1af18b — Merge pull request #104 from ryanb/github-workflows-ci (ryanb)
  • c4edb5e — Pass array to cucumber_opts to avoid warning (ryanb)
  • 3fc6654 — Fix spec failing due to hash of options passed to RubyWarrior::Turn mock (ryanb)
  • 45df5bb — Add GitHub CI workflow (ryanb)

🔒Security observations

The Ruby Warrior codebase has moderate security concerns primarily around dynamic code execution for level loading and potential deserialization issues with profile persistence. The application is educational in nature with limited exposure to external untrusted input, which reduces practical risk. However, the dynamic evaluation of user-written Ruby code (core to the game) requires careful sandboxing. No critical vulnerabilities were identified, but medium-severity issues with code injection and insecure deserialization should be addressed. The dependency file content was not provided, so transitive dependency vulnerabilities could not be assessed. Overall security posture is acceptable for an educational game but should implement input validation and safe serialization practices.

  • Medium · Potential Code Injection in Level Loader — lib/ruby_warrior/level_loader.rb. The level_loader.rb file likely uses dynamic code evaluation (eval or similar) to load and execute user-written level definitions. This could allow malicious code execution if user input is not properly sanitized. The file structure shows level_*.rb files in fixtures that are loaded dynamically. Fix: Use safe YAML parsing with restricted classes (Psych.safe_load) or abstract syntax tree (AST) parsing instead of eval(). Implement input validation and sandboxing for user-provided code execution.
  • Medium · Insecure Deserialization Risk — lib/ruby_warrior/profile.rb, lib/ruby_warrior/game.rb. Profile data and game state may be serialized/deserialized without proper validation. The profile.rb and game.rb files likely persist state that could be manipulated if stored insecurely. Ruby's Marshal format is particularly vulnerable to arbitrary code execution. Fix: Avoid using Ruby's Marshal for untrusted data. Use JSON with schema validation instead. Implement integrity checks (HMAC) for saved game data.
  • Low · Missing Input Validation in UI — lib/ruby_warrior/ui.rb. The ui.rb file handles user input for commands and profile names. There is no evidence of input sanitization or validation which could lead to unexpected behavior or local file access issues. Fix: Implement strict input validation for user-provided names and commands. Use allowlists for acceptable characters and limit input length.
  • Low · Hardcoded Configuration Paths — lib/ruby_warrior/config.rb. The config.rb file may contain hardcoded paths that could be predictable. Player profiles and save files are likely stored in predictable locations. Fix: Use standard OS directories (XDG_CONFIG_HOME on Linux, ~/Library on macOS, APPDATA on Windows) for storing configuration and save files. Implement proper file permission checks.
  • Low · Missing CHANGELOG Security Warnings — CHANGELOG.md. While a CHANGELOG.md exists, there is no evidence of security advisory documentation or deprecation warnings for known vulnerabilities in old versions. Fix: Maintain a SECURITY.md file documenting known vulnerabilities and remediation steps. Include security notes in CHANGELOG for each release.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · ryanb/ruby-warrior — RepoPilot