Agent skill

Openrouter Routing Rules

by jeremylongshore in jeremylongshore/tons-of-skills-marketplace

Define custom routing rules for OpenRouter requests based on user tier, task type, cost budget, and availability.

MITAuto-check passedAI & LLM Engineering

Install Openrouter Routing Rules

skills CLI
$ npx skills add jeremylongshore/tons-of-skills-marketplace --skill openrouter-routing-rules -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install jeremylongshore/tons-of-skills-marketplace openrouter-routing-rules --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/jeremylongshore/tons-of-skills-marketplace.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/.curated/openrouter-routing-rules .claude/skills/openrouter-routing-rules && rm -rf skills-src

Use ~/.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/

Facts

Skill name
openrouter-routing-rules
GitHub stars
2.8k
Token cost
~2.8k tokens
SKILL.md length
465 words
Files
8 (incl. references)
Skills in repo
3,342
Repo updated
First seen
Licence
MIT

At a glance

Define custom routing rules for OpenRouter requests based on user tier, task type, cost budget, and availability.

  • Works in 6 steps: Model each request's metadata as a… → Define RoutingRule entries in priority… → Resolve the winning rule with… → …
  • Tasks that involve Model routing and gateways
  • SKILL.md covers Overview, Prerequisites, Instructions and Rules Engine, plus 8 more sections
  • Reaches openrouter.ai; needs OPENROUTER_API_KEY

What it does

Openrouter Routing Rules is an agent skill from jeremylongshore/tons-of-skills-marketplace. Define custom routing rules for OpenRouter requests based on user tier, task type, cost budget, and availability. Triggers: 'openrouter rules', 'routing rules', 'custom routing openrouter', 'conditional model selection'.

Its SKILL.md is about 2.8k tokens, which your agent loads only when the skill is triggered. The skill folder holds 8 other files, including reference files (for example `references/basic-routing-strategies.md`, `references/cost-aware-routing.md` and `references/errors.md`). Compatibility notes: Designed for Claude Code

It sits in AI & LLM Engineering, covering Model routing and gateways. It works with OpenRouter. The repository describes itself as: Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com. The licence is MIT.

When your agent uses it

  • Tasks that involve Model routing and gateways

Example prompts

  • “openrouter rules”
  • “routing rules”
  • “custom routing openrouter”
  • “/openrouter-routing-rules”

Requirements

  • Python 3
  • A credential in OPENROUTER_API_KEY
  • Compatibility (from SKILL.md): Designed for Claude Code
  • Pre-approved tools (allowed-tools): Read, Write, Edit, Grep, Bash(python3:*)

Workflow steps

6 steps, taken from the first numbered list in SKILL.md.

  1. Model each request's metadata as a RoutingContext (user tier, task type, budget remaining, tools/vision flags, latency SLA) per Rules…
  2. Define RoutingRule entries in priority order — free-tier first, then budget, capability (tools/vision), task type, latency, and always a…
  3. Resolve the winning rule with evaluate_rules(ctx): first match by ascending priority wins; failing conditions return False instead of…
  4. Execute through routed_completion() per Routed Completion — it applies the rule's model, fallback chain (models + route: "fallback"), and…
  5. To make rules hot-reloadable, express them as JSON per Config-Driven Rules and match with match_config_rule() instead of lambdas.
  6. Validate any rule change on a slice of traffic with ab_test_routing() per A/B Testing Rules before full rollout.

What it can do on your machine

Read from SKILL.md and the folder at commit cfae287. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves these tools, so the agent can use them without asking each time:

    • Read
    • Write
    • Edit
    • Grep
    • Bash(python3:*)

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are python).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • openrouter.ai

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names these keys or tokens, usually read from environment variables:

    • OPENROUTER_API_KEY

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

  • Compatibility

    Designed for Claude Code

    From compatibility in the SKILL.md frontmatter.

Context cost

Openrouter Routing Rules loads about 2.8k tokens when it runs, and up to ~9k if it reads all its reference files. Until then it costs about 61 tokens; SKILL.md has 465 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~61
When it runs · the whole SKILL.md, loaded when a task matches
~2.8k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~9k

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.

Safety

Auto-check passed

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); files beside SKILL.md are not scanned.

SKILL.md

The full file from jeremylongshore/tons-of-skills-marketplace at commit cfae287, republished under its MIT licence (© jeremylongshore). 465 words, ~2,780 tokens.

