RepoPilotOpen in app →

standardrb/standard

Ruby's bikeshed-proof linter and formatter 🚲

Healthy

Healthy across the board

worst of 4 axes
Use as dependencyConcerns

non-standard license (Other)

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.

  • Last commit 5d ago
  • 5 active contributors
  • Distributed ownership (top contributor 40% of recent commits)
Show 4 more →
  • Other licensed
  • CI configured
  • Tests present
  • Non-standard license (Other) — review terms
What would change the summary?
  • Use as dependency ConcernsMixed if: clarify license terms

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/standardrb/standard)](https://repopilot.app/r/standardrb/standard)

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/standardrb/standard on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: standardrb/standard

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/standardrb/standard 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 5d ago
  • 5 active contributors
  • Distributed ownership (top contributor 40% of recent commits)
  • Other licensed
  • CI configured
  • Tests present
  • ⚠ Non-standard license (Other) — review terms

<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 standardrb/standard repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/standardrb/standard.

What it runs against: a local clone of standardrb/standard — 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 standardrb/standard | Confirms the artifact applies here, not a fork | | 2 | License is still Other | 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 ≤ 35 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>standardrb/standard</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of standardrb/standard. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/standardrb/standard.git
#   cd standard
#
# 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 standardrb/standard and re-run."
  exit 2
fi

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

# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
  && ok "license is Other" \\
  || miss "license drift — was Other 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/standard.rb" \\
  && ok "lib/standard.rb" \\
  || miss "missing critical file: lib/standard.rb"
test -f "lib/standard/cli.rb" \\
  && ok "lib/standard/cli.rb" \\
  || miss "missing critical file: lib/standard/cli.rb"
test -f "lib/standard/creates_config_store.rb" \\
  && ok "lib/standard/creates_config_store.rb" \\
  || miss "missing critical file: lib/standard/creates_config_store.rb"
test -f "lib/standard/plugin/initializes_plugins.rb" \\
  && ok "lib/standard/plugin/initializes_plugins.rb" \\
  || miss "missing critical file: lib/standard/plugin/initializes_plugins.rb"
test -f "lib/standard/lsp/server.rb" \\
  && ok "lib/standard/lsp/server.rb" \\
  || miss "missing critical file: lib/standard/lsp/server.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 35 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~5d)"
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/standardrb/standard"
  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

Standard is an opinionated, unconfigurable linter and formatter for Ruby built on top of RuboCop and rubocop-performance. It enforces a single bikeshed-proof style guide (inspired by StandardJS) with zero configurability, eliminating endless debates about code formatting while still catching bugs, security issues, and performance problems. Single-package structure: core linting logic in lib/standard/ with RuboCop config templates in config/ (base.yml, ruby-version-specific overrides). CLI entry point at exe/standardrb. Plugin system via lib/standard/base/plugin.rb. Ruby LSP integration at lib/ruby_lsp/standard/ for editor support. Config building orchestrated by lib/standard/creates_config_store/ with specialized handlers for path ignoring and user extensions.

👥Who it's for

Ruby developers and teams who want consistent code style without configuration overhead—particularly those tired of bikeshedding on linter rules. Contributors include maintainers at Test Double and the broader Ruby community building plugins like standard-rails and standard-sorbet.

🌱Maturity & risk

Production-ready. The repo shows active maintenance with versioning for Ruby 1.8 through 3.4, CI workflows via GitHub Actions (test.yml, update.yml), comprehensive documentation in docs/, and a full changelog. The codebase is well-structured with clear separation between core logic and plugins.

Low risk for a style tool. The gem wraps established RuboCop/rubocop-performance (reducing custom linting logic). Single maintainer (Test Double team) is mitigated by plugin architecture allowing community extensions. No high-risk dependencies visible in file structure; versioning strategy (config/ruby-X.Y.yml files) suggests stable, backward-compatible updates.

Active areas of work

Active maintenance: GitHub workflows run tests and dependency updates automatically. The file structure shows ongoing Ruby version support (config files for Ruby 3.3, 3.4 are present). Architecture docs exist (docs/ARCHITECTURE.md), suggesting recent refactoring or documentation effort. Plugin ecosystem is active (lint_roller integration visible in code).

🚀Get running

git clone https://github.com/standardrb/standard.git && cd standard && bundle install && bin/setup

Daily commands: bundle exec standardrb (runs linter); bundle exec standardrb --fix (auto-formats). Dev console: bin/console. Tests via: rake test (inferred from Rakefile presence).

🗺️Map of the codebase

  • lib/standard.rb — Main entry point that initializes the Standard gem and coordinates the entire linting/formatting pipeline.
  • lib/standard/cli.rb — Command-line interface handler that parses arguments and routes to appropriate runners (RuboCop, LSP, help, version).
  • lib/standard/creates_config_store.rb — Orchestrates configuration assembly from YAML files, user extensions, RuboCop settings, and Ruby version targeting.
  • lib/standard/plugin/initializes_plugins.rb — Core plugin system that loads and initializes third-party Standard plugins like standard-rails and standard-sorbet.
  • lib/standard/lsp/server.rb — LSP server implementation enabling IDE integration for real-time linting and formatting feedback.
  • lib/standard/builds_config.rb — Assembles final RuboCop configuration by merging base rules, user config, and plugin-contributed rules.
  • config/default.yml — The immutable, opinionated default RuboCop rules that define Standard's uncompromising style guide.

🧩Components & responsibilities

  • CLI Router (cli.rb) (Ruby, OptionParser) — Parse command-line arguments and dispatch to appropriate runner (RuboCop, LSP, version, help, genignore)
    • Failure mode: Unrecognized arguments crash with usage error; runner dispatch fails silently if runner class not found
  • Config Store (creates_config_store.rb) (YAML, RuboCop::ConfigStore) — Assemble final RuboCop configuration by layering base rules, version-specific overrides, user extensions, and plugin contributions
    • Failure mode: Invalid YAML or missing config files raise parse errors; incompatible rule conflicts may cause RuboCop to fail during execution
  • Plugin System (plugin/) (lint_roller gem, Ruby reflection (const_get)) — Discover, validate, and load third-party Standard plugins; merge their RuboCop rules and dependencies into the main configuration
    • Failure mode: Missing plugin gems cause LoadError; invalid plugin classes fail during initialization; conflicting rule names raise merge errors
  • RuboCop Runner (runners/rubocop.rb) — Execute the merged RuboCop configuration against target files, collect offenses, optionally auto

🛠️How to make changes

Add a new CLI command runner

  1. Create a new runner class in lib/standard/runners/ following the pattern of existing runners (e.g., rubocop.rb, version.rb) (lib/standard/runners/my_new_runner.rb)
  2. Implement a run(arguments) method that returns an integer exit code (lib/standard/runners/my_new_runner.rb)
  3. Register the runner in the CLI router by adding a condition in cli.rb to detect and invoke your runner (lib/standard/cli.rb)

Add a new RuboCop rule to the default style guide

  1. Edit the default RuboCop configuration to enable or customize a rule with your preferred severity and settings (config/default.yml)
  2. Test the rule against fixture files in test/fixture/cli/ or add new test fixtures (test/fixture/cli/autocorrectable-bad.rb)
  3. Run the test suite to ensure the rule doesn't break existing functionality (Rakefile)

Support a new Ruby version

  1. Create a new version-specific config file copying from the previous version's configuration (config/ruby-X.Y.yml)
  2. Override only the rules that differ for the new Ruby version (syntax changes, deprecated rules, etc.) (config/ruby-X.Y.yml)
  3. Update the version detection logic in creates_config_store/sets_target_ruby_version.rb to map to your new config (lib/standard/creates_config_store/sets_target_ruby_version.rb)
  4. Document the new version in docs/RUBY_VERSIONS.md (docs/RUBY_VERSIONS.md)

🔧Why these technologies

  • RuboCop — Industry-standard Ruby linter with extensive rule library; Standard builds on it rather than reinventing linting logic
  • YAML configuration files — Standard's opinionated rules are codified in immutable YAML configs that cannot be overridden, enforcing consistency across projects
  • lint_roller plugin system — Allows ecosystem extensions (standard-rails, standard-sorbet) without coupling Standard core to specific frameworks
  • Language Server Protocol (LSP) — Provides real-time IDE integration for linting and formatting without requiring editor-specific implementations

⚖️Trade-offs already made

  • Unconfigurable, opinionated defaults (no .standard.yml customization of rules)

    • Why: Eliminates bikeshed discussions and enforcement debates, mimicking StandardJS philosophy
    • Consequence: Users cannot customize linting rules, trading flexibility for uniformity and reduced decision fatigue
  • RuboCop as the sole underlying engine

    • Why: Leverages a mature, widely-used linter rather than building from scratch
    • Consequence: Standard is bound to RuboCop's architecture, rule set, and release cycle; cannot add rules outside RuboCop's scope
  • Ruby version-specific config files (ruby-3.1.yml, ruby-3.2.yml, etc.)

    • Why: Allows disabling rules incompatible with older Ruby versions while maintaining a single tool
    • Consequence: Adds maintenance burden to support multiple Ruby versions; config duplication across versions

🚫Non-goals (don't propose these)

  • Provide customizable linting rules—Standard intentionally forbids user configuration of RuboCop rules to enforce consistency
  • Support languages other than Ruby
  • Replace or extend RuboCop's core rule system—Standard only adds standard-rails and standard-sorbet through plugins
  • Provide real-time IDE feedback without LSP—IDE integration only available through the LSP server, not direct APIs

🪤Traps & gotchas

  1. Version-specific Ruby configs (config/ruby-X.Y.yml) override base.yml selectively; changes to base.yml may not apply to all versions unless explicitly inherited—check .yml override chain. 2) lint_roller plugin system requires plugins to conform to specific interface in lib/standard/base/plugin.rb; plugins with malformed return values fail silently. 3) Config store creation in lib/standard/creates_config_store/ has three specialized handlers that run sequentially; order matters (YAML assignment first, then path ignoring, then user merges). 4) The gem intentionally forbids .standard.yml custom configs to prevent bikeshedding; users must use .rubocop.yml only for RuboCop-specific tweaks, not Standard rules.

