← Back to Marketplace Gameplay
Commish banner
Commish icon

Commish

Discord plugin · Gameplay
by Paul
A discord friendly fantasy football commissioner tool.
v0.0.11 ↓1 install

A discord friendly fantasy football commissioner tool.

Commish screenshot 1

Commands this plugin adds

/commish-setup /commish-setup-fleaflicker /commish-setup-fantrax /commish-channel /commish-leagues /commish-switch /commish-unlink /commish-status /commish-help /commish-doctor /commish-week /commish-schedule /commish-matchups /commish-scores /commish-rankings /commish-standings /commish-streak-watch /commish-roster /commish-luck /commish-all-play /commish-record-book /commish-points-per-position /commish-optimal-lineup /commish-h2h /commish-budget /commish-injuries /commish-transactions /commish-waiver-claims /commish-waiver-targets /commish-trade-history /commish-trends /commish-nfl /commish-draft /commish-playoffs

About this plugin

Commish

Your fantasy football league, surfaced in Discord — weekly matchups, power rankings, injury alerts, waiver and start/sit reminders. Full Sleeper support, plus Fleaflicker (v2.0) and Fantrax (v2.1).

A plugin for YourBot.gg — runs sandboxed in the platform and reacts to Discord events on installed servers.

What it does

Links one or more fantasy leagues per Discord server — Sleeper (full support), Fleaflicker (core support, v2.0+) and Fantrax (standings/schedule tier, v2.1+) and exposes 34 manual slash commands — pre-week (/commish-matchups, /commish-week), in-week (/commish-scores, /commish-roster, /commish-waiver-claims, /commish-waiver-targets), retrospective (/commish-rankings, /commish-standings, /commish-streak-watch, /commish-luck, /commish-all-play, /commish-record-book, /commish-points-per-position, /commish-h2h, /commish-budget, /commish-injuries, /commish-transactions, /commish-trade-history, /commish-trends, /commish-nfl), season-context (/commish-draft, /commish-playoffs) and admin/config (/commish-setup, /commish-leagues, /commish-switch, /commish-unlink, /commish-channel, /commish-schedule, /commish-doctor, /commish-status, /commish-help) — plus a set of UTC-scheduled posts (waiver reminders, weekly previews, start/sit prompts, end-of-week recap, trade-deadline alert, playoff-clinching alerts, recurring injury scans, hourly transaction digest), dispatched from a platform-fired hourly cron tick with an on_ready catch-up sweep behind it. League data comes from each platform's public, no-auth API: Sleeper at api.sleeper.app, Fleaflicker at www.fleaflicker.com/api, Fantrax at www.fantrax.com/fxea; live NFL scores come from ESPN's public site API at site.api.espn.com (no league needed). Internally, provider adapters map foreign payloads into Sleeper shapes, so the same command surface serves every platform; league refs are composite (fleaflicker:<id>, fantrax:<id>) for non-Sleeper platforms. A per-platform feature matrix (PLATFORM_FEATURES) gates what each platform's API can actually power — unsupported commands reply with a clear refusal naming the platform instead of failing.

Feature Sleeper Fleaflicker Fantrax
Standings, rankings, week snapshot, rosters ✅ ✅ ✅
Weekly matchups ✅ ✅ ✅ (schedule only — fxea has no scores)
Live scores, luck, all-play, record book, h2h, recap, streaks ✅ ✅ ❌
Transactions, waivers, waiver targets, trade history, FAAB ✅ ❌ ❌
Draft, playoffs, injuries, skill rankings, points-per-position ✅ ❌ ❌

Channels for each post type are configured per-server via /commish-channel. If a given post type doesn't have a channel set, it falls back to whichever channel was set for general; if that's also unset, the cron logs and skips silently.

Sleeper integration

Sleeper is the primary platform; the plugin talks to api.sleeper.app (public endpoints, no auth, no API key) — see Capabilities for the full proxy-domain list across all platforms. The Sleeper endpoints used are:

Endpoint Used for
GET /v1/state/nfl Current week + season type — gates regular-season-only cron tasks.
GET /v1/league/{id} League validation in /commish-setup and league metadata.
GET /v1/league/{id}/users Team owner / display name lookup.
GET /v1/league/{id}/rosters Roster contents, win/loss/points-for stats, rostered player IDs.
GET /v1/league/{id}/matchups/{week} Weekly matchup pairings + points (with per-player points for /commish-optimal-lineup).
GET /v1/league/{id}/transactions/{week} Trades, waivers and free-agent moves — /commish-transactions, /commish-waiver-claims, /commish-trade-history, the hourly digest.
GET /v1/league/{id}/drafts + GET /v1/draft/{id}/picks /commish-draft.
GET /v1/league/{id}/winners_bracket /commish-playoffs.
GET /v1/players/nfl/trending/{add,drop} /commish-trends (global, no league needed); the add feed also powers /commish-waiver-targets and the waiver-reminder cron, intersected with the league's rosters.
GET /v1/players/nfl Player names, positions, teams and injury_status. See known limitation below.

Multi-league (v0.6+): a single Discord server can link any number of Sleeper leagues. Channel mappings are per-league — each league has its own general / waivers / news / previews / rankings channel set, so two leagues can post to two different channel groups in the same server. One league is "active" at a time; commands like /commish-week, /commish-rankings, etc. operate on the active league. Use /commish-switch league:<id-or-name> to change.

Embedded player catalog — workaround for the 1 MB proxy cap

Sleeper's full NFL player catalog is roughly 5 MB. The YourBot.gg outbound-HTTP proxy caps response bodies at 1 MB, so it can't be fetched at runtime. v0.3 sidesteps this by bundling a trimmed snapshot of the catalog inside __main__.py — fantasy-relevant positions only, five fields per player (full_name, first_name, last_name, team, position, injury_status), zlib-compressed + base64. Refresh it before every release with make refresh-players. The catalog is the only Sleeper endpoint we can't proxy; everything else (rosters, users, matchups, transactions, state) is hit live.

Trade-offs:

  • /commish-injuries shows the snapshot's injury_status and includes a footer with the snapshot date. Accuracy is good for ~a week (releases cadence); for live injury news, see Sleeper's own notifications.
  • The injury-scan cron still fires every 6 hours but now only posts when the embedded data has changed — effectively a delta-on-release digest.
  • Players added between releases (rookies, new signings) show up as Player <id> in transaction posts until the next refresh.

This is the workaround until the YourBot.gg platform ships a server-side player cache, at which point the embedded snapshot can be removed entirely.

