Antipattern Prevention
doorkeeper-gem/doorkeeper
Avoid common Ruby and Rails antipatterns that degrade maintainability and performance.
A skill your agent uses when writing or refactoring plain Ruby outside Rails — scripts, CLIs, gems, libraries: Enumerable chains and blocks, module mixins and value objects, Bundler/gemspec…
$ npx skills add ericrisco/rsc-harness --skill ruby -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install ericrisco/rsc-harness ruby --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/ruby .claude/skills/ruby && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "ruby" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/ruby into .claude/skills/ruby/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ruby", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/ericrisco/rsc-harness/tree/main/skills/rubyType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add ericrisco/rsc-harness --skill ruby -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install ericrisco/rsc-harness ruby --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/ruby .agents/skills/ruby && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "ruby" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/ruby into .agents/skills/ruby/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ruby", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ericrisco/rsc-harness --skill ruby -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install ericrisco/rsc-harness ruby --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/ruby .cursor/skills/ruby && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "ruby" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/ruby into .cursor/skills/ruby/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ruby", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/ericrisco/rsc-harness.git --path skills/ruby--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add ericrisco/rsc-harness --skill ruby -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install ericrisco/rsc-harness ruby --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/ruby .gemini/skills/ruby && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "ruby" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/ruby into .gemini/skills/ruby/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ruby", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install ericrisco/rsc-harness rubyInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add ericrisco/rsc-harness --skill ruby -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/ruby .github/skills/ruby && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "ruby" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/ruby into .github/skills/ruby/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ruby", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ericrisco/rsc-harness --skill ruby -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install ericrisco/rsc-harness ruby --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/ruby .opencode/skills/ruby && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "ruby" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/ruby into .opencode/skills/ruby/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ruby", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
rubyA skill your agent uses when writing or refactoring plain Ruby outside Rails — scripts, CLIs, gems, libraries: Enumerable chains and blocks, module mixins and value objects, Bundler/gemspec…
Ruby is an agent skill from ericrisco/rsc-harness. Use when writing or refactoring plain Ruby outside Rails — scripts, CLIs, gems, libraries: Enumerable chains and blocks, module mixins and value objects, Bundler/gemspec packaging, whether metaprogramming earns its keep, Minitest or RSpec, Ruby 3.4/4.0 frozen-string hygiene. NOT Rails, ActiveRecord, or ActiveSupport idioms (that is rails).
Its SKILL.md is about 3.2k tokens, which your agent loads only when the skill is triggered. The skill folder holds 8 other files, including scripts and reference files (for example `evals/README.md`, `evals/cases.yaml` and `references/gems-and-testing.md`).
It sits in Development, covering Backend development, ORMs and data access and Refactoring. It works with Ruby and Ruby on Rails. The repository describes itself as: Your agent invents things because it has no memory, and can't touch your database because it has no arms. rsc is the meta-harness that gives it both, plus the trade to know the… The licence is MIT.
6 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 92fde8f. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships 1 file in scripts/ (Shell), which the agent can run.
Shell commands in SKILL.md call:
bundlegemFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Ruby loads about 3.2k tokens when it runs, and up to ~5.9k if it reads all its reference files. Until then it costs about 87 tokens; SKILL.md has 1,136 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.
The full file from ericrisco/rsc-harness at commit 92fde8f, republished under its MIT licence (© ericrisco). 1,136 words, ~3,180 tokens.
.claude/skills/ruby/SKILL.md (or your agent's skills folder). This skill also uses 5 other files; get the full folder from GitHub.Write Ruby a senior Rubyist would sign off on: expression-oriented, block-driven,
leaning on Enumerable and Comparable instead of hand-rolled loops, with
frozen_string_literal hygiene and a real Gemfile/.gemspec when you package.
This is Ruby the language and its non-Rails ecosystem — blocks, modules, gems,
metaprogramming, Minitest/RSpec. Delegate: Rails apps, ActiveRecord models, controllers,
migrations, views, Hotwire — anything that loads Rails or uses ActiveSupport/ActiveRecord
idioms — to rails; the same task in another language to
python, go, rust,
elixir, php or
typescript; the CI pipeline that runs your Ruby tests to
github-actions — this skill writes the tests, not the workflow.
Targets Ruby 4.0 (released 2025-12-25) on 3.4 semantics: Prism is the default
parser, string literals warn on mutation without a magic comment, it is an implicit
block param, and Set is now a core class.
Internalize these before writing a line:
if, case, blocks, method
bodies all yield a value — name and return it instead of threading a flag.5.times, nil.to_a, "x".freeze.
There are no primitives to special-case.Enumerable before you write a loop. A manual index loop in Ruby is
almost always a map/select/reduce you have not spotted yet.# frozen_string_literal: true.Struct, or a Data does the job, use that.Blocks are the spine of Ruby. A method takes a block implicitly via yield, or
explicitly with &block when it must store or forward it.
# frozen_string_literal: true
# Implicit: yield runs the caller's block and returns its value.
def with_timing
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
result = yield
[result, Process.clock_gettime(Process::CLOCK_MONOTONIC) - start]
end
# Explicit: capture the block as a Proc to forward or store it.
def retrying(times, &block)
attempts = 0
begin
block.call
rescue StandardError
(attempts += 1) < times ? retry : raise
end
endproc vs lambda differ in two ways that bite:
| Aspect | proc / block | lambda / -> |
|---|---|---|
| Arity | Lenient — extra args dropped, missing become nil | Strict — wrong count raises ArgumentError |
return | Returns from the enclosing method (can surprise) | Returns from the lambda only |
Rule: use a lambda for a function-like value you call yourself; use a block/proc
for the "do this with each element" pattern. For cheap accumulation prefer
each_with_object (returns the seed) or reduce; use tap (returns the receiver) for
side effects and then for piping a value through a transform.
# Bad: index loop building a result by mutation.
result = []
(0...items.length).each { |i| result << items[i].upcase if items[i].size > 3 }
# Good: intent reads top-to-bottom, no index, no pre-seeded array.
result = items.select { |s| s.size > 3 }.map(&:upcase)Most loops map to one named method. Pick by intent, not by habit:
| You want to… | Use |
|---|---|
| Transform every element | map |
| Keep / drop by predicate | select / reject |
| Fold into one value | reduce / sum / min_by |
| Build a Hash or accumulate into a seed | each_with_object |
| Count occurrences | tally |
| Bucket by a key | group_by |
| First match | find (detect) |
| Pair index with element | each_with_index |
Make your own classes first-class collections by including Enumerable and defining
each; get <, >, between?, clamp, sort for free by including Comparable and
defining <=>.
# frozen_string_literal: true
class Playlist
include Enumerable
def initialize(tracks) = @tracks = tracks
def each(&) = @tracks.each(&) # one method unlocks map/select/sort/...
end
class Version
include Comparable
attr_reader :major, :minor
def initialize(major, minor)
@major = major
@minor = minor
end
def <=>(other) = [major, minor] <=> [other.major, other.minor]
endRuby favors composition through mixins over deep inheritance.
include M — adds M's instance methods to instances (the default mixin).prepend M — inserts M before the class in the lookup chain, so M's methods can
wrap the originals via super (cleaner than aliasing for decoration).extend M — adds M's methods as class/singleton methods.Rule: reach for a module mixin when the same behavior is shared across unrelated
classes; reserve inheritance for a genuine is-a hierarchy. Namespace with module Foo
to avoid global constant clashes. Need to patch a class without polluting it globally?
Use a refinement (refine … using) — a scoped, reversible scalpel — never a bare
monkey-patch. Full refinement scoping and prepend-wrapping in
references/metaprogramming.md.
# frozen_string_literal: true
Point = Data.define(:x, :y) # immutable value object (Ruby 3.2+)
origin = Point.new(x: 0, y: 0) # no setters; with(x: 1) returns a copy
Cursor = Struct.new(:x, :y) # mutable; has setters and is Enumerable| Need | Reach for |
|---|---|
Immutable value with equality + with | Data.define |
| Mutable record, or array/positional access | Struct.new |
Default to Data for value semantics; pick Struct only when you genuinely need
mutation or positional/to_a behavior.
Decision rule, in order: could a plain method, a Struct, or a Data do this?
If yes, do that. Only when the method names themselves are dynamic (driven by data or
config) does metaprogramming earn its keep.
define_method (defines real, introspectable methods) over method_missing
(intercepts at call time, slower, invisible to respond_to? and tooling).method_missing, you must also define respond_to_missing? —
otherwise respond_to?, method, and duck-typing all lie about your object.eval a string built from user input.# Good: dynamic method names, but real methods that introspect and document themselves.
class Config
def initialize(**data) = @data = data
%i[host port timeout].each do |key|
define_method(key) { @data[key] }
define_method("#{key}=") { |value| @data[key] = value }
end
endBuilding a real DSL, instance_eval/class_eval, and the full
method_missing + respond_to_missing? pairing live in
references/metaprogramming.md.
Bundler is the universal dependency manager. bundle init creates a Gemfile;
bundle install resolves and writes Gemfile.lock; run project binaries with
bundle exec so they use the locked versions.
~> 2.3 (allows 2.x >= 2.3, blocks 3.0) for
libraries; pin tighter only when forced.Gemfile.lock for applications (reproducible installs); for a library
gem, do not commit the lock — let consumers resolve.bundle gem NAME, which generates the lib/, test//spec/,
.gemspec, and Rakefile layout.# my_gem.gemspec
Gem::Specification.new do |spec|
spec.name = "my_gem"
spec.version = MyGem::VERSION # SemVer: MAJOR.MINOR.PATCH
spec.summary = "One-line description."
spec.authors = ["You"]
spec.files = Dir["lib/**/*.rb"]
spec.required_ruby_version = ">= 3.4"
spec.add_dependency "thor", "~> 1.3"
endFull bundle gem tree, publishing flow (gem build / gem push), and Rake test tasks
are in references/gems-and-testing.md.
# frozen_string_literal: true # without it, 3.4+ warns under -W:deprecated on mutation
nums.map { it * 2 } # `it` is the implicit single block param (3.4+)
seen = Set.new([1, 2, 3]) # Set is a core class in 4.0 — no `require "set"`FrozenError. This is the cause of most "my string froze after upgrading" reports.it reads cleaner than _1 for one-arg blocks.Ractor.yield/Ractor#take in favor of Ractor::Port.Both ship a clean path; choose by ceremony tolerance:
| Framework | Pick when… |
|---|---|
| Minitest | You want the default — ships with Ruby, tiny surface, assert-style or spec-style, fast. |
| RSpec | You want the expressive DSL and large ecosystem (describe/context/it/expect, let, mocks). |
# test/tally_test.rb (Minitest)
require "minitest/autorun"
require "tally"
class TallyTest < Minitest::Test
def test_counts_words
assert_equal({ "a" => 2, "b" => 1 }, Tally.count("a b a"))
end
end# spec/tally_spec.rb (RSpec)
RSpec.describe Tally do
subject(:counts) { described_class.count("a b a") }
it { is_expected.to eq("a" => 2, "b" => 1) }
endRun via bundle exec rake test (Minitest) or bundle exec rspec (RSpec). Fuller
examples with let/subject/context are in
references/gems-and-testing.md.
.rubocop.yml, every cop opt-in/out) when the team wants control..rbs
files, checked by Steep) and Sorbet (inline sig blocks, with experimental
inline-RBS-comment support). Add types only on a library's public surface or a hot,
bug-prone core — not on throwaway scripts. RuboCop vs Standard config sits in
references/gems-and-testing.md.| Anti-pattern | Why it bites | Do instead |
|---|---|---|
| Monkey-patching a core class globally | Action-at-a-distance; collides with gems and future Ruby | A refinement (scoped) or a wrapper/helper |
method_missing without respond_to_missing? | respond_to?/method/duck-typing all lie | Pair them, or prefer define_method |
| Mutating a frozen string literal | FrozenError after the magic comment | dup before mutating, or build a new string |
for x in coll loops | Leaks the loop var; un-idiomatic | coll.each/map/select |
rescue Exception (bare) | Swallows SignalException, NoMemoryError, exit | rescue StandardError (or specific classes) |
Not committing Gemfile.lock for an app | Non-reproducible installs across machines | Commit it for apps; omit only for library gems |
eval of user-derived input | Remote code execution | Parse explicitly; never eval untrusted data |
| Over-DSLing config a Hash would serve | Hidden control flow, slow method_missing | A plain Hash or Data object |
© ericrisco, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 5 other files (scripts, references) in skills/ruby of ericrisco/rsc-harness.
Open the folder on GitHubat commit 92fde8f
Ruby next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Ruby this skillericrisco/rsc-harness | 156 | — | ~3.2k | Automated safety check: Pass | MIT | |
| Antipattern Preventiondoorkeeper-gem/doorkeeper | 5.5k | — | ~1.1k | Automated safety check: Pass | MIT | |
| Ruby Patternssoftspark/ai-toolkit | 179 | — | ~2.3k | Automated safety check: Pass | Apache-2.0 | |
| Ruby Rulessoftspark/ai-toolkit | 179 | — | ~3.4k | Automated safety check: Pass | Apache-2.0 | |
| Rails Hotwirepproenca/dot-skills | 214 | — | ~2.3k | Automated safety check: Pass | MIT | |
| Ruby Optimisepproenca/dot-skills | 214 | — | ~1.7k | Automated safety check: Pass | MIT |
doorkeeper-gem/doorkeeper
Avoid common Ruby and Rails antipatterns that degrade maintainability and performance.
softspark/ai-toolkit
Ruby/Rails: blocks, metaprogramming, ActiveRecord, Sidekiq, RSpec, Sorbet, Hanami.
softspark/ai-toolkit
Ruby coding rules: style, patterns, security, testing. An agent skill from softspark/ai-toolkit.
pproenca/dot-skills
Ruby on Rails Hotwire best practices for building interactive applications with Turbo Drive, Turbo Frames, Turbo Streams, Turbo 8 morphing, and Stimulus controllers.
pproenca/dot-skills
Ruby performance optimization guidelines. An agent skill from pproenca/dot-skills.
Jeffallan/claude-skills
Builds Rails 7+ apps with Hotwire Turbo Frames and Streams, Active Record tuning, Action Cable, Sidekiq jobs and RSpec specs, with migration and N+1 checks.
ericrisco/rsc-harness
A skill your agent uses when designing or analyzing a controlled experiment — falsifiable hypothesis, sample size from an MDE, reading significance/CI/power, CUPED, or rescuing tests that won't go…
ericrisco/rsc-harness
A skill your agent uses when making a web UI conform to WCAG 2.2 Level AA — axe-core or Lighthouse a11y violations, keyboard operability, focus management, ARIA roles/names/live regions, contrast…
ericrisco/rsc-harness
A skill your agent uses when running or fixing paid acquisition on Google or Meta — campaign structure (Performance Max, Demand Gen, Search, Advantage+), platform-fit creative, budget/scaling rules…
ericrisco/rsc-harness
A skill your agent uses when measuring whether an LLM or agent system actually got better and gating merges on it: golden sets, fixing an inflated LLM-as-judge, scoring RAG (faithfulness, contextual…
ericrisco/rsc-harness
A skill your agent uses when a creative goal must become a finished media file: pick and order generative-media models per modality — AI voiceover, image-to-video clips, score — then glue them with…
ericrisco/rsc-harness
A skill your agent uses when instrumenting product or web analytics — GA4/PostHog SDK wiring, event taxonomy, funnels, double-counted events, consent gating, PII scrubbing.
Works with
Categories
A skill your agent uses when writing or refactoring plain Ruby outside Rails — scripts, CLIs, gems, libraries: Enumerable chains and blocks, module mixins and value objects, Bundler/gemspec…. Ruby is an agent skill from ericrisco/rsc-harness.0 frozen-string hygiene.
Ruby fits situations like: refactoring plain Ruby outside Rails — scripts; libraries: Enumerable chains and blocks; module mixins and value objects; bundler/gemspec packaging.
Run `npx skills add ericrisco/rsc-harness --skill ruby -a claude-code`. Or copy the skill folder (skills/ruby in ericrisco/rsc-harness) into .claude/skills/ruby in your project. Claude Code loads it when a task matches its description.
Run `npx skills add ericrisco/rsc-harness --skill ruby -a codex`. Or copy the skill folder (skills/ruby in ericrisco/rsc-harness) into .agents/skills/ruby in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ericrisco/rsc-harness --skill ruby -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/ruby, .gemini/skills/ruby, .github/skills/ruby and .opencode/skills/ruby in your project.
Going by SKILL.md and its folder, Ruby needs a shell for the scripts in its folder and the command-line tools its instructions call (bundle and gem). Our summary lists: A Bash shell.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.
Ruby is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.2k tokens (SKILL.md is roughly 13k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 2.7k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Ruby: Antipattern Prevention (doorkeeper-gem/doorkeeper, 5.5k stars), Ruby Patterns (softspark/ai-toolkit, 179 stars), Ruby Rules (softspark/ai-toolkit, 179 stars) and Rails Hotwire (pproenca/dot-skills, 214 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
ericrisco (a GitHub user) maintains it in ericrisco/rsc-harness, which has 156 GitHub stars. The repository holds 229 skills in this directory. The repository was last updated on October 6, 2026.
Source: ericrisco/rsc-harness on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.