🏗️Architecture

💡Concepts to learn

  • Unconfigurable Configuration — Core philosophy of Standard—users cannot debate rules because the config is locked; understanding why this is a feature (not a bug) is essential to contributing without suggesting configurability.
  • RuboCop Rule Sets & Cops — Standard's entire function is selecting and bundling RuboCop 'cops' (linting rules) into config/base.yml; you must understand how RuboCop rules work to modify linting behavior.
  • Plugin Architecture via lint_roller — Standard delegates domain-specific rules (Rails, Sorbet) to plugins; lint_roller is the loader mechanism, so understanding how plugins register and merge configs is crucial for extending Standard.
  • YAML Config Inheritance & Merging — Standard layers configs (base.yml → ruby-X.Y.yml → user .rubocop.yml); understanding precedence and merge semantics in lib/standard/creates_config_store/ is vital for debugging config issues.
  • Ruby LSP Addon Pattern — lib/ruby_lsp/standard/addon.rb integrates Standard into IDEs via the Ruby LSP protocol; understanding this pattern enables real-time linting UX improvements.
  • Bikeshedding (Yak Shaving) — The motivation behind Standard—endless linter configuration debates waste time; Poul-Henning Kamp's bikeshed principle explains why Standard exists and why its 'no config' stance is intentional.
  • AST Linting & Static Analysis — RuboCop operates on Ruby Abstract Syntax Trees to detect code issues; Standard inherits this; understanding AST-based analysis helps when reading RuboCop rule docs.
  • rubocop/rubocop — RuboCop is the underlying linting engine that Standard wraps with opinionated defaults
  • standardrb/standard-rails — Official plugin extending Standard with Rails-specific rules; demonstrates lint_roller plugin pattern
  • standardrb/lint_roller — Plugin system foundation; used by Standard to load third-party rule sets without configuration
  • rubocop/rubocop-performance — Performance rule set bundled with Standard; provides performance-optimization linting rules alongside RuboCop's core rules
  • standardjs/standard — Inspiration and design predecessor in JavaScript ecosystem; Standard's Ruby philosophy mirrors StandardJS's 'no config' approach