Capabilities

This plugin requests the following capabilities (all Safe tier — no Risky or Dangerous caps):

Capability Tier Why
discord:send_message Safe Post matchups, rankings, injury updates and reminders from cron and slash commands.
interaction:respond Safe Reply to all 34 slash commands (auto-added because slash_commands is non-empty, declared explicitly for review clarity).
proxy:http Safe Fetch league data from api.sleeper.app, www.fleaflicker.com and www.fantrax.com, plus live NFL scores from ESPN's public site.api.espn.com.
storage:kv Safe Per-server league config, channel mappings, and per-player injury-status state for cron dedup.

proxy_domains_requested is exactly ["api.sleeper.app", "www.fleaflicker.com", "www.fantrax.com", "site.api.espn.com"]. Nothing else is reachable.

If any future capability would push the plugin into Risky or Dangerous tier, that change will be called out in CHANGELOG.md and bump the major version.

Slash commands

Admin-only commands (/commish-setup, /commish-channel, /commish-schedule) should be restricted via Discord's per-command permissions in Server Settings → Integrations. The YourBot.gg manifest schema doesn't have a server-side admin flag, so gating is enforced at the Discord layer, not in the plugin code.

Setup & configuration (admin)

Command Description
/commish-setup sleeper_league_id:<id> Validates the Sleeper league ID against the API and links it to this server. As of v0.6 this adds to the linked-league list — running it more than once with different IDs gives you multiple linked leagues, with the most-recently-added one becoming active.
/commish-setup-fleaflicker league_id:<id> Links a Fleaflicker league (the number in fleaflicker.com/nfl/leagues/<id>). Stored as the composite ref fleaflicker:<id>, so it coexists with Sleeper leagues on the same server. Core support — see the feature matrix below for what Fleaflicker's API can power (v2.0).
/commish-setup-fantrax league_id:<id> Links a Fantrax league (the letters-and-digits code in fantrax.com/fantasy/league/<id>/...). Stored as fantrax:<id>. Standings/schedule tier — Fantrax's public API exposes no weekly scores, so score-derived commands refuse by name (v2.1).
/commish-leagues List every league linked to this server, with ⭐ marking the active one.
/commish-switch league:<id-or-name> Change which linked league is active (admin). Accepts either a Sleeper league ID or a unique substring of the league name.
/commish-unlink league:<id-or-name> Remove a linked league (admin). Per-league channel mappings for the unlinked league are deleted.
/commish-channel type:<...> [league:<id-or-name>] Sets the CURRENT channel as the destination for one of general, waivers, news, previews, rankings. As of v0.6 channel mappings are per-league — pass league: to target a specific league, otherwise the active league is configured.
/commish-schedule Shows when each cron post fires next for the active league, and which channel each will land in.
/commish-doctor Diagnostic snapshot — linked leagues, channel coverage, Sleeper API connectivity, KV read/write health, and per-cron last-fired timestamps. Ephemeral.

Discovery & info

