mlb-player-analyzer

$npx mdskill add lyndonkl/claude/mlb-player-analyzer

Analyze MLB players using web data to generate structured signals.

  • Helps agents compute daily quality and regression indices for lineup decisions.
  • Integrates FanGraphs, Baseball Savant, MLB.com, RotoWire, and RotoBaller.
  • Decides recommendations by cross-referencing projections, splits, and injury reports.
  • Delivers structured scores for hitters and pitchers via the signal framework.

SKILL.md

.github/skills/mlb-player-analyzerView on GitHub ↗
---
name: mlb-player-analyzer
description: Deep-dive analysis of a single MLB player (hitter or pitcher) for the Yahoo Fantasy Baseball 2K25 league. Web-searches FanGraphs (ATC projections), Baseball Savant (xwOBA/xBA/xERA), MLB.com (lineups, probables), RotoWire (weather, injuries), and RotoBaller (closer depth) to produce the full set of structured player signals defined in the signal framework. Emits form_score, matchup_score, opportunity_score, daily_quality, regression_index, obp_contribution, sb_opportunity, role_certainty for hitters and qs_probability, k_ceiling, era_whip_risk, streamability_score, two_start_bonus, save_role_certainty for pitchers. Use when you need to analyze player, compute daily_quality, compute regression index, produce player signals, run a hitter analysis, run a pitcher analysis, or prep start/sit inputs for the lineup optimizer.
---

# MLB Player Analyzer