🪄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 LSP server diagnostic handling in lib/standard/lsp/diagnostic.rb

The LSP diagnostic module (lib/standard/lsp/diagnostic.rb) is critical for IDE integration but appears to lack dedicated unit tests. This is a core feature for the Ruby LSP addon. Adding tests would ensure diagnostic severity mapping, message formatting, and range calculations work correctly across different RuboCop violation types.

  • [ ] Create test/standard/lsp/diagnostic_test.rb with unit tests for diagnostic conversion
  • [ ] Test mapping of RuboCop severity levels to LSP DiagnosticSeverity constants
  • [ ] Test range calculation from RuboCop offense location data
  • [ ] Test filtering of diagnostics based on configuration
  • [ ] Verify integration with lib/standard/lsp/stdin_rubocop_runner.rb output

Add missing test coverage for plugin system in lib/standard/plugin/ directory

The plugin system (lib/standard/plugin/combines_plugin_configs.rb, creates_runner_context.rb, determines_class_constant.rb, initializes_plugins.rb) is central to extending Standard but test files appear minimal. This system needs robust tests since plugins like standard-rails depend on correct initialization and configuration merging.

  • [ ] Create test/standard/plugin/combines_plugin_configs_test.rb to verify config merging logic
  • [ ] Create test/standard/plugin/initializes_plugins_test.rb to test plugin instantiation with mocked plugins
  • [ ] Create test/standard/plugin/determines_class_constant_test.rb to test string-to-class resolution
  • [ ] Add edge case tests for conflicting plugin configurations
  • [ ] Test interaction with lib/standard/plugin.rb base plugin class