Command Description
/commish-help Lists every command and shows the current setup status. The "I just installed this, now what" command.
/commish-status Linked league + channel mappings (no command listing — that's /commish-help).

League content

Command Description
/commish-week One-shot snapshot for the current week — header + matchups + top-3 power rankings, in a single message. Best for daily check-ins. Carries the navigation hub (🗓️ Matchups, 📊 Standings, 📈 Rankings, 🏈 Live scores, 👥 Rosters) — one click posts the full view; the Live-scores button only appears for platforms that expose live scoring (v2.2, Matchups added v2.7, Rosters v2.9). A second row jumps to season analytics — 🍀 Luck, 🎲 All-play, 📖 Record book, 🪑 Bench points — gated to platforms whose API can power them (v2.9).
/commish-matchups Posts this week's matchups embed. Carries the navigation hub (v2.7).
/commish-scores Live in-progress scoring — same week as /commish-matchups, sorted by closest matchup first. Shows leader, spread, and an approximate yet-to-play starter count per team. Footer carries the UTC snapshot timestamp so you can tell whether the data is fresh. Carries a 🔄 Refresh button to re-pull live scores in one tap (v2.4), followed by the rest of the navigation hub (v2.7). Regular-season only.
/commish-rankings [mode:all|skill] Power rankings. Default all ranks by roster.settings.fpts. skill recomputes from per-player matchup data, excluding K and DEF — needs at least one completed regular-season week. Carries the navigation hub (v2.7).
/commish-standings Full standings table — W-L-T record, PF, PA, streak, and games-back from the leader. Record-first sort (PF as tiebreaker), the complement to /commish-rankings's points-first sort. Carries the navigation hub (v2.7).
/commish-streak-watch Current active streaks per team, sorted hottest-to-coldest (W3 → W1 → none → L1 → L3). Reads Sleeper's native roster.metadata.streak field — same source /commish-standings uses for its streak column.
/commish-roster [team:<id-or-name>] Show one team's starters (by lineup slot), bench, IR/reserve, and taxi squad. team: accepts a team-name substring, owner display name, or numeric roster ID. Omitting it shows a clickable team-picker (one button per team, v1.13); the same picker opens from the 👥 Rosters button on any league view (v2.9).
/commish-luck Luck rating — each team's actual W-L vs expected wins from all-play (you beat everyone who scored less than you that week). Positive luck = winning more than scores alone would predict. Needs at least one completed regular-season week.
/commish-all-play All-play standings — every team's record as if it played everyone every week (beat all who scored less, lose to all who scored more; equal scores are half-wins), ranked by all-play win%. Strips schedule luck out of the standings, so a team can be 5-8 head-to-head yet near the top. Shares the tested all-play math with /commish-luck. Needs at least one completed regular-season week (v2.5).
/commish-record-book Season records — highest single-week score, biggest blowout, closest game, longest win streak, longest losing streak, toughest schedule (most points-against). Needs at least one completed regular-season week.
/commish-optimal-lineup [team:<id-or-name>] [week:<n>] Points left on the bench for a completed week. Without team:, a league-wide table (actual / optimal / left) with the biggest blunder first; with team:, that team's optimal lineup slot by slot, ➕-marking the bench players who should have started. week: defaults to the most recently completed week. The optimal lineup is the best legal lineup from the full roster — slots are filled most-restrictive-first, which is optimal here because flex eligibility is nested (every slot that takes an RB is a subset of what FLEX takes). Sleeper only: it needs per-player weekly scoring (player_points), which Fleaflicker and Fantrax don't expose. Completed weeks are KV-cached, so re-running the same argument is free. (v2.8)
/commish-points-per-position Per-team season scoring broken down by lineup slot (QB / RB / WR / TE / FLEX / K / DEF — whatever the league's roster_positions declares). Reveals positional strengths. Same-name slots (two RB slots) lump into one column. Skips BYE weeks.
/commish-h2h team1:<id-or-name> team2:<id-or-name> Head-to-head record between two teams across every completed regular-season week they shared a matchup_id. Shows per-game scores, total PF on each side, and average margin. Both args required — reuses the _resolve_team_arg resolver per-arg so ambiguous/unknown matches surface per-team error messages.
/commish-budget FAAB budget remaining per team, sorted most-remaining first. FAAB-only leagues (priority-based waiver leagues see a "doesn't use FAAB" message). Reads league.settings.waiver_budget and roster.settings.waiver_budget_used.
/commish-injuries Lists injured / questionable / doubtful / out players across the league. Data is from an embedded snapshot — refresh date shown in the footer.
/commish-transactions This week's completed transactions (trades, waivers, free agents) in a single embed. Manual catch-up companion to the hourly digest cron.
/commish-waiver-claims This week's pending waiver claims (pre-Tuesday processing), grouped by team and sorted within each team by FAAB bid descending. Companion to /commish-transactions — useful for "who's bidding on whom?" before the waiver run.
/commish-waiver-targets [position:<QB|RB|WR|TE|K|DEF>] Hot pickups still on your wire — Sleeper's most-added players over the past 24 hours, minus everyone already rostered in this league, ranked by adds with position/team and the snapshot injury flag. Two proxied requests (the ~900-byte trending feed + live rosters). Sleeper only: the feed carries Sleeper player ids. Distinguishes "every hot pickup is taken" from a Sleeper outage. The Tuesday waiver reminder carries the top five automatically. (v2.10)
/commish-trade-history [team:<id-or-name>] Every completed trade this season, newest week first. Optional team: arg narrows to trades involving that team only. Reuses the same team: resolver as /commish-roster.
/commish-trends Most-added and most-dropped NFL players across all Sleeper leagues, past 24h. Doesn't require a linked league.
/commish-nfl Live NFL game scoreboard from ESPN's public API, bucketed In progress → Upcoming → Final (live games first). Platform-agnostic — doesn't require a linked league (v2.3).
/commish-draft League draft summary — date/time, format (teams × rounds × snake/linear), current status (pre-draft / drafting / complete), and the most recent picks once drafting starts.
/commish-playoffs Playoff bracket — championship side only, with team names resolved at each round and winners marked once games complete.

If /commish-setup hasn't been run, every command replies ephemerally with a "run /commish-setup first" hint and posts nothing.

Scheduled posts (cron — UTC)

When Channel type What
Tue 02:00 UTC waivers Waiver-wire reminder — with the five hottest pickups still on the league's wire (v2.10; the plain reminder still posts if the feed is down).
Tue 10:00 UTC general Trade-deadline alert — fires only on the league's configured trade_deadline week.
Tue 14:00 UTC rankings Weekly power rankings (all positions; use /commish-rankings mode:skill for the K/DEF-excluded view).
Tue 16:00 UTC general End-of-week recap — final scores + winners + biggest blowout + closest game for the week that just ended.
Tue 17:00 UTC general Playoff clinching update — fires once per team when they're mathematically locked into the playoffs (or eliminated). KV-deduped so each transition is announced only once.
Thu 14:00 UTC previews This week's matchup preview.
Sat 17:00 UTC general Start/sit prompt.
Every 6 hours news Injury scan — posts only when at least one rostered player's injury_status has changed since the last scan (KV-backed dedup keyed by player ID). Since the player catalog is embedded, changes only show up after make refresh-players ships in a release.
Hourly (top of hour) news Transaction digest — posts each new completed trade / waiver / free-agent move once. Skipped outside the regular season.

Channel fallback: if a given post type's channel isn't set, the plugin uses general. If general is also unset, the cron logs and skips. Pre-season and post-season runs (state.nfl returns week=0 or season_type != "regular") skip every content cron — matchup preview, start/sit, waiver reminder, power rankings, recap, deadline/clinching alerts and the transaction digest (as of v1.12 the waiver reminder and power rankings are season-gated like the rest); only the injury scan still runs year-round, and it only posts on actual status changes.

/commish-schedule is the easiest way to verify that each cron will fire where you expect.

How scheduled posts actually fire

Marketplace installs run on pooled workers, and the SDK never starts a plugin's @plugin.cron / @plugin.schedule background threads there — pooled workers serve many servers and carry no per-install state. Scheduled work fires only from manifest.json's "cron" array: the platform delivers a synthetic cron event to each enabled server on schedule, and the SDK routes it to the @plugin.cron function whose name matches the entry.

As of v2.6.0 Commish uses that mechanism. It declares exactly one entry:

"cron": [
  {"spec": "0 * * * *", "name": "cron_dispatch"}
]

cron_dispatch is the only @plugin.cron task in the plugin. On each tick it sweeps CRON_SCHEDULE and fires whatever is due. One tick covers all nine schedules because the platform caps a plugin at five cron entries while Commish has nine — and because every schedule fires at minute 0, an hourly tick lands on each one's exact scheduled minute. Adding a tenth schedule needs no manifest change.

Two paths converge on the same KV state of record, and both take the same atomic per-slot kv.increment claim before firing, so they can never double-post:

Path When it runs Role
cron_dispatch (manifest cron) Top of every hour, per enabled server Primary. This is what runs in production.
on_ready sweep Once per (worker, server) bootup Fallback. Cron delivery is at-most-once with no replay; a firing missed during a platform blip would otherwise wait a full schedule period, whereas the next inbound event bridges the gap immediately.

Each fire is recorded in state:cron_last_fired:<key>. First-run handling: an empty timestamp seeds without firing, so a freshly-installed server doesn't get spammed with nine catch-up messages. The on_ready sweep runs on a daemon thread so it can't delay the interaction that woke the worker past Discord's 3-second ack window.

Before v2.6.0 the on_ready sweep was the only path. The SDK of the day (0.5.x–0.8.x) documented no manifest-cron schema, so the nine schedules fired opportunistically on whatever event happened to wake a worker — a quiet server got quiet crons. yourbot-sdk 0.9.0 added _dispatch_cron_event and the manifest "cron" contract, and v2.6.0 adopted it.

/commish-schedule shows where each post will land and when it next fires; /commish-doctor exposes the last-fired timestamps so you can see at a glance which crons are tracking and which are silent. The manual slash commands work identically either way.

Lifecycle hooks also work in pool mode under yourbot-sdk 0.6.1+ (this plugin pins yourbot-sdk>=0.6.1,<0.11.0; the SDK was renamed from mmo-maid-sdk at 0.6.0 and the old import keeps working only via a deprecated shim). Specifically, @plugin.on_ready fires once per (worker, server) on the first event for each tenant, synchronously before the event handler runs. That guarantee is what makes the v0.6 multi-league migration safe: when a pool-mode worker receives its first event for a server that's still on the legacy single-league schema, on_ready runs _migrate_legacy_league_keys() to completion before the user-facing handler sees KV. The guarantee first landed in legacy SDK 0.5.2 (pool-mode on_ready was effectively non-functional in 0.5.0/0.5.1) and is preserved through the 0.6.x–0.10.x releases.

KV schema

Colon-delimited keys per the SDK style guide. KV is automatically namespaced by plugin_id and server_id at the runtime layer, so these keys do not include either prefix.

Key Purpose
cfg:leagues List of every linked Sleeper league: [{"id": "...", "name": "..."}].
cfg:active_league_id The league ID that "active-league" commands target by default.
cfg:channel:<league_id>:<type> Destination channel ID for a post type within a specific league. Per-league as of v0.6.
cfg:migrated_to_multi_league Set to "1" after the v0.6 schema migration runs. Idempotent guard.
cfg:league_id / cfg:league_name / cfg:channel:<type> Legacy (pre-v0.6) single-league keys. Read once during migration, then ignored. Left in place after migration so a v0.5 downgrade still works.
state:last_news_scan ISO timestamp of the most recent injury-scan cron run.
state:player_status:<league_id>:<player_id> Last-seen injury status for a rostered player, used by the injury-scan cron to dedup. League-scoped as of v2.1.1. Deleted when a player returns to "Active"; written with a 90-day TTL so players dropped while injured don't hold keys forever.
cache:rostered_players:<league_id> List of player IDs currently rostered in a league. Refreshed by the injury cron at most once per day. League-scoped as of v1.12 (the old unscoped key is orphaned, not read). 7-day TTL (v2.8.1); deleted by /commish-unlink.
cache:rostered_players:<league_id>:ts ISO timestamp of the last rostered-players refresh for that league. Same TTL and cleanup as the list.
cache:matchups:<league_id>:<week> Trimmed matchup data for a completed week (roster_id, matchup_id, points, starters, starters_points). Immutable once a week ends, so season-wide commands and dashboards read KV instead of re-walking Sleeper. The most recent completed week carries a 2-day TTL to pick up stat corrections.
cache:trades:<league_id>:<week> Trimmed completed trades for a completed week — same caching rules as cache:matchups.
cache:optimal:<league_id>:<week> Computed optimal-lineup rows for a completed week (/commish-optimal-lineup, v2.8) — same caching rules as cache:matchups.
state:transactions:seen:<league_id> Ordered list (oldest→newest) of transaction IDs the hourly digest cron has already posted for that league. Capped at 500 entries, trimmed oldest-first. League-scoped as of v2.1.1 (the pre-v2.1.1 global state:transactions:seen is read once as a seed); deleted by /commish-unlink.
state:playoff_status:<league_id>:<roster_id> Per-team playoff status (clinched / eliminated / unset). League-scoped as of v1.12; the pre-v1.12 unscoped key is read once as a fallback, then migrated. 120-day TTL, refreshed weekly by the clinching cron while the season runs (v2.8.1 — previously no TTL, so every past season's keys accumulated forever).
state:cron_last_fired:<cron_key> ISO UTC timestamp of each cron's most recent successful fire. Written by the cron's @_register_lazy_cron wrapper; read by the hourly cron_dispatch tick and by the on_ready catch-up sweep to decide what is overdue. Surfaced in /commish-doctor.
state:cron_claim:<cron_key>:<due-slot> Atomic fire claim (kv.increment) preventing two pool workers from double-posting the same overdue cron. Self-expires after 7 days.
state:doctor_probe Transient KV health-check value written and immediately deleted by /commish-doctor; only persists if the delete fails.

The full Sleeper player catalog is never cached in KV — it's ~5 MB and would blow the 64 KB per-value limit anyway. A trimmed snapshot is instead bundled in __main__.py (see "Embedded player catalog" above). Per-player status is stored individually (each value is a single short string).

Configuration walkthrough

  1. Install the plugin from the YourBot.gg marketplace; grant the four capabilities listed above.
  2. Link your league: in any channel, run /commish-setup sleeper_league_id:<your-id> (the long number in the Sleeper URL, e.g. https://sleeper.com/leagues/123456789012345678/league) — or /commish-setup-fleaflicker league_id:<your-id> for a Fleaflicker league (the number in fleaflicker.com/nfl/leagues/<id>), or /commish-setup-fantrax league_id:<your-id> for a Fantrax league (the letters-and-digits code in fantrax.com/fantasy/league/<id>/...).
  3. Set channels. Easiest: click "Post league updates in this channel" on the setup confirmation — that maps general, which every other post type falls back to. For finer routing, run /commish-channel type:<type> in each channel you want a specific post type to land in.
  4. Verify setup: run /commish-help (or /commish-status) to confirm the league is linked and channels are mapped, then /commish-schedule to see when the next cron post will fire.
  5. Try it: /commish-week for the daily snapshot — then tap its Standings / Rankings / Live scores / Rosters buttons — or the second row's Luck / All-play / Record book / Bench points — to drill in without retyping. Every league view carries the same two rows, so no view is a dead end. /commish-standings and /commish-rankings give the leaderboard views (record-first vs PF-first), /commish-roster team:<name> a specific lineup, /commish-scores live in-progress points during a slate. /commish-waiver-targets (hot pickups still on your wire), /commish-injuries, /commish-transactions, /commish-draft, /commish-playoffs, /commish-trends and /commish-nfl (live NFL scoreboard — no league needed) round out the catalog.

The cron jobs start firing automatically at their next UTC trigger. No further setup needed.

Roadmap

v1.0 shipped the Sleeper-only, full-featured milestone. As of v2.1 the project is multi-platform (Fleaflicker and Fantrax shipped): a provider abstraction so the same command surface can serve leagues hosted on other fantasy platforms, starting with the ones whose APIs work inside the platform sandbox (public JSON, no OAuth — Fleaflicker first; ESPN read-only next; Yahoo stays blocked until the platform offers an OAuth broker, because Yahoo's token refresh requires a client secret the sandbox can't hold). The catalog cap forced a build-time snapshot rather than a runtime fetch (see "Embedded player catalog" above).

Shipped

v0.3

  • ✅ Embedded player catalog — workaround for the 1 MB proxy cap. Verified there's no smaller Sleeper or third-party feed that joins to Sleeper rosters, so we bundle a trimmed snapshot in __main__.py. Refresh via make refresh-players before each release.
  • ✅ Transaction-feed alerts — cron_transaction_digest (hourly) posts new trades, waivers and free-agent moves into the news channel as they happen. /commish-transactions is the manual catch-up companion.

v0.4

  • ✅ DST/kicker filtering for power rankings — /commish-rankings mode:skill recomputes points-for from per-player matchup data, excluding K and DEF. Uses the embedded catalog's position metadata.
  • ✅ End-of-week recap cron — Tue 16:00 UTC during regular season. Final scores + winners + biggest blowout + closest game.
  • ✅ Trade-deadline alert cron — Tue 10:00 UTC, fires only on the week matching the league's configured trade_deadline.
  • ✅ /commish-trends — most-added / most-dropped players across all Sleeper leagues, past 24h.

v0.5

  • ✅ /commish-draft — draft date, format, status, and the last N picks once drafting starts. Picks the most recent regular-season draft when a league has multiple (mock + real).
  • ✅ /commish-playoffs — winners-bracket view rendered as Quarterfinals / Semifinals / Championship, with team names resolved at each round and winner of m{X} placeholders for unresolved slots. Completed matchups show ✅ + strike-through loser.
  • ✅ Playoff clinching cron — Tue 17:00 UTC weekly during regular season. Announces each team's transition to "clinched" or "eliminated" exactly once via KV dedup. Uses purely-mathematical win-count analysis (PF tiebreakers can still flip an edge case but the message is "guaranteed top-N by wins").

v0.6

  • ✅ Multi-league per server — KV schema refactored from single cfg:league_id to cfg:leagues + cfg:active_league_id, with per-league channel mappings (cfg:channel:<league_id>:<type>). Legacy single-league installs auto-migrate on first read after deploy. New slash commands: /commish-leagues, /commish-switch league:<...>, /commish-unlink league:<...>. /commish-setup now adds rather than replaces.
  • ✅ Manifest-mode dashboard (dashboard_manifest.json). Two pages: Overview (linked-leagues stat card, current NFL week, standings leader for active league, recent-transactions table) and Settings (linked-leagues markdown summary + 5-channel form for the active league). Seven @plugin.on_dashboard(...) handlers.

v0.7

  • ✅ /commish-standings — full standings table (W-L-T record, PF, PA, streak, games-back). Sorts by record first with PF as tiebreaker, the complement to /commish-rankings's points-first sort. Reads roster.settings.fpts_against and roster.metadata.streak (both Sleeper-provided, both untouched by existing commands). Code-block rendered for monospace column alignment.

v0.8

  • ✅ /commish-roster [team:<id-or-name>] — per-team lineup view. Shows starters by league.roster_positions slot (QB / RB / WR / TE / FLEX / K / DEF / SUPER_FLEX / IDP — whatever the league declares), bench, IR/reserve (with injury status), and taxi squad. Team resolver accepts a team-name substring, owner display name, or numeric roster ID; omitting the arg returns an ephemeral "pick a team" list, ambiguous matches list the candidates, and bad input gracefully lists all teams as fallback.

v0.9

  • ✅ /commish-scores — live in-progress matchup scoring. Same Sleeper endpoints as /commish-matchups but presents the pairings sorted closest-spread first so daily check-ins see the dramatic games at the top, not the matchup-ID-ordered list. Each pair shows leader, spread, and a yet-to-play starter count (heuristic: starters with exactly 0.00 points so far). Footer carries the UTC snapshot timestamp.

v0.10

  • ✅ Regression / edge-case pass. Two /commish-roster bugs fixed (partial lineups dropping slots silently; IR section emitting — — noise when no injury status is known) and seven new regression tests pin behaviors that should stay stable as the plugin evolves — standings + rankings during post-season, BYE rendering, all-zero scores edge, mid-season setup, and the two roster fixes above.

v1.0

  • ✅ Documentation pass. README updated to reflect the v0.7→v0.10 push: command count corrected (9 → 19) everywhere it was stale, "What it does" rewritten to call out the full slash-command surface, "Try it" walkthrough expanded with the new commands and when to reach for each.
  • ✅ Feature surface frozen. No new slash commands or schema changes planned for v1.0+ on the Sleeper-only path. (Re-opened at v1.1 — see below.)

v1.1 (post-v1.0 feature expansion)

  • ✅ /commish-luck — luck rating. Per-team, computes actual wins vs expected wins from all-play (you "win" against every team that scored less than you each week). Sorted luckiest-first; positive luck = winning more than scores alone predict, negative luck = losing despite scoring well. Uses the same multi-week matchup loop as the skill-rankings code path.
  • ✅ /commish-record-book — single-season aggregates: highest single-week score, biggest blowout, closest game, longest win streak, longest losing streak, toughest schedule (most PA). Shared _completed_weeks_matchups helper with /commish-luck so both commands pay the same N proxy calls once each.
  • ✅ /commish-trade-history [team:<id-or-name>] — every completed trade across the season, newest week first. Optional team filter reuses the /commish-roster resolver. Filters out waivers and free-agent moves (those live in /commish-transactions).

v1.2 (operational)

  • ✅ Lazy-cron pool-mode fallback. The SDK's "server-side cron in manifest" mitigation isn't documented at the schema level, so Commish takes the documented alternative: each @plugin.cron records its successful fire in state:cron_last_fired:<key>, and on_ready (guaranteed once per (worker, server) under SDK v0.5.2+) re-fires anything overdue. First-run seeding prevents spam on fresh installs; corrupt timestamps re-seed defensively. A drift-guard test fails CI if a new @plugin.cron is added without the @_register_lazy_cron decorator.
  • ✅ /commish-doctor — diagnostic snapshot: leagues + active, channel coverage, Sleeper API reachability + current week, KV read/write probe, and per-cron last-fired relative times ("2h ago", "3d ago"). Ephemeral admin tool, useful for ops debugging and as a contract for the new last-fired KV slots.

v1.3 (dashboard polish)

  • ✅ Dashboard expanded from 2 pages to 4. New "Live week" page (top score stat, closest spread stat, this-week matchups table sorted closest-first) and "Season summary" page (total trades stat, top-3 luckiest teams list, season records list). Six new @plugin.on_dashboard handlers, all reusing the same _build_*_embed / _completed_weeks_matchups helpers that power the slash commands so no business logic is duplicated.

v1.4 (massive regression sweep)

  • ✅ Two real fixes surfaced during the audit. /commish-luck and /commish-record-book were both including BYE-week roster entries (matchup_id=None) in their math — phantom all-play comparisons in luck, and a phantom "high score" record without a real game behind it. Both fixed; only affected odd-team leagues where rotating BYEs exist.
  • ✅ 21 new regression tests across five themes — Sleeper-outage resilience for every public command, multi-league isolation, season-boundary behavior, per-cron lazy-fallback smoke, and BYE-week math — plus a single end-to-end install→use→unlink journey that exercises the full lifecycle in one MockContext.
  • ✅ Latent timing bug surfaced. The v1.2 lazy-cron skip test was flaky on the top-of-the-hour boundary; refactored _lazy_cron_check_and_fire to accept an optional now parameter for deterministic testing.

v1.5 (FAAB visibility)

  • ✅ /commish-budget — FAAB remaining per team, sorted most-remaining first with wins as tiebreak. FAAB-only command — leagues using priority-based waivers (no FAAB) get an explanatory message rather than a meaningless $0/$0 table. Reads league.settings.waiver_budget (total) and roster.settings.waiver_budget_used (spent).

v1.6 (head-to-head)

  • ✅ /commish-h2h team1 team2 — head-to-head record between two specific teams. Iterates _completed_weeks_matchups (the v1.1 helper) and counts only weeks where both teams shared a matchup_id. Renders per-week scores, total PF on each side, and average margin. Both args required; team resolution reuses _resolve_team_arg per-arg so an ambiguous or unknown team1 surfaces as a **team1:** prefixed error rather than confusing the user about which arg was wrong.

v1.7 (pre-waiver visibility)

  • ✅ /commish-waiver-claims — this week's pending waiver claims (Sleeper marks them status="pending", type="waiver" pre-processing; after Tuesday's run they flip to complete or failed). Grouped by team (most active first), sorted within each team by FAAB bid descending — mirrors Sleeper's own resolution order. Renders + AddPlayer and optional / − DropPlayer. Companion to /commish-transactions which only surfaces post-run results.

v1.8 (observability)

  • ✅ ctx.metrics instrumentation across the three highest-signal paths. sleeper_request counter tagged with path (normalized — league/{id}/rosters, not the literal league_id) and outcome (success/failure/rate_limit/retry) gives a per-endpoint health view in the metrics dashboard. cron_fired (from the wrapper) and cron_lazy_fired (from the lazy dispatcher) together partition the cron fire path — the ratio surfaces whether the plugin is running pooled (lazy carries the schedule) or single-tenant (scheduler does). command_invoked (from the new _slash_command(name) wrapper around @plugin.on_slash_command) is tagged with the command name so per-command usage rolls up cleanly. All three write paths are wrapped in try/except so a metrics outage can't break a Sleeper call, a cron handler, or a slash command. Drift guards in the test suite fail loudly if a new cron skips @_register_lazy_cron or a new command skips @_slash_command.

v1.9 (positional breakdown)

  • ✅ /commish-points-per-position — per-team scoring breakdown by lineup slot across all completed regular-season weeks. Reads league.roster_positions to label each starter-index, sums points, lumps same-name slots (two RB slots → one RB column), skips BN/IR/RSV/TAXI and BYE weeks. Code-block rendered to align columns; truncates to first 8 slot types if a league has more (rare).

v1.10 (streak watch)

  • ✅ /commish-streak-watch — current active streaks per team, sorted hottest-to-coldest. Reads Sleeper's roster.metadata.streak via the v0.7 _format_streak helper — same data source /commish-standings uses for its streak column. New _streak_sort_value() maps W3 → +3, L1 → −1, — → 0 for ranking. Cheaper than the multi-week views (no per-week loop).

v1.11 (observability dashboard)

  • ✅ Dashboard expanded from 4 pages to 5. New "Observability" page wires the v1.8 ctx.metrics counters (sleeper_request, cron_fired, cron_lazy_fired, command_invoked) into four widgets: a stat card with the pool-mode rate as percentage + classification, a line chart of Sleeper requests by outcome over 7d, a bar chart of cron fires by cron over 30d, and a top-10 commands list by 30d invocation count. New _safe_metrics_query / _safe_metrics_total helpers defensively shield every dashboard handler so a metrics-backend hiccup returns an empty-state shape rather than breaking the page.

v2.10 (waiver targets)

  • ✅ /commish-waiver-targets [position] — Sleeper's most-added players (24h) minus everyone rostered in this league: the answer to "who's hot AND still on my wire?" in two proxied requests. Live-probed first (feed 200 / 890 B; all 25 ids resolve in the embedded catalog, DEF units included). Sleeper-only via a new waiver_targets feature key; "every hot pickup is taken" and a Sleeper outage read differently. The Tuesday waiver reminder now carries the top five automatically and still posts plain if the feed is down. 34 commands.

v2.9 (season hub row + Rosters everywhere)

  • ✅ Two-row navigation hub under every league view. The week row gained 👥 Rosters (opens the team picker; a roster is two clicks from any view), and a second row jumps to season analytics — 🍀 Luck, 🎲 All-play, 📖 Record book, 🪑 Bench points — each gated to platforms whose API can power it (Fantrax gets no season row rather than buttons that refuse; Fleaflicker gets everything but Bench points). The hub now also renders under the views that lacked it (streaks, points-per-position, h2h, FAAB, transactions, trade history, waiver claims, injuries, rosters, draft, playoffs), and outage copy names the league's actual platform instead of always blaming Sleeper. 15 new tests cover picker round-trips, every season click, pre-season and wrong-platform refusals, and a 2-rows × 5-buttons limit sweep across all platforms.

v2.8.1 (tune-up: KV leaks + dashboard fetch sharing)

  • ✅ Audit fixes. Playoff-status and rostered-player-cache keys now carry TTLs — they leaked one orphan key per roster (or per league) per season, because Sleeper mints a new league id every year — and /commish-unlink deletes the roster-cache pair. Dashboard widgets on one page share fetches through a 20-second, dashboard-only memo (Live week: 10 → 4 proxied requests per view; the live-scores Refresh button and every slash command still fetch live). Embedded catalogs refreshed for the 2026 season. Docs: KV-schema and endpoint tables caught up with the code; a test now pins every manifest command to a README row and the quoted command counts to the manifest.

v2.8 (optimal lineup)

  • ✅ /commish-optimal-lineup — the one league-chat stat Commish couldn't answer: how many points each manager left on their bench. Every other season view reads the trimmed completed-week cache (_trim_matchup_entry drops players_points to stay under the 64 KB KV value cap), so this needed a fresh look at what Sleeper actually returns. Live-probed a real 12-team 2025 league first: matchups/<week> carries players, players_points and starters/starters_points together at 6.1 KB for 12 teams (the proxy caps bodies at 1 MB), and all 181 players in that week — DEF units included, which Sleeper keys by team abbreviation — resolved against the embedded catalog with zero misses, so slot eligibility is decided offline with no extra call. Costs 5 proxied GETs league-wide (3 on a cache hit), 7 for the team: view. Gated on the existing player_points feature key, so Fleaflicker and Fantrax get a named refusal rather than a wrong number. No new capability and no new external API — the platform tier is unchanged.

v2.7 (navigation hub everywhere)

  • ✅ Every league view is one click from every other one. The quick-action row that shipped on /commish-week in v2.2 now renders under /commish-matchups, /commish-standings, /commish-rankings and the live-scores view, and under the three scheduled posts that render a league view (matchup preview, power rankings, end-of-week recap) — a Thursday preview a member scrolls past was otherwise a dead end. A new 🗓️ Matchups action completes the set, so navigation never leaves the hub. Each row drops the view you are already looking at, which removes a button that only points at itself and keeps the widest row (live scores: 🔄 Refresh + three) inside Discord's limit of five per row. No new component handler, no new capability, no new command — the same commish:wk:<action>:<league_ref> custom_id shape and the same comp_week_hub route, so a click on a post from three weeks ago still resolves. A drift guard pins every rendered button to a branch that handles it, in both directions.

v2.6 (tune-up: server-side cron + SDK 0.10 adoption)

  • ✅ Scheduled posts actually fire on a schedule. Pool mode is every marketplace install and pooled workers never start @plugin.cron threads, so all nine per-task decorators were dead code — the scheduled posts fired only when the on_ready catch-up sweep happened to run. yourbot-sdk 0.9.0 added the manifest "cron" contract, so v2.6 declares one hourly cron_dispatch entry that sweeps CRON_SCHEDULE; one tick covers all nine (the platform caps entries at five, and every schedule fires at minute 0). The on_ready sweep stays as a fallback since cron delivery is at-most-once with no replay, and both paths take the same atomic per-slot claim.
  • ✅ Metric names de-dotted. SDK 0.9.0 narrowed metric names to letters/digits/underscores; all eight counters were dotted, and every write is try/except-shielded, so a host enforcing the rule would have dropped every data point silently and blanked the Observability page.
  • ✅ Slash-command registrations made visible to the platform's scanner (the local decorator factory hid all 32 literal names, silently disabling the manifest-vs-handler cross-check), level="warn" → "warning", SDK pin ceiling <0.9.0 → <0.11.0. Artifact validator: 10 warnings → 0.

v2.5 (all-play standings)

  • ✅ /commish-all-play — full all-play standings: every team's record as if it played every other team every week (beat everyone who scored less, lose to everyone who scored more; equal scores half-wins), ranked by all-play win%. The honest "who's actually been strongest" view that strips schedule luck out of the head-to-head standings. Reuses the tested all-play math already inside /commish-luck (no new computation, no new external API) and gates on the existing weekly_results feature key (Sleeper + Fleaflicker; Fantrax has no weekly scores and gets a named refusal). Picked as the Phase-4 expansion after live-probing the remaining external platforms came up empty (see below).
  • ❌ No new external platform this cycle. A fresh live-probe (2026-06-27) reconfirmed the blockers: MFL issues a 302 redirect from its central host to a per-league sharded home host (api.myfantasyleague.com → www49.myfantasyleague.com for one probed league; leagues spread across www1..www60+), which a fixed proxy_domains_requested allow-list can't express; ESPN fantasy still needs a production ctx.http reachability probe (lm-api-reads.fantasy.espn.com) before committing, and private leagues need espn_s2/SWID cookies the sandbox can't hold; Yahoo remains OAuth-blocked.

v2.4 (one-tap live-scores refresh)

  • ✅ /commish-scores 🔄 Refresh button — live scores move during games, so the scores view now carries a one-tap Refresh that re-pulls without retyping the command. It reuses the week-hub scores action (commish:wk:scores:<league_id>) — no new component handler, no new capability — and re-attaches itself on every refresh so the message stays refreshable. State is encoded in the custom_id (league ref parsed from the end, colon-safe), and a stale click whose league is no longer linked gets a named refusal.

v2.3.1 (tune-up: SDK update + drift/honesty hardening)

  • ✅ SDK ceiling <0.8.0 → <0.9.0 after diffing 0.7.1 → 0.8.2 (purely additive: ctx.ws, secret_auth/auth http kwargs, dashboard quarter width — all behind caps we don't request; the modules Commish uses are byte-identical). Honesty fixes: /commish-injuries and the injury cron now use the char-budget join + an honest "Showing N of M" footer instead of a silent [:25] slice with a lying count; /commish-draft and /commish-playoffs distinguish a Sleeper outage from a genuinely-empty state via no_draft/no_bracket sentinels. Deadline: comp_setup_channel defers before its blocking KV work. KV: completed-week caches expire after a 150-day season-length TTL (prevents cross-season stale reads on Fleaflicker/Fantrax, whose league IDs persist across seasons, and bounds key growth).

v2.3 (NFL scoreboard)

  • ✅ /commish-nfl — live NFL game scoreboard from ESPN's public site API (site.api.espn.com), bucketed In progress → Upcoming → Final. Platform-agnostic (no linked league, like /commish-trends). Chosen after an empirical live-probe sweep; a full ESPN fantasy platform adapter stays deferred (private leagues need espn_s2/SWID cookies, and production datacenter-proxy reachability needs a ctx.http probe first).

v2.2 (interactive week hub)

  • ✅ /commish-week quick-action buttons — 📊 Standings / 📈 Rankings / 🏈 Live scores jump to the full view in one click, turning the snapshot into a discovery surface. State encoded in custom_id (parsed from the end, since league refs contain colons); Live scores is platform-gated; stale-league / unsupported-platform clicks get named, actionable refusals. New week_hub:<action> component metric.

v2.1.1 (multi-platform regression-hardening)

  • ✅ Audit-driven fix sweep (see REGRESSION-REPORT.md): Fleaflicker BYE detection (the lone-survivor convention) no longer corrupts luck / record-book / high-score views; transaction- and injury-dedup KV keys are now per-league (multi-Sleeper-league servers no longer cross-contaminate); waiver/start-sit crons are platform-correct; playoff round labels derive from distance-to-final; plus never-raise hardening on adapter routes and the lazy-cron sweep. 13 new foreign-platform / multi-league regression tests. SDK pin ceiling raised to <0.8.0 after diffing 0.7.x (purely additive).

v2.1 (Fantrax + feature matrix)

  • ✅ Fantrax support via the same provider seam (fantrax:<id> refs). Standings, all-mode rankings, weekly matchup schedules, the week snapshot and rosters work; Fantrax's public fxea API exposes no weekly scores or transactions (live-probed — the score-bearing internal API requires a login session), so score-derived features are gated. Player names resolve through a second embedded catalog (make refresh-players bundles both; the live Fantrax id map is 1.7 MB, over the proxy cap). Alphanumeric team ids map to stable ints via sorted order. The binary "Sleeper-only" guards became a per-platform feature matrix so each platform gets exactly what its API can power.

v2.0 (multi-platform era — Fleaflicker)

  • ✅ Provider abstraction + Fleaflicker support. Composite league refs (fleaflicker:<id>) route through an adapter inside the fetch layer that returns Sleeper-shaped data, so every existing builder, cache and command works unchanged. Supported on Fleaflicker: matchups, live scores (with real yet-to-play counts), standings, rankings (all-mode), week, luck, record book, h2h, streaks, rosters (inline player names via FetchRoster — no embedded catalog needed) and the content crons. Sleeper-only commands explain themselves politely. New /commish-setup-fleaflicker; www.fleaflicker.com added to the proxy allow-list. Next candidates per the platform-feasibility research: ESPN (read-only), then MFL; Yahoo is structurally blocked (OAuth secret + rotating refresh tokens can't live in the sandbox).

v1.13 (interactive UX)

  • ✅ First message components. /commish-roster (no arg) shows a clickable team picker; /commish-setup's confirmation carries a one-click "Post league updates in this channel" button (maps general, the universal fallback — a fresh install is fully configured in one click); /commish-help is categorized into five titled groups with a 3-step quick start for un-setup servers. New component_invoked metric. Built on SDK 0.6.x on_component(prefix=...) with all state encoded in custom_ids (the platform's interaction events don't carry select-menu values, so buttons it is).

v1.12 (SDK rename migration + audit hardening)

  • ✅ Migrated to yourbot-sdk 0.6.x — the platform SDK was renamed from mmo-maid-sdk at 0.6.0 (the platform itself rebranded MMO Maid → YourBot.gg). Imports, requirements pins, the pre-flight validator, the Makefile dev loop (yourbot dev --watch) and all docs updated; the old import name only survives via a deprecated shim.
  • ✅ Completed-week KV caches (cache:matchups, cache:trades) — season-wide commands and the Season-summary dashboard page no longer re-walk every week over HTTP per view; the dashboard page alone was exceeding the proxy's 30 req/min budget from ~week 9 onward.
  • ✅ Lazy-cron hardening — the on_ready sweep moved to a daemon thread (it ran synchronously before the interaction handler that woke a pool worker, eating the 3-second ack budget), and overdue fires now take an atomic per-slot KV claim so two pool workers can't double-post.
  • ✅ Multi-league state scoping — the rostered-player cache and playoff-clinching dedup keys are now league-scoped; previously /commish-switch leaked one league's state into another's posts.
  • ✅ Embed overflow guards — /commish-trade-history, /commish-waiver-claims and /commish-transactions now truncate to a ~3900-char budget with honest footers instead of silently failing past Discord's 4096-char description cap.
  • ✅ A dozen smaller fixes — waiver-reminder and power-rankings crons gated to the regular season; week 18 recognized as regular season; transactions dedup list trims oldest-first; command metric recorded after the handler (not inside the 3s ack window); Sleeper outages no longer reported as "no transactions yet"; standings-leader widget uses the standings sort; BYE entries excluded from the week-high-score widget; draft renderer tolerates missing pick numbers; metrics path tags strip query strings; per-player injury keys expire after 90 days.

Deferred (post-v1.0, conditional)

  • Screenshots. No Discord-embed screenshots have ever shipped with the repo; capturing them requires a real Discord install with live data and is a manual step, not something this CLI-driven release can do. Tracking as a future PR rather than blocking v1.0 on it.

Out of scope

  • Yahoo Fantasy — requires an OAuth authorization-code flow with a client secret and rotating refresh tokens, none of which the sandbox can hold. Revisit if the platform ships an OAuth broker or ctx.secrets-based token exchange.
  • NFL.com Fantasy — no league-scoped API exists anymore.
  • Anything requiring server-side processing the YourBot.gg platform doesn’t offer.

Quick start (development)

# 1. Clone & install
git clone https://github.com/your-org/commish.git
cd commish
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt -r requirements-dev.txt

# 2. Tests
python -m pytest -q

# 3. Pre-flight validation (also runs in CI)
python scripts/validate_plugin.py .

# 4. Local dev loop (hot-reload + mock host)
yourbot dev --watch

yourbot dev hot-reloads on file change; add an events.yaml to fire sample events against a MockContext (without one the dev host only reloads — this repo doesn't ship one).

Release process

Releases are tagged on main with semver tags (v1.2.3), which triggers .github/workflows/release.yml to validate, test, build the upload zip, and attach it to the GitHub release.

# 1. Bump manifest.json "version" and update CHANGELOG.md
# 2. Verify locally
make release          # refreshes the embedded player catalog (mutates __main__.py),
                      # validates, tests, builds dist/commish-<version>.zip.
                      # Commit the refreshed catalog before tagging — the target
                      # aborts if __main__.py is dirty at zip time.

# 3. Commit, tag, push
git commit -am "Release v0.2.0"
git tag v0.2.0
git push && git push --tags

The tag's version (v0.2.0 → 0.2.0) must match manifest.json's version field; CI rejects the release otherwise.

License

MIT — see LICENSE.

Related plugins

Have a question?

Ask the developer of Commish directly. Sign in with Discord to send your question. You'll be notified when they reply.

Sign in to ask the developer →

Ready to install Commish?

Sign in with Discord, set up your server and add it in minutes.

Install on your server →
Screenshot preview