rails/thor
Thor is a toolkit for building powerful command-line interfaces.
Healthy across the board
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 6d ago
- ✓24+ active contributors
- ✓MIT licensed
Show 3 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Concentrated ownership — top contributor handles 50% 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.
[](https://repopilot.app/r/rails/thor)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/rails/thor on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: rails/thor
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:
- 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. - 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.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/rails/thor 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 the board
- Last commit 6d ago
- 24+ active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Concentrated ownership — top contributor handles 50% 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 rails/thor
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/rails/thor.
What it runs against: a local clone of rails/thor — 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 rails/thor | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 36 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of rails/thor. If you don't
# have one yet, run these first:
#
# git clone https://github.com/rails/thor.git
# cd thor
#
# 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 rails/thor and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "rails/thor(\\.git)?\\b" \\
&& ok "origin remote is rails/thor" \\
|| miss "origin remote is not rails/thor (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 main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "lib/thor.rb" \\
&& ok "lib/thor.rb" \\
|| miss "missing critical file: lib/thor.rb"
test -f "lib/thor/base.rb" \\
&& ok "lib/thor/base.rb" \\
|| miss "missing critical file: lib/thor/base.rb"
test -f "lib/thor/command.rb" \\
&& ok "lib/thor/command.rb" \\
|| miss "missing critical file: lib/thor/command.rb"
test -f "lib/thor/parser/options.rb" \\
&& ok "lib/thor/parser/options.rb" \\
|| miss "missing critical file: lib/thor/parser/options.rb"
test -f "lib/thor/invocation.rb" \\
&& ok "lib/thor/invocation.rb" \\
|| miss "missing critical file: lib/thor/invocation.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 36 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~6d)"
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/rails/thor"
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).
⚡TL;DR
Thor is a Ruby toolkit that eliminates boilerplate for building command-line interfaces by providing declarative DSL syntax for defining commands, options, arguments, and file operations. It removes the pain of manual option parsing, USAGE banner generation, and can replace Rake for build automation tasks—offering Rake-like syntax with cleaner semantics for CLI composition. Monolithic library structured as: lib/thor.rb entry point → lib/thor/base.rb (core DSL class definition) → lib/thor/command.rb and lib/thor/group.rb (task/group abstractions) → lib/thor/parser/* (option/argument parsing) → lib/thor/actions/* (file manipulation operations) → lib/thor/shell/* (output formatting and UI). Invocation and group composition handled by lib/thor/invocation.rb and lib/thor/nested_context.rb.
👥Who it's for
Ruby developers building command-line tools and utilities who want to avoid repetitive OptionParser/argument parsing code; Gem authors distributing executables via RubyGems who need structured subcommand handling; developers migrating from or replacing Rake build scripts with more modular task runners.
🌱Maturity & risk
Production-ready and actively maintained. The repo shows consistent CI/CD via GitHub Actions (lint.yml, tests.yml, release.yml), organized test structure (implied by .rspec config), and semantic versioning releases. The codebase is well-established (442K Ruby LOC across 60+ files) with clear architectural separation of concerns (parser, shell, actions, invocation subsystems).
Low-to-moderate risk for CLI tools. Security caveat explicitly flagged in README: Thor's design for seamless file/URL access via open-uri creates command injection vectors if used with untrusted application user input—requires careful input sanitization. Maintainer dependency is moderate (rails organization ownership reduces bus-factor). No obvious stale code paths, but the mature codebase means breaking changes require careful deprecation cycles.
Active areas of work
Active maintenance via GitHub Actions workflows (tests.yml runs on push, lint.yml enforces code style via RuboCop per .rubocop.yml, release.yml handles gem publishing). Workflow files suggest continuous integration discipline. No visible breaking PR activity in file list, indicating stable API and incremental improvements focus.
🚀Get running
git clone https://github.com/rails/thor.git && cd thor && bundle install && bundle exec rspec to run the test suite. Verify installation: ruby -Ilib bin/thor help to execute the bundled example Thor CLI.
Daily commands: bundle exec rake (implied via Thorfile presence, or use bundled CLI) bin/thor help shows all available commands. For development, bundle exec rspec runs test suite. No server or daemon mode—Thor executes synchronously as a command-line invocation.
🗺️Map of the codebase
lib/thor.rb— Main entry point and loader for all Thor functionality; sets up the core class definitions and version.lib/thor/base.rb— Core base class that all Thor command classes inherit from; defines argument/option parsing and execution flow.lib/thor/command.rb— Represents a single command with its options, arguments, and execution logic; central abstraction for command definition.lib/thor/parser/options.rb— Parses CLI options and arguments into an organized structure; critical for turning raw argv into structured data.lib/thor/invocation.rb— Handles invoking and executing Thor commands, including nested command dispatch and output routing.lib/thor/shell/basic.rb— Provides user-facing output methods (say, ask, confirm) and file/directory interaction helpers used throughout Thor.lib/thor/actions.rb— Mixin that bundles all file and directory manipulation actions; used extensively in generators and command implementations.
🛠️How to make changes
Add a new command to an existing CLI
- In your Thor class, define a method with a description and options using class_option or method-level option DSL (
lib/thor/base.rb) - Use the Shell API (say, ask, confirm) for user interaction and Actions mixin for file operations (
lib/thor/shell/basic.rb) - Arguments are extracted from method parameters; options from class_option or desc block in method definition (
lib/thor/command.rb) - Test your command by invoking it via Thor's invoke or directly via the executable (
spec/command_spec.rb)
Add a new generator with file scaffolding
- Extend Thor::Group instead of Thor::Base to enable ordered command execution and file action batching (
lib/thor/group.rb) - Include the Actions mixin to gain access to create_file, directory, inject_into_file, and template methods (
lib/thor/actions.rb) - Define template files in a templates/ subdirectory and reference them in create_file or directory calls (
lib/thor/actions/create_file.rb) - Use ERB templating syntax in .tt files and pass locals as a hash to process template variables (
spec/fixtures/doc/config.yaml.tt)
Customize option parsing and validation
- Define options in class body with class_option(:name, type: :string, required: true) or in method with option(:name) (
lib/thor/parser/option.rb) - Use Banner type for enum-like choices, :boolean for flags, :numeric for numbers, :array for comma-separated lists (
lib/thor/parser/options.rb) - Access parsed options in command methods via options hash (options[:key]) or as method parameters (
lib/thor/base.rb) - Add custom validation by checking options in the method and raising Thor::Error with a descriptive message (
lib/thor/error.rb)
Enhance output formatting and interactivity
- Use say(message) for plain output, say(message, :green) for colored output, or print_table for tabular data (
lib/thor/shell/basic.rb) - Prompt users with ask(prompt), yes?(prompt), or no?(prompt) which return user input or boolean (
lib/thor/shell/basic.rb) - Use set_color(text, color) for fine-grained color control; colors available are :black, :red, :green, :yellow, :blue, :magenta, :cyan, :white (
lib/thor/shell/color.rb) - For advanced formatting, use ColumnPrinter or TablePrinter to render aligned columns and rows (
lib/thor/shell/table_printer.rb)
🔧Why these technologies
- Ruby metaprogramming (method_missing, define_method, class_eval) — Allows dynamic command definition from class methods, DSL-like syntax for options/arguments without explicit declaration objects
- ARGV parsing and regex-based option matching — Provides flexible, zero-dependency CLI parsing without requiring complex external libraries; works across platforms
- ERB templating (via Ruby's ERB stdlib) — Enables generators to produce scaffolded files with dynamic variable interpolation using familiar Rails-like syntax
- Readline library (optional, graceful fallback) — Provides interactive command history and line editing for REPL-like Thor invocations without hard dependency
⚖️Trade-offs already made
-
Commands defined as class methods rather than explicit descriptor objects
- Why: Provides Rake-like, intuitive syntax for developers familiar with the Ruby ecosystem; reduces boilerplate
- Consequence: Requires introspection of method signatures at runtime; harder for static analysis tools; method names must conform to CLI naming conventions
-
No built-in authentication or permission system
- Why: Thor is designed for system/build tools, not user-facing applications with access control
- Consequence: Developers must implement their own security layers; security warnings in README about avoiding untrusted input with open-uri
-
File actions are synchronous and blocking
- Why: Simplifies API and matches typical build-tool use case of sequential file generation; avoids callback complexity
- Consequence: Large file operations or network-based templates block execution; generators are not suitable for concurrent mass operations
-
Global Thor runner discovers .thor files from filesystem
- Why: Allows ad-hoc task definition and execution without explicit project structure or gem installation
- Consequence: Security model relies on filesystem trust; no built-in sandboxing; tasks from arbitrary files are executable
🚫Non-goals (don't propose these)
- Does not handle application-level authentication or user permission management
- Not designed for real-time or concurrent task execution
- Does not provide built-in dependency injection or service container
- Not a task scheduler or job
🪤Traps & gotchas
open-uri security vector: Thor's file/URL operations rely on open-uri which is vulnerable to command injection if given unsanitized user input—this is by design and documented but often missed. Method-to-command mapping: private methods are NOT exposed as commands; underscore prefixes hide them from the CLI. Thor inheritance gotcha: method definitions in a Thor subclass become commands unless explicitly hidden with 'private' or named with leading underscore; easy to accidentally expose internal methods. Option parsing order: long options must precede arguments in some parsing modes; if tests pass locally but fail in CI, check argument vs option ordering. Shell output buffering: lib/thor/shell/ uses real-time output by default; for testing, inject a mock shell or capture stdout/stderr explicitly.
🏗️Architecture
💡Concepts to learn
- Method Introspection & Dynamic Dispatch — Thor converts user-defined methods into CLI commands via reflection; understanding Ruby's method_missing, define_method, and instance_variable_get is essential to grasping how lib/thor/base.rb wraps methods into Command objects
- Option Parser State Machine — Thor's lib/thor/parser/options.rb implements a finite state machine that tokenizes, classifies, and binds CLI arguments to option definitions; understanding state transitions (flag → value, long option parsing, short flag bundling) is crucial for debugging argument binding issues
- Visitor Pattern in AST-like Parsing — lib/thor/parser/arguments.rb and lib/thor/parser/options.rb traverse parsed token lists using Visitor-like iteration; recognizing this pattern helps when extending parser functionality for custom argument types
- Template Method Pattern in File Actions — Each action in lib/thor/actions/ (CreateFile, InjectIntoFile, Directory) inherits from FileManipulation and implements invoke() with predictable hooks for pretend mode, logging, and undo; understanding the template method flow is essential for adding custom actions
- Interactive Terminal Control (TTY Abstraction) — lib/thor/shell/basic.rb abstracts terminal I/O (stdin, stdout, isatty checks, color ANSI codes); lib/thor/line_editor/ adds readline support; understanding TTY behavior is critical when implementing interactive prompts or handling piped input in tests
- Rake Compatibility & Build Tool Interop — lib/thor/rake_compat.rb provides Thor-to-Rake conversion; understanding how Thor tasks can be exposed as Rake tasks bridges two Ruby build ecosystems and is important for mixed CI/CD pipelines
- Lazy String Interpolation & Help Text Generation — Thor uses deferred command description/banner evaluation (lib/thor/command.rb defers usage() calls) to avoid expensive string computation on every help invocation; grasping lazy evaluation patterns helps optimize CLI responsiveness
🔗Related repos
ruby/rake— Rake is Thor's inspiration and competitor for task automation; Rake tasks are procedural while Thor uses declarative method-based CLI syntax, and Thor can replace Rake in many build scenarioserikhuda/bundler— Bundler's CLI was historically powered by Thor; studying Bundler's lib/bundler/cli.rb shows production use of Thor's DSL at scalerails/rails— Rails uses Thor extensively forrails generateand scaffold commands; Rails generators inherit from Thor::Generators, making Thor essential for understanding Rails CLIdavismcphew/commander— Alternative Ruby CLI framework with more minimal DSL; good for comparing design philosophy if you need lighter-weight option parsing without Thor's full feature setjashkenas/coffeescript— Historical precedent in JavaScript ecosystem for building elegant CLIs; inspired similar ergonomic DSL thinking that influenced Thor's design philosophy
🪄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 test coverage for lib/thor/shell/column_printer.rb and lib/thor/shell/table_printer.rb
The file structure shows lib/thor/shell/column_printer.rb and lib/thor/shell/table_printer.rb exist, but there are no corresponding spec files in spec/shell/ (which doesn't appear in the listing). These are critical UI components for formatted output, and comprehensive tests would ensure consistent behavior across different terminal widths, content types, and edge cases.
- [ ] Create spec/shell/column_printer_spec.rb with tests for various column widths and content alignment
- [ ] Create spec/shell/table_printer_spec.rb with tests for table borders, padding, and multi-line cells
- [ ] Test edge cases: empty tables, single columns, very long content, special characters
- [ ] Verify tests pass with existing shell implementations (basic, color, html)
Add missing integration tests for lib/thor/line_editor/ with actual user input scenarios
The lib/thor/line_editor/basic.rb and lib/thor/line_editor/readline.rb modules handle interactive user input, but there don't appear to be corresponding spec files. These are critical for REPL-like interfaces and require tests that simulate terminal input/output behavior to prevent regressions in interactive command handling.
- [ ] Create spec/line_editor/basic_spec.rb testing line reading, editing, and history (if applicable)
- [ ] Create spec/line_editor/readline_spec.rb for readline-specific features (auto-complete, history navigation)
- [ ] Test fallback behavior when readline is unavailable
- [ ] Add tests for special input: empty lines, multi-line inputs, escape sequences
Add test coverage for lib/thor/nested_context.rb functionality
The nested_context.rb file exists in the codebase but there's no corresponding spec file visible. This module likely handles nested command contexts (important for subcommands), and without tests it's difficult to ensure proper isolation and state management across command hierarchies. This is critical for maintaining the integrity of complex CLI applications.
- [ ] Create spec/nested_context_spec.rb with tests for context creation and isolation
- [ ] Test nesting depth limits and stack behavior
- [ ] Verify that nested contexts don't leak state to parent or sibling contexts
- [ ] Test interaction with lib/thor/invocation.rb for proper command invocation within nested contexts
🌿Good first issues
- Add missing test coverage for lib/thor/shell/column_printer.rb and lib/thor/shell/table_printer.rb—these files are likely absent from test/ directory and could have detailed table formatting tests added
- Document the invocation and method dispatch flow in lib/thor/invocation.rb with inline comments and an architecture guide in CONTRIBUTING.md explaining how a user-defined method becomes a CLI command with options
- Implement a built-in validation helper for lib/thor/parser/argument.rb (e.g., 'validate_argument :name, type: String, required: true') to provide better error messages when arguments fail validation, with tests in spec/thor/parser/
⭐Top contributors
Click to expand
Top contributors
- @rafaelfranca — 50 commits
- @yahonda — 9 commits
- @G-Rath — 6 commits
- @p8 — 4 commits
- @deivid-rodriguez — 3 commits
📝Recent commits
Click to expand
Recent commits
6a680f2— Prepare for 1.5.0 (rafaelfranca)615b0c2— Merge pull request #919 from rails/rmf-ci (rafaelfranca)f16a2db— Unlock bundler development dependency (rafaelfranca)7b99536— Test with Ruby 4.0 (rafaelfranca)2a1eecb— Merge pull request #918 from rails/dependabot/github_actions/actions/checkout-6 (rafaelfranca)ed9ffca— Merge pull request #916 from moritzschepp/ec-encoding (rafaelfranca)5b85a33— Bump actions/checkout from 5 to 6 (dependabot[bot])2e2b684— fix encoding error when running a merge tool (moritzschepp)b2d98fe— Remove whatisthor.com references (rafaelfranca)17a3be9— Merge pull request #912 from rails/dependabot/github_actions/actions/checkout-5 (byroot)
🔒Security observations
The Thor codebase has moderate security concerns centered on command injection vectors and file system manipulation. The most critical issue is the acknowledged design pattern of accepting system-level access, which requires strict input validation. File operation modules lack visible path traversal protection, and shell execution capabilities require careful handling. The codebase would benefit from comprehensive input validation,
- High · Command Injection via open-uri Integration —
lib/thor/actions/ (file manipulation modules), README.md. The README explicitly acknowledges that Thor is designed for system access with file and URL handling via open-uri. When combined with application user input, this creates a command injection attack vector. The codebase appears to support dynamic file operations and directory creation which could be exploited if user input is not properly sanitized. Fix: Implement strict input validation and sanitization for all user-provided paths and URLs. Use allowlists for permitted operations. Add warnings in documentation about restricting Thor to trusted input sources only. Consider sandboxing or capability restrictions for file operations. - High · Arbitrary File Creation and Manipulation —
lib/thor/actions/create_file.rb, lib/thor/actions/create_link.rb, lib/thor/actions/directory.rb, lib/thor/actions/inject_into_file.rb, lib/thor/actions/file_manipulation.rb. Multiple action modules (create_file.rb, create_link.rb, directory.rb, inject_into_file.rb) handle file system operations. Without proper path validation, these could be exploited for directory traversal attacks, allowing creation or modification of files outside intended directories. Fix: Implement path canonicalization and validation to prevent directory traversal. Use realpath() to resolve actual paths and verify they exist within allowed directories. Implement strict permission checks before file operations. - Medium · Potential Template Injection in File Operations —
lib/thor/actions/ (template handling), spec/fixtures/doc/. The codebase references template files (*.tt files) in fixtures (spec/fixtures/doc/%file_name%.rb.tt). If template processing uses string interpolation with user input without proper escaping, this could lead to template injection vulnerabilities. Fix: Use safe template engines with auto-escaping enabled. Validate and sanitize all variables passed to templates. Avoid using eval() or instance_eval() on user-provided data. Implement a whitelist of allowed template variables. - Medium · Hash with Indifferent Access Security —
lib/thor/core_ext/hash_with_indifferent_access.rb. Custom implementation of HashWithIndifferentAccess (lib/thor/core_ext/hash_with_indifferent_access.rb) may have edge cases or security issues not present in standard Ruby implementations. Custom implementations risk introducing vulnerabilities. Fix: Review the custom hash implementation for potential prototype pollution or type confusion attacks. Consider using Rails' ActiveSupport::HashWithIndifferentAccess if available. Ensure proper handling of symbol/string key collisions. - Medium · Shell Command Execution Risk —
lib/thor/shell/, lib/thor/line_editor/. The presence of shell modules (lib/thor/shell/) and line editor functionality suggests command execution capabilities. Improper handling of shell metacharacters in user input could lead to command injection. Fix: Use parameterized execution methods (e.g., system with array arguments) instead of shell string interpolation. Properly escape or avoid shell metacharacters. Use Shellwords.escape() for any shell operations required. - Low · Missing Security Headers in HTML Output —
lib/thor/shell/html.rb. HTML shell module exists (lib/thor/shell/html.rb) for generating HTML output, but there's no evidence of security headers or content-type validation for HTML generation. Fix: Ensure proper HTML escaping of all output. Add Content-Type headers with charset specification. Implement Content-Security-Policy if generating HTML that could be served via HTTP. - Low · No Visible Dependency Version Pinning —
Gemfile, gemspec. Gemfile was not provided in the submission. Without dependency pinning, Thor could be vulnerable to transitive dependency attacks or supply chain compromises. Fix: Pin all direct and important transitive dependencies to specific versions. Regularly audit dependencies using bundler-audit or similar tools. Implement automated dependency scanning in CI/CD.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.