## Table of Contents
- [Example](#example)
- [Workflow](#workflow)
- [Common Patterns](#common-patterns)
- [Guardrails](#guardrails)
- [Quick Reference](#quick-reference)

## Example

**Scenario**: Hitter analysis for Junior Caminero (TB 3B), today's opponent BOS, opp SP Brayan Bello (RHP), park Fenway, light wind.

**Inputs assembled from web search**:
- Last 15 days xwOBA: .410 vs season xwOBA .355 (Baseball Savant)
- Bello 2026 K/9: 8.1, xFIP 4.05, wOBA-vs-RHH .335 (FanGraphs)
- Fenway park factor: 103 R, 105 HR (FanGraphs park factors)
- Caminero vs RHP wOBA: .360 (FanGraphs splits)
- Weather: 62F, 8mph wind LF-to-CF (RotoWire)
- Lineup: confirmed #3 hitter (MLB.com starting lineups)
- Season actual wOBA .340 vs xwOBA .370 -> unlucky +.030

**Signal computation**:

| Signal | Value | Quick read |
|---|---|---|
| form_score | 66 | rolling xwOBA 15% above season baseline |
| matchup_score | 58 | decent park, neutral SP, slight wind-aided |
| opportunity_score | 78 | #3 slot, ~4.6 expected PAs |
| daily_quality | 66 | START-tier (>=60) |
| regression_index | +15 | unlucky, buy-window |
| obp_contribution | 62 | projected .355 OBP x 4.6 PAs |
| sb_opportunity | 35 | Bello holds runners average, BOS catcher CS 28%, Caminero sprint 26.5 ft/s |
| role_certainty | 100 | confirmed lineup posted |

**Recommendation to lineup-optimizer**: `daily_quality = 66` -> START. `regression_index = +15` suggests no need to sit on any recent cold-streak noise.

**Pitcher counter-example (pitcher start)**: Bowden Francis (TOR) at COL. daily_quality replaced by `streamability_score`. Coors kills `streamability_score` regardless of raw stuff; skill would emit qs_probability ~28, k_ceiling ~40, era_whip_risk ~82 -> streamability_score ~32 (sub-70 threshold -> SIT / DO NOT STREAM).

## Workflow

Copy this checklist and track progress:

```
MLB Player Analysis Progress:
- [ ] Step 1: Classify player (hitter vs pitcher; SP vs RP)
- [ ] Step 2: Collect season + 15-day performance (Savant, FanGraphs)
- [ ] Step 3: Collect today's context (opp SP/hitters, park, weather, lineup)
- [ ] Step 4: Compute normalized component scores
- [ ] Step 5: Compute composite signals (daily_quality or streamability_score)
- [ ] Step 6: Check regression_index and role_certainty
- [ ] Step 7: Validate against rubric and emit signal file
```

**Step 1: Classify player**

Determine role: hitter (any position player), SP (starter), RP (reliever, closer or setup). The signal set is different per role. See [resources/methodology.md](resources/methodology.md#role-classification) for role determination rules when a player has dual eligibility (two-way player, opener + bulk).

- [ ] Confirm today's role: is the player in today's lineup? Is the SP on the probable-pitcher chart today?
- [ ] If RP: is this a save-role RP or middle-relief RP? Closer depth lookup required.

**Step 2: Collect performance data**

Web-search the primary sources. Every URL goes in the signal file's `source_urls:` list.

- [ ] Baseball Savant player page: season xwOBA, 15-day xwOBA, xBA, barrel %, hard-hit %, sprint speed (hitters); xERA, whiff %, chase %, CSW (pitchers)
- [ ] FanGraphs player page: ATC projections (rest-of-season rate stats), splits tab (vs LHP / vs RHP)
- [ ] If search fails for any metric: record the attempt, set `confidence: 0.3`, and note the gap in the red-team field

See [resources/data-cheatsheet](resources/methodology.md#source-cheatsheet) for exact URL patterns.

**Step 3: Collect today's context**

- [ ] Opp SP (from MLB.com probable pitchers or matchup-analyzer signal if already emitted)
- [ ] Park factor (from FanGraphs park factors, or matchup-analyzer's `park_hitter_factor` / `park_pitcher_factor`)
- [ ] Weather (from RotoWire weather-forecast, or matchup-analyzer's `weather_risk`)
- [ ] Confirmed lineup slot (from MLB.com starting-lineups; posts ~2-3h pre-game)
- [ ] If a matchup-analyzer signal file exists for today's game, consume those signals -- do not re-derive

**Step 4: Compute normalized component scores**

All raw stats are converted to 0-100 (unipolar) or +/-100 (bipolar) per the signal framework. See [resources/methodology.md](resources/methodology.md#normalization-formulas) for each formula.

- [ ] Hitter: form_score, matchup_score, opportunity_score (components of daily_quality)
- [ ] Hitter: regression_index, obp_contribution, sb_opportunity, role_certainty
- [ ] Pitcher: qs_probability, k_ceiling, era_whip_risk
- [ ] Pitcher RP: save_role_certainty

**Step 5: Compute composite signals**

- [ ] Hitter primary: `daily_quality = 0.35 * form_score + 0.40 * matchup_score + 0.25 * opportunity_score`
- [ ] Pitcher SP primary: `streamability_score = 0.40 * qs_probability + 0.30 * k_ceiling + 0.30 * (100 - era_whip_risk)`
- [ ] Pitcher SP weekly: `two_start_bonus` (bool from FantasyPros two-start page)

**Step 6: Check regression and role**

- [ ] `regression_index = clamp((xwOBA - wOBA) * 500, -100, +100)`. Positive = unlucky (buy). Negative = lucky (sell / fade).
- [ ] `role_certainty` (hitter): 100 = confirmed in today's lineup, 70 = probable per beat reporter, 40 = platoon uncertain, 0 = benched or injured
- [ ] `save_role_certainty` (RP): 100 = locked closer per RotoBaller, 50 = timeshare, 20 = 7th-inning guy

**Step 7: Validate and emit**

- [ ] Fill [resources/template.md](resources/template.md) frontmatter and tables
- [ ] Score against [resources/evaluators/rubric_mlb_player_analyzer.json](resources/evaluators/rubric_mlb_player_analyzer.json). Target average >= 3.5
- [ ] Every numeric signal has `confidence` and at least one `source_url`
- [ ] Call `mlb-signal-emitter` (validation); on failure, log to `tracker/decisions-log.md`

## Common Patterns

**Pattern 1: Hot Streak Hitter (Sell-the-News)**

- **Profile**: Rolling 15-day wOBA well above xwOBA (actual outperforming expected)
- **Signal signature**: `form_score` high (>=70), `regression_index` negative (e.g., -25)
- **Read**: Production is BABIP-aided and not backed by Statcast quality. Do not overweight recent numbers.
- **Action feed to lineup-optimizer**: trim daily_quality by ~5 points mentally; flag for the waiver-analyst if the user is considering selling high

**Pattern 2: Cold Hitter with Loud Contact (Buy-Window)**

- **Profile**: Rolling 15-day wOBA below season average but xwOBA still strong (>=season xwOBA)
- **Signal signature**: `form_score` depressed, `regression_index` positive (>=+20), barrel% still good
- **Read**: Bad-luck stretch. Underlying contact quality intact. Start through it.
- **Action**: keep daily_quality weight as computed; flag positive regression to category-strategist (this is the guy who will pop next week)

**Pattern 3: Two-Start Pitcher in a Bad Park**

- **Profile**: SP with two starts this scoring week, one of which is at COL / CIN / BOS
- **Signal signature**: `two_start_bonus = true`, but one start has `era_whip_risk` >= 70
- **Read**: Volume pays in K and QS, but a blowup in Coors could torch ERA/WHIP for the week
- **Action**: Emit both starts as separate pitcher signals, each with its own streamability_score; streaming-strategist decides whether to eat the bad park for the volume

**Pattern 4: Closer in Committee / Role Uncertainty**

- **Profile**: RP with save opportunities but manager has said "mix-and-match" or "matchup based"
- **Signal signature**: `save_role_certainty` <= 50, `k_ceiling` decent, `era_whip_risk` low
- **Read**: Rostering pays only if saves materialize. Great ratios but the fantasy cat (SV) is unreliable.
- **Action**: Note explicitly in the signal body. Waiver-analyst uses this to decide FAAB willingness.

## Guardrails

1. **Cite every fact.** Every numeric input (xwOBA, projected PAs, park factor, CS%) must trace to a URL in `source_urls:`. Unsourced claims fail the rubric's Source Citation criterion.

2. **OBP matters more than AVG for this league.** Our batting cats are R/HR/RBI/SB/OBP (not AVG). When computing `obp_contribution` and when choosing which rate stat to weight in form_score, use OBP or wOBA (which is walk-inclusive), never AVG alone. Walk rate is a feature, not a footnote.

3. **QS matters more than W for this league.** For `qs_probability`, compute the probability of 6+ IP and <=3 ER, not the probability of a win. Ignore bullpen-game starters and openers -- they score zero QS points by definition.

4. **Use ATC projections, not Steamer alone.** FanGraphs ATC is the consensus ensemble and is the most accurate single source. Steamer and ZiPS can be consulted for triangulation but do not substitute ATC without noting it.

5. **Degrade gracefully on search failure.** If a source is unreachable, do not invent numbers. Set that component's `confidence` to 0.3 and record the gap in the red-team `note` field. The red-team pass will escalate if confidence < 0.4.

6. **Do not re-derive matchup-analyzer signals.** If `signals/YYYY-MM-DD-matchup.md` exists for today's game, consume `opp_sp_quality`, `park_hitter_factor`, `park_pitcher_factor`, `weather_risk`, `bullpen_state` directly. Re-deriving wastes runtime and risks inconsistency across agents.

7. **Timestamp every signal.** `computed_at: YYYY-MM-DDTHH:MMZ`. Morning-brief calls are fresh; afternoon re-checks (once lineups post) supersede the morning signal with higher role_certainty.

8. **Range-check every number.** 0-100 signals never exceed 100 or go negative. +/-100 signals (regression_index) are clamped. The `mlb-signal-emitter` validator rejects out-of-range values -- check before calling.

9. **Plain-English body.** The frontmatter is for machines; the body must be jargon-free or translate jargon inline for the end user. "xwOBA" -> "expected offensive output based on how hard and at what angle he hit the ball, regardless of whether balls found gloves."

## Quick Reference

**Composite formulas** (see [resources/methodology.md](resources/methodology.md) for derivations):

```
daily_quality       = 0.35 * form_score + 0.40 * matchup_score + 0.25 * opportunity_score
streamability_score = 0.40 * qs_probability + 0.30 * k_ceiling + 0.30 * (100 - era_whip_risk)
regression_index    = clamp((xwOBA - wOBA) * 500, -100, +100)
```

**Action thresholds** (feed to lineup-optimizer / streaming-strategist):

| Signal | START / STREAM | Neutral | SIT / FADE |
|---|---|---|---|
| daily_quality (hitter) | >= 60 | 45-59 | < 45 |
| streamability_score (SP) | >= 70 | 55-69 | < 55 |
| save_role_certainty (RP) | >= 70 | 40-69 | < 40 |
| regression_index | >= +25 (buy) | -24..+24 | <= -25 (sell) |

**Source priority** (always try in this order):

| Need | Primary | Fallback |
|---|---|---|
| Projections | FanGraphs ATC | Steamer, ZiPS, FantasyPros |
| Statcast / xwOBA / xERA | Baseball Savant | -- (no substitute) |
| Lineup / probable SP | MLB.com | RotoWire, FanGraphs Roster Resource |
| Park factor | FanGraphs park factors | Baseball-Reference park factors |
| Weather | RotoWire weather forecast | Google weather + MLB.com game page |
| Closer depth | RotoBaller closer charts | Pitcher List, Closer Monkey |
| Two-start week | FantasyPros two-start planner | FanGraphs probables grid |

**Key resources:**

- **[resources/template.md](resources/template.md)**: Signal file template with YAML frontmatter, hitter and pitcher signal tables, plain-English body, and a worked example
- **[resources/methodology.md](resources/methodology.md)**: Source URL cheatsheet, per-signal normalization formulas, composite computation, regression math, confidence-assignment rules
- **[resources/evaluators/rubric_mlb_player_analyzer.json](resources/evaluators/rubric_mlb_player_analyzer.json)**: 9-criterion scoring rubric

**Inputs required:**

- Player name (exact, with team abbreviation if ambiguous, e.g., "Will Smith (LAD)")
- Player's MLB team (3-letter abbr)
- Today's opponent SP (if known; otherwise skill will web-search MLB.com probables)
- Today's park / weather (from matchup-analyzer signal file if available)

**Outputs produced:**

- `signals/YYYY-MM-DD-player-<lastname>-<firstinitial>.md` (one file per player analyzed per day)
- Populated with all hitter or pitcher signals per signal-framework.md
- Body includes plain-English translation for the end user

More from lyndonkl/claude

SkillDescription
abstraction-concrete-examplesBuilds structured abstraction ladders that translate high-level principles into concrete, actionable examples across 3-5 levels. Bridges communication gaps, reveals hidden assumptions, and tests whether abstract ideas work in practice. Use when explaining concepts at different expertise levels, moving between abstract principles and concrete implementation, identifying edge cases by testing ideas against scenarios, designing layered documentation, decomposing complex problems into actionable steps, or bridging strategy-execution gaps.
academic-letter-architectGuides the creation of evidence-based academic recommendation letters, reference letters, and award nominations that combine concrete examples, meaningful comparisons, and genuine enthusiasm. Use when writing recommendation letters for students, postdocs, or colleagues, or when user mentions recommendation letter, reference, nomination, letter of support, endorsement, or needs help with strong advocacy and comparative statements.
adr-architectureDocuments significant architectural and technical decisions with full context, alternatives considered, trade-offs analyzed, and consequences understood. Creates a decision trail that helps teams understand why decisions were made. Use when choosing between technology options, making infrastructure decisions, establishing standards, migrating systems, or when user mentions ADR, architecture decision, technical decision record, or decision documentation.
adverse-selection-priorProduces a Bayesian prior probability that an offered transaction is +EV for the recipient, given that the counterparty chose to propose it. Applies Akerlof market-for-lemons logic -- if they offered it, they believe it is +EV for them, so the prior that it is +EV for us is materially below 50%. Reusable across trade evaluation, waiver drops (another team dropping a player is also adverse selection), job-offer analysis, M&A, and any "someone offered me this" situation. Use when you receive an unsolicited trade/offer/proposal, analyzing incoming trade prior, evaluating why a counterparty proposed a deal, or when user mentions adverse selection, market for lemons, why did they offer this, incoming trade prior, they proposed it, Bayesian adjustment on received offer.
alignment-values-north-starCreates actionable alignment frameworks that give teams a shared North Star (direction), values (guardrails), and decision tenets (behavioral standards). Enables autonomous decision-making while maintaining organizational coherence. Use when starting new teams, scaling organizations, defining culture, establishing product vision, resolving misalignment, creating strategic clarity, or when user mentions North Star, team values, mission, principles, guardrails, decision framework, or cultural alignment.
analogy-weight-checkFor every analogy in a substacker draft, verifies it carries mechanical weight — the analogy does real work explaining the mechanism, not merely decorates it. Cross-references analogy-catalog.md for novelty (is this analogy reused from a prior post?) and domain fit (biology > organizational > sports preferred; physics/military disfavored). Use whenever an analogy appears in the draft. Trigger keywords: analogy weight, decorative, mechanical weight, reused analogy, catalog check, metaphor check.
answer-uncomfortable-questionTakes one strategic question about substacker ("should we launch paid?", "is this section dead?", "are we writing for the wrong audience?") and produces the mandatory evidence + reasoning + downside triad plus a recommendation. Used 3 times per Growth Strategist review. Trigger keywords: uncomfortable question, strategic question, evidence reasoning downside, triad.
attribute-performanceFor each substacker post that materially over- or under-performs the rolling baseline (|z| ≥ 1.0), produces a plain-English attribution paragraph with calibrated confidence (high / medium / low / unexplained). Considers subject-line effect, topic zeitgeist, external share, day-of-week, length effect, and audience-notes signals. Labels unexplained outliers explicitly rather than fabricating a story. Use after compute-baseline when outlier posts exist. Trigger keywords: attribution, why did this post work, outlier explanation, performance analysis.
auction-first-price-shadingComputes the optimal shaded bid for a first-price sealed-bid auction given a true private value, an estimate of the number of competing bidders N, and a value-distribution assumption. Implements the `(N-1)/N` equilibrium shading rule for uniform private values, adjusts for log-normal or empirical value distributions, layers a risk-aversion adjustment, and caps output against the bidder's remaining budget. Domain-neutral auction theory reusable across fantasy sports (baseball FAAB, NBA/NHL waiver auctions), prediction-market limit sizing, sealed procurement bids, and any blind-bid context. Use when user mentions "first-price auction bid", "sealed bid shading", "(N-1)/N", "FAAB bid amount", "auction shading", "optimal bid first-price", "bid for sealed-bid", "blind bid sizing", or when downstream logic needs a principled shade factor rather than an ad-hoc heuristic.
auction-winners-curse-haircutApplies a Bayesian haircut to a bid valuation for common-value auctions where winning is itself evidence the bidder over-estimated. Takes a raw valuation, a value-type classification (common_value / private_value / mixed), the number of informed bidders N, and a signal-dispersion estimate, and returns an adjusted valuation. Domain-neutral and reusable across fantasy FAAB, prediction markets, M&A bids, ad-auction budgets, and any generic bidding context. Use when user mentions "winner's curse", "common value auction", "valuation haircut", "adverse valuation", "Bayesian bid adjustment", or "over-paying in auction".