Add GitHub Actions workflow to test Standard against multiple Ruby versions with different RuboCop versions

The repo supports Ruby 1.8 through 3.4 (config/ruby-*.yml files exist) and depends on RuboCop, but the test.yml workflow likely doesn't test the matrix of Ruby versions × RuboCop versions. This is critical since config/base.yml and version-specific configs suggest version-dependent behavior.

  • [ ] Review current .github/workflows/test.yml to identify missing matrix dimensions
  • [ ] Add strategy.matrix for Ruby versions [2.7, 3.0, 3.1, 3.2, 3.3, 3.4]
  • [ ] Add strategy.matrix for RuboCop versions (current, latest-1, latest-2) to test compatibility
  • [ ] Ensure lib/standard/creates_config_store/sets_target_ruby_version.rb behavior is tested across all combinations
  • [ ] Verify config files in config/ directory apply correctly for each Ruby version

🌿Good first issues

  • Add test coverage for lib/standard/creates_config_store/assigns_rubocop_yaml.rb—no test file visible in structure for this critical config assignment logic.
  • Document plugin development workflow in docs/ with a full example (currently docs/ARCHITECTURE.md exists but lacks concrete plugin scaffolding steps and lint_roller integration examples).
  • Add Ruby 3.5 config file (config/ruby-3.5.yml) with forward compatibility rules, following the pattern of existing ruby-3.4.yml, when Ruby 3.5 stabilizes.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 697036e — Merge pull request #804 from standardrb/dependabot/github_actions/step-security/harden-runner-2.18.0 (jasonkarns)
  • 4395612 — Bump step-security/harden-runner from 2.14.1 to 2.18.0 (dependabot[bot])
  • b83a805 — Merge pull request #803 from standardrb/dependabot/bundler/rake-13.4.2 (jasonkarns)
  • cd05aad — Bump rake from 13.3.1 to 13.4.2 (dependabot[bot])
  • ae9a02b — Merge pull request #793 from standardrb/dependabot/bundler/ruby-lsp-0.26.8 (jasonkarns)
  • e122dbc — Merge pull request #795 from standardrb/dependabot/bundler/json-2.19.2 (jasonkarns)
  • 1b155ec — Bump json from 2.18.0 to 2.19.2 (dependabot[bot])
  • 515e20c — Bump ruby-lsp from 0.26.7 to 0.26.8 (dependabot[bot])
  • 0fa2bfd — Merge pull request #790 from standardrb/dependabot/bundler/ruby-lsp-0.26.7 (jasonkarns)
  • b98308a — Bump ruby-lsp from 0.26.6 to 0.26.7 (dependabot[bot])

