Sisyphus was created under Riot Games' “Legal Jibber Jabber” policy using assets owned by Riot Games. Riot Games does not endorse or sponsor this project.
Snapshot
Goal Turn ranked games that would normally disappear into match history and Discord messages into a persistent shared record for the squad.
Challenge Reconcile delayed and imperfect third-party game state while keeping Discord interaction, history, markets and private analytics consistent.
Outcome A live friend-group product with 13 tracked players and 1,507 games recorded as of 13 November 2026.
Sisyphus did not start as a platform. It started because a friend said he was going to grind ranked.
01.1The joke that became the product
A friend said he was going to start a League of Legends ranked grind. I was bored and thought: "what if I build something to track him and potentially make fun of him :p".
That was basically the first product brief. The earliest version only needed to notice the climb and give the group something to react to.
Then more people in the squad were playing ranked and asked to be tracked too. The project stopped being about one friend and became a shared record of the group.
A shared record
STARTED AS A JOKEA friend said he was going to grind ranked.One friend → the squad
ItemsShadowflame · Blackfire Torch · Swiftmarch · Cosmic Drive · Oblivion Orb · Needlessly Large Rod
📊 Overview🔵 Blue Team🔴 Red Team🏅 Full LeaderboardRemember
FIG. 01 · STARTED AS A JOKE · sisyphus/views.py · recap embed
01.2The real value was the shared story
Without Sisyphus, ranked progress is split across match history, Discord messages and memory. You can look up a game, but the group loses the surrounding story: who was grinding, how LP moved, what people predicted, what everyone argued about afterwards and which matches became memorable.
That is why I think of Sisyphus as a chronicle rather than a stat lookup. A game becomes a recap. The recap becomes a conversation. The result affects fictional markets and records. The history accumulates into something the squad can revisit.
MATCH ROWJuno · Win +18 LP
LP DELTA🥇 Gold IV · +18 LP
RECAP▣ Win · 8 / 3 / 11
CHRONICLETHE BOULDER CHRONICLE Juno · Win
The shared story
FIG. 02 · THE PRODUCT LOOP · sisyphus/views.py · recap and dashboard/web/src/App.tsx
01.3Who it is for
Sisyphus is deliberately shaped around one private Discord squad. Anyone in the group can opt in to tracking, and the main product surface is Discord because that is where the group is already talking while games happen.
The dashboard is secondary. It gives the same history a richer analytical view, but the product would feel wrong if the group had to leave Discord for every interaction.
Most of the architecture choices are intentionally small-product choices: use the surfaces and storage that fit the squad, and harden the parts where external state is unreliable.
02.1Discord first, dashboard second
Discord is where the social moment happens, so recaps, queue state, live-room updates, predictions and reactions belong there. The website is better for long-lived exploration: LP journeys, activity, markets, records and the Boulder Archive.
This division kept the product from becoming a dashboard that happens to have a bot. The bot is the product surface; the dashboard is the deeper history.
Discord first
Sisyphus-BotAPPToday at 8:22 PM
Kairo#0000
Today's Stats
RankPLATINUM IV — 42 LP
Today✅ 2❌ 1➖ 0 +18 LP
📊 Today🏆 All-time
THE BOULDER CHRONICLERANKED RECORD
THE BOULDER CHRONICLE / THE SQUAD LEDGER
The Squad Ledger
Tracked players13
Games recorded1,507as of 13 November 2026
FIG. 03 · TWO SURFACES · sisyphus/views.py · dashboard/web/src/App.tsx overview
02.2Why JSON stayed the source of truth
The bot still uses JSON as its primary state store. For one small private guild, that has been a deliberate fit-for-scale choice rather than something I am trying to hide.
A heavier database would add operational complexity without solving the main problems I have today. The migration trigger would be a real change in the product: more users, multiple guilds, significantly more history or enough concurrency that whole-file state updates become a limitation.
The rule has been to scale the architecture when the product needs it, not because a hypothetical future version might.
02.3Riot and OP.GG are complementary, not interchangeable
The hardest technical theme in Sisyphus is external truth. Riot is useful for live presence, account information and LP-related state. OP.GG provides ranked history and match-detail information that fills different gaps.
The problem is timing. A match can finish before every source reflects the new state. If the bot posts the first value it sees, LP can be wrong, an old match can appear as new, or a downtime recovery can flood the channel with stale recaps.
So the ingestion path is built around reconciliation: bounded first-run backfill, recap age caps, duplicate guards and delayed LP re-fetch after match completion.
External truth arrives late
Live detection
History + detail
LP re-fetch
Canonical outcome
Recap
FIG. 04 · RECONCILIATION · sisyphus/match_processing.py · processing states
02.4Private community data stays private
The raw bot state contains identifiers and operational information that should never become public just because the code is on GitHub. Historical state even included PUUIDs, Discord IDs, message/channel IDs and other private records.
The dashboard therefore consumes a sanitized, allowlisted export rather than raw bot state. Member identifiers are replaced by opaque keys, and dashboard access is scoped through Discord OAuth and guild membership.
The system grew from a match tracker into a stateful community product with reconciliation, live interaction, fictional markets, analytics and operations.
03.1From a tracked player to a recap
The bot polls tracked players for active Ranked Solo/Duo games. Riot live state helps identify active games, while OP.GG supplies recent ranked history and detail. The system identifies unseen matches, rejects stale recap candidates and re-fetches LP after a match to reduce timing errors.
Remakes under two minutes are canonicalized as draws. Related fictional markets are voided and refunded rather than settled as a normal win or loss. Otherwise the outcome updates history, records and market state before the recap is posted.
The recap itself is intentionally dense but social: result, rank/LP transition, KDA, CS/min, damage, gold, vision, items, team context and drill-down views. Friends use it both as a summary and as evidence in the inevitable "that loss was not my fault" argument.
ItemsShadowflame · Blackfire Torch · Swiftmarch · Cosmic Drive · Oblivion Orb · Needlessly Large Rod
📊 Overview🔵 Blue Team🔴 Red Team🏅 Full LeaderboardRemember
03 · FULL SCOREBOARD
Sisyphus-BotAPPToday at 9:42 PM
Juno#0000
🏅 Full Scoreboard · 35m 42s
🔵 Blue Team ✅ VictoryAhri 8/3/11 CS:212
🔴 Red Team ❌ DefeatRenekton 3/7/10 CS:254
📊 Overview🔵 Blue Team🔴 Red Team🏅 Full LeaderboardRemember
FIG. 06 · COMPLETED MATCH · sisyphus/views.py · interactive recap
03.2Queue Beacon to Live Game Room
One of the more product-like state transitions is the Queue Beacon. Instead of posting a new message for every phase, one Discord message can become the Live Game Room and update in place.
The room tracks the game, teams, watcher count, voice presence, streaming state and a final snapshot. Watchers are aggregated from the relevant voice channel and the tracked player is not counted as their own watcher.
When the game disappears, the room is finalized and the historical record can preserve things such as peak watchers and stream time.
One message changes in place
Sisyphus-BotAPPToday at 9:41 PM
Juno is pushing the boulder.
Queue Beacon
Juno is pushing the boulder on Renekton.
QueueRanked Solo/Duo
StreamNo stream yet
Watching0 watching
Watcher IntentNo watchers yet
Sisyphus-BotAPPToday at 9:41 PM
Juno is pushing the boulder.
Queue Beacon
Juno is pushing the boulder on Renekton.
QueueRanked Solo/Duo
StreamNo stream yet
Watching0 watching
Watcher IntentNo watchers yet
Sisyphus-BotAPPToday at 9:41 PM
Juno is pushing the boulder.
Queue Beacon
Juno is pushing the boulder on Renekton.
QueueRanked Solo/Duo
StreamStreaming
Watching2 watching
Watcher Intent🫡 1 · 💀 0 · 👀 1
Sisyphus-BotAPPToday at 9:41 PM
Juno is pushing the boulder.
Queue Beacon
Juno is pushing the boulder on Renekton.
QueueRanked Solo/Duo
StreamStreaming
Watching2 watching
Watcher Intent🫡 1 · 💀 0 · 👀 1
Finalized
FIG. 07 · QUEUE TO ROOM · sisyphus/live.py · Queue Beacon and Live Game Room
03.3Fictional markets and community state
The betting layer uses fictional points only. It exists because lightweight stakes make the squad pay attention to games they are already watching, not because I wanted to build a finance product.
Markets have explicit open, locked, settled and void/refund states. That state has to agree with the same canonical game outcome used by recaps and history, otherwise the social layer becomes inconsistent.
Profiles, records, goals, rivalries, memories and recurring recaps use the same accumulated history to turn repeated ranked games into a longer-running community record.
The Boulder Chronicle dashboard is a separate FastAPI and React/Vite application. It does not read the raw bot state directly. A sanitized export defines the fields the dashboard is allowed to see and rejects forbidden keys.
The dashboard then turns that safe export into overview, player journeys, markets and community/archive views. Discord OAuth plus guild-membership checks keep the real dashboard private to the group.
Games recorded
THE BOULDER CHRONICLERANKED RECORD
THE BOULDER CHRONICLE / THE SQUAD LEDGER
The Squad Ledger
Tracked players13
Games recorded1,507as of 13 November 2026
Known-match LP+18 LP
Squad LP trajectoriesSolid recorded · dashed estimated
Compare players · Juno / Kairo / Wren
600 LP400 LP
19 May 2026
Last resultsJuno · Win +18 LPKairo · Loss −12 LP
THE BOULDER CHRONICLERANKED RECORD
THE BOULDER CHRONICLE / PLAYER JOURNEYS
Player Journeys
Juno · LP journeyRank changes · match form
LP over timeSolid recorded · dashed estimated
600 LP400 LP
19 May 2026
THE BOULDER CHRONICLERANKED RECORD
THE BOULDER CHRONICLE / THE BOULDER ARCHIVE
The Boulder Archive
RecordsJuno · Ahri
KDA ratioJuno / Ahri / 29 August 20266.33 KDA
Vision scoreJuno / Ahri / 29 August 202627 vision
Known LP gainJuno / Ahri / 29 August 2026+18 LP
FIG. 09 · THE BOULDER CHRONICLE · dashboard/web/src/App.tsx overview · player · community
03.5Operations for a passion project
The bot runs on my Mac. The dashboard and uptime tooling run on Oracle infrastructure that I also administer. That split is pragmatic, but it also means I own the operational edges on both sides.
The project includes process locking, health snapshots, backup validation and rotation, supervisor restart/backoff, deployment coordination, status publishing and log monitoring. None of that makes Sisyphus "enterprise software"; it is simply what was needed to keep a small service I care about running reliably.
Own the edges
MAC BOTprivate state · process lock
SANITIZED EXPORTallowlisted fields
ORACLE DASHBOARDaccess · uptime · logs
FIG. 10 · RUNNING THE SERVICE · sisyphus/process_lock.py · dashboard/export_model.py
03.6Refactoring and hardening as the project grew
The original bot became harder to maintain as features accumulated, so I split the monolith into modules. The motivation was straightforward: make new features easier to add without turning every change into a risk to unrelated behaviour.
A separate hardening pass replaced an earlier dynamic evaluation path with a strict fail-closed AST allowlist for OP.GG-derived expressions. I treat that as security hardening, not as a story about a known exploit.
Mistral also exists in a very bounded place: summarizing Git commits for release notes with a local fallback and approval gate. It does not drive match tracking, markets or game decisions.
The outcome I care about is not hypothetical scale. It is that a joke turned into software the group actually uses.
04.1Live since May
Sisyphus went live on May 19, 2026. It has 13 tracked players and 1,507 games recorded as of 13 November 2026.
I use "games in view" deliberately rather than calling that a lifetime count. The live number is useful context, but the stronger outcome is that the system is still running and the squad still uses it.
Games recorded
THE BOULDER CHRONICLERANKED RECORD
THE BOULDER CHRONICLE / SISYPHUS STATUS
Sisyphus status
Live sinceMay 19, 2026
Tracked players13
Games recorded1,507as of 13 November 2026
FIG. 11 · LIVE SINCE MAY · dashboard/web/src/App.tsx overview · live count
04.2What the squad actually values
The features that matter are not always the most technically complicated ones. Friends use the win/loss and LP view, fictional betting, recaps and the dashboard. The recap is especially social because it gives everyone a shared artifact immediately after a game.
That is the product test I get with a friend-group project: if a feature does not become part of the routine, there is no abstract user story to hide behind.
04.3What I learned
Sisyphus taught me that small real products still need state correctness. External APIs can disagree or update at different times, and a wrong recap or LP change is immediately visible to the people using the bot.
It also reinforced a pragmatic architecture lesson. JSON is fine until it is not. A Mac plus an Oracle host is fine until the product needs something else. I would rather change those decisions in response to real scale than design a multi-guild platform nobody asked for.
For a small product, correctness and usefulness matter long before theoretical scale.
04.4If it grows
If Sisyphus eventually supports more guilds, much larger history or significantly more concurrent state, the storage and deployment model should change with it. A database and a more centralized service topology would make sense then.
For now, I want to preserve what made the project fun in the first place: it is software built around one group of people and the way they actually play together.