# Sports Scores

> Live scores, standings, odds, and F1 data from ESPN, Ergast, and The Odds API.

- **Type:** Skill
- **Install:** `agentstack add skill-drknght4-hermes-sports-skill-hermes-sports-skill`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Drknght4](https://agentstack.voostack.com/s/drknght4)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Drknght4](https://github.com/Drknght4)
- **Source:** https://github.com/Drknght4/hermes-sports-skill

## Install

```sh
agentstack add skill-drknght4-hermes-sports-skill-hermes-sports-skill
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Sports Scores

Live scores, standings, odds, and F1 data from free public APIs plus The Odds API for betting lines.

## API Keys

| API | Required | Location |
|-----|----------|----------|
| ESPN | No | — |
| Ergast / OpenF1 | No | — |
| The Odds API | Yes — for odds queries | `~/.hermes/skills/tools/sports-scores/.env` → `ODDS_API_KEY` |

If `ODDS_API_KEY` is missing, odds commands will fail gracefully with a message to configure the key. Scores and standings work without it.

## Installation

```bash
# From GitHub repo (recommended)
hermes skills install https://github.com/Drknght4/hermes-sports-skill

# Or manually
cp SKILL.md ~/.hermes/skills/tools/sports-scores/SKILL.md
```

Repo: [github.com/Drknght4/hermes-sports-skill](https://github.com/Drknght4/hermes-sports-skill)

Restart Hermes or reload skills — the skill activates automatically when sports questions are detected.

## When to Use

- User asks about any sports score, game result, or standings
- User asks "how did [team] do" or "what's the score"
- User asks about F1 race results, driver standings, or next race
- User asks about betting odds, lines, spreads, or over/unders
- User says "odds on", "what are the odds", "betting line", "Vegas line", "spread"
- User says team name, sport name, or league name casually ("Knicks game", "F1 standings", "Premier League table")

## API Endpoints

### ESPN (no key required)

| Sport | League | Scores | Standings |
|-------|--------|--------|-----------|
| Basketball | NBA | `https://site.api.espn.com/apis/site/v2/sports/basketball/nba/scoreboard` | `https://site.api.espn.com/apis/site/v2/sports/basketball/nba/standings` |
| Football | NFL | `https://site.api.espn.com/apis/site/v2/sports/football/nfl/scoreboard` | `https://site.api.espn.com/apis/site/v2/sports/football/nfl/standings` |
| Baseball | MLB | `https://site.api.espn.com/apis/site/v2/sports/baseball/mlb/scoreboard` | `https://site.api.espn.com/apis/site/v2/sports/baseball/mlb/standings` |
| Hockey | NHL | `https://site.api.espn.com/apis/site/v2/sports/hockey/nhl/scoreboard` | `https://site.api.espn.com/apis/site/v2/sports/hockey/nhl/standings` |
| Soccer | La Liga | `https://site.api.espn.com/apis/site/v2/sports/soccer/esp.1/scoreboard` | `https://site.api.espn.com/apis/site/v2/sports/soccer/esp.1/standings` |
| Soccer | Premier League | `https://site.api.espn.com/apis/site/v2/sports/soccer/eng.1/scoreboard` | `https://site.api.espn.com/apis/site/v2/sports/soccer/eng.1/standings` |
| Soccer | Champions League | `https://site.api.espn.com/apis/site/v2/sports/soccer/UEFA.CHAMPIONS/scoreboard` | `https://site.api.espn.com/apis/site/v2/sports/soccer/UEFA.CHAMPIONS/standings` |
| Soccer | MLS | `https://site.api.espn.com/apis/site/v2/sports/soccer/usa.1/scoreboard` | — |
| Soccer | Bundesliga | `https://site.api.espn.com/apis/site/v2/sports/soccer/ger.1/scoreboard` | `https://site.api.espn.com/apis/site/v2/sports/soccer/ger.1/standings` |
| Soccer | Serie A | `https://site.api.espn.com/apis/site/v2/sports/soccer/ita.1/scoreboard` | `https://site.api.espn.com/apis/site/v2/sports/soccer/ita.1/standings` |
| Soccer | Ligue 1 | `https://site.api.espn.com/apis/site/v2/sports/soccer/fra.1/scoreboard` | `https://site.api.espn.com/apis/site/v2/sports/soccer/fra.1/standings` |
| Soccer | Liga MX | `https://site.api.espn.com/apis/site/v2/sports/soccer/mex.1/scoreboard` | — |
| Soccer | Copa Libertadores | `https://site.api.espn.com/apis/site/v2/sports/soccer/CONMEBOL.LIBERTADORES/scoreboard` | — |
| Soccer | FIFA World Cup | `https://site.api.espn.com/apis/site/v2/sports/soccer/fifa.world/scoreboard` | — |
| Soccer | International Friendlies | `https://site.api.espn.com/apis/site/v2/sports/soccer/fifa.friendly/scoreboard` | — |

| MMA/UFC | UFC | `https://site.api.espn.com/apis/site/v2/sports/mma/ufc/scoreboard` | — |
| Tennis | ATP/WTA | `https://site.api.espn.com/apis/site/v2/sports/tennis/scoreboard` | — |
| Golf | PGA | `https://site.api.espn.com/apis/site/v2/sports/golf/pga/scoreboard` | — |
| Rugby | Rugby | `https://site.api.espn.com/apis/site/v2/sports/rugby/scoreboard` | — |
| Basketball | WNBA | `https://site.api.espn.com/apis/site/v2/sports/basketball/wnba/scoreboard` | — |

### Ergast F1 API (no key required)

| Data | Endpoint |
|------|-----------|
| Last race results | `https://ergast.com/api/f1/current/last/results.json` |
| Driver standings | `https://ergast.com/api/f1/current/driverStandings.json` |
| Constructor standings | `https://ergast.com/api/f1/current/constructorStandings.json` |
| Next race | `https://ergast.com/api/f1/current/next.json` |
|| Live timing | `https://api.openf1.org/v1/position?session_key=latest` |

### The Odds API (API key required)

Base URL: `https://api.the-odds-api.com`
Auth: `apiKey` query parameter (stored in `~/.hermes/skills/tools/sports-scores/.env` as `ODDS_API_KEY`)

**Key endpoint:**
```
GET /v4/sports/{sport_key}/odds/?apiKey={KEY}&regions=us,eu&markets=h2h
```

**Parameters:**
- `regions` — `us`, `eu`, `uk`, `au`, or comma-separated (default: `us,eu`)
- `markets` — `h2h` (moneyline), `spreads`, `totals` (over/under), or comma-separated (default: `h2h`)
- `oddsFormat` — `decimal` (default), `american`
- `dateFormat` — `iso` (default)

**Available sports** — fetch the full list with:
```bash
curl -s "https://api.the-odds-api.com/v4/sports/?apiKey=$ODDS_API_KEY"
```

**Common sport keys for odds:**

| Sport | Odds API Key | Notes |
|-------|-------------|-------|
| NFL | `americanfootball_nfl` | Active Sep–Feb |
| NBA | `basketball_nba` | Active Oct–Jun |
| MLB | `baseball_mlb` | Active Mar–Oct |
| NHL | `icehocey_nhl` | Active Oct–Jun |
| La Liga | `soccer_spain_la_liga` | In-season only (`active=true`) |
| Premier League | `soccer_epl` | In-season only |
| Champions League | `soccer_uefa_champs_league` | In-season only |
| MLS | `soccer_usa_mls` | In-season only |
| Bundesliga | `soccer_germany_bundesliga` | In-season only |
| Serie A | `soccer_italy_serie_a` | In-season only |
| Ligue 1 | `soccer_france_ligue_one` | In-season only |
| Copa Libertadores | `soccer_conmebol_copa_libertadores` | Year-round |
| FIFA World Cup | `soccer_fifa_world_cup` | Tournament only |
| WNBA | `basketball_wnba` | Active May–Oct |
| UFC/MMA | `mma_mixed_martial_arts` | Event-based |

**Seasonality:** Many sports return empty results (`[]`) when out of season. Always check the `/v4/sports/` endpoint — the `active` field shows whether a sport currently has odds available.

## Sport Detection

Map the user's question to the right endpoint:

|| Keywords | Sport | League Code | Odds API Key |
||----------|-------|-------------|-------------|
|| nba, basketball, knicks, lakers, celtics, warriors, bucks, etc. | Basketball | nba | `basketball_nba` |
|| nfl, football, superbowl, chiefs, 49ers, cowboys, patriots, etc. | Football | nfl | `americanfootball_nfl` |
|| mlb, baseball, yankees, dodgers, mets, red sox, etc. | Baseball | mlb | `baseball_mlb` |
|| nhl, hockey, rangers, avalanche, panthers, oilers, etc. | Hockey | nhl | `icehocey_nhl` |
|| la liga, barcelona, barca, real madrid, atletico, spanish league | Soccer | esp.1 | `soccer_spain_la_liga` |
|| premier league, epl, manchester, liverpool, arsenal, chelsea, english league | Soccer | eng.1 | `soccer_epl` |
|| champions league, ucl, champions | Soccer | UEFA.CHAMPIONS | `soccer_uefa_champs_league` |
|| mls, inter miami, lafc, american soccer | Soccer | usa.1 | `soccer_usa_mls` |
|| world cup, fifa, fifa world cup, mundial | Soccer | fifa.world | `soccer_fifa_world_cup` |
|| international friendly, friendlies, friendly match, morocco, norway, national team friendly | Soccer | fifa.friendly | — |
|| bundesliga, bayern, dortmund, german league | Soccer | ger.1 | `soccer_germany_bundesliga` |
|| serie a, ac milan, inter, juve, juventus, italian league | Soccer | ita.1 | `soccer_italy_serie_a` |
|| ligue 1, psg, paris saint-germain, french league | Soccer | fra.1 | `soccer_france_ligue_one` |
|| liga mx, mexican league, club america, chivas | Soccer | mex.1 | — |
|| copa libertadores, libertadores | Soccer | CONMEBOL.LIBERTADORES | `soccer_conmebol_copa_libertadores` |
|| ufc, mma, ufc fight night, octagon | MMA | ufc | `mma_mixed_martial_arts` |
|| tennis, atp, wta, wimbledon, roland garros, us open tennis, australian open | Tennis | tennis | — |
|| golf, pga, masters, pga tour | Golf | pga | — |
|| rugby, rugby world cup, six nations | Rugby | rugby | — |
|| wnba, women's basketball | Basketball | wnba | `basketball_wnba` |
|| f1, formula 1, formula one, grand prix, gp, race, verstappen, hamilton, leclerc, etc. | F1 | f1 | — |

## Fetching Data

Always use `terminal` with `curl` + `python3` for JSON parsing. Example patterns:

### Scores (ESPN)

```bash
curl -s "https://site.api.espn.com/apis/site/v2/sports/basketball/nba/scoreboard" | python3 -c "
import sys, json
d = json.load(sys.stdin)
for ev in d.get('events', []):
    name = ev.get('name', '')
    status = ev.get('status', {}).get('type', {}).get('description', '')
    short_detail = ev.get('status', {}).get('type', {}).get('shortDetail', '')
    for c in ev.get('competitions', []):
        for comp in c.get('competitors', []):
            team = comp.get('team', {}).get('abbreviation', '')
            score = comp.get('score', '?')
            home_away = 'HOME' if comp.get('homeAway') == 'home' else 'AWAY'
            print(f'{home_away} {team}: {score}')
        print(f'  Status: {status} - {short_detail}')
        print()
"
```

### Standings (ESPN — NBA/NFL/MLB/NHL)

```bash
curl -s "https://site.api.espn.com/apis/site/v2/sports/basketball/nba/standings" | python3 -c "
import sys, json
d = json.load(sys.stdin)
# Standings structure varies by sport — parse entries appropriately
# NBA: entries[].teamStats[] with stats like wins, losses, gamesBehind, etc.
for entry in d.get('standings', {}).get('entries', [])[:10]:
    team = entry.get('team', {})
    abbr = team.get('abbreviation', '')
    name = team.get('shortDisplayName', '')
    stats = {}
    for s in entry.get('stats', []):
        stats[s.get('name')] = s.get('value')
    wins = stats.get('wins', '?')
    losses = stats.get('losses', '?')
    pct = stats.get('winPercent', '?')
    gb = stats.get('gamesBehind', '?')
    print(f'{abbr:4} {name:20} {wins}-{losses}  PCT: {pct}  GB: {gb}')
"
```

### Standings (ESPN — Soccer / La Liga / Premier League)

Soccer standings use a different structure — group entries with team stats inside.

```bash
curl -s "https://site.api.espn.com/apis/site/v2/sports/soccer/esp.1/standings" | python3 -c "
import sys, json
d = json.load(sys.stdin)
for entry in d.get('standings', {}).get('entries', []):
    team = entry.get('team', {})
    name = team.get('shortDisplayName', team.get('displayName', ''))
    abbr = team.get('abbreviation', '')
    stats = {}
    for s in entry.get('stats', []):
        stats[s.get('name')] = s.get('value')
    wins = stats.get('wins', '?')
    losses = stats.get('losses', '?')
    draws = stats.get('ties', stats.get('draws', '?'))
    pts = stats.get('points', '?')
    gd = stats.get('goalDiff', stats.get('goalDifference', '?'))
    played = stats.get('gamesPlayed', stats.get('matchesPlayed', '?'))
    pos = stats.get('rank', stats.get('position', '?'))
    print(f'{str(pos):>2}. {name:2}. {name:2}: {driver:2}: {driver:2} Pts:{points:>4}')
"
```

### F1 — Next Race

```bash
curl -s "https://ergast.com/api/f1/current/next.json" | python3 -c "
import sys, json
d = json.load(sys.stdin)
race = d['MRData']['RaceTable']['Races'][0]
print(f'Next: {race[\"raceName\"]}')
print(f'Date: {race[\"date\"]}')
print(f'Circuit: {race[\"Circuit\"][\"circuitName\"]}')
print(f'Location: {race[\"Circuit\"][\"Location\"][\"locality\"]}, {race[\"Circuit\"][\"Location\"][\"country\"]}')
"
```

### F1 — Live Timing (during race sessions)

```bash
curl -s "https://api.openf1.org/v1/position?session_key=latest" | python3 -c "
import sys, json
d = json.load(sys.stdin)
# Sort by position
positions = sorted(d, key=lambda x: x.get('position', 999))
if not positions:
    print('No live session currently active')
else:
    session = positions[0].get('session_key', 'unknown')
    print(f'Session: {session}')
    for p in positions:
        pos = p.get('position', '?')
        driver = p.get('driver_number', '?')
        print(f'P{pos}: #{driver}')
"
```

### Odds — H2H / Moneyline (The Odds API)

```bash
# Read API key from skill .env
ODDS_API_KEY=$(grep ODDS_API_KEY ~/.hermes/skills/tools/sports-scores/.env | cut -d= -f2)

# Fetch odds for a sport (example: NBA)
curl -s "https://api.the-odds-api.com/v4/sports/basketball_nba/odds/?apiKey=${ODDS_API_KEY}&regions=us,eu&markets=h2h" | python3 -c "
import sys, json
d = json.load(sys.stdin)
if not d:
    print('No upcoming odds found — sport may be off-season.')
for ev in d[:8]:
    home = ev.get('home_team', '?')
    away = ev.get('away_team', '?')
    commence = ev.get('commence_time', '?')[:16]
    print(f'{home} vs {away}  ({commence})')
    for bk in ev.get('bookmakers', [])[:3]:
        for m in bk.get('markets', []):
            if m['key'] == 'h2h':
                prices = ' | '.join([f\"{o['name']}: {o['price']}\" for o in m.get('outcomes', [])])
                print(f'  {bk[\"key\"]}: {prices}')
    print()
"
```

### Odds — Spreads & Totals (The Odds API)

```bash
ODDS_API_KEY=$(grep ODDS_API_KEY ~/.hermes/skills/tools/sports-scores/.env | cut -d= -f2)

# Spreads (point spreads for US sports)
curl -s "https://api.the-odds-api.com/v4/sports/basketball_nba/odds/?apiKey=${ODDS_API_KEY}&regions=us&markets=spreads" | python3 -c "
import sys, json
d = json.load(sys.stdin)
for ev in d[:5]:
    home = ev.get('home_team', '?')
    away = ev.get('away_team', '?')
    print(f'{home} vs {away}')
    for bk in ev.get('bookmakers', [])[:2]:
        for m in bk.get('markets', []):
            if m['key'] == 'spreads':
                lines = ' | '.join([f\"{o['name']}: {o.get('point','?')} ({o['price']})\" for o in m.get('outcomes', [])])
                print(f'  {bk[\"key\"]}: {lines}')
    print()
"

# Totals (over/under)
curl -s "https://api.the-odds-api.com/v4/sports/basketball_nba/odds/?apiKey=${ODDS_API_KEY}&regions=us&markets=totals" | python3 -c "
import sys, json
d = json.load(sys.stdin)
for ev in d[:5]:
    home = ev.get('home_team', '?')
    away = ev.get('away_team', '?')
    print(f'{home} vs {away}')
    for bk in ev.get('bookmakers', [])[:2]:
        for m in bk.get('markets', []):
            if m['key'] == 'totals':
                lines = ' | '.join([f\"{o['name']}: {o.get('point','?')} ({o['price']})\" for o in m.get('outcomes', [])])
                print(f'  {bk[\"key\"]}: {lines}')
    print()
"
```

### Odds — Check Active Sports

```bash
ODDS_API_KEY=$(grep ODDS_API_KEY ~/.hermes/skills/tools/sports-scores/.env | cut -d= -f2)

# List only currently active sports with odds
curl -s "https://api.the-odds-api.com/v4/sports/?apiKey=${ODDS_API_KEY}" | python3 -c "
import sys, json
sports = json.load(sys.stdin)
active = [s for s in sports if s.get('active')]
for s in sorted(active, key=lambda x: x['key']):
    print(f\"{s['key']:<40} {s['title']}\")
print(f'Active: {len(active)} / {len(sports)}')
"
```

### Odds — American Format

Append `&oddsFormat=american` to any odds URL to get American odds (e.g., `-110`, `+150`) instead of decimal (e.g., `1.91`, `2.50`).

```bash
ODDS_API_KEY=$(grep ODDS_API_KEY ~/.hermes/skills/tools/sports-scores/.env | cut -d= -f2)
curl -s "https://api.the-odds-api.com/v4/sports/basketball_nba/odds/?apiKey=${ODDS_API_KEY}&regions=us&markets=h2h&oddsFormat=american"
```

## Output Rules

1. **Clean format.** Never dump raw JSON. Parse and present human-readable summaries.
2. **Live games.** If a game status is "In Progress" or similar, clearly note it: **🔴 LIVE**.
3. **Scheduled games.** Show date, time, and broadcast info.
4. **Completed games.** Show final score with winner bold or marked.
5. **Standings.** Top 10 only unless user asks

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Drknght4](https://github.com/Drknght4)
- **Source:** [Drknght4/hermes-sports-skill](https://github.com/Drknght4/hermes-sports-skill)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-drknght4-hermes-sports-skill-hermes-sports-skill
- Seller: https://agentstack.voostack.com/s/drknght4
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