🔒Security observations

The Standard gem codebase demonstrates generally good security practices as a linter/formatter tool. Primary concerns are around dynamic YAML loading, potential command injection in CLI/LSP components, and plugin system governance. No hardcoded credentials were detected. The project uses RuboCop as its foundation, which is well-maintained. Recommendations focus on input validation, safer deserialization, and plugin security documentation. The tool itself has low attack surface as it's primarily a development-time linter, but secure practices should still be enforced given its use in build pipelines.

  • Medium · Potential Command Injection in LSP/CLI Components — lib/standard/lsp/stdin_rubocop_runner.rb, lib/standard/cli.rb. The codebase includes LSP server functionality and CLI tools that parse user input and interact with external tools (RuboCop). While no explicit code is visible, the presence of lib/standard/lsp/stdin_rubocop_runner.rb suggests stdin/stdout handling that could be vulnerable to injection if user-supplied paths or options are not properly sanitized. Fix: Ensure all user inputs are properly sanitized before passing to shell commands. Use Ruby's subprocess APIs (Kernel.spawn, Open3) with array syntax rather than shell string interpolation. Implement strict validation for file paths and configuration options.
  • Medium · Dynamic YAML Configuration Loading — lib/standard/loads_yaml_config.rb, lib/standard/creates_config_store/assigns_rubocop_yaml.rb. The codebase loads YAML configuration files from multiple sources (lib/standard/loads_yaml_config.rb, lib/standard/creates_config_store/assigns_rubocop_yaml.rb). YAML parsing can be vulnerable to arbitrary code execution if untrusted YAML is deserialized without proper restrictions. Fix: Use YAML.safe_load() with explicit permitted_classes and symbols parameters instead of YAML.load(). Ensure all configuration sources are trusted and validated before parsing.
  • Low · Missing Security Headers Documentation — lib/standard/lsp/server.rb. No evidence of security configuration documentation for the LSP server (lib/standard/lsp/server.rb). If this is exposed as a network service, it may lack proper authentication, TLS, or other security headers. Fix: Document security model for LSP server. Ensure it validates client connections, implements proper authentication if exposed over network, and uses TLS for encrypted communication.
  • Low · Plugin System Without Explicit Integrity Verification — lib/standard/plugin/initializes_plugins.rb, lib/standard/plugin/determines_class_constant.rb. The plugin system (lib/standard/plugin/ directory) dynamically loads and initializes third-party plugins. While using lint_roller is good practice, there's no visible signature verification or checksum validation for plugin integrity. Fix: Document plugin security model. Consider implementing plugin signature verification or requiring plugins to come from trusted sources only. Audit plugin dependencies regularly.
  • Low · GitHub Workflow Execution Without Visible Security Controls — .github/workflows/test.yml, .github/workflows/update.yml. .github/workflows files are present but content not provided. GitHub Actions workflows can be vulnerable to supply chain attacks if they use untrusted actions or run with excessive permissions. Fix: Review GitHub Actions workflows to ensure: (1) actions use pinned versions with commit SHAs, (2) workflows run with minimal required permissions, (3) secrets are properly scoped, (4) no sensitive data is logged.

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 · standardrb/standard — RepoPilot