From Upgrade Tickets to a Health Dashboard: Six Years of Open edX Maintenance
How a narrow upgrade ticket turned into an ecosystem-wide maintenance practice, and how that practice became a public health dashboard for every Open edX repository.
Why this post
The short version
- Open edX is more than 150 repositories that have to be upgraded in step. In 2020 the map of how they depend on each other lived only in people’s heads.
- Over six years a group of people, started by edX’s Architecture team and carried by Arbisoft’s BOM squad and community maintainers, turned that map into code: upgrade tooling, then health checks, then a public dashboard.
- The dashboard grades all 169 repositories every day, and the first thing it showed was that more than half of the upgrade bot’s pull requests were noise.
Open edX is the open-source platform that organisations around the world use to run online courses, from universities to companies. It is not one program but a family of more than 150 repositories, and keeping them upgraded together is a problem of its own.
When I joined the maintenance team in January 2020 my job in the Open edX ecosystem was narrow. Upgrade the repositories edX maintained, get CI green, move on. Six years later there is a public dashboard at openedx.ossvitals.org that grades every one of the 169 repositories in the Open edX GitHub organisation on nine health metrics, every day, with every weight and threshold published. I built the hosted version. The idea, the checks, the method and most of the upgrade work behind it belong to a longer list of people: Jeremy Bowman and the edX Architecture team who started it, the Arbisoft BOM squad who ran the upgrade waves, and the maintainers at Axim, eduNEXT and 2U who kept the checks alive in between.
This post is the long version of how one led to the other, and it makes one argument. A maintenance problem spread across 150 repositories only gets solved once someone makes the system legible, and that legibility is built by many hands over years. I have linked the actual pull requests throughout, with counts wherever a wave was shared, because the story is only interesting if it is true, and the git history is public.
The problem I kept running into
Open edX is not one codebase. It is more than 150 repositories maintained by Axim Collaborative, 2U, OpenCraft, eduNEXT and dozens of individual contributors. The repositories share dependency constraints, reusable CI workflows, cookiecutter templates and release calendars, but in 2020 those relationships existed only in people’s heads.
The first time this bit me was 25 September 2020. A new release of importlib-metadata broke the Python 3.5 and 3.6 test matrix in every repository that still supported those versions. There was no list of which repositories those were. I knew because I had touched them. I pinned the package to 1.7.0 in six repositories that day, django-config-models, edx-cookiecutters, edx-repo-health, edx-rest-api-client, opaque-keys and pytest-repo-health, with xss-utils following five days later. Two months later the same package broke tox and virtualenv, and the pin changed to <3.0 in another round.
That was the pattern for the next two years. Fix a failure in one repository, then go find the same failure everywhere else by memory.
The fix was never the hard part. Knowing where to apply it was.
The sharper version of the problem is that fixes propagate too. In May 2022 pip 22.1 broke pip-tools, which broke the automated requirements upgrade job in every repository at once. I pinned pip<22.1 in the common constraints file in edx-lint (#258), which every repository consumes, and removed it three days later once pip-tools shipped a fix (#261). One line in one file changed what more than a hundred repositories installed that week. Nobody had a picture of that blast radius either.
Going beyond the tickets
The question I could not let go of was simple. Why did a change in one place produce failures somewhere else, and why did nobody have a clear picture of it? I wanted to see the whole graph, not just my corner.
None of what follows was a solo effort. Arbisoft staffed two teams for edX, and later 2U, under one engineering manager, Jeremy Bowman: bom-squad for the backend and bom-frontend for the micro-frontends. After Jeremy Bowman left 2U, Jeremy Ristau, Director of Engineering at 2U and a member of the Open edX Technical Oversight Committee, led both teams until Arbisoft’s engagement with 2U ended. The 2U commitment to the Core Contributor programme still describes the arrangement: “the BOM team to assist in maintenance and upgrades of the Open edX core system which are defined and/or coordinated by the Maintainers WG”. Inside bom-squad the lead role moved over the years, from Awais Qureshi to Aarif to Muhammad Soban Javed, while Muhammad Abdullah Waheed led bom-frontend. I never held the lead title at Arbisoft, but in practice I took charge of the major epics within the team: running each effort end to end, writing the tracking issues and codemods, and being the person the wider Open edX community worked with on them. In the later years that also meant mentoring newer teammates, interviewing candidates and setting up the team’s on-call rotation. In a January 2025 LinkedIn recommendation, Jeremy Ristau wrote that I had “delivered on my expectations of a team lead role”, leading three workstreams across Open edX in parallel: the Node 20 upgrade, the Python 3.11 upgrade and the devstack deprecation (public-engineering #247 is the public DEPR ticket for it). My share of each wave is stated below, because the point of this post is the map, not the headcount.
Automating the upgrades themselves. The method came from Jeremy Bowman, who managed the Architecture team at edX and later presented it at DjangoCon US 2021 as Herding Ponies: Coordinating and Automating Django Upgrades Across 100+ Repositories: codemods for the breaking changes, scripts that rewrite tox and CI configs, dependency support tracking, and a schedule across dozens of repositories. Our squad built and ran that tooling. In March 2021 I added a GitHub Action to edx-repo-health that opened requirements upgrade PRs automatically (#129), and over 2021 I wrote codemods in repo-tools that applied the same change across every repository that needed it: removing python_2_unicode_compatible (#185) and adding new Django 3.2 settings (#196).
A codemod is a map of the ecosystem written as code.
To write one you have to know which repositories it applies to.
Travis CI to GitHub Actions. This one was mine. In October and November 2021 I converted nineteen of the twenty-four repositories that moved from Travis CI to GitHub Actions in that wave: frontend-app-authn, frontend-platform, frontend-app-gradebook, xblock-sdk, openedx-webhooks, ccx-keys, cc2olx, django-wiki and the rest, with Jawayria (edx-search, api-doc-tools), Mohammad Ahtasham ul Hassan (openedx-chem) and Ned Batchelder covering the others. Doing twenty of anything in six weeks forces you to notice what the repositories have in common and where they differ. That is where the mental map started turning into a written one.
Here is who carried each of the four waves that were shared across the team. The detail behind it, with names and pull request counts for every wave, is folded away below. Open it if you want the evidence; the story carries on in the section after.
Wave by wave: Django 3.2 to React 18, with names and pull request counts
Django 3.2. The 2021 Django 3.2 wave was mostly other people’s work. M. Zulqarnain and Jawayria led it with thirteen PRs each, Muhammad Soban Javed added nine (xblock-google-drive), Awais Qureshi five and Aarif three. I did seven, among them xqueue, xblock-sdk and codejail, and Zulqarnain closed the wave with the post-upgrade cleanup in edx-platform. The year before, the Python 3.8 wave had been carried largely by Luis Moreno and ericfab179 at eduNEXT with Awais and Aarif.
Django 4.2. By late 2023 the squad had changed shape and the wave was shared more evenly: Zubair Shakoor opened nineteen Django 4.2 PRs, Irtaza Akram sixteen, Muhammad Soban Javed fifteen, I did thirteen, Salman Nawaz twelve and Awais Qureshi six. Mine went through license-manager, edx-notes-api, edx-rest-api-client, edx-enterprise-data, edx-celeryutils and the CI matrix in course-discovery.
Python 3.12. In 2024 I coordinated the Python 3.12 migration and did ten of the service upgrades myself, including enterprise-catalog, enterprise-access, enterprise-subsidy, license-manager, course-discovery, edx-enterprise-data, taxonomy-connector and django-wiki. Irtaza Akram did nine, Salman Nawaz five, and Feanil Patel and Farhan four each on the Axim and platform side. Each one meant auditing dependencies, patching upstream packages that had not caught up, rebuilding Docker images and staggering rollouts so that a failure in one service did not block the others.
Django 5.2. The 2025 wave was the first one I led outright. Of the Django 5.2 support PRs opened that year I wrote 23, Awais Qureshi 13, Mubbshar Anwar and Hina Khadim nine each, Irtaza Akram six and Jillian at OpenCraft three. Most of mine landed in one week in April across the shared libraries, django-user-tasks, event-bus-kafka, help-tokens, django-wiki, edx-milestones, taxonomy-connector and openedx-ledger among them, followed in May by the series that rewrote index_together into indexes across edx-platform’s models (#36693, #36702, #36708, #36716). Before it could ship, the renaming had to be timed against production-sized tables with 2U’s infrastructure team, tracked in edx-arch-experiments #1031. By then the method was second nature: libraries first so the services have something to depend on, then the platform, then the long tail.
The frontend track. bom-frontend, led by Muhammad Abdullah Waheed and reporting to Jeremy, ran the frontend upgrades in parallel, and there I was mostly a bystander on the pull requests, though in 2024 I also coordinated the Node 20 workstream. In early 2022 Jawayria wrote the Node 16 modernizer in repo-tools (#255) and carried fourteen of the 47 Node 16 PRs across the micro-frontends (frontend-app-authn, frontend-app-account, frontend-component-header), with Mohammad Ahtasham ul Hassan on eight, Muhammad Soban Javed on four (frontend-component-cookie-policy-banner), and Mehak Nasir and Awais Qureshi on three each. Mashal Malik and Adam Stankiewicz led the Paragon major-version upgrades through 2022 and 2023 (frontend-app-gradebook). After Jeremy left 2U the track kept going: Abdullah opened the Node 18 wave in 2023 (frontend-app-discussions), Bilal Qamar carried it through 2024 alongside Brian Smith at Axim and then did 59 of the 86 Node 20 PRs the same year (frontend-app-account), and the 2025 React 18 wave was Brian Smith’s and Adam Stankiewicz’s, with my two PRs in edx-ora2 and edx-platform. My own frontend footprint is otherwise small: five of the Travis conversions above were micro-frontends, and in April 2022 I swept the Transifex pull-translations command across ten of them (frontend-app-learning, frontend-app-authoring).
Coordinating, not just committing. The part of my work that does not show up in PR counts is the tracking. One step in Jeremy’s method was a script that captured deprecation warnings from pytest and summarised them. Between June 2022 and June 2023 I turned that output into 71 individual issues in public-engineering, one per warning, each with the fix and the owning package (#85, #103, #128). For Django 4.2 in 2023 I wrote the programme itself, and it sat on the Open edX Roadmap board rather than a 2U one: the roadmap epic, the umbrella issues for third-party packages and Open edX packages, the specifications for the tox and GitHub Actions modernizers and the MemcachedCache and providing_args codemods, and on 25 July 2023 one tracking issue per service, from edx-platform and course-discovery to credentials, xqueue and license-manager, so that anyone in any organisation could pick one up. The same pattern carried the Python 3.11 image upgrade in 2024, React 18 and Django 5.2 in 2025. Across the whole period that adds up to 782 pull requests opened in the openedx organisation, 136 issues, 4,323 pull requests reviewed and roughly 4,400 comments on other people’s PRs and issues. In September 2023 I announced the Repo Health workflow on Discourse; in December 2024 I volunteered to maintain edx-rest-api-client, django-user-tasks and django-config-models; in January 2025 the community made me a Core Contributor; and in December 2025 I took over as maintainer of edx-repo-health and pytest-repo-health when both were listed as seeking one.
The public pull requests were half of each wave. Behind most of them was a production deployment: merging, deploying, watching the monitoring dashboards and, when a change broke something elsewhere, rolling it back with the infrastructure team and trying again. Between 2021 and 2025 I rolled back more than twenty changes. None of that appears in git history, and it is why I came to care about knowing which repositories were drifting before a change shipped.
By this point the question had changed. It was no longer “which repositories need this change” but “which repositories are drifting, and how would we know before something breaks”.
Here is the whole stretch on one page. The rest of the post follows it in order.
Taking over Repo Health
Repo Health was Jeremy Bowman’s idea before it was anyone else’s. He managed the Architecture team at edX, and after 2U acquired edX he was the engineering manager over both BOM teams. In March 2020 the Architecture team, starting with Manjinder Singh, built pytest-repo-health and edx-repo-health: a set of pytest plugins that clone every repository in the organisation and record facts about each one. Which Python and Django versions it declares, whether it has a README with working links, whether Dependabot or Renovate is configured, who owns it. The results land in a CSV. Jeremy wrote the GitHub API checks and the ownership checks himself that summer (#34, #44, pytest-repo-health #24), and the Herding Ponies talk a year later was the method behind all of it. He also reviewed 81 of my pull requests over those years, which is where I learned most of what this post describes.
It was an internal edX tool first, and that matters for what came later. The checks were open source, but the job ran on edX infrastructure, the results went to a private store because some checks flag security problems before anyone has assessed them, and the Google Sheet it fed was internal. That was a reasonable shape while edX was the organisation driving upstream maintenance for the whole ecosystem, which it was until 2U acquired it in late 2021. After the acquisition that driving role tapered off. 2U’s own engineers did less upstream, the Arbisoft BOM team carried much of the maintenance that continued, and the tool’s audience shrank to the teams that already knew it existed. By early 2024 Jeremy had moved on from 2U, and the tooling kept running without an owner.
By then the nightly job ran on Jenkins and the output went to a Google Sheet. In early 2023 I rewrote the job as a script (#349), moved it into a reusable GitHub Actions workflow in the organisation-level .github repository (#52), and retired the Jenkins job (jenkins-job-dsl #1692). Any repository or working group could now run the full scan by calling one workflow. The rewrite itself sat from January to April waiting on credentials and private-repository access that only 2U’s infrastructure team could provision, which is exactly the dependency the public version removes.
Jeremy also built the first dashboard. In 2023, from a hackathon project, he turned the SQLite output into a console report and a Streamlit grid (#374, #466) and wrote the design doc that still describes the pipeline, Repository Health Data and Dashboards: checks, jobs, storage, dashboards. It ran on a laptop from a downloaded file, which is why it never became the thing people opened in the morning. The public dashboard is that design, hosted.
In July 2024 Muhammad Soban Javed and I presented the result at the Open edX Conference in Stellenbosch, South Africa, the first time the conference was held in Africa. The talk, Elevating Open edX Development: The Repo Health Dashboard, walked through the checks, the daily job and the per-repository reports. Arbisoft’s conference write-up has a summary.
The talk was well received, and nothing much happened afterwards. That is worth being honest about.
A CSV in a repository is not a tool anyone opens in the morning.
The checks did not stand still in those years, though. Zubair Shakoor added the Python dependency dashboard script (#462), Syed Ali Abbas Zaidi fixed the Renovate check (#425), Hunia Fatima added the pinned dependency count check (#532), Salman Nawaz retired the openedx.yaml check, and Muhammad Tayyab Tahir Qureshi brought the plugin to Python 3.12 (pytest-repo-health #340). Ned Batchelder, Tim McCormack and Feanil Patel reviewed and maintained throughout, and Feanil has kept pytest-repo-health releasing, most recently 4.0 in 2026. Jeremy’s last contribution was a check proposal in January 2024.
The handover to the community was slow and public. In November 2022 Feanil Patel at Axim opened a ticket to collect and publish repo-health data for every public repository; Jeremy wrote up the steps in June 2023 and confirmed them with our team, but 2U’s own switch to the new workflow was stuck behind a Google Sheet bug and the ticket was closed in July 2025 without moving forward. In June 2024 Kyle McCormick put a blunter question on the Maintenance Working Group board: who owns the Repo Health Dashboard, and should it be kept, transferred to 2U or deprecated. Feanil noted it was not running at all. That issue sat for fourteen months until August 2025, when I asked for it to be assigned to me, two weeks before my last day on the 2U engagement. Kyle’s reply was two words. The maintainer transfers in December 2025 and the move into wg-maintenance in April 2026 followed from that.
What changed in 2026
Two things made the project urgent again.
The first was that Bitergia, the analytics vendor whose dashboards the community had used for contribution statistics, shut down its Open edX instance in March 2026. In April the Maintenance Working Group asked for a way to get those metrics back.
The second was that the pipeline had quietly broken. Feanil Patel created the Maintenance Working Group’s own repository in April 2026, and I moved the job there (wg-maintenance #3) with the reusable workflow updated to Python 3.12 (.github #217). Then the data stopped flowing, partly because the job’s output PRs needed a human to merge them and nobody did.
So the rebuild had one design goal the original never had: everything public. I had run the 2U setup from the inside for years and knew which parts depended on private infrastructure, a private results store, an internal spreadsheet and a token with organisation-wide scope. The job was to take each of those apart and replace it with something anyone in the community could read, run or reproduce from public data. The checks and the dashboard that follow are what that looked like.
So between June and September 2026 I rebuilt the checks. The Travis CI checks were removed, because no tracked repository used Travis any more (#674). The Python 3.8 classifier check became a Python 3.12 one (#677). Then came the new signals: activity trends (#694), an explicit count of PRs opened in the last 90 days so a dormant repository reads zero rather than blank (#720), issue backlog, default-branch CI state and first-time contributor response (#722), and commit volume, contributor absence factor and lockfile age read straight from the local clone with no API calls (#723).
Some of the most useful work was fixing what the checks had been getting wrong.
Ownership had never been recorded. The ownership check read each repository’s catalog-info.yaml, but a default argument stopped pytest from injecting the repository path, so every owner column had been empty since the check was written (#718).
Bots were counted as reviewers. The PR response time metric excluded accounts whose login ended in [bot]. GitHub’s GraphQL API returns Dependabot, Codecov and Copilot as bare logins, so the filter never matched and automation counted as a human response. Once bots were excluded properly, response times rose on most repositories, and repositories whose only recent PRs came from bots correctly showed no value at all (#722).
The CI check measured the wrong thing. It reported whether GitHub Actions was configured, which was true for 167 of 168 repositories, not whether CI passed. The new default-branch CI state column fixes that (#719), and the limitation is disclosed on the scoring page until the score itself switches over.
The dashboard
OSSvitals, the dashboard itself, is the layer on top. Its design is deliberately boring.
A small workflow in wg-maintenance calls the shared repo health workflow in the organisation’s .github repository every morning. That workflow clones every repository, runs the checks and commits the CSV. A second workflow in the dashboard repository reads that CSV, computes scores and commits the result as JSON. The site at openedx.ossvitals.org is a static build that bundles those pre-computed files at deploy time, so the browser loads nothing else. There are no API calls at runtime, so the dashboard never hits a rate limit, never leaks a token and can be rebuilt by anyone from public data (#4, #5). A third workflow opens an issue if the data goes stale (#20).
Scoring is nine metrics, each normalised to 0 to 100, weighted into a composite and mapped to a letter grade from A to F. Commit recency, PR response time, PR closure ratio, release frequency and contributor absence factor cover activity. README quality, CI status, metadata compliance and dependency update tooling cover structure. Missing data scores 50, not zero, so a stable finished library is not punished for being finished. Every weight, threshold and parse rule lives in one YAML file, and the dashboard’s How Scoring Works page is generated from it (#9).
The view the working group actually uses is At Risk (#7). It joins ownership with activity, so you can see which production repositories are owned by nobody or by a single person and are getting worse. The Upgrades page tracks the upgrade jobs, migration waves and redundant bot PRs (#11, #13) hoping to track all upcoming work in the future in similar method too.
The Upgrades page, wave tab, tracking one migration across 106 repositories. Snapshot of 5 October 2026.
On 5 October 2026, 126 of the 169 repositories graded A or B and none graded F. That is the baseline the next section is read against.
What the data showed
The first thing a tool like this does is tell you things you did not want to know.
The automated requirements upgrade bot had opened 7,206 pull requests across 80 repositories since mid-2024. Of those, 3,174 were merged and 3,985 were closed without merging, with 47 still open. More than half of the bot’s output was noise, superseded by the next week’s PR before anyone looked. Nobody had measured that because nobody had the data in one place. The dashboard now has a redundant PR view so the working group can decide what to do about it.
The history also showed what the community does well. In two weeks of May 2026, a single campaign pinned GitHub Actions to full commit SHAs in 123 repositories, with 119 merged. Switching builds to ubuntu-latest went through 75 repositories with every PR merged.
The ecosystem can move fast when someone draws the map first.
And it showed that several of the original checks had stopped carrying information. A check that returns the same value for 99 percent of repositories is not a health signal, it is a historical record. The dashboard now flags those for the working group to retire (#23).
What I took from it
Three things, mostly.
Make the system legible before you automate it.
Every codemod, every bulk migration and every dashboard view started with a list of which repositories were affected. The tooling was only ever a way to stop keeping that list in my head.
Automate at the scale of the ecosystem, not the ticket.
Fixing one repository is boring. Understanding why 150 repositories fail in correlated ways, and building something so they stop, is the kind of work I will stay up for. The same instinct carried into the work I have done since: owning the infrastructure for a commercial AI document validation platform on AWS, and building Model Context Protocol servers that expose production tools to AI assistants. In both cases the first job was the same. Draw the map.
Stewardship is recognised differently from output.
Core Contributor status in Open edX is given for looking after the commons, not for pull request counts. The pull requests were how I learned where the commons was.
The dashboard is live at openedx.ossvitals.org, the project page is at ossvitals.org, the source is at UsamaSadiq/OSSvitals, and the checks are at openedx/edx-repo-health. If you maintain an Open edX repository and your grade surprises you, the How Scoring Works page will tell you exactly why, and I would like to hear whether it is wrong.
References
Origins
- Jeremy Bowman, Herding Ponies: Coordinating and Automating Django Upgrades Across 100+ Repositories, DjangoCon US 2021, 22 October 2021; talk page
- Ned Batchelder, Two Open edX talks at DjangoCon, Open edX blog, 27 October 2021
- Jeremy Bowman, Repository Health Data and Dashboards, Open edX wiki, January 2024
- Manjinder Singh’s first commits: pytest-repo-health #1, edx-repo-health #2, March and April 2020
- Jeremy Bowman’s checks, 2020: edx-repo-health #34, #36, #44, #47, pytest-repo-health #24, #28
- Jeremy Bowman’s dashboards, 2023: edx-repo-health #374, #466
- Later maintainers: #425 Syed Ali Abbas Zaidi, #462 Zubair Shakoor, #532 Hunia Fatima, pytest-repo-health #340 Muhammad Tayyab Tahir Qureshi
Coordination
- Django 4.2 programme, 2023: platform-roadmap #269, public-engineering #197, #199, #205 to #210, repo-tools #389, #390, #396, #411, openedx-platform #32833
- Deprecation warning triage, 2022 to 2023: public-engineering #85 through #128
- Later programmes: Python 3.11 images #34984, React 18 #36559, Django 5.2 #367
- Repo Health workflow announcement, Discourse, September 2023; merge request to Axim, axim-engineering #694
- Handover: axim-engineering #530 (Feanil Patel, November 2022; Jeremy Bowman’s steps, June 2023); .github #138 (Kyle McCormick, June 2024; assigned August 2025)
- Maintainership: edx-platform dependencies, December 2024; edx-repo-health and pytest-repo-health, December 2025
- Core Contributor: onboarding request, January 2025; roster
- 2U commitment naming the BOM team: Declaration of Commitment to the Core Contributor Program
Dashboard and tooling
- OSSvitals, Open edX dashboard: openedx.ossvitals.org, project page ossvitals.org
- Dashboard source: UsamaSadiq/OSSvitals
- Health checks: openedx/edx-repo-health, built on openedx/pytest-repo-health
- Daily job: openedx/wg-maintenance
- Conference talk: Elevating Open edX Development: The Repo Health Dashboard, Open edX Conference 2024, with Muhammad Soban Javed
- Conference write-up: Reflecting on the Open edX Conference 2024
2020
- importlib-metadata pin, 25 September: django-config-models #90, edx-cookiecutters #66, edx-repo-health #59, edx-rest-api-client #100, opaque-keys #147, pytest-repo-health #50, xss-utils #11
- importlib-metadata below 3.0, 30 November: edx-repo-health #91, pytest-repo-health #63
2021
- Requirements upgrade GitHub Action: edx-repo-health #129
- Codemods: repo-tools #185, repo-tools #196
- Travis CI to GitHub Actions: frontend-component-cookie-policy-banner #374, frontend-app-authn #452, frontend-app-gradebook #212, event-tracking #128, edx-bootstrap #107, edx-ui-toolkit #195, openedx-calc #34, openedx-webhooks #156, cc2olx #80, xblock-sdk #211, xqueue-watcher #67, ccx-keys #30, frontend-platform #245, django-wiki #89
2022
- pip 22.1 pin and removal: edx-lint #258, edx-lint #261
- Reusable requirements upgrade workflow adoption: xblock-sdk #248
2023
- Repo health job script: edx-repo-health #349
- Reusable repo health workflow: .github #52
- Jenkins job retired: jenkins-job-dsl #1692
- Django 4.2: license-manager #525, edx-notes-api #349, edx-rest-api-client #300, edx-enterprise-data #402, course-discovery #4101
2024
- Python 3.12: enterprise-catalog #824, enterprise-access #467, enterprise-subsidy #242, license-manager #655, course-discovery #4405, edx-enterprise-data #524, taxonomy-connector #207, django-wiki #269
- Django 4.2: edx-celeryutils #263
- Bulk repo update workflow: .github #115
2025
- Django 5.2: django-user-tasks #412, event-bus-kafka #307, help-tokens #262, django-wiki #298, edx-milestones #100, taxonomy-connector #232, openedx-ledger #159, openedx-platform #36693, #36702, #36708, #36716
- React 18: edx-ora2 #2297, openedx-platform #36568
- Maintainer transfers: edx-repo-health #627, pytest-repo-health #372
2026
