
Pp Espn
- 3.4k installs
- 1.9k repo stars
- Updated August 4, 2026
- mvanhorn/printing-press-library
pp-espn is an agent skill that drives the espn-pp-cli for live ESPN sports scores, standings, schedules, and rich game summaries without an API key.
About
ESPN Printing Press CLI is an agent skill that drives the espn-pp-cli binary for live and offline sports data across NFL, NBA, MLB, NHL, NCAA, MLS, EPL, and WNBA. It covers cross-league discovery with today and trending, rich per-game summaries with box scores, leaders, scoring plays, odds, and win probability, standings, rankings, injuries, transactions, and head-to-head comparisons. Local sync stores datasets in SQLite for offline search and read-only SQL queries. The skill requires verifying espn-pp-cli installation via npx or go install, using --agent mode for compact JSON output, and --select to trim large payloads for agent context. A recall-and-teach learning loop caches entity matches and playbooks to skip rediscovery on repeat questions. Developers use it when users ask for scores, schedules, standings, polls, or detailed game breakdowns in natural language without subscribing to paid sports data feeds.
- Covers ten leagues with live scores, standings, rankings, injuries, and transactions.
- summary command returns box score, leaders, scoring plays, odds, and win probability.
- today command surfaces cross-league scores without picking a sport first.
- Local sync plus search and sql commands enable offline analysis from SQLite.
- recall and teach protocol caches entity matches and playbooks across sessions.
Pp Espn by the numbers
- 3,409 all-time installs (skills.sh)
- +292 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #61 of 550 CLI & Terminal skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
pp-espn capabilities & compatibility
- Capabilities
- live scores · standings lookup · game summary · head to head · offline search · playbook caching · cross league discovery
- Use cases
- web search · data analysis
- Pricing
- Free
What pp-espn says it does
No API key required.
**`today`** — Today's scores across all major sports in one call.
Auth Setup **None required.** ESPN's public endpoints don't require an API key.
npx skills add https://github.com/mvanhorn/printing-press-library --skill pp-espnAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 3.4k |
|---|---|
| repo stars | ★ 1.9k |
| Security audit | 2 / 3 scanners passed |
| Last updated | August 4, 2026 |
| Repository | mvanhorn/printing-press-library ↗ |
What is the score, schedule, or standing for a team or league right now without a paid sports data API?
Answer live sports scores, standings, schedules, box scores, and head-to-head stats through the espn-pp-cli without an API key.
Who is it for?
Agents answering natural-language sports questions across major US and soccer leagues using a local CLI.
Skip if: Real-time websocket feeds, paid Stats Perform or Sportradar integrations, or league-wide odds-only workflows.
When should I use this skill?
Use when the user asks about live sports scores, standings, team stats, game summaries, schedules, polls, rankings, or head-to-head records.
What you get
Structured JSON with scores, box scores, standings, or offline search hits the agent can summarize for the user.
- live score data
- standings and schedule output
- box score summaries
By the numbers
- Covers 10 sports leagues including NFL, NBA, MLB, NHL, NCAA, MLS, EPL, and WNBA
- Requires no API key for ESPN data access
Files
<!-- GENERATED FILE — DO NOT EDIT. This file is a verbatim mirror of library/media-and-entertainment/espn/SKILL.md, regenerated post-merge by tools/generate-skills/. Hand-edits here are silently overwritten on the next regen. Edit the library/ source instead. See the repository agent guide, section "Generated artifacts: registry.json, cli-skills/". -->
ESPN — Printing Press CLI
Prerequisites: Install the CLI
This skill drives the espn-pp-cli binary. You must verify the CLI is installed before invoking any command from this skill. If it is missing, install it first:
1. Install via the Printing Press installer. It defaults binaries to $HOME/.local/bin on macOS/Linux and %LOCALAPPDATA%\Programs\PrintingPress\bin on Windows:
npx -y @mvanhorn/printing-press-library install espn --cli-only2. Verify: espn-pp-cli --version 3. Ensure the reported install directory is on $PATH for the agent/runtime that will invoke this skill.
If the npx install fails (no Node, offline, etc.), fall back to a direct Go install (requires Go 1.26.4 or newer):
go install github.com/mvanhorn/printing-press-library/library/media-and-entertainment/espn/cmd/espn-pp-cli@latestIf --version reports "command not found" after install, the runtime cannot see the binary directory on $PATH. Do not proceed with skill commands until verification succeeds.
When to Use This CLI
Reach for this when a user wants a quick sports lookup - current score, standings, upcoming schedule, head-to-head record, or a rich per-game summary (box score, leaders, scoring plays, odds, win probability). Also good for cross-league discovery (today) and offline search across synced data.
Don't reach for this if the user has a paid feed like Stats Perform or Sportradar that provides cleaner data, or if they need real-time websocket updates (ESPN's endpoints are polling-only). For betting odds in isolation, the per-game summary payload includes them but there is no league-wide odds command.
Unique Capabilities
Commands that only work because of local sync + cross-league tooling.
Cross-league discovery
- `today` — Today's scores across all major sports in one call. The fastest "what's on tonight" answer without picking a sport first.
- `trending` — Most-followed athletes and teams across all leagues, ranked by current popularity. Good for "who is hot right now" without naming a sport.
- `dashboard` — Reads
[favorites]from~/.config/espn-pp-cli/config.tomland shows scores for each favorited team across leagues, in one call.
- `watch <sport> <league> --event <game_id>` — Live score updates for a specific game (polls every 30s). Use
scoresortodayto find the game, thenwatchto follow it live.
Game-state intelligence
- `summary <sport> <league> --event <game_id>` — Detailed game summary including box score, leaders, scoring plays, odds, and win probability. The single richest payload per game.
- `boxscore <event_id>` — Just the per-player box score for an event id, with sport+league inferred from a recent scoreboard cache hit. Pass
--sport/--leagueto skip inference.
- `plays <sport> <league> --event <id>` — Play-by-play feed for a specific event. Optional
--limit(default 200).
- `recap <sport> <league>` — Post-game recap with box score and leaders for the most recent completed game in a league.
- `scoreboard <sport> <league>` — Live scoreboard with date filtering, week/group selectors, and competition metadata.
- `odds <sport> <league>` — Spread, over/under, and moneyline lines for tonight's slate, derived from the scoreboard payload (no per-game summary calls).
Standings and rankings
- `standings <sport> <league>` — Conference/division standings.
- `rankings <sport> <league>` — Current AP, Coaches, and CFP poll rankings (NCAAF/NCAAM).
- `streak <sport> <league>` — Current win/loss streaks across teams in a league, computed from synced data.
- `rivals <sport> <league>` — Head-to-head records between teams in a league from synced data.
- `h2h <team1> <team2> --sport <s> --league <l>` — Deeper head-to-head detail for one specific pair, including average score and recent meetings list.
- `sos <sport> <league>` — Strength-of-schedule per team, derived from the standings payload, sorted descending.
People
- `leaders <sport> <league> [--category <name>]` — Statistical leaders across categories with optional filter.
- `compare <athlete1> <athlete2> --sport <s> --league <l>` — Side-by-side season stats for two athletes. Ambiguous names list candidates and exit 2.
- `injuries <sport> <league>` — Active injury report across the league, grouped by team.
- `transactions <sport> <league>` — Recent trades, signings, and waivers.
Local store
- `sync` — Pull a sport+league dataset into local SQLite for offline analysis.
- `search "<query>"` — Full-text search across synced events and news.
- `sql <query>` — Run read-only SQL queries against the local database.
Command Reference
Live action:
espn-pp-cli scores <sport> <league>— Current scoresespn-pp-cli today— Today's scores across all major sportsespn-pp-cli scoreboard <sport> <league>— Scoreboard with optional date filteringespn-pp-cli watch <sport> <league> --event <game_id>— Live score polling for one gameespn-pp-cli standings <sport> <league>— League standingsespn-pp-cli trending— Most-followed athletes and teams across leaguesespn-pp-cli dashboard— Favorites snapshot from~/.config/espn-pp-cli/config.toml
Team detail:
espn-pp-cli teams <sport> <league> <team_id>— Schedule for one team (past + upcoming)espn-pp-cli teams get <sport> <league> <team_id>— Team record, links, and logosespn-pp-cli teams list <sport> <league>— All teams in a leagueespn-pp-cli streak <sport> <league>— Current win/loss streaks from synced dataespn-pp-cli rivals <sport> <league>— Head-to-head records between teams from synced dataespn-pp-cli h2h <team1> <team2> --sport <s> --league <l>— Deeper detail for one team pair (avg score, meetings)espn-pp-cli sos <sport> <league>— Strength-of-schedule, sorted descending
Game detail:
espn-pp-cli summary <sport> <league> --event <game_id>— Full game summary (box score, leaders, scoring plays, odds, win probability)espn-pp-cli boxscore <event_id>— Just the box score subtree (sport/league inferred from cache)espn-pp-cli plays <sport> <league> --event <id>— Play-by-play feed (optional--limit, default 200)espn-pp-cli recap <sport> <league>— Most recent completed game recapespn-pp-cli odds <sport> <league>— Spread, over/under, moneyline for tonight's slate
People:
espn-pp-cli leaders <sport> <league> [--category <name>]— Statistical leaders by categoryespn-pp-cli compare <athlete1> <athlete2> --sport <s> --league <l>— Side-by-side athlete statsespn-pp-cli injuries <sport> <league>— Active injury reportespn-pp-cli transactions <sport> <league>— Recent trades, signings, waivers
Polls and rankings:
espn-pp-cli rankings <sport> <league>— AP, Coaches, and CFP polls
Info:
espn-pp-cli news <sport> <league>— Latest news
Discovery and local:
espn-pp-cli search "<query>"— Full-text search across synced events and newsespn-pp-cli sync— Sync a sport+league into local SQLiteespn-pp-cli sql "<query>"— Run read-only SQL against the local storeespn-pp-cli load— Show workload distribution per assignee (synced data)espn-pp-cli orphans/stale— Maintenance views over the local storeespn-pp-cli doctor— Verify connectivity and configuration
Sport values: football, basketball, baseball, hockey, soccer. League values: nfl, nba, mlb, nhl, ncaaf, ncaam, ncaaw, mls, eng.1 (EPL), wnba.
Recipes
Morning sports scan
espn-pp-cli today --agent --select events.shortName,events.status
espn-pp-cli scores football nfl --agent --select events.shortName,events.competitions.competitors.team.displayName,events.status.type.detail
espn-pp-cli standings football nfl --agentOne today call covers cross-league activity, one scores for the league you care about, one standings for context. The nested --select paths cut a scoreboard payload from tens of KB down to the fields that actually matter — essential for keeping agent context small.
Pre-game research from synced data
espn-pp-cli sync --sport football --league nfl
espn-pp-cli rivals football nfl --agent # historical records from synced data
espn-pp-cli streak football nfl --agent # current streaks
espn-pp-cli summary football nfl --event <id> --agent # full game payload incl. odds and box scoreRun sync once, then rivals and streak answer instantly from the local store. summary is the richest single payload for a specific game (box score, leaders, scoring plays, odds, win probability).
Offline search after sync
espn-pp-cli sync --sport football --league nfl
espn-pp-cli search "Mahomes" # finds in local storeUseful for repeated lookups in poor-connectivity environments or when batch-analyzing historical data.
Favorites dashboard
Add a [favorites] block to ~/.config/espn-pp-cli/config.toml:
[favorites]
nfl = ["KC", "BAL"]
nba = ["LAL"]Then:
espn-pp-cli dashboard --agentOne call surfaces tonight's matchup status for every favorited team, grouped by league. Per-league fetches run in parallel and partial failures are reported alongside successful results.
Pre-game odds and player digging
espn-pp-cli odds basketball nba --agent # tonight's spreads / totals / moneylines
espn-pp-cli leaders basketball nba --category points --agent
espn-pp-cli compare "LeBron James" "Stephen Curry" --sport basketball --league nba --agent
espn-pp-cli boxscore <event_id> --agent # post-game player stats
espn-pp-cli plays basketball nba --event <id> --limit 50 --agentodds reads the scoreboard's per-event lines (no per-game summary calls). leaders --category filters to one stat category. compare resolves athlete ids by name, listing candidates and exiting 2 on ambiguity. boxscore infers sport+league from the most recent cache hit; pass --sport/--league to skip inference.
Auth Setup
None required. ESPN's public endpoints don't require an API key. The auth command exists for consistency but is a no-op.
Optional config:
ESPN_CONFIG— override config file pathESPN_BASE_URL— override base URL (for proxies or mirrors)NO_COLOR— standard no-color env var
Agent Mode
Add --agent to any command. Expands to --json --compact --no-input --no-color --yes. Use --select for field cherry-picking, --dry-run to preview requests, --no-cache to bypass GET cache.
Filtering output
--select accepts dotted paths to descend into nested responses; arrays traverse element-wise:
espn-pp-cli <command> --agent --select id,name
espn-pp-cli <command> --agent --select items.id,items.owner.nameUse this to narrow huge payloads to the fields you actually need — critical for deeply nested API responses.
Response envelope
Data-layer commands wrap output in {"meta": {...}, "results": <data>}. Parse .results for data and .meta.source to know whether it's live or local. The N results (live) summary is printed to stderr only when stdout is a TTY; piped/agent consumers see pure JSON on stdout.
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 2 | Usage error |
| 3 | Not found (team, game, athlete) |
| 5 | API error |
| 7 | Rate limited |
Installation
go install github.com/mvanhorn/printing-press-library/library/media-and-entertainment/espn/cmd/espn-pp-cli@latest
espn-pp-cli doctorMCP Server
go install github.com/mvanhorn/printing-press-library/library/media-and-entertainment/espn/cmd/espn-pp-mcp@latest
claude mcp add espn-pp-mcp -- espn-pp-mcpArgument Parsing
Given $ARGUMENTS:
1. Empty, `help`, or `--help` → run espn-pp-cli --help 2. `install` → CLI; `install mcp` → MCP 3. Anything else → resolve <sport> <league> from user intent (e.g., "Lakers" → basketball nba), check which espn-pp-cli (offer install if missing), run with --agent.
<!-- pr-218-features -->
Automatic learning
Two-call protocol: recall before discovery, teach & before emitting. The CLI does entity-aware match validation AND surfaces stored playbooks for the query family; you read the envelope and follow the six-branch decision tree. Skipping either side costs you free recall hits in future sessions.
Step 1: recall before any discovery
Before scoreboard, teams, boxscore, search, standings, or any other discovery command on a new user question, run:
espn-pp-cli recall "<user's question>" --agentThe response envelope:
{
"query": "...",
"normalized": "game tonight",
"query_entities": ["Niners"],
"found": true | false,
"match_score": 0.0,
"results": [
{ "resource_id": "...", "resource_type": "events|news|...", "venue": "...",
"confidence": 2, "entity_match": "exact|partial|unknown",
"source": "taught|preseed|pattern", "warnings": ["..."] }
],
"mismatches": [ /* only when --debug-mismatches */ ],
"warnings": [ /* top-level */ ],
"playbook": {
"query_family": "...",
"playbook": {
"steps": [ { "cmd": "teams basketball nba {team.id}", "purpose": "..." }, ... ],
"entity_slots": ["$TEAM", "$STATS"],
"expected_tool_calls": 3
},
"slots_resolved": { "$TEAM": { "token": "pistons", "canonical": "Detroit Pistons" } },
"notes": "byathlete needs seasontype=2; categories has dup labels"
},
"notes": "byathlete needs seasontype=2; categories has dup labels"
}Step 2: six-branch decision tree
Read playbook, notes, results[0], and warnings in that order:
if Playbook present:
-> READ Playbook.notes verbatim FIRST (workarounds + gotchas the CLI surface doesn't expose)
-> replay Playbook.steps in order, substituting Playbook.slots_resolved entries
for the entity slot tokens. If a step's slot is unresolved, fall back to
discovery for that step only.
-> the Playbook's expected_tool_calls is a budget; if you find yourself running
materially more, record the divergence via teach-playbook at end-of-session.
elif Notes present (no Playbook):
-> read Notes verbatim before any discovery step; they carry known gotchas
for this query family even when no structured choreography exists yet.
elif Found AND Results[0].EntityMatch == "exact" AND Results[0].Confidence >= 2:
-> skip discovery; fetch live data for Results[*].ResourceID in parallel
(e.g., espn-pp-cli boxscore <eid> for an event, espn-pp-cli teams ... for a team)
elif Found AND Results[0].EntityMatch == "partial":
-> candidate hint, NOT a hit; read the resource title to validate before trusting
elif (any row in Mismatches[] when --debug-mismatches was passed):
-> treat as cold start; the stored learning is for a different entity
(e.g., a "Cowboys" learning won't satisfy a "Niners" query — different canonical)
else: // Found == false, no playbook, no notes
-> cold start; run discovery normally; teach the answer afterward AND record
a playbook + notes via teach --playbook-file --playbook-notes-file so the
next session of the same family is faster.Playbook and Notes are orthogonal to the per-resource path. A recall response can carry both a Playbook AND a Results[] hit — use both: the Playbook tells you which choreography to run; the resource hits short-circuit specific steps. Default to skipping mismatches; pass --debug-mismatches only when investigating cold-start surprises.
Step 3: always read warnings
low_confidence: row exists atconfidence<2. Treat as a hint, not a skip-discovery hit.resource_not_in_store: the local store doesn't have the resource the learning points at. The match validator couldn't classify entities — direct-fetch and re-evaluate.- Top-level
no_learnings_for_query_family: the table had no rows above the Jaccard floor. Pure cold start.
Step 4: teach & after finalizing your response
After assembling your user-facing response containing event/team IDs but BEFORE emitting it, fire the teach call in the background. Append a shell & so the call returns immediately and does not block the user-facing response:
espn-pp-cli teach --query "<user's question>" --resource-type <events|news|teams> --resource <id1> --resource <id2>
# (append shell `&` to background it)Silent on success. Teach the most specific resource — if the user asked "when's next Spurs game" and you walked the teams scoreboard to find event 401747632, teach that event ID, not the team ID. The CLI uses the seeded entity_lookups (NFL/NBA/MLB/MLS team rosters with aliases like Niners/49ers/SF) for cross-alias resolution at recall time, so a teach under "Niners" will satisfy future "49ers" queries automatically.
Step 5: record a playbook when discovery took >5 calls
If you ran more than 5 tool calls to answer the question AND you discovered workarounds the CLI didn't surface (silently-dropped flags, undocumented params, pagination tricks, payload gotchas), record them so the next session of the same query family skips that discovery. Two surfaces:
# Common case: along with the resource teach
espn-pp-cli teach --query "<question>" --resource-type <type> --resource <id> \
--playbook-file ~/playbooks/season-recap.json \
--playbook-notes-file ~/playbooks/season-recap-notes.md
# (append shell `&` to background it)
# Standalone: notes-only or recipe-only
espn-pp-cli teach-playbook --query "<question>" \
--playbook-file ~/playbooks/season-recap.json \
--notes "byathlete needs seasontype=2; categories has dup labels"Playbook files are JSON with steps, entity_slots, expected_tool_calls. Notes files are markdown carrying the gotchas verbatim. Either field may be empty; both empty is rejected. Playbooks are keyed on the structural query family (entities stripped) so a recipe taught from "how did Warriors end the season" applies to Pistons, Heat, and every other team query of the same shape.
When you DO find a playbook on a future recall, treat it as ground truth: replay the steps with slots_resolved substitutions, skip the discovery that the choreography already documents, and read notes before any step.
Step 6: playbook amend & when your debug response identifies a correction
If your debug-protocol response identifies a concrete correction the notes or playbook should know — a workaround, an undocumented endpoint shape, a stale field name, observed schema drift, an empty-payload fallback — fire playbook amend BEFORE emitting your user-facing response. Same fire-and-forget posture as teach.
espn-pp-cli playbook amend \
--query "<exact recall query string>" \
--add-note "<your concrete correction>"
# (append shell `&` to background it)What counts as worth amending: a behavior you OBSERVED this session that future-you would benefit from knowing. Examples worth amending:
- "summary endpoint wraps response in
{meta, results}-- data lives at.results.header, not.header" - "compare returns empty
teamfield for athletes whose team isn't in current playoffs" - "byathlete category index for avgRebounds drifted from general[9] to general[11] this season"
What does NOT belong in notes:
- The year-specific answer ("Curry shot 4-16 in his last game"). That's the response, not a learning.
- Per-team or per-athlete data that the playbook already retrieves at runtime.
- Statements that paraphrase what the existing notes already say.
The amend command appends to the family's existing notes with a timestamped marker ([amend YYYY-MM-DDTHH:MMZ]: <text>). Multiple amends accumulate; the audit trail is visible. If no playbook exists yet for the family, amend creates a notes-only one (so cold-start corrections still land).
Worked examples
1. Cold: "when's next Spurs game?" — recall returns found=false. Walk the teams scoreboard, find next upcoming Spurs event ID, answer. Teach the event:
espn-pp-cli recall "when's next Spurs game?" --agent
# found=false -> discovery
espn-pp-cli teams basketball nba 24 --agent --select events.id,events.shortName,events.date
# ...answer "Tue May 26 SA @ OKC, event 401747632"...
espn-pp-cli teach --query "when's next Spurs game?" --resource-type events --resource 401747632
# (append shell `&` to background it)2. Warm: "Niners game tonight" — recall returns found=true, results[0].entity_match="exact", results[0].confidence>=2. Skip discovery; fetch the box score directly:
espn-pp-cli recall "Niners game tonight" --agent
# found=true, results=[{resource_id: "401547432", entity_match: "exact"}]
espn-pp-cli boxscore 401547432 --agent3. Cross-alias hit: "49ers game tonight" — never directly taught. recall resolves "49ers" → "San Francisco 49ers" canonical via entity_lookups (nfl_team kind), finds the "Niners game tonight" learning (same canonical), returns found=true. Skip discovery.
4. Entity mismatch: "Cowboys game tonight" — has a Niners learning above the Jaccard floor on non-entity tokens (game, tonight), but the entity canonical differs (Dallas Cowboys ≠ San Francisco 49ers). Filtered into mismatches; recall returns found=false. Treat as cold start.
When the loop is broken: learnings list --warnings surfaces local issues; espn-pp-cli feedback "<what tripped you up>" records the friction so the next print can fix it.
---
Agent Workflow Features
This CLI exposes three shared agent-workflow capabilities patched in from cli-printing-press PR #218.
Named profiles
Persist a set of flags under a name and reuse them across invocations.
# Save the current non-default flags as a named profile
espn-pp-cli profile save <name>
# Use a profile — overlays its values onto any flag you don't set explicitly
espn-pp-cli --profile <name> <command>
# List / inspect / remove
espn-pp-cli profile list
espn-pp-cli profile show <name>
espn-pp-cli profile delete <name> --yesFlag precedence: explicit flag > env var > profile > default.
--deliver
Route command output to a sink other than stdout. Useful when an agent needs to hand a result to a file, a webhook, or another process without plumbing.
espn-pp-cli <command> --deliver file:/path/to/out.json
espn-pp-cli <command> --deliver webhook:https://hooks.example/inFile sinks write atomically (tmp + rename). Webhook sinks POST application/json (or application/x-ndjson when --compact is set). Unknown schemes produce a structured refusal listing the supported set.
feedback
Record in-band feedback about this CLI from the agent side of the loop. Local-only by default; safe to call without configuration.
espn-pp-cli feedback "what surprised you or tripped you up"
espn-pp-cli feedback list # show local entries
espn-pp-cli feedback clear --yes # wipeEntries append to ~/.espn-pp-cli/feedback.jsonl as JSON lines. When ESPN_FEEDBACK_ENDPOINT is set and either --send is passed or ESPN_FEEDBACK_AUTO_SEND=true, the entry is also POSTed upstream (non-blocking — local write always succeeds).
Related skills
How it compares
Pick pp-espn over paid sports API integrations when prototyping agents or CLI tools that need free ESPN live data without credential management.
FAQ
Does pp-espn require an API key?
No. ESPN public endpoints do not require an API key and auth is a no-op.
Which leagues are supported?
NFL, NBA, MLB, NHL, NCAA football and basketball, MLS, EPL, and WNBA via sport and league arguments.
How do agents shrink large responses?
Add --agent and use --select with dotted paths to return only needed JSON fields.
Is Pp Espn safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.