mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-11 21:26:44 +00:00
web-svc-css becomes web-svc-design and owns the configuration that lived in group_vars/all/13_design.yml. Consumers switch their css service key to design, and sys-front-inj-css becomes sys-front-inj-design. javascript stays an independent key; a role's optional design.js.j2 is injected together with the design and CSP-hashed like the functional script. An in-repo OKLCH lookup replaces colorscheme_generator. From design.colors.base alone it derives surfaces, text, borders, the primary and status fills with their on-colors, hover and active states and a dedicated dark palette; a unit test proves WCAG AA, and AAA for body text, across six base colors in both modes. Semantic --design-* tokens replace --color-NN-SS in every role stylesheet. The shared element styles sit in the cascade layer infinito-design, so an app's own design system always wins and takes the palette through a variable mapping in its role stylesheet or through its own theming mechanism. design.logo and design.title resolve globally from web-svc-design or per role from its design entry, and false or 0 disables the replacement. The design_assets action renders the logo lockup per slot as SVG, PNG and ICO, and the legacy title keys move into the design entries. Three roles carry the design end to end. The dashboard takes logo, favicon and title from the generator and replaces the hard-coded port-ui colors. Gitea maps its theme variables onto the tokens and mounts the generated logo and a branded start page. Nextcloud receives primary color, logo, name and slogan through occ theming and ships no stylesheet. make design-sync re-renders the static design files of a deployed app, make design-gallery captures before and after screenshots in light, dark, desktop and mobile, and make design-queue orders the roles that are due for a design pass. The i8-designer skill and docs/agents/action/design.md describe that loop. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
653 lines
19 KiB
Python
Executable File
653 lines
19 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
"""Generate the role×role integration matrix.
|
||
|
||
Source of truth for the integration-matrix markdown emitted alongside this
|
||
script. Regenerate it from the repository root and commit the regenerated file.
|
||
|
||
Axes are the entity names of every web-app-* and web-svc-* role.
|
||
A cell [row][col] marks whether the ROW role ships an addon/plugin that wires
|
||
in the COLUMN role:
|
||
- check -> a real upstream plugin exists (cell links to its page)
|
||
- coin -> integration exists but is gated behind a commercial/paid tier
|
||
- cross -> no known plugin
|
||
- dash -> diagonal (same role)
|
||
"""
|
||
|
||
# nocheck: file-size curated EDGES data table plus matrix renderers; the data and the renderer read together, splitting them only adds indirection.
|
||
|
||
import re
|
||
|
||
from utils.cache.files import read_text
|
||
from utils.roles.mapping import ROLE_FILE_META_SERVICES
|
||
|
||
from . import PROJECT_ROOT
|
||
|
||
ROLES_DIR = PROJECT_ROOT / "roles"
|
||
REPORT = PROJECT_ROOT / "docs" / "requirements" / "027-integration-matrix.md"
|
||
|
||
FRAMEWORK = {
|
||
"sso": "keycloak",
|
||
"matomo": "matomo",
|
||
"prometheus": "prometheus",
|
||
"email": "mailu",
|
||
"dashboard": "dashboard",
|
||
"design": "design",
|
||
"logout": "logout",
|
||
"cdn": "cdn",
|
||
"coturn": "coturn",
|
||
"collabora": "collabora",
|
||
"onlyoffice": "onlyoffice",
|
||
"libretranslate": "libretranslate",
|
||
"litellm": "litellm",
|
||
}
|
||
|
||
WEB_APP = [
|
||
"akaunting",
|
||
"baserow",
|
||
"bigbluebutton",
|
||
"bluesky",
|
||
"bookwyrm",
|
||
"bridgy-fed",
|
||
"chess",
|
||
"confluence",
|
||
"dashboard",
|
||
"decidim",
|
||
"discourse",
|
||
"erpnext",
|
||
"espocrm",
|
||
"fediwall",
|
||
"fider",
|
||
"flowise",
|
||
"friendica",
|
||
"funkwhale",
|
||
"fusiondirectory",
|
||
"gitea",
|
||
"gitlab",
|
||
"hugo",
|
||
"jenkins",
|
||
"jira",
|
||
"jitsi",
|
||
"joomla",
|
||
"keycloak",
|
||
"kix",
|
||
"lam",
|
||
"listmonk",
|
||
"litellm",
|
||
"littlejs",
|
||
"magento",
|
||
"mailu",
|
||
"mastodon",
|
||
"matomo",
|
||
"matrix",
|
||
"mattermost",
|
||
"mediawiki",
|
||
"mig",
|
||
"minio",
|
||
"mini-qr",
|
||
"mobilizon",
|
||
"moodle",
|
||
"n8n",
|
||
"navigator",
|
||
"nextcloud",
|
||
"odoo",
|
||
"opencloud",
|
||
"openproject",
|
||
"opentalk",
|
||
"openwebui",
|
||
"peertube",
|
||
"pgadmin",
|
||
"phpldapadmin",
|
||
"phpmyadmin",
|
||
"pixelfed",
|
||
"postmarks",
|
||
"pretix",
|
||
"prometheus",
|
||
"roulette-wheel",
|
||
"shopware",
|
||
"snipe-it",
|
||
"socialhome",
|
||
"sphinx",
|
||
"suitecrm",
|
||
"taiga",
|
||
"wordpress",
|
||
"xwiki",
|
||
"yourls",
|
||
"zammad",
|
||
]
|
||
WEB_SVC = [
|
||
"asset",
|
||
"cdn",
|
||
"collabora",
|
||
"coturn",
|
||
"design",
|
||
"file",
|
||
"html",
|
||
"legal",
|
||
"libretranslate",
|
||
"logout",
|
||
"onlyoffice",
|
||
"simpleicons",
|
||
"xmpp",
|
||
]
|
||
ENTITIES = WEB_APP + WEB_SVC
|
||
|
||
EDGES = [
|
||
(
|
||
"nextcloud",
|
||
"openproject",
|
||
"https://github.com/nextcloud/integration_openproject",
|
||
"check",
|
||
),
|
||
("nextcloud", "gitlab", "https://github.com/nextcloud/integration_gitlab", "check"),
|
||
(
|
||
"nextcloud",
|
||
"discourse",
|
||
"https://github.com/nextcloud/integration_discourse",
|
||
"check",
|
||
),
|
||
(
|
||
"nextcloud",
|
||
"mattermost",
|
||
"https://github.com/nextcloud/integration_mattermost",
|
||
"check",
|
||
),
|
||
("nextcloud", "matrix", "https://github.com/nextcloud/integration_matrix", "check"),
|
||
("nextcloud", "jira", "https://github.com/nextcloud/integration_jira", "check"),
|
||
("nextcloud", "zammad", "https://github.com/nextcloud/integration_zammad", "check"),
|
||
(
|
||
"nextcloud",
|
||
"openwebui",
|
||
"https://github.com/nextcloud/integration_openai",
|
||
"check",
|
||
),
|
||
(
|
||
"nextcloud",
|
||
"flowise",
|
||
"https://github.com/nextcloud/integration_openai",
|
||
"check",
|
||
),
|
||
(
|
||
"nextcloud",
|
||
"mastodon",
|
||
"https://github.com/nextcloud/integration_mastodon",
|
||
"check",
|
||
),
|
||
(
|
||
"nextcloud",
|
||
"peertube",
|
||
"https://github.com/nextcloud/integration_peertube",
|
||
"check",
|
||
),
|
||
("nextcloud", "moodle", "https://github.com/nextcloud/integration_moodle", "check"),
|
||
(
|
||
"nextcloud",
|
||
"suitecrm",
|
||
"https://github.com/eneiluj/integration_suitecrm",
|
||
"check",
|
||
),
|
||
("nextcloud", "bigbluebutton", "https://apps.nextcloud.com/apps/bbb", "check"),
|
||
("nextcloud", "xwiki", "https://apps.nextcloud.com/apps/xwiki", "check"),
|
||
("nextcloud", "collabora", "https://github.com/nextcloud/richdocuments", "check"),
|
||
(
|
||
"nextcloud",
|
||
"onlyoffice",
|
||
"https://github.com/ONLYOFFICE/onlyoffice-nextcloud",
|
||
"check",
|
||
),
|
||
("nextcloud", "keycloak", "https://github.com/nextcloud/user_oidc", "check"),
|
||
("nextcloud", "matomo", "https://apps.nextcloud.com/apps/matomo", "check"),
|
||
(
|
||
"mattermost",
|
||
"gitlab",
|
||
"https://github.com/mattermost/mattermost-plugin-gitlab",
|
||
"check",
|
||
),
|
||
(
|
||
"mattermost",
|
||
"jira",
|
||
"https://github.com/mattermost/mattermost-plugin-jira",
|
||
"check",
|
||
),
|
||
(
|
||
"mattermost",
|
||
"jenkins",
|
||
"https://github.com/mattermost/mattermost-plugin-jenkins",
|
||
"check",
|
||
),
|
||
(
|
||
"mattermost",
|
||
"jitsi",
|
||
"https://github.com/mattermost-community/mattermost-plugin-jitsi",
|
||
"check",
|
||
),
|
||
(
|
||
"mattermost",
|
||
"openwebui",
|
||
"https://github.com/mattermost/mattermost-plugin-agents",
|
||
"check",
|
||
),
|
||
(
|
||
"mattermost",
|
||
"prometheus",
|
||
"https://github.com/cpanato/mattermost-plugin-alertmanager",
|
||
"check",
|
||
),
|
||
(
|
||
"mattermost",
|
||
"keycloak",
|
||
"https://docs.mattermost.com/administration-guide/onboard/sso-saml.html",
|
||
"coin",
|
||
),
|
||
(
|
||
"gitlab",
|
||
"mattermost",
|
||
"https://docs.gitlab.com/user/project/integrations/mattermost_notifications/",
|
||
"check",
|
||
),
|
||
("gitlab", "jira", "https://docs.gitlab.com/integration/jira/", "check"),
|
||
("gitlab", "jenkins", "https://docs.gitlab.com/integration/jenkins/", "check"),
|
||
(
|
||
"gitlab",
|
||
"matrix",
|
||
"https://docs.gitlab.com/user/project/integrations/matrix/",
|
||
"check",
|
||
),
|
||
(
|
||
"gitlab",
|
||
"confluence",
|
||
"https://docs.gitlab.com/user/project/integrations/confluence/",
|
||
"check",
|
||
),
|
||
("gitlab", "keycloak", "https://docs.gitlab.com/integration/saml/", "check"),
|
||
(
|
||
"discourse",
|
||
"mattermost",
|
||
"https://github.com/discourse/discourse-chat-integration",
|
||
"check",
|
||
),
|
||
(
|
||
"discourse",
|
||
"matrix",
|
||
"https://github.com/discourse/discourse-chat-integration",
|
||
"check",
|
||
),
|
||
(
|
||
"discourse",
|
||
"prometheus",
|
||
"https://github.com/discourse/discourse-prometheus",
|
||
"check",
|
||
),
|
||
(
|
||
"discourse",
|
||
"bigbluebutton",
|
||
"https://github.com/discourse/discourse-bbb",
|
||
"check",
|
||
),
|
||
("discourse", "jitsi", "https://github.com/discourse/discourse-jitsi", "check"),
|
||
("discourse", "openwebui", "https://github.com/discourse/discourse-ai", "check"),
|
||
(
|
||
"discourse",
|
||
"matomo",
|
||
"https://github.com/discourse/discourse-matomo-analytics",
|
||
"check",
|
||
),
|
||
(
|
||
"discourse",
|
||
"keycloak",
|
||
"https://github.com/discourse/discourse-openid-connect",
|
||
"check",
|
||
),
|
||
(
|
||
"discourse",
|
||
"mastodon",
|
||
"https://github.com/discourse/discourse-activity-pub",
|
||
"check",
|
||
),
|
||
("matrix", "gitlab", "https://github.com/matrix-org/matrix-hookshot", "check"),
|
||
("matrix", "jira", "https://github.com/matrix-org/matrix-hookshot", "check"),
|
||
(
|
||
"matrix",
|
||
"keycloak",
|
||
"https://matrix-org.github.io/synapse/latest/openid.html",
|
||
"check",
|
||
),
|
||
(
|
||
"matrix",
|
||
"prometheus",
|
||
"https://matrix-org.github.io/synapse/latest/metrics-howto.html",
|
||
"check",
|
||
),
|
||
(
|
||
"matrix",
|
||
"jitsi",
|
||
"https://github.com/element-hq/element-web/blob/develop/docs/jitsi.md",
|
||
"check",
|
||
),
|
||
(
|
||
"moodle",
|
||
"bigbluebutton",
|
||
"https://moodle.org/plugins/mod_bigbluebuttonbn",
|
||
"check",
|
||
),
|
||
("moodle", "nextcloud", "https://moodle.org/plugins/repository_owncloud", "check"),
|
||
("moodle", "matrix", "https://docs.moodle.org/en/Matrix", "check"),
|
||
("moodle", "keycloak", "https://moodle.org/plugins/auth_oidc", "check"),
|
||
("moodle", "jitsi", "https://moodle.org/plugins/mod_jitsi", "check"),
|
||
("moodle", "matomo", "https://moodle.org/plugins/tool_webanalytics", "check"),
|
||
("moodle", "openwebui", "https://moodle.org/plugins/aiprovider_openwebui", "check"),
|
||
("jenkins", "gitlab", "https://plugins.jenkins.io/gitlab-plugin", "check"),
|
||
("jenkins", "gitea", "https://plugins.jenkins.io/gitea/", "check"),
|
||
("jenkins", "mattermost", "https://plugins.jenkins.io/mattermost/", "check"),
|
||
("jenkins", "prometheus", "https://plugins.jenkins.io/prometheus", "check"),
|
||
("jenkins", "keycloak", "https://plugins.jenkins.io/oic-auth/", "check"),
|
||
(
|
||
"openproject",
|
||
"nextcloud",
|
||
"https://www.openproject.org/docs/system-admin-guide/integrations/nextcloud/",
|
||
"check",
|
||
),
|
||
(
|
||
"openproject",
|
||
"gitlab",
|
||
"https://www.openproject.org/docs/system-admin-guide/integrations/gitlab-integration/",
|
||
"check",
|
||
),
|
||
(
|
||
"openproject",
|
||
"keycloak",
|
||
"https://www.openproject.org/docs/system-admin-guide/authentication/openid-providers/",
|
||
"coin",
|
||
),
|
||
("wordpress", "matomo", "https://wordpress.org/plugins/matomo/", "check"),
|
||
("wordpress", "mastodon", "https://wordpress.org/plugins/activitypub/", "check"),
|
||
("wordpress", "discourse", "https://wordpress.org/plugins/wp-discourse/", "check"),
|
||
(
|
||
"wordpress",
|
||
"keycloak",
|
||
"https://wordpress.org/plugins/daggerhart-openid-connect-generic/",
|
||
"check",
|
||
),
|
||
(
|
||
"wordpress",
|
||
"listmonk",
|
||
"https://wordpress.org/plugins/integration-for-listmonk-mailing-list-and-newsletter-manager/",
|
||
"check",
|
||
),
|
||
(
|
||
"wordpress",
|
||
"bigbluebutton",
|
||
"https://wordpress.org/plugins/video-conferencing-with-bbb/",
|
||
"check",
|
||
),
|
||
(
|
||
"wordpress",
|
||
"peertube",
|
||
"https://wordpress.org/plugins/video-manager-for-peertube/",
|
||
"check",
|
||
),
|
||
(
|
||
"mediawiki",
|
||
"keycloak",
|
||
"https://www.mediawiki.org/wiki/Extension:OpenID_Connect",
|
||
"check",
|
||
),
|
||
("mediawiki", "matomo", "https://www.mediawiki.org/wiki/Extension:Matomo", "check"),
|
||
(
|
||
"mediawiki",
|
||
"discourse",
|
||
"https://www.mediawiki.org/wiki/Extension:DiscourseSsoConsumer",
|
||
"check",
|
||
),
|
||
(
|
||
"mediawiki",
|
||
"peertube",
|
||
"https://www.mediawiki.org/wiki/Extension:PeerTubeEmbed",
|
||
"check",
|
||
),
|
||
(
|
||
"mediawiki",
|
||
"libretranslate",
|
||
"https://www.mediawiki.org/wiki/Extension:MachineTranslation",
|
||
"check",
|
||
),
|
||
("mediawiki", "minio", "https://www.mediawiki.org/wiki/Extension:AWS", "check"),
|
||
(
|
||
"mediawiki",
|
||
"openwebui",
|
||
"https://www.mediawiki.org/wiki/Extension:AIEditingAssistant",
|
||
"check",
|
||
),
|
||
(
|
||
"xwiki",
|
||
"keycloak",
|
||
"https://extensions.xwiki.org/xwiki/bin/view/Extension/OpenID%20Connect/",
|
||
"check",
|
||
),
|
||
(
|
||
"xwiki",
|
||
"matomo",
|
||
"https://extensions.xwiki.org/xwiki/bin/view/Extension/Piwiki%20Integration",
|
||
"check",
|
||
),
|
||
(
|
||
"joomla",
|
||
"keycloak",
|
||
"../../roles/web-app-joomla/files/joomla-oidc-plugin/",
|
||
"check",
|
||
),
|
||
(
|
||
"joomla",
|
||
"matomo",
|
||
"https://extensions.joomla.org/extension/itcs-matomo/",
|
||
"check",
|
||
),
|
||
("friendica", "matomo", "https://github.com/friendica/friendica-addons", "check"),
|
||
(
|
||
"pretix",
|
||
"keycloak",
|
||
"https://docs.pretix.eu/en/latest/admin/installation/index.html",
|
||
"check",
|
||
),
|
||
(
|
||
"peertube",
|
||
"keycloak",
|
||
"https://www.npmjs.com/package/peertube-plugin-auth-openid-connect",
|
||
"check",
|
||
),
|
||
(
|
||
"bigbluebutton",
|
||
"keycloak",
|
||
"https://docs.bigbluebutton.org/greenlight/v3/external-authentication/",
|
||
"check",
|
||
),
|
||
(
|
||
"zammad",
|
||
"keycloak",
|
||
"https://admin-docs.zammad.org/en/latest/settings/security/third-party/saml.html",
|
||
"check",
|
||
),
|
||
(
|
||
"zammad",
|
||
"mailu",
|
||
"https://admin-docs.zammad.org/en/latest/channels/email/index.html",
|
||
"check",
|
||
),
|
||
("espocrm", "keycloak", "https://docs.espocrm.com/administration/oidc/", "check"),
|
||
(
|
||
"espocrm",
|
||
"mailu",
|
||
"https://docs.espocrm.com/user-guide/imap-smtp-configuration/",
|
||
"check",
|
||
),
|
||
(
|
||
"suitecrm",
|
||
"keycloak",
|
||
"https://docs.suitecrm.com/8.x/admin/configuration/saml/8.7.0-saml-configuration/",
|
||
"check",
|
||
),
|
||
(
|
||
"suitecrm",
|
||
"mailu",
|
||
"https://github.com/SuiteCRM/SuiteCRM",
|
||
"check",
|
||
),
|
||
(
|
||
"odoo",
|
||
"keycloak",
|
||
"https://github.com/OCA/server-auth/tree/16.0/auth_oidc",
|
||
"check",
|
||
),
|
||
(
|
||
"odoo",
|
||
"mailu",
|
||
"https://www.odoo.com/documentation/latest/applications/general/email_communication.html",
|
||
"check",
|
||
),
|
||
(
|
||
"odoo",
|
||
"nextcloud",
|
||
"https://apps.odoo.com/apps/modules/19.0/nextcloud_odoo_integration",
|
||
"coin",
|
||
),
|
||
(
|
||
"erpnext",
|
||
"keycloak",
|
||
"https://docs.frappe.io/framework/user/en/guides/integration/openid_connect_and_frappe_social_login",
|
||
"check",
|
||
),
|
||
(
|
||
"erpnext",
|
||
"mailu",
|
||
"https://docs.frappe.io/erpnext/user/manual/en/setting-up-email-account",
|
||
"check",
|
||
),
|
||
(
|
||
"baserow",
|
||
"keycloak",
|
||
"https://baserow.io/user-docs/configure-openid-connect-for-oauth-2-sso",
|
||
"coin",
|
||
),
|
||
(
|
||
"taiga",
|
||
"keycloak",
|
||
"https://github.com/taigaio/taiga-contrib-oidc-auth",
|
||
"check",
|
||
),
|
||
]
|
||
|
||
CHECK = "✅"
|
||
WIRED = "☑️"
|
||
COIN = "🪙"
|
||
CROSS = "❌"
|
||
DASH = "—"
|
||
|
||
|
||
def scan_framework_edges():
|
||
"""Derive infinito-native integration edges from each role's meta/services.yml."""
|
||
edges = []
|
||
for prefix in ("web-app-", "web-svc-"):
|
||
for path in sorted(ROLES_DIR.glob(f"{prefix}*/{ROLE_FILE_META_SERVICES}")):
|
||
role = path.parent.parent.name
|
||
entity = role[len(prefix) :]
|
||
lines = read_text(str(path)).splitlines()
|
||
if not lines:
|
||
continue
|
||
seen = set()
|
||
for line in lines:
|
||
m = re.match(r"^([a-z0-9_]+):", line)
|
||
if not m:
|
||
continue
|
||
key = m.group(1)
|
||
target = FRAMEWORK.get(key)
|
||
if target and target != entity and target not in seen:
|
||
seen.add(target)
|
||
rel = f"../../roles/{role}/{ROLE_FILE_META_SERVICES}"
|
||
edges.append((entity, target, rel, "wired"))
|
||
return edges
|
||
|
||
|
||
def build():
|
||
by_pair = {(s, d): (url, kind) for (s, d, url, kind) in scan_framework_edges()}
|
||
by_pair.update({(s, d): (url, kind) for (s, d, url, kind) in EDGES})
|
||
corner = "↓ row wires → col"
|
||
|
||
def render_row(label, cells):
|
||
out = [label]
|
||
for j, cell in enumerate(cells):
|
||
out.append(cell)
|
||
if (j + 1) % 10 == 0 and (j + 1) < len(cells):
|
||
out.append(label)
|
||
return "| " + " | ".join(out) + " |"
|
||
|
||
header = render_row(corner, ENTITIES)
|
||
ncols = header.count("|") - 1
|
||
sep = "|" + "---|" * ncols
|
||
rows = [header, sep]
|
||
for i, src in enumerate(ENTITIES):
|
||
cells = []
|
||
for dst in ENTITIES:
|
||
if src == dst:
|
||
cells.append(DASH)
|
||
elif (src, dst) in by_pair:
|
||
url, kind = by_pair[(src, dst)]
|
||
sym = {"coin": COIN, "wired": WIRED}.get(kind, CHECK)
|
||
cells.append(f"[{sym}]({url})")
|
||
else:
|
||
cells.append(CROSS)
|
||
rows.append(render_row(f"**{src}**", cells))
|
||
if (i + 1) % 10 == 0 and (i + 1) < len(ENTITIES):
|
||
rows.append(header)
|
||
return "\n".join(rows)
|
||
|
||
|
||
HEADER = """# 027 - Integration Matrix
|
||
|
||
> Generated by `make integration-matrix`. Do not edit by hand, edit the generator's `EDGES` map and re-run.
|
||
|
||
Companion artifact for [026-unified-addon-syntax.md](026-unified-addon-syntax.md).
|
||
Axes are the **entity names** of every `web-app-*` and `web-svc-*` role.
|
||
A cell marks whether the **row** role ships an addon/plugin that wires in the **column** role.
|
||
|
||
## Legend
|
||
|
||
| Symbol | Meaning |
|
||
|---|---|
|
||
| {wired} | Already wired via an infinito-native service flag in the row role's `meta/services.yml` (group-gated). Links to that declaration. |
|
||
| {check} | A verified upstream app↔app plugin exists but is not yet declared as an addon. Links to the plugin page. This is the backlog. |
|
||
| {coin} | Integration exists but is gated behind a commercial / paid tier. |
|
||
| {cross} | No known integration to wire these two. |
|
||
| {dash} | Same role (diagonal). |
|
||
|
||
Notes:
|
||
|
||
- The matrix is **directional**: the row hosts the plugin/flag. Bidirectional pairs (e.g. `nextcloud`↔`openproject`) carry a symbol in both cells, each linking to that side.
|
||
- {wired} edges are derived automatically by scanning every role's `meta/services.yml` for integration service keys (`sso`→keycloak, `matomo`→matomo, `prometheus`→prometheus, `email`→mailu, `dashboard`, `css`, `logout`, `cdn`, `coturn`, `collabora`, `onlyoffice`, `libretranslate`, `litellm`). `ldap`/`redis`/`mariadb` map to `svc-db-*` roles that are off these axes and are not shown. The `litellm` column is the AI gateway surface of [036](036-native-ai-gateway-integration.md): the service key resolves to `svc-ai-litellm`, which is off-axis, so the edge is drawn to the `litellm` entity that fronts it.
|
||
- `→ keycloak` {wired} cells are the central `sso` service; a {check}/{coin} on `→ keycloak` instead means a role-local OIDC/SAML addon path beyond the central service.
|
||
- Native ActivityPub federation between fediverse roles (`mastodon`, `peertube`, `pixelfed`, `funkwhale`, `mobilizon`, `bookwyrm`, `socialhome`) needs **no plugin** and is therefore not a {check} edge unless an installable connector exists.
|
||
|
||
## Matrix
|
||
|
||
{matrix}
|
||
|
||
## Maintenance
|
||
|
||
- [ ] Regenerate this matrix after adding or removing any integration edge.
|
||
"""
|
||
|
||
|
||
def main():
|
||
fw = scan_framework_edges()
|
||
out = HEADER.format(
|
||
check=CHECK, wired=WIRED, coin=COIN, cross=CROSS, dash=DASH, matrix=build()
|
||
)
|
||
path = REPORT
|
||
path.write_text(out, encoding="utf-8")
|
||
print(
|
||
f"wrote {path} ({len(ENTITIES)}x{len(ENTITIES)} matrix, "
|
||
f"{len(fw)} wired + {len(EDGES)} upstream edges)"
|
||
)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|