Download SKILL.mdSave it as .claude/skills/openrouter-routing-rules/SKILL.md (or your agent's skills folder). This skill also uses 7 other files; get the full folder from GitHub.
name
openrouter-routing-rules
description
Define custom routing rules for OpenRouter requests based on user tier, task type, cost budget, and availability. Triggers: 'openrouter rules', 'routing rules', 'custom routing openrouter', 'conditional model selection'.
allowed-tools
Read, Write, Edit, Grep, Bash(python3:*)
compatibility
Designed for Claude Code
version
1.20.0
license
MIT
author
Jeremy Longshore <jeremy@intentsolutions.io>
tags
saas, openrouter, routing, rules-engine

OpenRouter Routing Rules

Overview

Beyond simple task-based model selection, production systems need configurable routing rules that consider user tier, cost budget, time of day, model availability, and feature requirements. This skill covers building a rules engine for OpenRouter model selection with config-driven rules, dynamic conditions, and override capabilities.

Prerequisites

  • An OpenRouter API key (sk-or-v1-...) exported as OPENROUTER_API_KEY — see the openrouter-install-auth skill for setup
  • Python 3.8+ with the OpenAI SDK — the rules engine itself is stdlib (dataclasses, json, random) layered on top
  • Per-request metadata available in your app: user tier, task type, remaining budget, tool/vision needs, latency SLA (the RoutingContext fields)
  • Budget tracking wired up (see openrouter-cost-controls) if you use budget-conditioned rules like low-budget

Instructions

  1. Model each request's metadata as a RoutingContext (user tier, task type, budget remaining, tools/vision flags, latency SLA) per Rules Engine.
  2. Define RoutingRule entries in priority order — free-tier first, then budget, capability (tools/vision), task type, latency, and always a priority=99 default catch-all.
  3. Resolve the winning rule with evaluate_rules(ctx): first match by ascending priority wins; failing conditions return False instead of raising.
  4. Execute through routed_completion() per Routed Completion — it applies the rule's model, fallback chain (models + route: "fallback"), and max_tokens.
  5. To make rules hot-reloadable, express them as JSON per Config-Driven Rules and match with match_config_rule() instead of lambdas.
  6. Validate any rule change on a slice of traffic with ab_test_routing() per A/B Testing Rules before full rollout.

Rules Engine

python
import os, json, time
from dataclasses import dataclass
from typing import Optional, Callable
from openai import OpenAI

client = OpenAI(
    base_url="https://openrouter.ai/api/v1",
    api_key=os.environ["OPENROUTER_API_KEY"],
    default_headers={"HTTP-Referer": "https://my-app.com", "X-Title": "my-app"},
)

@dataclass
class RoutingContext:
    user_tier: str = "free"        # "free" | "basic" | "pro" | "enterprise"
    task_type: str = "general"     # "chat" | "code" | "analysis" | "classification"
    budget_remaining: float = 0.0  # Remaining daily budget in dollars
    prompt_tokens_est: int = 0     # Estimated prompt tokens
    needs_tools: bool = False      # Requires function calling
    needs_vision: bool = False     # Requires image input
    max_latency_ms: int = 30000    # Latency SLA

@dataclass
class RoutingRule:
    name: str
    priority: int                  # Lower = higher priority
    condition: Callable[[RoutingContext], bool]
    model: str
    fallbacks: list[str] = None
    max_tokens: int = 1024

    def matches(self, ctx: RoutingContext) -> bool:
        try:
            return self.condition(ctx)
        except Exception:
            return False

# Define rules in priority order
RULES = [
    # Rule 1: Free users get free models only
    RoutingRule(
        name="free-tier",
        priority=1,
        condition=lambda ctx: ctx.user_tier == "free",
        model="google/gemma-2-9b-it:free",
        fallbacks=["meta-llama/llama-3.1-8b-instruct"],
        max_tokens=512,
    ),
    # Rule 2: Low budget → cheap models
    RoutingRule(
        name="low-budget",
        priority=2,
        condition=lambda ctx: ctx.budget_remaining < 1.0 and ctx.user_tier != "enterprise",
        model="openai/gpt-4o-mini",
        fallbacks=["meta-llama/llama-3.1-8b-instruct"],
        max_tokens=512,
    ),
    # Rule 3: Tool calling required → tool-capable models
    RoutingRule(
        name="tools-required",
        priority=3,
        condition=lambda ctx: ctx.needs_tools,
        model="openai/gpt-4o",
        fallbacks=["anthropic/claude-3.5-sonnet"],
    ),
    # Rule 4: Vision required
    RoutingRule(
        name="vision-required",
        priority=4,
        condition=lambda ctx: ctx.needs_vision,
        model="openai/gpt-4o",
        fallbacks=["anthropic/claude-3.5-sonnet", "google/gemini-2.0-flash-001"],
    ),
    # Rule 5: Code tasks → Claude
    RoutingRule(
        name="code-tasks",
        priority=5,
        condition=lambda ctx: ctx.task_type == "code",
        model="anthropic/claude-3.5-sonnet",
        fallbacks=["openai/gpt-4o"],
    ),
    # Rule 6: Latency-sensitive → fast models
    RoutingRule(
        name="low-latency",
        priority=6,
        condition=lambda ctx: ctx.max_latency_ms < 3000,
        model="openai/gpt-4o-mini",
        fallbacks=["anthropic/claude-3-haiku"],
    ),
    # Rule 7: Enterprise gets premium
    RoutingRule(
        name="enterprise-default",
        priority=7,
        condition=lambda ctx: ctx.user_tier == "enterprise",
        model="anthropic/claude-3.5-sonnet",
        fallbacks=["openai/gpt-4o", "openai/gpt-4o-mini"],
    ),
    # Rule 8: Default catch-all
    RoutingRule(
        name="default",
        priority=99,
        condition=lambda ctx: True,  # Always matches
        model="openai/gpt-4o-mini",
        fallbacks=["meta-llama/llama-3.1-8b-instruct"],
    ),
]

def evaluate_rules(ctx: RoutingContext) -> RoutingRule:
    """Find the first matching rule (sorted by priority)."""
    sorted_rules = sorted(RULES, key=lambda r: r.priority)
    for rule in sorted_rules:
        if rule.matches(ctx):
            return rule
    return sorted_rules[-1]  # Default catch-all

Config-Driven Rules (JSON)

python
RULES_CONFIG = {
    "rules": [
        {
            "name": "free-tier",
            "priority": 1,
            "conditions": {"user_tier": "free"},
            "model": "google/gemma-2-9b-it:free",
            "max_tokens": 512,
        },
        {
            "name": "code-pro",
            "priority": 5,
            "conditions": {"task_type": "code", "user_tier": ["pro", "enterprise"]},
            "model": "anthropic/claude-3.5-sonnet",
            "max_tokens": 2048,
        },
        {
            "name": "default",
            "priority": 99,
            "conditions": {},
            "model": "openai/gpt-4o-mini",
        },
    ]
}

def match_config_rule(ctx: RoutingContext, rule_config: dict) -> bool:
    """Match a context against config-driven conditions."""
    conditions = rule_config.get("conditions", {})
    for key, expected in conditions.items():
        actual = getattr(ctx, key, None)
        if isinstance(expected, list):
            if actual not in expected:
                return False
        elif actual != expected:
            return False
    return True

Routed Completion

python
def routed_completion(messages: list[dict], ctx: RoutingContext, **kwargs):
    """Execute completion with rule-based routing."""
    rule = evaluate_rules(ctx)

    extra_body = {}
    if rule.fallbacks:
        extra_body = {
            "models": [rule.model] + rule.fallbacks,
            "route": "fallback",
        }

    response = client.chat.completions.create(
        model=rule.model,
        messages=messages,
        max_tokens=rule.max_tokens,
        extra_body=extra_body or None,
        **kwargs,
    )

    return {
        "content": response.choices[0].message.content,
        "model": response.model,
        "rule": rule.name,
        "tokens": response.usage.prompt_tokens + response.usage.completion_tokens,
    }

# Usage
ctx = RoutingContext(user_tier="pro", task_type="code", budget_remaining=50.0)
result = routed_completion(
    [{"role": "user", "content": "Refactor this function..."}],
    ctx=ctx,
)
print(f"Rule: {result['rule']}, Model: {result['model']}")

A/B Testing Rules

python
import random

def ab_test_routing(ctx: RoutingContext, test_name: str, variant_b_pct: float = 0.10):
    """Route a percentage of traffic to variant B for comparison."""
    rule = evaluate_rules(ctx)

    if random.random() < variant_b_pct:
        # Variant B: try a different model
        return RoutingRule(
            name=f"{rule.name}:variant-b",
            priority=rule.priority,
            condition=rule.condition,
            model="openai/gpt-4o",  # Test against a different model
            fallbacks=rule.fallbacks,
            max_tokens=rule.max_tokens,
        )
    return rule

Output

  • A resolved RoutingRule per request — name, model, fallbacks, max_tokens — from evaluate_rules()
  • A completion result dict from routed_completion(): {content, model, rule, tokens}; the rule field makes every routing decision auditable
  • A JSON rules config (Config-Driven Rules) that can be hot-reloaded without redeployment
  • A/B variant assignments (<rule-name>:variant-b) for a configurable percentage of traffic
Show full SKILL.md (169 more words)Show less

Examples

A pro-tier code request falls through the free-tier, budget, tools, and vision rules and matches code-tasks:

python
ctx = RoutingContext(user_tier="pro", task_type="code", budget_remaining=50.0)
result = routed_completion([{"role": "user", "content": "Refactor this function..."}], ctx=ctx)
print(f"Rule: {result['rule']}, Model: {result['model']}")
# Rule: code-tasks, Model: anthropic/claude-3.5-sonnet

The same context with user_tier="free" matches the priority-1 free-tier rule instead, landing on google/gemma-2-9b-it:free capped at 512 tokens. More worked examples: references/examples.md.

Error Handling

ErrorCauseFix
No rule matchedMissing default catch-allAlways include a priority=99 default rule
Rule condition errorDynamic check raised exceptionWrap condition in try/catch; return False on error
Wrong model selectedRule priority incorrectLog matching rule name; review priority ordering
Config parse errorInvalid JSON rule definitionValidate config at startup; fail fast

Enterprise Considerations

  • Store rules in a config file or database for hot-reloading without redeployment
  • Log every routing decision (rule name, model, context) for analytics and debugging
  • Use A/B testing to validate rule changes before full rollout
  • Always include a default catch-all rule with a reliable, affordable model
  • Version your rule configurations and track changes alongside code deployments
  • Combine routing rules with budget enforcement (see openrouter-cost-controls)

References

© jeremylongshore, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 7 other files (references) in skills/.curated/openrouter-routing-rules of jeremylongshore/tons-of-skills-marketplace.

  • SKILL.md
  • references/basic-routing-strategies.md
  • references/cost-aware-routing.md
  • references/errors.md
  • references/examples.md
  • references/implementation.md
  • references/latency-aware-routing.md
  • references/rule-based-router.md

Open the folder on GitHubat commit cfae287

Compare with similar skills

Openrouter Routing Rules 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.

Openrouter Routing Rules compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Openrouter Routing Rules this skilljeremylongshore/tons-of-skills-marketplace2.8k—~2.8kAutomated safety check: PassMIT
Add Modelget-convex/convex-evals130—~1.5kAutomated safety check: NotesApache-2.0
To Imgrtadewald/skills185—~673Automated safety check: NotesNone
Openrouterdavidondrej/skills4.1k—~1.3kAutomated safety check: PassMIT
Openrouter Text2musicQinghongLin/data2story-skill155—~618Automated safety check: PassMIT
Fabrica Personagenscorosolto/client257—~1.6kAutomated safety check: NotesAGPL-3.0

Similar skills

  • Add Model

    get-convex/convex-evals

    Add a new model to the convex-evals coding leaderboard, and optionally the decision benchmark, through a PR, then dispatch its baseline runs.

    130 GitHub stars~1.5k tokensUpdated yesterday
    AI & LLM EngineeringAuto-check: notes
  • To Img

    rtadewald/skills

    Gera imagens em paralelo via OpenRouter a partir de um pedido simples ou de um batch com prompts e filenames definidos.

    185 GitHub stars~673 tokensUpdated 12 days ago
    AI & LLM EngineeringAuto-check: notes
  • Openrouter

    davidondrej/skills

    Design, build, debug, and optimize OpenRouter API integrations.

    4.1k GitHub stars~1.3k tokensUpdated today
    AI & LLM EngineeringAuto-check passed
  • Openrouter Text2music

    QinghongLin/data2story-skill

    Generate atmospheric sound-design / SFX (NOT speech, NOT the front-of-blog BGM) via OpenRouter using Google Lyria 3 Pro.

    155 GitHub stars~618 tokensUpdated 3 mo ago
    AI & LLM EngineeringAuto-check passed
  • Fabrica Personagens

    corosolto/client

    Fábrica de personagens e skins do CS BRASIL, da ficha ao personagem no jogo com avatar e arte de resultado.

    257 GitHub stars~1.6k tokensUpdated yesterday
    AI & LLM EngineeringAuto-check: notes
  • Openrouter Text2music

    QinghongLin/data2story-skill

    Generate music (NOT speech) via OpenRouter using Google Lyria 3 Pro.

    155 GitHub stars~407 tokensUpdated 3 mo ago
    AI & LLM EngineeringAuto-check passed

More from jeremylongshore/tons-of-skills-marketplace

All 3,342 skills in this repo
  • Performing Security Code Review

    jeremylongshore/tons-of-skills-marketplace

    Execute this skill enables AI assistant to conduct a security-focused code review using the security-agent plugin.

    2.8k GitHub starsUsed in 2 repos~1.3k tokens
    Auto-check: notes
  • Adapting Transfer Learning Models

    jeremylongshore/tons-of-skills-marketplace

    Build this skill automates the adaptation of pre-trained machine learning models using transfer learning techniques.

    2.8k GitHub stars~1.1k tokensUpdated today
    Auto-check passed
  • Agent Context Loader

    jeremylongshore/tons-of-skills-marketplace

    Execute proactive auto-loading: automatically detects and loads agents.md files.

    2.8k GitHub stars~1.1k tokensUpdated today
    Auto-check passed
  • Aggregating Performance Metrics

    jeremylongshore/tons-of-skills-marketplace

    Aggregate and centralize performance metrics from applications, systems, databases, caches, and services.

    2.8k GitHub stars~1.2k tokensUpdated today
    Auto-check passed
  • Analyzing Capacity Planning

    jeremylongshore/tons-of-skills-marketplace

    Execute this skill enables AI assistant to analyze capacity requirements and plan for future growth.

    2.8k GitHub stars~947 tokensUpdated today
    Auto-check passed
  • Analyzing Database Indexes

    jeremylongshore/tons-of-skills-marketplace

    Process use when you need to work with database indexing. An agent skill from jeremylongshore/tons-of-skills-marketplace.

    2.8k GitHub stars~2k tokensUpdated today
    Auto-check passed

Works with

Questions about Openrouter Routing Rules

What does Openrouter Routing Rules do?

Define custom routing rules for OpenRouter requests based on user tier, task type, cost budget, and availability. Openrouter Routing Rules is an agent skill from jeremylongshore/tons-of-skills-marketplace. Define custom routing rules for OpenRouter requests based on user tier, task type, cost budget, and availability.

When should I use Openrouter Routing Rules?

Openrouter Routing Rules fits situations like: tasks that involve Model routing and gateways.

How do I install Openrouter Routing Rules in Claude Code?

Run `npx skills add jeremylongshore/tons-of-skills-marketplace --skill openrouter-routing-rules -a claude-code`. Or copy the skill folder (skills/.curated/openrouter-routing-rules in jeremylongshore/tons-of-skills-marketplace) into .claude/skills/openrouter-routing-rules in your project. Claude Code loads it when a task matches its description.

How do I install Openrouter Routing Rules in Codex?

Run `npx skills add jeremylongshore/tons-of-skills-marketplace --skill openrouter-routing-rules -a codex`. Or copy the skill folder (skills/.curated/openrouter-routing-rules in jeremylongshore/tons-of-skills-marketplace) into .agents/skills/openrouter-routing-rules in your project. Codex loads it when a task matches its description.

Can I use Openrouter Routing Rules in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add jeremylongshore/tons-of-skills-marketplace --skill openrouter-routing-rules -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/openrouter-routing-rules, .gemini/skills/openrouter-routing-rules, .github/skills/openrouter-routing-rules and .opencode/skills/openrouter-routing-rules in your project.

What does Openrouter Routing Rules need to run?

Going by SKILL.md and its folder, Openrouter Routing Rules needs credentials named OPENROUTER_API_KEY. Our summary lists: Python 3; A credential in OPENROUTER_API_KEY. Its frontmatter pre-approves these tools: Read, Write, Edit, Grep, Bash(python3:*). Compatibility (from SKILL.md): Designed for Claude Code.

Does Openrouter Routing Rules access the network?

SKILL.md names 1 domain. In commands or code: openrouter.ai; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.

Is Openrouter Routing Rules safe to install?

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. Review the folder before installing.

What licence does Openrouter Routing Rules use?

Openrouter Routing Rules is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Openrouter Routing Rules use?

About 2.8k tokens (SKILL.md is roughly 11k 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 6.2k tokens, read only when the agent opens those files.

What are the alternatives to Openrouter Routing Rules?

Skills that share tags, products or a category with Openrouter Routing Rules: Add Model (get-convex/convex-evals, 130 stars), To Img (rtadewald/skills, 185 stars), Openrouter (davidondrej/skills, 4.1k stars) and Openrouter Text2music (QinghongLin/data2story-skill, 155 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Openrouter Routing Rules?

jeremylongshore (a GitHub user) maintains it in jeremylongshore/tons-of-skills-marketplace, which has 2,827 GitHub stars. The repository holds 3,342 skills in this directory. The repository was last updated on October 10, 2026.

Source: jeremylongshore/tons-of-skills-marketplace on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.