skills/mlb-playoff-scheduler/SKILL.md
Counts MLB games per team during the Yahoo fantasy playoff window (weeks 21, 22, 23 -- Aug 17 through Sep 6, 2026) and grades the quality of each team's opponents. Emits three signals per rostered player -- playoff_games (int, max ~21), playoff_matchup_quality (0-100), holding_value (0-100) -- that drive trade-deadline and playoff-lineup decisions. Use when the user mentions playoff weeks, weeks 21-23, playoff schedule, game count, holding value, or asks whether to keep/trade a player for the playoff run. Pre-July 1 this skill returns "insufficient signal -- too early"; from July 1 onward it fires weekly.
npx skillsauth add lyndonkl/claude mlb-playoff-schedulerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Scenario: It is 2026-07-14. The trade deadline (Aug 6) is three weeks away. User asks "should I hold Junior Caminero (TB, 3B) or trade him for a pitcher?" The trade-analyzer needs playoff_games, playoff_matchup_quality, and holding_value for Caminero before it can weigh the offer.
Research pass (web search every fact, cite every URL):
Normalization pass:
playoff_games = 7 + 7 + 6 = 20 (strong volume; max observed in the league this year is 21)playoff_matchup_quality (hitter view) = 100 - ((0.323 - 0.300) x 1000) = 100 - 23 = 77 (opposing pitching is worse than league average -> good for Caminero)holding_value = 0.6 x normalize(20 / 21) + 0.4 x 77 = 0.6 x 95 + 0.4 x 77 = 88Downstream composition:
mlb-trade-analyzer reads these. Caminero's holding_value = 88 is very high. If the offered pitcher's holding_value is 65, the trade favors the status quo -> REJECT or COUNTER with a lesser hitter.mlb-playoff-planner reads the same signals to identify roster holes for playoff weeks (e.g., any starter with playoff_games < 14 is a bench candidate).Pre-July 1 behavior:
If the skill is invoked before 2026-07-01, it emits a minimal signal file with all three fields set to null, confidence: 0.0, and body text: "Insufficient signal -- too early. Schedule volatility (trades, rotation flux, injuries) before July makes playoff projections unreliable. Re-run after July 1."
Copy this checklist and track progress:
MLB Playoff Scheduler Progress:
- [ ] Step 1: Check date gate (today >= 2026-07-01)
- [ ] Step 2: Define the three playoff week windows (Mon-Sun)
- [ ] Step 3: For each MLB team, pull the schedule for weeks 21-23
- [ ] Step 4: Count games per team per week
- [ ] Step 5: Score each opponent (wOBA for hitters, ERA for pitchers)
- [ ] Step 6: Compute playoff_matchup_quality per team (volume-weighted)
- [ ] Step 7: Compute holding_value per team (blend volume + quality)
- [ ] Step 8: Map per-team scores to every rostered player
- [ ] Step 9: Emit signal file and validate
Step 1: Check the date gate
Today's date is inside the prompt. If today < 2026-07-01, skip Steps 2-8 and emit the "insufficient signal" stub (see resources/methodology.md). Do not guess or pre-compute; schedule churn (July trades, rotation flux, call-ups) breaks pre-July projections.
Step 2: Define playoff week windows
Per yahoo-mlb/context/league-config.md, playoffs are weeks 21, 22, 23 and end Sunday Sep 6, 2026. Working backward (weeks are Mon-Sun):
| Fantasy Week | Start (Mon) | End (Sun) | |---|---|---| | Week 21 | 2026-08-17 | 2026-08-23 | | Week 22 | 2026-08-24 | 2026-08-30 | | Week 23 | 2026-08-31 | 2026-09-06 |
Total: 21 calendar days. Max games per team = ~21 (only if no off-days, rare).
Step 3: Pull each MLB team's schedule
Web-search mlb.com/schedule and FanGraphs team schedule pages. See resources/methodology.md for queries and fallbacks. Cite every URL.
Step 4: Count games per team per week
For each of the 30 MLB teams, tally games in each of the three playoff weeks. Output a 30-row grid. See resources/template.md for the output format.
playoff_games figure)Step 5: Score each opponent
For each opponent, pull two metrics:
See resources/methodology.md for sources and lookup procedure. Use season-to-date as of the run date; do not forecast.
Step 6: Compute playoff_matchup_quality
Volume-weighted across all games in weeks 21-23:
For hitters on team T:
avg_opp_wOBA_allowed = sum over games g of (opp_staff_wOBA_allowed_g) / playoff_games_T
playoff_matchup_quality = 100 - (avg_opp_wOBA_allowed - 0.300) x 1000
(clamped [0, 100]; league-average staff wOBA allowed ~ 0.320 -> score ~ 80)
For pitchers on team T:
avg_opp_lineup_wOBA = sum over games g of (opp_lineup_wOBA_vs_P_handedness_g) / playoff_games_T
playoff_matchup_quality = 100 - (avg_opp_lineup_wOBA - 0.300) x 1000
(same clamp; easier-hitting opposing lineups -> higher quality for this pitcher)
Anchor: 50 = neutral opponent strength. See resources/methodology.md for the derivation.
Step 7: Compute holding_value
Blend volume and quality:
volume_score = (playoff_games / 21) x 100
holding_value = 0.6 x volume_score + 0.4 x playoff_matchup_quality
(clamped [0, 100])
Rationale: more games carry more weight than softer opponents (volume is certain; opponent wOBA will wobble). See resources/methodology.md for the weight justification and alternative blends (e.g., punting specific categories changes the weights).
Step 8: Map team scores to players
Every rostered player on team T inherits team T's three signals. Pitchers further modify playoff_matchup_quality by handedness (the lineup they face varies L/R). See resources/methodology.md.
Step 9: Emit and validate
Write to signals/YYYY-MM-DD-playoff.md using resources/template.md. Call mlb-signal-emitter for schema validation. Score the output against resources/evaluators/rubric_mlb_playoff_scheduler.json. Minimum standard: average 3.5+.
| Signal | Range | Meaning |
|---|---|---|
| playoff_games | int 0-21 | Games scheduled across fantasy weeks 21+22+23 (Aug 17 - Sep 6). Max ~21 assuming no off-days. |
| playoff_matchup_quality | 0-100 | Volume-weighted opponent strength. 50 = neutral. >50 = softer opponents (good to hold). Hitter view uses opposing staff wOBA allowed; pitcher view uses opposing lineup wOBA vs this pitcher's hand. |
| holding_value | 0-100 | 0.6 x volume + 0.4 x quality. Primary signal for hold-vs-trade decisions. >70 = strong hold; <40 = trade candidate if you can get a higher-value bat/arm back. |
Downstream: mlb-trade-analyzer uses holding_value to value both sides of any proposed deal. mlb-playoff-planner uses playoff_games to flag bench vs start decisions for playoff weeks.
Pre-July 1, return the stub. Do not pre-compute. Before July, 30-40% of teams will see rotation, bullpen, or lineup churn that invalidates opponent-quality scoring. The stub is honest; a precomputed signal is false precision.
50 is neutral, always. Every 0-100 score anchors to 50 at league average. If your distribution doesn't hit 50 at the median MLB team, re-anchor.
Cite every URL. Game counts, doubleheaders, and opponent wOBA must each be traceable to a specific mlb.com/schedule or FanGraphs URL in source_urls:. Signals without sources get confidence <= 0.3 and are red-teamed.
Doubleheaders count as 2. If MLB.com schedule lists two games on the same calendar day, that is 2 games for that team. Some scraped sources collapse them -- cross-check.
Use handedness-specific opponent wOBA for pitchers. A LHP facing the Yankees (heavy LHB lineup) is not the same as a RHP facing the Yankees. Use opposing lineup wOBA vs LHP for LHP pitchers, vs RHP for RHP.
Season-to-date wOBA, not projection. The opponent quality score uses actual season stats as of the run date. Do not project forward -- projections add noise without adding signal for this short 3-week window.
Max games = ~21, not 21 exactly. A team playing every day would log 21 games but off-days are built into the MLB schedule. Typical range is 17-20. A team with 21 games has a doubleheader somewhere; flag it (DH games are often bullpen games, which changes matchup quality).
Holding value is not trade value. holding_value answers "is this player more valuable for MY playoff run than the replacement-level player available?" It is not a generic trade-market price. The trade-analyzer combines holding_value with market value to reach the final verdict.
Re-run weekly after July 1. Schedules change (rainouts, makeup games, early-September call-ups alter opponent lineups). The playoff-planner fires every Sunday; refresh these signals each time.
Playoff week windows (2026):
Week 21: Mon 2026-08-17 -> Sun 2026-08-23
Week 22: Mon 2026-08-24 -> Sun 2026-08-30
Week 23: Mon 2026-08-31 -> Sun 2026-09-06
Total: 21 calendar days; max ~21 games per team
Key formulas:
playoff_games = games_wk21 + games_wk22 + games_wk23
For hitters:
playoff_matchup_quality = 100 - (avg_opp_staff_wOBA_allowed - 0.300) x 1000
(clamped [0, 100]; league avg ~ 0.320 -> 80)
For pitchers:
playoff_matchup_quality = 100 - (avg_opp_lineup_wOBA_vs_hand - 0.300) x 1000
(same clamp)
volume_score = (playoff_games / 21) x 100
holding_value = 0.6 x volume_score + 0.4 x playoff_matchup_quality
(clamped [0, 100])
Pre-July 1: playoff_games = null, playoff_matchup_quality = null,
holding_value = null, confidence = 0.0,
body = "insufficient signal -- too early"
Key sources (see yahoo-mlb/context/frameworks/data-sources.md):
Inputs required: run date (always passed in); optionally, a roster list to scope output (else, emit all 30 teams).
Outputs produced: one signal file at signals/YYYY-MM-DD-playoff.md with YAML frontmatter, a 30-row per-team games grid, per-team opponent-quality table, and per-player mapping for rostered players. Fails-open pre-July 1 with the stub.
Key resources:
testing
Cluster a conference's event records into a small set of coarse themes with finer sub-clusters, an explicit outlier bucket, and soft (multi-membership) affinities — using the hybrid embed-then-label pipeline (embed abstracts, reduce, density-cluster, then LLM-label the clusters) when embedding libraries are available, and an LLM-reasoned hierarchical fallback when they are not. Embeddings do the grouping; the LLM only names the groups. Conference-agnostic. Use when turning structured event records into a navigable theme map for preference elicitation and scheduling, when you need 6-8 reasonable themes rather than 20 muddy ones, or when overlapping talks must belong to more than one theme. Trigger keywords - theme clustering, cluster talks, embed then label, soft membership, outlier talks, conference themes, topic map.
development
Build a personal conference schedule as a constraint-optimization problem — hard constraints (no time overlap, room-to-room travel time, capacity/registration, the attendee's own must-attends and blackouts) plus a user-owned weighted objective trading interest against breadth, pacing (maximize contiguous free time), and serendipity. Surfaces unbreakable conflicts (two high-value overlapping talks the model cannot rank) as decisions for the human rather than silently picking, and reports what each choice traded away. Conference-agnostic. Use to turn a preference profile plus a theme map into a day-by-day plan, to resolve overlapping sessions, or to balance a packed vs paced schedule. Trigger keywords - schedule optimization, conference schedule, constraint optimization, overlapping talks, contiguous free time, conflict surfacing, packed vs paced.
development
Parse a heterogeneous conference program (markdown, HTML, PDF-derived text, or JSON) into normalized event records with per-field confidence scores and independent classification axes (topic, depth, format, prerequisites, recorded, capacity). Detects the program's format before extracting, treats every inferred field as uncertain (present vs inferred vs missing), and flags thin or missing abstracts so downstream enrichment can target them. Conference-agnostic. Use when ingesting a conference or event schedule into a structured store, normalizing a talk/session list, or extracting per-session metadata with calibrated confidence. Trigger keywords - program ingestion, parse schedule, session extraction, event records, conference program, talk metadata, per-field confidence.
development
Build a personalized preference profile from a small number of well-chosen, cluster-grounded questions instead of a long survey. Represents the person's interests as an uncertainty region over the theme map, picks the single highest-information-gain choice-based question (contrasting real talks from different clusters), balances exploiting known interests against exploring uncertain ones, deliberately injects outlier probes to fight selection bias, and stops as soon as the schedule would be stable. Also elicits the user-owned objective weights and hard constraints. Interactive — runs where it can actually ask the person. Conference-agnostic. Use to turn a theme map into a preference profile, to decide what to ask a conference attendee, or to elicit scheduling priorities. Trigger keywords - preference elicitation, ask few questions, information gain, choice-based questions, selection bias probe, objective weights, attendee preferences.