AgentStack
SKILL verified MIT Self-run

Sports Scores

skill-drknght4-hermes-sports-skill-hermes-sports-skill · by Drknght4

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

No reviews yet
0 installs
0 views
view→install

Install

$ agentstack add skill-drknght4-hermes-sports-skill-hermes-sports-skill

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Sports Scores? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

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/.envODDS_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

# 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

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:

  • regionsus, eu, uk, au, or comma-separated (default: us,eu)
  • marketsh2h (moneyline), spreads, totals (over/under), or comma-separated (default: h2h)
  • oddsFormatdecimal (default), american
  • dateFormatiso (default)

Available sports — fetch the full list with:

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)

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)

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.

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

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)

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)

# 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)

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

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).

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.

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

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.