{
 "name": "57 open-source web apps counted: screens, API operations and end-to-end spec files",
 "description": "57 open-source web apps counted from their repositories: screens (page files or route declarations), API operations in a committed OpenAPI spec, and end-to-end spec files. 14 have no end-to-end spec file; 32 of the 40 with a screen count have fewer spec files than screens (median 0.25 per screen). Spec files are not tests and screens are not features. Counted 17 Sep 2026 and 28 Sep 2026, each row with its repository, commit and rule.",
 "url": "https://featkpr.com/library/counted",
 "licence": {
  "id": "CC-BY-4.0",
  "name": "Creative Commons Attribution 4.0 International (CC BY 4.0)",
  "short": "CC BY 4.0",
  "url": "https://creativecommons.org/licenses/by/4.0/"
 },
 "creator": {
  "name": "featkpr",
  "url": "https://featkpr.com"
 },
 "published": "2026-09-28",
 "cite": "featkpr, 57 open-source web apps counted, 28 Sep 2026, CC BY 4.0, https://featkpr.com/library/counted",
 "cite_bibtex": "@misc{featkpr_counted_20260928,\n  author       = {{featkpr}},\n  title        = {57 open-source web apps counted: screens, API operations and end-to-end spec files},\n  year         = {2026},\n  month        = {sep},\n  howpublished = {\\url{https://featkpr.com/library/counted}},\n  note         = {Dataset, CC BY 4.0. Counted 17 Sep 2026 and 28 Sep 2026}\n}",
 "method": "https://featkpr.com/library/counted#method",
 "sources": {
  "t2": {
   "what": "featkpr research report T2: 14 apps counted by hand",
   "counted": "2026-09-17"
  },
  "script": {
   "what": "tools/library_count.py: T2's protocol made mechanical; 43 apps counted and 4 of T2's recounted",
   "counted": "2026-09-28",
   "receipt": "research/reports/library-count-2026-09-28.json"
  }
 },
 "summary": {
  "apps": 57,
  "no_e2e_spec_file": 14,
  "no_e2e_spec_file_apps": [
   "Akaunting",
   "BookStack",
   "ERPNext",
   "Firefly III",
   "FreshRSS",
   "Hoppscotch",
   "Kanboard",
   "Kimai",
   "Medusa",
   "NocoDB",
   "Outline",
   "Plane",
   "Snipe-IT",
   "Sylius"
  ],
  "with_screen_count": 40,
  "fewer_spec_files_than_screens": 32,
  "more_spec_files_than_screens": 8,
  "median_e2e_spec_files_per_screen": 0.246,
  "with_committed_api_spec": 19
 },
 "columns": [
  {
   "name": "app",
   "description": "the app"
  },
  {
   "name": "what",
   "description": "what it is"
  },
  {
   "name": "stack",
   "description": "its stack: server, then front end"
  },
  {
   "name": "licence",
   "description": "the licence its LICENSE file names; \"+ ee\" when a directory is under its own (enterprise) licence"
  },
  {
   "name": "repository",
   "description": "the repository counted"
  },
  {
   "name": "commit",
   "description": "the commit counted (full SHA), or the tag; empty where report T2 recorded no commit"
  },
  {
   "name": "commit_date",
   "description": "the date of that commit or tag"
  },
  {
   "name": "counted_on",
   "description": "the day it was counted"
  },
  {
   "name": "counted_by",
   "description": "\"report T2, by hand\" (17 Sep 2026) or \"tools/library_count.py\" (28 Sep 2026)"
  },
  {
   "name": "screens",
   "description": "pages a person can land on: page files or route declarations, never components; empty when they cannot be counted from the files"
  },
  {
   "name": "api_operations",
   "description": "(path, method) pairs in the OpenAPI or Swagger spec committed to the repository; empty when no spec is committed"
  },
  {
   "name": "e2e_spec_files",
   "description": "files of the end-to-end suite the project runs against the running app (browser or HTTP); files, not tests"
  },
  {
   "name": "e2e_spec_files_per_screen",
   "description": "e2e_spec_files divided by screens, to 3 decimals; empty without a screen count"
  },
  {
   "name": "screens_rule",
   "description": "the rule that produced screens (for the script: the path pattern, the text pattern and the exclusion), or why there is no count"
  },
  {
   "name": "api_rule",
   "description": "the spec file(s) read and the operations in each, or why there is no count"
  },
  {
   "name": "e2e_rule",
   "description": "the rule that produced e2e_spec_files"
  },
  {
   "name": "recount_on",
   "description": "for report T2's apps the script recounted: the day"
  },
  {
   "name": "recount_commit",
   "description": "the commit recounted (full SHA)"
  },
  {
   "name": "recount_screens",
   "description": "screens on the recount"
  },
  {
   "name": "recount_api_operations",
   "description": "API operations on the recount"
  },
  {
   "name": "recount_e2e_spec_files",
   "description": "end-to-end spec files on the recount"
  }
 ],
 "apps": [
  {
   "app": "Akaunting",
   "what": "accounting",
   "stack": "Laravel",
   "licence": "BSL-1.1",
   "repository": "https://github.com/akaunting/akaunting",
   "commit": "0c7792b2e8cbfe75c6f4f76f78e519770e3601bd",
   "commit_date": "2026-09-27",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 121,
   "api_operations": null,
   "e2e_spec_files": 0,
   "e2e_spec_files_per_screen": 0,
   "screens_rule": "121 = files containing <x-layouts\\. in ^resources/views/.*\\.blade\\.php$ minus ^resources/views/(components|vendor|partials|modals)/",
   "api_rule": "no committed spec",
   "e2e_rule": "no end-to-end suite in the tree",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Appsmith",
   "what": "internal-tool builder",
   "stack": "Java · React",
   "licence": "Apache-2.0",
   "repository": "https://github.com/appsmithorg/appsmith",
   "commit": "c7e65f8f80b39fb33ff4d42fdb91db1dd69a69df",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 21,
   "api_operations": null,
   "e2e_spec_files": 667,
   "e2e_spec_files_per_screen": 31.762,
   "screens_rule": "21 = occurrences of <SentryRoute\\b in ^app/client/src/ce/AppRouter\\.tsx$",
   "api_rule": "no committed spec",
   "e2e_rule": "661 = files ^app/client/cypress/e2e/.*_spec\\.(js|ts)$; 6 = files ^app/client/playwright/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Baserow",
   "what": "no-code database",
   "stack": "Django · Nuxt",
   "licence": "MIT + premium",
   "repository": "https://gitlab.com/baserow/baserow",
   "commit": "",
   "commit_date": "",
   "counted_on": "2026-09-17",
   "counted_by": "report T2, by hand",
   "screens": 54,
   "api_operations": null,
   "e2e_spec_files": 37,
   "e2e_spec_files_per_screen": 0.685,
   "screens_rule": "Nuxt pages: core plus premium and enterprise",
   "api_rule": "not counted: generated at runtime (drf-spectacular)",
   "e2e_rule": "Playwright specs in e2e-tests",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "BookStack",
   "what": "wiki",
   "stack": "PHP · Laravel",
   "licence": "MIT",
   "repository": "https://codeberg.org/bookstack/bookstack",
   "commit": "v26.05.5",
   "commit_date": "2026-09-14",
   "counted_on": "2026-09-17",
   "counted_by": "report T2, by hand",
   "screens": 93,
   "api_operations": 77,
   "e2e_spec_files": 0,
   "e2e_spec_files_per_screen": 0,
   "screens_rule": "GET routes whose controller renders a Blade template that @extends a layout (php artisan route:list --json): full-page views",
   "api_rule": "the API routes of the framework's route table",
   "e2e_rule": "none: PHPUnit tests only, no browser suite",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Cal.diy",
   "what": "scheduling",
   "stack": "Next.js",
   "licence": "MIT",
   "repository": "https://github.com/calcom/cal.diy",
   "commit": "",
   "commit_date": "",
   "counted_on": "2026-09-17",
   "counted_by": "report T2, by hand",
   "screens": 78,
   "api_operations": 121,
   "e2e_spec_files": 53,
   "e2e_spec_files_per_screen": 0.679,
   "screens_rule": "page.tsx files",
   "api_rule": "the v2 spec (it may describe the removed platform API)",
   "e2e_rule": "*.e2e.ts files",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Chatwoot",
   "what": "customer support",
   "stack": "Rails · Vue",
   "licence": "MIT + enterprise",
   "repository": "https://github.com/chatwoot/chatwoot",
   "commit": "",
   "commit_date": "",
   "counted_on": "2026-09-17",
   "counted_by": "report T2, by hand",
   "screens": null,
   "api_operations": 154,
   "e2e_spec_files": 3,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "not counted: dashboard *.routes.js files, routes not counted",
   "api_rule": "swagger/swagger.json, the public API",
   "e2e_rule": "Playwright specs in tests/playwright",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Directus",
   "what": "data platform",
   "stack": "Node · Vue",
   "licence": "MSCL-1.0 (source-available)",
   "repository": "https://github.com/directus/directus",
   "commit": "1694b19048c8523bc90dd1fd11566b748b155ec4",
   "commit_date": "2026-09-25",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 73,
   "api_operations": 136,
   "e2e_spec_files": 99,
   "e2e_spec_files_per_screen": 1.356,
   "screens_rule": "73 = files ^app/src/modules/[^/]+/routes/.*\\.vue$ minus /components/",
   "api_rule": "packages/specs/src/openapi.yaml: 136",
   "e2e_rule": "99 = files ^tests/e2e/tests/.*\\.test\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Discourse",
   "what": "forum",
   "stack": "Rails · Ember",
   "licence": "GPL-2.0",
   "repository": "https://github.com/discourse/discourse",
   "commit": "3b6713ef7768d10cee4f11d033e37f66a1ccad5c",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 166,
   "api_operations": null,
   "e2e_spec_files": 295,
   "e2e_spec_files_per_screen": 1.777,
   "screens_rule": "166 = files ^frontend/discourse/app/routes/.*\\.(js|gjs|ts)$",
   "api_rule": "the API docs are another repository",
   "e2e_rule": "295 = files ^spec/system/.*_spec\\.rb$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Documenso",
   "what": "document signing",
   "stack": "React Router 7",
   "licence": "AGPL-3.0 + ee",
   "repository": "https://github.com/documenso/documenso",
   "commit": "",
   "commit_date": "",
   "counted_on": "2026-09-17",
   "counted_by": "report T2, by hand",
   "screens": 115,
   "api_operations": null,
   "e2e_spec_files": 132,
   "e2e_spec_files_per_screen": 1.148,
   "screens_rule": "React Router 7 route modules minus layouts",
   "api_rule": "tRPC and ts-rest, no committed spec",
   "e2e_rule": "Playwright specs in packages/app-tests",
   "recount_on": "2026-09-28",
   "recount_commit": "a1d4bec1430a937395db9a4aae28979cd71c2831",
   "recount_screens": 112,
   "recount_api_operations": null,
   "recount_e2e_spec_files": 135
  },
  {
   "app": "ERPNext",
   "what": "ERP",
   "stack": "Frappe (Python)",
   "licence": "GPL-3.0",
   "repository": "https://github.com/frappe/erpnext",
   "commit": "89f490f72edd25d7f0f4fc4c219fd704564d6af7",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": null,
   "api_operations": null,
   "e2e_spec_files": 0,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "screens are generated from DocType records",
   "api_rule": "generated per DocType, no committed spec",
   "e2e_rule": "no end-to-end suite in the tree",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Firefly III",
   "what": "personal finance",
   "stack": "PHP",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/firefly-iii/firefly-iii",
   "commit": "",
   "commit_date": "",
   "counted_on": "2026-09-17",
   "counted_by": "report T2, by hand",
   "screens": null,
   "api_operations": null,
   "e2e_spec_files": 0,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "not counted",
   "api_rule": "not counted: the spec is another repository",
   "e2e_rule": "none",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Formbricks",
   "what": "surveys",
   "stack": "Next.js",
   "licence": "AGPL-3.0 + ee",
   "repository": "https://github.com/formbricks/formbricks",
   "commit": "",
   "commit_date": "",
   "counted_on": "2026-09-17",
   "counted_by": "report T2, by hand",
   "screens": 76,
   "api_operations": 72,
   "e2e_spec_files": 48,
   "e2e_spec_files_per_screen": 0.632,
   "screens_rule": "page.tsx files, modules/ee included",
   "api_rule": "the v1 and v2 specs in the docs",
   "e2e_rule": "Playwright specs",
   "recount_on": "2026-09-28",
   "recount_commit": "43db6ad83f98a827db2d551981359c8e11838a0b",
   "recount_screens": 78,
   "recount_api_operations": 72,
   "recount_e2e_spec_files": 49
  },
  {
   "app": "FreshRSS",
   "what": "feed reader",
   "stack": "PHP",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/FreshRSS/FreshRSS",
   "commit": "a8e5e6300b80514d5a14140566c2386a80cf8450",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 63,
   "api_operations": null,
   "e2e_spec_files": 0,
   "e2e_spec_files_per_screen": 0,
   "screens_rule": "63 = files ^app/views/[^/]+/[^/_][^/]*\\.phtml$ minus ^app/views/helpers/",
   "api_rule": "compatible with other readers' APIs, no spec",
   "e2e_rule": "no end-to-end suite in the tree",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Ghost",
   "what": "publishing",
   "stack": "Node · Ember/React",
   "licence": "MIT",
   "repository": "https://github.com/TryGhost/Ghost",
   "commit": "7c306768041d7a9e240336af42954cc86deaedfe",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": null,
   "api_operations": null,
   "e2e_spec_files": 101,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "the admin is moving from an Ember router to React routers",
   "api_rule": "no committed spec",
   "e2e_rule": "101 = files ^e2e/tests/.*\\.test\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Gitea",
   "what": "code hosting",
   "stack": "Go templates",
   "licence": "MIT",
   "repository": "https://github.com/go-gitea/gitea",
   "commit": "fba8d7eaceeed3f8bbc364386d2a35aa672285a2",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 111,
   "api_operations": 537,
   "e2e_spec_files": 30,
   "e2e_spec_files_per_screen": 0.27,
   "screens_rule": "111 = files containing \\{\\{\\s*template\\s+\"base/head\" in ^templates/.*\\.tmpl$",
   "api_rule": "templates/swagger/v1-swagger.generated.json: 537",
   "e2e_rule": "30 = files ^tests/e2e/.*\\.test\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "GLPI",
   "what": "IT service desk",
   "stack": "PHP · Twig",
   "licence": "GPL-3.0",
   "repository": "https://github.com/glpi-project/glpi",
   "commit": "af37be7a77e6196c49244a2d93e9328003d2c930",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 315,
   "api_operations": null,
   "e2e_spec_files": 107,
   "e2e_spec_files_per_screen": 0.34,
   "screens_rule": "315 = files ^front/[^/]+\\.php$",
   "api_rule": "generated at runtime",
   "e2e_rule": "106 = files ^tests/e2e/specs/.*\\.spec\\.ts$; 1 = files ^tests/cypress/e2e/.*\\.cy\\.js$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Grafana",
   "what": "dashboards",
   "stack": "Go · React",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/grafana/grafana",
   "commit": "5f4490098b3555e5e9ce6d0a59c07d7463eaeadc",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 90,
   "api_operations": 314,
   "e2e_spec_files": 213,
   "e2e_spec_files_per_screen": 2.367,
   "screens_rule": "90 = occurrences of \\bpath:\\s in ^public/app/routes/routes\\.tsx$",
   "api_rule": "public/api-merged.json: 314",
   "e2e_rule": "213 = files ^e2e-playwright/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Hoppscotch",
   "what": "API client",
   "stack": "Vue · NestJS",
   "licence": "MIT",
   "repository": "https://github.com/hoppscotch/hoppscotch",
   "commit": "a9ffa29ce5036ef5be0768db35a8b6bae32e1160",
   "commit_date": "2026-09-23",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 32,
   "api_operations": null,
   "e2e_spec_files": 0,
   "e2e_spec_files_per_screen": 0,
   "screens_rule": "32 = files ^packages/hoppscotch-(common|sh-admin)/src/pages/.*\\.vue$",
   "api_rule": "GraphQL",
   "e2e_rule": "no end-to-end suite in the tree",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Immich",
   "what": "photos",
   "stack": "NestJS · SvelteKit",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/immich-app/immich",
   "commit": "",
   "commit_date": "",
   "counted_on": "2026-09-17",
   "counted_by": "report T2, by hand",
   "screens": 56,
   "api_operations": 276,
   "e2e_spec_files": 49,
   "e2e_spec_files_per_screen": 0.875,
   "screens_rule": "+page.svelte files",
   "api_rule": "open-api/immich-openapi-specs.json (checked in CI)",
   "e2e_rule": "e2e/src/**/*.e2e-spec.ts (API and web)",
   "recount_on": "2026-09-28",
   "recount_commit": "aa023378477fb1a65d24f4614de0940f6a769794",
   "recount_screens": 56,
   "recount_api_operations": 276,
   "recount_e2e_spec_files": 49
  },
  {
   "app": "InvenTree",
   "what": "inventory",
   "stack": "Django · React",
   "licence": "MIT",
   "repository": "https://github.com/inventree/InvenTree",
   "commit": "",
   "commit_date": "",
   "counted_on": "2026-09-17",
   "counted_by": "report T2, by hand",
   "screens": 87,
   "api_operations": 670,
   "e2e_spec_files": 26,
   "e2e_spec_files_per_screen": 0.299,
   "screens_rule": "page files in src/frontend/src/pages",
   "api_rule": "the schema export kept in the inventree/schema repository",
   "e2e_rule": "Playwright specs in src/frontend/tests",
   "recount_on": "2026-09-28",
   "recount_commit": "c2b7f71f2f21f89dd29102130bba3c190bda51b6",
   "recount_screens": 87,
   "recount_api_operations": null,
   "recount_e2e_spec_files": 26
  },
  {
   "app": "Kanboard",
   "what": "kanban",
   "stack": "PHP",
   "licence": "MIT",
   "repository": "https://github.com/kanboard/kanboard",
   "commit": "cf53b54597b67b60140586c09c2fe6132ead013c",
   "commit_date": "2026-09-11",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 102,
   "api_operations": null,
   "e2e_spec_files": 0,
   "e2e_spec_files_per_screen": 0,
   "screens_rule": "102 = distinct ->helper->layout->\\w+\\(\\s*'([^']+)' in ^app/Controller/.*\\.php$",
   "api_rule": "JSON-RPC, no spec",
   "e2e_rule": "no end-to-end suite in the tree",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Keycloak",
   "what": "identity and access",
   "stack": "Java · React",
   "licence": "Apache-2.0",
   "repository": "https://github.com/keycloak/keycloak",
   "commit": "9f8eb2d23818d11420d80af682e8e9fc6dc4abd8",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 94,
   "api_operations": null,
   "e2e_spec_files": 81,
   "e2e_spec_files_per_screen": 0.862,
   "screens_rule": "94 = files ^js/apps/admin-ui/src/.*/routes/[^/]+\\.tsx$",
   "api_rule": "the committed spec covers only the new admin API v2 (6 operations)",
   "e2e_rule": "81 = files ^js/apps/(admin|account)-ui/test/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Kimai",
   "what": "time tracking",
   "stack": "Symfony · Twig",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/kimai/kimai",
   "commit": "8528bb174469f0dcc0c4efb5bd18971460d74c78",
   "commit_date": "2026-09-27",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 48,
   "api_operations": null,
   "e2e_spec_files": 0,
   "e2e_spec_files_per_screen": 0,
   "screens_rule": "48 = files containing \\{%\\s*extends\\s+['\\\"](base|kimai-theme|.*layout)[^'\\\"]*\\.html\\.twig in ^templates/.*\\.html\\.twig$ minus /(macros|embeds?|partials?|components?|bundles|email)/|/_[^/]+$",
   "api_rule": "generated at runtime",
   "e2e_rule": "no end-to-end suite in the tree",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Linkwarden",
   "what": "bookmarks",
   "stack": "Next.js",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/linkwarden/linkwarden",
   "commit": "952ac4540657cae3a67c3ca59433899d2fda8374",
   "commit_date": "2026-09-09",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 36,
   "api_operations": null,
   "e2e_spec_files": 1,
   "e2e_spec_files_per_screen": 0.028,
   "screens_rule": "36 = files ^apps/web/pages/.*\\.tsx$ minus /pages/api/|/_(app|document|error)\\.|\\.(test|spec|stories)\\.",
   "api_rule": "no committed spec",
   "e2e_rule": "1 = files ^apps/web/e2e/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Mastodon",
   "what": "social network",
   "stack": "Rails · React",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/mastodon/mastodon",
   "commit": "35c345010f65b74062bae1d16dcf16924ac6058d",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 214,
   "api_operations": null,
   "e2e_spec_files": 107,
   "e2e_spec_files_per_screen": 0.5,
   "screens_rule": "160 = files ^app/views/.*\\.html\\.(haml|erb)$ minus /_[^/]+$|/layouts/|mailer/|_mailer/|/mailers?/|\\.(js|json|api\\.rsb|text|txt|xml|atom|csv|pdf)\\.; 54 = occurrences of <WrappedRoute\\b in ^app/javascript/mastodon/features/ui/index\\.(jsx|tsx)$",
   "api_rule": "no committed spec",
   "e2e_rule": "107 = files ^spec/system/.*_spec\\.rb$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Mattermost",
   "what": "team chat",
   "stack": "Go · React",
   "licence": "Apache-2.0 + ee",
   "repository": "https://github.com/mattermost/mattermost",
   "commit": "05553d083cd8b9a92ccbcddca6202896ce60c4ae",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": null,
   "api_operations": 605,
   "e2e_spec_files": 996,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "routes are declared across the React code, not one router file",
   "api_rule": "api/v4/source/access_control.yaml: 18, api/v4/source/actions.yaml: 4, api/v4/source/agents.yaml: 3, api/v4/source/audit_logging.yaml: 2, api/v4/source/boards.yaml: 1, api/v4/source/bookmarks.yaml: 5, api/v4/source/bots.yaml: 8, api/v4/source/brand.yaml: 3, api/v4/source/channels.yaml: 60, api/v4/source/cloud.yaml: 15, api/v4/source/cluster.yaml: 1, api/v4/source/commands.yaml: 10, api/v4/source/compliance.yaml: 4, api/v4/source/content_flagging.yaml: 14, api/v4/source/custom_profile_attributes.yaml: 8, api/v4/source/dataretention.yaml: 15, api/v4/source/definitions.yaml: 0, api/v4/source/delivery_tracking.yaml: 2, api/v4/source/elasticsearch.yaml: 2, api/v4/source/emoji.yaml: 9, api/v4/source/ephemeral_mode.yaml: 3, api/v4/source/exports.yaml: 4, api/v4/source/files.yaml: 13, api/v4/source/groups.yaml: 25, api/v4/source/imports.yaml: 2, api/v4/source/introduction.yaml: 0, api/v4/source/ip_filters.yaml: 3, api/v4/source/jobs.yaml: 7, api/v4/source/ldap.yaml: 13, api/v4/source/limits.yaml: 1, api/v4/source/logs.yaml: 1, api/v4/source/metrics.yaml: 1, api/v4/source/oauth.yaml: 10, api/v4/source/outgoing_oauth_connections.yaml: 6, api/v4/source/permissions.yaml: 1, api/v4/source/plugins.yaml: 14, api/v4/source/posts.yaml: 28, api/v4/source/preferences.yaml: 5, api/v4/source/properties.yaml: 9, api/v4/source/reactions.yaml: 3, api/v4/source/recaps.yaml: 8, api/v4/source/remoteclusters.yaml: 12, api/v4/source/reports.yaml: 4, api/v4/source/roles.yaml: 5, api/v4/source/saml.yaml: 10, api/v4/source/scheduled_post.yaml: 4, api/v4/source/scheduled_recaps.yaml: 7, api/v4/source/schemes.yaml: 7, api/v4/source/service_terms.yaml: 2, api/v4/source/sharedchannels.yaml: 7, api/v4/source/status.yaml: 7, api/v4/source/system.yaml: 51, api/v4/source/teams.yaml: 37, api/v4/source/uploads.yaml: 3, api/v4/source/usage.yaml: 3, api/v4/source/users.yaml: 87, api/v4/source/views.yaml: 7, api/v4/source/webhooks.yaml: 11",
   "e2e_rule": "621 = files ^e2e-tests/cypress/tests/integration/.*_spec\\.(js|ts)$; 375 = files ^e2e-tests/playwright/specs/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Mealie",
   "what": "recipes",
   "stack": "FastAPI · Nuxt",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/mealie-recipes/mealie",
   "commit": "86aec702a72f60fa83727b86cb95584bb6e339f0",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 66,
   "api_operations": null,
   "e2e_spec_files": 2,
   "e2e_spec_files_per_screen": 0.03,
   "screens_rule": "66 = files ^frontend/app/pages/.*\\.vue$",
   "api_rule": "generated at runtime",
   "e2e_rule": "2 = files ^tests/e2e/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Medusa",
   "what": "commerce",
   "stack": "Node · React",
   "licence": "MIT + ee",
   "repository": "https://github.com/medusajs/medusa",
   "commit": "",
   "commit_date": "",
   "counted_on": "2026-09-17",
   "counted_by": "report T2, by hand",
   "screens": 186,
   "api_operations": 486,
   "e2e_spec_files": 0,
   "e2e_spec_files_per_screen": 0,
   "screens_rule": "admin page modules across its route modules",
   "api_rule": "the admin and store specs",
   "e2e_rule": "none: integration tests only",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Metabase",
   "what": "analytics",
   "stack": "Clojure · React",
   "licence": "AGPL-3.0 + ee",
   "repository": "https://github.com/metabase/metabase",
   "commit": "1a0ff4340be84ec613b09a4613b7d12a44f2403a",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": null,
   "api_operations": 637,
   "e2e_spec_files": 427,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "routes are spread over more than 30 route files, with redirects and modals",
   "api_rule": "resources/openapi/openapi.json: 637",
   "e2e_rule": "427 = files ^e2e/test/scenarios/.*\\.cy\\.spec\\.(js|ts)$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "n8n",
   "what": "workflow automation",
   "stack": "Node · Vue",
   "licence": "Sustainable Use (fair-code) + ee",
   "repository": "https://github.com/n8n-io/n8n",
   "commit": "41dbfd987b6467b34c572d3b63962213e6befec4",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 61,
   "api_operations": 32,
   "e2e_spec_files": 284,
   "e2e_spec_files_per_screen": 4.656,
   "screens_rule": "61 = occurrences of \\bcomponents?:\\s in ^packages/frontend/editor-ui/src/app/router\\.ts$",
   "api_rule": "packages/cli/src/public-api/v1/openapi.yml: 32",
   "e2e_rule": "284 = files ^packages/testing/playwright/tests/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Nextcloud server",
   "what": "file sync and share",
   "stack": "PHP · Vue",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/nextcloud/server",
   "commit": "c41a9138d715c31e9a7684e5ed91ef9c62ccd2b8",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": null,
   "api_operations": 301,
   "e2e_spec_files": 102,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "pages are PHP templates and Vue views in each bundled app, with no one rule for both",
   "api_rule": "apps/appstore/openapi.json: 7, apps/cloud_federation_api/openapi.json: 2, apps/comments/openapi.json: 0, apps/dashboard/openapi.json: 7, apps/dav/openapi.json: 12, apps/federatedfilesharing/openapi.json: 9, apps/federation/openapi-full.json: 7, apps/files/openapi.json: 16, apps/files_external/openapi.json: 1, apps/files_reminders/openapi.json: 3, apps/files_sharing/openapi.json: 23, apps/files_trashbin/openapi.json: 1, apps/files_versions/openapi.json: 1, apps/oauth2/openapi.json: 2, apps/profile/openapi.json: 1, apps/provisioning_api/openapi-full.json: 49, apps/settings/openapi-full.json: 4, apps/sharebymail/openapi.json: 0, apps/sharing/openapi.json: 17, apps/systemtags/openapi.json: 0, apps/theming/openapi.json: 11, apps/updatenotification/openapi.json: 2, apps/user_ldap/openapi.json: 8, apps/user_status/openapi.json: 10, apps/weather_status/openapi.json: 7, apps/webhook_listeners/openapi.json: 6, apps/workflowengine/openapi-full.json: 10, core/openapi-full.json: 85",
   "e2e_rule": "102 = files ^tests/playwright/e2e/.*\\.spec\\.ts$; 0 = files ^cypress/e2e/.*\\.cy\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "NocoDB",
   "what": "no-code database",
   "stack": "Node · Nuxt",
   "licence": "Sustainable Use (fair-code)",
   "repository": "https://github.com/nocodb/nocodb",
   "commit": "8cfa45dcb8ab9241ea06dc255d87bff955de76d9",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 66,
   "api_operations": 278,
   "e2e_spec_files": 0,
   "e2e_spec_files_per_screen": 0,
   "screens_rule": "66 = files ^packages/nc-gui/pages/.*\\.vue$",
   "api_rule": "packages/nocodb/src/schema/swagger.json: 278",
   "e2e_rule": "no end-to-end suite in the tree",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Odoo",
   "what": "business suite",
   "stack": "Python · OWL",
   "licence": "LGPL-3.0",
   "repository": "https://github.com/odoo/odoo",
   "commit": "a240a91eb01223f59190f4853f748d675f68eaf2",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": null,
   "api_operations": null,
   "e2e_spec_files": 525,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "screens are XML view records, not page files",
   "api_rule": "RPC, no committed spec",
   "e2e_rule": "525 = files /static/tests/tours/.*\\.js$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "OpenProject",
   "what": "project management",
   "stack": "Rails · Angular",
   "licence": "GPL-3.0",
   "repository": "https://github.com/opf/openproject",
   "commit": "c0146dbdd26a2e1be15123cc69e1406746c34ef5",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 406,
   "api_operations": 331,
   "e2e_spec_files": 787,
   "e2e_spec_files_per_screen": 1.938,
   "screens_rule": "406 = files ^(app|modules/[^/]+/app)/views/.*\\.html\\.(erb|haml)$ minus /_[^/]+$|/layouts/|mailer/|_mailer/|/mailers?/|\\.(js|json|api\\.rsb|text|txt|xml|atom|csv|pdf)\\.",
   "api_rule": "docs/api/apiv3/openapi-spec.yml: 331",
   "e2e_rule": "787 = files ^(spec|modules/[^/]+/spec)/(features|system)/.*_spec\\.rb$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Outline",
   "what": "team wiki",
   "stack": "Node · React",
   "licence": "BSL-1.1",
   "repository": "https://github.com/outline/outline",
   "commit": "179d7dd7be2cb395d45f0151b858e14009cec9d1",
   "commit_date": "2026-09-27",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 32,
   "api_operations": null,
   "e2e_spec_files": 0,
   "e2e_spec_files_per_screen": 0,
   "screens_rule": "32 = occurrences of <Route\\b in ^app/routes/.*\\.tsx?$",
   "api_rule": "the API spec is another repository (outline/openapi)",
   "e2e_rule": "no end-to-end suite in the tree",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Paperless-ngx",
   "what": "documents",
   "stack": "Django · Angular",
   "licence": "GPL-3.0",
   "repository": "https://github.com/paperless-ngx/paperless-ngx",
   "commit": "88000aab45a2b7d321efb9988cd993dd7ee69119",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 21,
   "api_operations": null,
   "e2e_spec_files": 5,
   "e2e_spec_files_per_screen": 0.238,
   "screens_rule": "21 = occurrences of \\bcomponent:\\s*\\w+ in ^src-ui/src/app/app-routing\\.module\\.ts$",
   "api_rule": "generated at runtime",
   "e2e_rule": "5 = files ^src-ui/e2e/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Penpot",
   "what": "design tool",
   "stack": "Clojure",
   "licence": "MPL-2.0",
   "repository": "https://github.com/penpot/penpot",
   "commit": "f9b8f1ba75f04e84a1940ef19d29fc92cb5d6abc",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": null,
   "api_operations": null,
   "e2e_spec_files": 65,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "routes are data in ClojureScript, not page files",
   "api_rule": "RPC, no committed spec",
   "e2e_rule": "65 = files ^frontend/playwright/.*\\.spec\\.js$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Plane",
   "what": "project tracking",
   "stack": "Django · Next.js",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/makeplane/plane",
   "commit": "",
   "commit_date": "",
   "counted_on": "2026-09-17",
   "counted_by": "report T2, by hand",
   "screens": 72,
   "api_operations": null,
   "e2e_spec_files": 0,
   "e2e_spec_files_per_screen": 0,
   "screens_rule": "page.tsx files (web, admin and space)",
   "api_rule": "not counted: Django REST framework, no committed spec",
   "e2e_rule": "none: no Playwright config",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Plausible",
   "what": "web analytics",
   "stack": "Elixir · React",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/plausible/analytics",
   "commit": "ee3a27bb3d63dd04e51e6e1d811e5d43999e6ac1",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": null,
   "api_operations": null,
   "e2e_spec_files": 12,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "the Phoenix router mixes pages, API, dev and test routes",
   "api_rule": "no committed spec",
   "e2e_rule": "12 = files ^e2e/tests/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "PostHog",
   "what": "product analytics",
   "stack": "Django · React",
   "licence": "MIT + ee",
   "repository": "https://github.com/PostHog/posthog",
   "commit": "cb45223750b15b39ba39e333d4c167f440e3920a",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 169,
   "api_operations": null,
   "e2e_spec_files": 43,
   "e2e_spec_files_per_screen": 0.254,
   "screens_rule": "169 = occurrences of ^\\s*\\[urls\\. in ^frontend/src/scenes/scenes\\.ts$",
   "api_rule": "generated at runtime",
   "e2e_rule": "43 = files ^playwright/e2e/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Redmine",
   "what": "project tracking",
   "stack": "Rails",
   "licence": "GPL-2.0+",
   "repository": "https://github.com/redmine/redmine",
   "commit": "c9008f4cebbb882d9a16a0b81b18e888744dedc8",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 223,
   "api_operations": null,
   "e2e_spec_files": 28,
   "e2e_spec_files_per_screen": 0.126,
   "screens_rule": "223 = files ^app/views/.*\\.html\\.erb$ minus /_[^/]+$|/layouts/|mailer/|_mailer/|/mailers?/|\\.(js|json|api\\.rsb|text|txt|xml|atom|csv|pdf)\\.",
   "api_rule": "no committed spec",
   "e2e_rule": "28 = files ^test/system/.*_test\\.rb$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Rocket.Chat",
   "what": "team chat",
   "stack": "Meteor · React",
   "licence": "MIT + ee",
   "repository": "https://github.com/RocketChat/Rocket.Chat",
   "commit": "b149e10ee028e087ef8b25442dc7329f0b038972",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": null,
   "api_operations": null,
   "e2e_spec_files": 280,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "routes are registered across the client code",
   "api_rule": "typed in code (rest-typings), no committed spec",
   "e2e_rule": "176 = files ^apps/meteor/tests/e2e/.*\\.spec\\.ts$; 104 = files ^apps/meteor/tests/end-to-end/.*\\.(ts|js)$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Saleor dashboard",
   "what": "commerce admin",
   "stack": "React (GraphQL API)",
   "licence": "BSD",
   "repository": "https://github.com/saleor/saleor-dashboard",
   "commit": "8d678ea217a17187e3bc3dda03df468f3a826617",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": null,
   "api_operations": null,
   "e2e_spec_files": 40,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "routes are built from URL helpers in code",
   "api_rule": "GraphQL",
   "e2e_rule": "1 = files ^e2e/.*\\.spec\\.ts$; 39 = files ^e2e-legacy/tests/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Snipe-IT",
   "what": "asset management",
   "stack": "Laravel",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/grokability/snipe-it",
   "commit": "d5bf95c02a24bbe977b5f21552992a5ef7d3b60b",
   "commit_date": "2026-09-26",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 154,
   "api_operations": null,
   "e2e_spec_files": 0,
   "e2e_spec_files_per_screen": 0,
   "screens_rule": "154 = files containing @extends\\(\\s*['\\\"]layouts in ^resources/views/.*\\.blade\\.php$ minus ^resources/views/(vendor|partials|modals|notifications)/",
   "api_rule": "no committed spec",
   "e2e_rule": "no end-to-end suite in the tree",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Strapi",
   "what": "headless CMS",
   "stack": "Node · React",
   "licence": "MIT + ee",
   "repository": "https://github.com/strapi/strapi",
   "commit": "bba9685b9620d09ba87aaeee150f0021335928dd",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": null,
   "api_operations": null,
   "e2e_spec_files": 100,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "the admin routes are declared across each package",
   "api_rule": "generated per content type",
   "e2e_rule": "100 = files ^tests/e2e/tests/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Supabase Studio",
   "what": "database dashboard",
   "stack": "Next.js",
   "licence": "Apache-2.0",
   "repository": "https://github.com/supabase/supabase",
   "commit": "8e2071247527a8ba90c588deb0aee6d6ea2bc95f",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 190,
   "api_operations": 170,
   "e2e_spec_files": 29,
   "e2e_spec_files_per_screen": 0.153,
   "screens_rule": "190 = files ^apps/studio/pages/.*\\.tsx$ minus /pages/api/|/_(app|document|error)\\.|\\.(test|spec|stories)\\.",
   "api_rule": "apps/docs/spec/api_v1_openapi.json: 170",
   "e2e_rule": "29 = files ^e2e/studio/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Sylius",
   "what": "commerce",
   "stack": "PHP",
   "licence": "MIT",
   "repository": "https://github.com/Sylius/Sylius",
   "commit": "",
   "commit_date": "",
   "counted_on": "2026-09-17",
   "counted_by": "report T2, by hand",
   "screens": null,
   "api_operations": null,
   "e2e_spec_files": 0,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "not counted",
   "api_rule": "not counted: generated at runtime",
   "e2e_rule": "none",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Taiga",
   "what": "agile boards",
   "stack": "Django · AngularJS",
   "licence": "AGPL-3.0 front · MPL-2.0 back",
   "repository": "https://github.com/taigaio/taiga-front",
   "commit": "d2da061168ad6d2526dcc68fdf6117d029c0164c",
   "commit_date": "2026-09-04",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 72,
   "api_operations": null,
   "e2e_spec_files": 47,
   "e2e_spec_files_per_screen": 0.653,
   "screens_rule": "72 = occurrences of \\$routeProvider\\.when\\( in ^app/coffee/app\\.coffee$",
   "api_rule": "no committed spec",
   "e2e_rule": "47 = files ^e2e/suites/.*\\.js$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Twenty",
   "what": "CRM",
   "stack": "NestJS · React",
   "licence": "AGPL-3.0 + ee",
   "repository": "https://github.com/twentyhq/twenty",
   "commit": "",
   "commit_date": "",
   "counted_on": "2026-09-17",
   "counted_by": "report T2, by hand",
   "screens": 186,
   "api_operations": null,
   "e2e_spec_files": 9,
   "e2e_spec_files_per_screen": 0.048,
   "screens_rule": "page .tsx files, sub-pages included",
   "api_rule": "not counted: GraphQL and REST generated per object, no committed spec",
   "e2e_rule": "specs in twenty-e2e-testing",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Umami",
   "what": "web analytics",
   "stack": "Next.js",
   "licence": "MIT",
   "repository": "https://github.com/umami-software/umami",
   "commit": "ec0ff50388c264ed8ce46f00967e92f7e71476ae",
   "commit_date": "2026-09-16",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 59,
   "api_operations": null,
   "e2e_spec_files": 8,
   "e2e_spec_files_per_screen": 0.136,
   "screens_rule": "59 = files ^src/app/.*/page\\.tsx$",
   "api_rule": "no committed spec",
   "e2e_rule": "8 = files ^tests/e2e/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Uptime Kuma",
   "what": "uptime monitor",
   "stack": "Node · Vue",
   "licence": "MIT",
   "repository": "https://github.com/louislam/uptime-kuma",
   "commit": "b6adc19d00e4e6700f4b6ffc64a5c4e105e8004c",
   "commit_date": "2026-09-23",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 15,
   "api_operations": null,
   "e2e_spec_files": 7,
   "e2e_spec_files_per_screen": 0.467,
   "screens_rule": "15 = files ^src/pages/.*\\.vue$",
   "api_rule": "Socket.IO, no spec",
   "e2e_rule": "7 = files ^test/e2e/specs/.*\\.spec\\.js$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Vikunja",
   "what": "tasks",
   "stack": "Go · Vue",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/go-vikunja/vikunja",
   "commit": "18f3572ed40db4b88d5901c2847efe592c88e9c7",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 59,
   "api_operations": 172,
   "e2e_spec_files": 72,
   "e2e_spec_files_per_screen": 1.22,
   "screens_rule": "59 = files ^frontend/src/views/.*\\.vue$ minus /components/",
   "api_rule": "pkg/swagger/swagger.json: 172",
   "e2e_rule": "72 = files ^frontend/tests/e2e/.*\\.spec\\.ts$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Wagtail",
   "what": "CMS",
   "stack": "Django",
   "licence": "BSD",
   "repository": "https://github.com/wagtail/wagtail",
   "commit": "e57ccdbc07a0f124e3b88ad69612bafd4131b4cf",
   "commit_date": "2026-09-25",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 165,
   "api_operations": null,
   "e2e_spec_files": 8,
   "e2e_spec_files_per_screen": 0.048,
   "screens_rule": "165 = files containing \\{%-?\\s*extends\\s in ^wagtail/.*/templates/.*\\.html$ minus /(includes?|partials?|snippets?|mail|emails?|widgets?|forms?|tests?|test)/|/_[^/]+$|^wagtail/test/",
   "api_rule": "no committed spec",
   "e2e_rule": "8 = files ^client/tests/integration/.*\\.test\\.js$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Weblate",
   "what": "translation",
   "stack": "Django",
   "licence": "GPL-3.0",
   "repository": "https://github.com/WeblateOrg/weblate",
   "commit": "6ff77533c8bb4bb514824cc80496e3ab3d29e261",
   "commit_date": "2026-09-27",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": 120,
   "api_operations": 202,
   "e2e_spec_files": 1,
   "e2e_spec_files_per_screen": 0.008,
   "screens_rule": "120 = files containing \\{%-?\\s*extends\\s in ^weblate/templates/.*\\.html$ minus /(includes?|partials?|snippets?|mail|emails?|widgets?|forms?|tests?|test)/|/_[^/]+$",
   "api_rule": "docs/specs/openapi.yaml: 202",
   "e2e_rule": "1 = files test_selenium\\.py$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Wiki.js",
   "what": "wiki",
   "stack": "Node · Vue",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/requarks/wiki",
   "commit": "712a3a5bb23b70d7f7325a04b80cc5f20a8f9d9a",
   "commit_date": "2026-09-22",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": null,
   "api_operations": null,
   "e2e_spec_files": 1,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "pages are server templates plus Vue apps, not one rule",
   "api_rule": "GraphQL",
   "e2e_rule": "1 = files ^dev/cypress/integration/.*\\.js$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Zammad",
   "what": "helpdesk",
   "stack": "Rails · Vue",
   "licence": "AGPL-3.0",
   "repository": "https://github.com/zammad/zammad",
   "commit": "619ef87bb2173ee91640ff58b1eed2edcec5fabb",
   "commit_date": "2026-09-28",
   "counted_on": "2026-09-28",
   "counted_by": "tools/library_count.py",
   "screens": null,
   "api_operations": null,
   "e2e_spec_files": 286,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "two front ends (CoffeeScript and Vue) with different routers",
   "api_rule": "no committed spec",
   "e2e_rule": "286 = files ^spec/system/.*_spec\\.rb$",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  },
  {
   "app": "Zulip",
   "what": "team chat",
   "stack": "Django · Tornado",
   "licence": "Apache-2.0",
   "repository": "https://github.com/zulip/zulip",
   "commit": "",
   "commit_date": "",
   "counted_on": "2026-09-17",
   "counted_by": "report T2, by hand",
   "screens": null,
   "api_operations": null,
   "e2e_spec_files": 20,
   "e2e_spec_files_per_screen": null,
   "screens_rule": "not counted: server templates, few screens",
   "api_rule": "not counted: an OpenAPI spec in zerver/openapi",
   "e2e_rule": "Puppeteer specs",
   "recount_on": "",
   "recount_commit": "",
   "recount_screens": null,
   "recount_api_operations": null,
   "recount_e2e_spec_files": null
  }
 ]
}
