diff --git a/.github/workflows/oss-discoverability-drift.yml b/.github/workflows/oss-discoverability-drift.yml index 833d4f7..9df9ea5 100644 --- a/.github/workflows/oss-discoverability-drift.yml +++ b/.github/workflows/oss-discoverability-drift.yml @@ -10,6 +10,7 @@ on: - 'brand/seo-metadata.json' - 'brand/update-topics.sh' - 'brand/apply-seo-metadata.sh' + - 'brand/check-catalog-coverage.sh' - '.github/workflows/oss-discoverability-drift.yml' push: branches: [main] @@ -18,6 +19,7 @@ on: - 'brand/seo-metadata.json' - 'brand/update-topics.sh' - 'brand/apply-seo-metadata.sh' + - 'brand/check-catalog-coverage.sh' - '.github/workflows/oss-discoverability-drift.yml' schedule: # Weekly: catch drift from GitHub Settings edits outside the catalog. @@ -37,6 +39,12 @@ jobs: steps: - uses: actions/checkout@v7 + - name: Verify every public repo is in the catalogs + working-directory: brand + env: + GH_TOKEN: ${{ github.token }} + run: ./check-catalog-coverage.sh + - name: Verify topics catalog matches GitHub working-directory: brand env: diff --git a/brand/README.md b/brand/README.md index 86c44b6..9d0cf6d 100644 --- a/brand/README.md +++ b/brand/README.md @@ -104,7 +104,17 @@ See also [distribution.md](distribution.md) for npm, PyPI, and GHCR publish targ ### CI drift gate -Workflow [`.github/workflows/oss-discoverability-drift.yml`](../.github/workflows/oss-discoverability-drift.yml) runs on PRs that touch the catalogs, on merges to `main`, weekly (Mondays 14:00 UTC), and on demand. It fails if live GitHub topics or About metadata differ from `topics.json` / `seo-metadata.json`. +Workflow [`.github/workflows/oss-discoverability-drift.yml`](../.github/workflows/oss-discoverability-drift.yml) runs on PRs that touch the catalogs, on merges to `main`, weekly (Mondays 14:00 UTC), and on demand. It fails if: + +1. A public non-archived org repo is **missing** from `topics.json` or `seo-metadata.json` (reverse coverage; see #17). +2. Live GitHub topics or About metadata differ from the catalog rows that do exist. + +```bash +cd brand +./check-catalog-coverage.sh # every public repo has catalog rows +./update-topics.sh --check +./apply-seo-metadata.sh --check +``` After editing a catalog, apply live state before merge: diff --git a/brand/check-catalog-coverage.sh b/brand/check-catalog-coverage.sh new file mode 100755 index 0000000..0d2710e --- /dev/null +++ b/brand/check-catalog-coverage.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +# Fail when a public non-archived skyphusion-labs repo is missing from the +# discoverability catalogs (topics.json / seo-metadata.json). +# +# The existing --check scripts only iterate catalog rows, so a brand-new +# public repo that never got a catalog entry would otherwise pass green. +# See skyphusion-labs/.github#17. +# +# Requires: gh (authenticated), jq +# +# Usage: +# ./check-catalog-coverage.sh +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +TOPICS="${SCRIPT_DIR}/topics.json" +SEO="${SCRIPT_DIR}/seo-metadata.json" +OWNER="${CATALOG_OWNER:-skyphusion-labs}" + +for cmd in gh jq; do + if ! command -v "$cmd" >/dev/null 2>&1; then + echo "Missing required command: $cmd" >&2 + exit 1 + fi +done + +for f in "$TOPICS" "$SEO"; do + if [[ ! -f "$f" ]]; then + echo "Catalog not found: $f" >&2 + exit 1 + fi +done + +# Public, non-archived repos under the org (name only). +mapfile -t public_repos < <( + gh repo list "$OWNER" --visibility public --limit 200 --json name,isArchived \ + --jq '.[] | select(.isArchived | not) | .name' | sort -u +) + +if [[ "${#public_repos[@]}" -eq 0 ]]; then + echo "No public repos returned for ${OWNER}; refusing to pass vacuously." >&2 + exit 1 +fi + +topics_repos="$(jq -r --arg o "$OWNER" '[.[] | select(.owner == $o) | .repo] | unique | .[]' "$TOPICS" | sort -u)" +seo_repos="$(jq -r --arg o "$OWNER" '[.[] | select(.owner == $o) | .repo] | unique | .[]' "$SEO" | sort -u)" + +missing_topics=() +missing_seo=() +for repo in "${public_repos[@]}"; do + if ! grep -Fxq "$repo" <<<"$topics_repos"; then + missing_topics+=("$repo") + fi + if ! grep -Fxq "$repo" <<<"$seo_repos"; then + missing_seo+=("$repo") + fi +done + +fail=0 +if [[ "${#missing_topics[@]}" -gt 0 ]]; then + fail=1 + echo "Public repos missing from brand/topics.json:" >&2 + printf ' %s\n' "${missing_topics[@]}" >&2 +fi +if [[ "${#missing_seo[@]}" -gt 0 ]]; then + fail=1 + echo "Public repos missing from brand/seo-metadata.json:" >&2 + printf ' %s\n' "${missing_seo[@]}" >&2 +fi + +if [[ "$fail" -ne 0 ]]; then + echo "Reverse-coverage check failed. Add catalog rows for each missing public repo (see brand/README.md)." >&2 + exit 1 +fi + +echo "All ${#public_repos[@]} public non-archived ${OWNER} repo(s) are present in topics.json and seo-metadata.json." diff --git a/brand/seo-metadata.json b/brand/seo-metadata.json index b339d29..a6c8d10 100644 --- a/brand/seo-metadata.json +++ b/brand/seo-metadata.json @@ -7,75 +7,75 @@ }, { "owner": "skyphusion-labs", - "repo": "vivijure", - "description": "The Vivijure constellation map: self-hosted AGPL AI film studio. Control panel on Cloudflare (vivijure-cf) or home/cloud server (vivijure-local); shared via vivijure-core.", - "homepage": "https://vivijure.com" + "repo": "SidVicious_exe", + "description": "Punk-rock Discord roadie: Claude, web search, Vectorize knowledge base, and Workers AI image generation.", + "homepage": "https://github.com/skyphusion-labs/SidVicious_exe" }, { "owner": "skyphusion-labs", - "repo": "vivijure-cf", - "description": "Vivijure Studio Cloudflare control panel: Workers host for storyboard, cast, modules, and render orchestration. Builds on vivijure-core; pairs with vivijure-local.", - "homepage": "https://vivijure.com" + "repo": "common-thread", + "description": "Sockpuppet attribution methodology and reference implementation for litigants, journalists, and OSINT practitioners.", + "homepage": "https://common-thread.skyphusion.org" }, { "owner": "skyphusion-labs", - "repo": "vivijure-local", - "description": "Vivijure Local: run the film studio control panel on a home computer or any cloud server (Node, SQLite, S3/MinIO). No Cloudflare required. Shares vivijure-core with vivijure-cf.", - "homepage": "https://vivijure.com" + "repo": "crew-bus", + "description": "Cross-crew MCP message bus for coordinating multiple agent runtimes (Cursor and Claude Code). AGPL.", + "homepage": "https://github.com/skyphusion-labs/crew-bus" }, { "owner": "skyphusion-labs", - "repo": "vivijure-core", - "description": "Vivijure Core: shared orchestration unifying vivijure-cf and vivijure-local (module registry, film pipeline, Platform ICD).", - "homepage": "https://vivijure.com" + "repo": "hollow-grid-go", + "description": "Go world-server port for The Hollow Grid federated MUD: a Grid node speaking the language-agnostic wire protocol.", + "homepage": "https://hollow.skyphusion.org" }, { "owner": "skyphusion-labs", - "repo": "vivijure-mcp", - "description": "Vivijure Studio MCP: drive the film studio API from an agent. Works with both vivijure-cf and vivijure-local.", - "homepage": "https://vivijure.com" + "repo": "hollow-grid-py", + "description": "Python world-server port for The Hollow Grid federated MUD: a Grid node speaking the language-agnostic wire protocol.", + "homepage": "" }, { "owner": "skyphusion-labs", - "repo": "vivijure-backend", - "description": "RunPod GPU render engine for Vivijure: SDXL keyframes, Wan image-to-video, LoRA training, ffmpeg assembly. Pairs with vivijure-cf or vivijure-local.", - "homepage": "https://vivijure.com" + "repo": "mud-bots", + "description": "AI players for The Hollow Grid: LLM bots on Workers AI that make real moral choices via structured game state.", + "homepage": "https://hollow.skyphusion.org" }, { "owner": "skyphusion-labs", - "repo": "vivijure-com", - "description": "Product site and showcase for Vivijure: the self-hosted AGPL AI film studio. Control panel on Cloudflare or any server.", - "homepage": "https://vivijure.com" + "repo": "postern", + "description": "Self-hostable email for humans and agents on Cloudflare: send, receive, search, MCP, IMAP, and webmail.", + "homepage": "https://github.com/skyphusion-labs/postern" }, { "owner": "skyphusion-labs", - "repo": "vivijure-local-12gb", - "description": "Consumer-GPU Vivijure backend: LTX-Video i2v on a 12GB card. Homelab motion for vivijure-cf or vivijure-local. AGPL.", - "homepage": "https://vivijure.com" + "repo": "prism", + "description": "Multimodal AI playground in one Cloudflare Worker: 35 chat models, voice chat, image/video/music, RAG, and web search.", + "homepage": "https://play.skyphusion.org" }, { "owner": "skyphusion-labs", - "repo": "vivijure-local-16gb", - "description": "Higher-fidelity consumer-GPU Vivijure backend: CogVideoX-5B-I2V on a 16GB card. Works with vivijure-cf or vivijure-local. AGPL.", - "homepage": "https://vivijure.com" + "repo": "search-mcp", + "description": "Cloudflare AI Search toolkit: MCP server, streaming /ask Worker, docs widget, and git-to-R2 corpus sync. AGPL.", + "homepage": "https://github.com/skyphusion-labs/search-mcp" }, { "owner": "skyphusion-labs", - "repo": "vivijure-musetalk", - "description": "MuseTalk lip-sync finish engine for Vivijure on RunPod GPU. Pairs with vivijure-cf or vivijure-local.", - "homepage": "https://vivijure.com" + "repo": "skyphusion-monitor", + "description": "External security-posture and uptime monitor (Cloudflare Worker cron). Probes public surfaces; alerts to ntfy.", + "homepage": "https://github.com/skyphusion-labs/skyphusion-monitor" }, { "owner": "skyphusion-labs", - "repo": "vivijure-upscale", - "description": "Real-ESRGAN CUDA video upscale finish module for Vivijure on RunPod. Pairs with vivijure-cf or vivijure-local.", - "homepage": "https://vivijure.com" + "repo": "skyphusion-net", + "description": "Engineering blog of Conrad Rockenhaus (Skyphusion): Astro 7 on Cloudflare Workers, markdown-authored.", + "homepage": "https://skyphusion.net" }, { "owner": "skyphusion-labs", - "repo": "vivijure-audio-upscale", - "description": "GPU speech enhancement finish engine for Vivijure (resemble-enhance on RunPod). Pairs with vivijure-cf or vivijure-local.", - "homepage": "https://vivijure.com" + "repo": "skyphusion-org", + "description": "skyphusion.org: Skyphusion Labs intro site. Open-source tools you own, including Vivijure (Cloudflare or self-hosted control panel).", + "homepage": "https://skyphusion.org" }, { "owner": "skyphusion-labs", @@ -85,74 +85,80 @@ }, { "owner": "skyphusion-labs", - "repo": "prism", - "description": "Multimodal AI playground in one Cloudflare Worker: 35 chat models, voice chat, image/video/music, RAG, and web search.", - "homepage": "https://play.skyphusion.org" + "repo": "the-hollow-grid", + "description": "Federated post-apocalyptic MUD on Cloudflare Workers and Durable Objects. Play free at hollow and dustfall.", + "homepage": "https://hollow.skyphusion.org" }, { "owner": "skyphusion-labs", - "repo": "postern", - "description": "Self-hostable email for humans and agents on Cloudflare: send, receive, search, MCP, IMAP, and webmail.", - "homepage": "https://github.com/skyphusion-labs/postern" + "repo": "vivijure", + "description": "The Vivijure constellation map: self-hosted AGPL AI film studio. Control panel on Cloudflare (vivijure-cf) or home/cloud server (vivijure-local); shared via vivijure-core.", + "homepage": "https://vivijure.com" }, { "owner": "skyphusion-labs", - "repo": "search-mcp", - "description": "Cloudflare AI Search toolkit: MCP server, streaming /ask Worker, docs widget, and git-to-R2 corpus sync. AGPL.", - "homepage": "https://github.com/skyphusion-labs/search-mcp" + "repo": "vivijure-audio-upscale", + "description": "GPU speech enhancement finish engine for Vivijure (resemble-enhance on RunPod). Pairs with vivijure-cf or vivijure-local.", + "homepage": "https://vivijure.com" }, { "owner": "skyphusion-labs", - "repo": "the-hollow-grid", - "description": "Federated post-apocalyptic MUD on Cloudflare Workers and Durable Objects. Play free at hollow and dustfall.", - "homepage": "https://hollow.skyphusion.org" + "repo": "vivijure-backend", + "description": "RunPod GPU render engine for Vivijure: SDXL keyframes, Wan image-to-video, LoRA training, ffmpeg assembly. Pairs with vivijure-cf or vivijure-local.", + "homepage": "https://vivijure.com" }, { "owner": "skyphusion-labs", - "repo": "mud-bots", - "description": "AI players for The Hollow Grid: LLM bots on Workers AI that make real moral choices via structured game state.", - "homepage": "https://hollow.skyphusion.org" + "repo": "vivijure-cf", + "description": "Vivijure Studio Cloudflare control panel: Workers host for storyboard, cast, modules, and render orchestration. Builds on vivijure-core; pairs with vivijure-local.", + "homepage": "https://vivijure.com" }, { "owner": "skyphusion-labs", - "repo": "hollow-grid-go", - "description": "Go world-server port for The Hollow Grid federated MUD: a Grid node speaking the language-agnostic wire protocol.", - "homepage": "https://hollow.skyphusion.org" + "repo": "vivijure-com", + "description": "Product site and showcase for Vivijure: the self-hosted AGPL AI film studio. Control panel on Cloudflare or any server.", + "homepage": "https://vivijure.com" }, { "owner": "skyphusion-labs", - "repo": "common-thread", - "description": "Sockpuppet attribution methodology and reference implementation for litigants, journalists, and OSINT practitioners.", - "homepage": "https://common-thread.skyphusion.org" + "repo": "vivijure-core", + "description": "Vivijure Core: shared orchestration unifying vivijure-cf and vivijure-local (module registry, film pipeline, Platform ICD).", + "homepage": "https://vivijure.com" }, { "owner": "skyphusion-labs", - "repo": "SidVicious_exe", - "description": "Punk-rock Discord roadie: Claude, web search, Vectorize knowledge base, and Workers AI image generation.", - "homepage": "https://github.com/skyphusion-labs/SidVicious_exe" + "repo": "vivijure-local", + "description": "Vivijure Local: run the film studio control panel on a home computer or any cloud server (Node, SQLite, S3/MinIO). No Cloudflare required. Shares vivijure-core with vivijure-cf.", + "homepage": "https://vivijure.com" }, { "owner": "skyphusion-labs", - "repo": "skyphusion-net", - "description": "Engineering blog of Conrad Rockenhaus (Skyphusion): Astro 7 on Cloudflare Workers, markdown-authored.", - "homepage": "https://skyphusion.net" + "repo": "vivijure-local-12gb", + "description": "Consumer-GPU Vivijure backend: LTX-Video i2v on a 12GB card. Homelab motion for vivijure-cf or vivijure-local. AGPL.", + "homepage": "https://vivijure.com" }, { "owner": "skyphusion-labs", - "repo": "skyphusion-org", - "description": "skyphusion.org: Skyphusion Labs intro site. Open-source tools you own, including Vivijure (Cloudflare or self-hosted control panel).", - "homepage": "https://skyphusion.org" + "repo": "vivijure-local-16gb", + "description": "Higher-fidelity consumer-GPU Vivijure backend: CogVideoX-5B-I2V on a 16GB card. Works with vivijure-cf or vivijure-local. AGPL.", + "homepage": "https://vivijure.com" }, { "owner": "skyphusion-labs", - "repo": "skyphusion-monitor", - "description": "External security-posture and uptime monitor (Cloudflare Worker cron). Probes public surfaces; alerts to ntfy.", - "homepage": "https://github.com/skyphusion-labs/skyphusion-monitor" + "repo": "vivijure-mcp", + "description": "Vivijure Studio MCP: drive the film studio API from an agent. Works with both vivijure-cf and vivijure-local.", + "homepage": "https://vivijure.com" }, { "owner": "skyphusion-labs", - "repo": "crew-bus", - "description": "Cross-crew MCP message bus for coordinating multiple agent runtimes (Cursor and Claude Code). AGPL.", - "homepage": "https://github.com/skyphusion-labs/crew-bus" + "repo": "vivijure-musetalk", + "description": "MuseTalk lip-sync finish engine for Vivijure on RunPod GPU. Pairs with vivijure-cf or vivijure-local.", + "homepage": "https://vivijure.com" + }, + { + "owner": "skyphusion-labs", + "repo": "vivijure-upscale", + "description": "Real-ESRGAN CUDA video upscale finish module for Vivijure on RunPod. Pairs with vivijure-cf or vivijure-local.", + "homepage": "https://vivijure.com" } ] diff --git a/brand/topics.json b/brand/topics.json index 579e511..54853c2 100644 --- a/brand/topics.json +++ b/brand/topics.json @@ -59,6 +59,27 @@ "typescript" ] }, + { + "owner": "skyphusion-labs", + "repo": "crew-bus", + "family": "infra", + "topics": [ + "agent-coordination", + "agents", + "agpl", + "claude-code", + "cloudflare-workers", + "crew-bus", + "cursor", + "d1", + "mcp", + "message-bus", + "model-context-protocol", + "open-source", + "self-hosted", + "typescript" + ] + }, { "owner": "skyphusion-labs", "repo": "hollow-grid-go", @@ -79,6 +100,26 @@ "websocket" ] }, + { + "owner": "skyphusion-labs", + "repo": "hollow-grid-py", + "family": "hollow-grid", + "topics": [ + "agents", + "docker", + "federated", + "game-server", + "hollow-grid", + "mud", + "multiplayer", + "open-source", + "python", + "self-hosted", + "text-game", + "the-hollow-grid", + "websocket" + ] + }, { "owner": "skyphusion-labs", "repo": "mud-bots", @@ -309,6 +350,54 @@ "vivijure-studio" ] }, + { + "owner": "skyphusion-labs", + "repo": "vivijure-audio-upscale", + "family": "vivijure", + "topics": [ + "agpl", + "ai-video", + "audio", + "audio-enhancement", + "cuda", + "docker", + "finish-engine", + "gpu", + "python", + "resemble-enhance", + "runpod", + "self-hosted", + "serverless", + "speech-denoising", + "speech-enhancement", + "vivijure", + "vivijure-module" + ] + }, + { + "owner": "skyphusion-labs", + "repo": "vivijure-backend", + "family": "vivijure", + "topics": [ + "agpl", + "ai-filmmaking", + "ai-video", + "docker", + "ffmpeg", + "generative-ai", + "gpu", + "image-to-video", + "keyframes", + "python", + "runpod", + "sdxl", + "serverless", + "stable-diffusion", + "video-generation", + "vivijure", + "wan" + ] + }, { "owner": "skyphusion-labs", "repo": "vivijure-cf", @@ -335,27 +424,28 @@ }, { "owner": "skyphusion-labs", - "repo": "vivijure-local", + "repo": "vivijure-com", "family": "vivijure", "topics": [ "agpl", "ai-film", "ai-video", - "control-plane", - "docker", - "docker-compose", + "cloudflare-workers", "filmmaking", "generative-ai", "homelab", - "module-host", - "nodejs", + "landing-page", + "open-source", + "portfolio", + "promotional-site", "self-hosted", - "sqlite", - "storyboard", + "serverless", + "showcase", + "static-site", "typescript", + "vanilla-js", "video-generation", - "vivijure", - "vivijure-studio" + "vivijure" ] }, { @@ -380,95 +470,27 @@ }, { "owner": "skyphusion-labs", - "repo": "vivijure-mcp", + "repo": "vivijure-local", "family": "vivijure", "topics": [ - "agents", "agpl", - "ai-agents", "ai-film", - "cloudflare-workers", - "mcp", - "model-context-protocol", - "self-hosted", - "typescript", - "video-generation", - "vivijure", - "vivijure-studio" - ] - }, - { - "owner": "skyphusion-labs", - "repo": "vivijure-audio-upscale", - "family": "vivijure", - "topics": [ - "agpl", - "ai-video", - "audio", - "audio-enhancement", - "cuda", - "docker", - "finish-engine", - "gpu", - "python", - "resemble-enhance", - "runpod", - "self-hosted", - "serverless", - "speech-denoising", - "speech-enhancement", - "vivijure", - "vivijure-module" - ] - }, - { - "owner": "skyphusion-labs", - "repo": "vivijure-backend", - "family": "vivijure", - "topics": [ - "agpl", - "ai-filmmaking", "ai-video", + "control-plane", "docker", - "ffmpeg", - "generative-ai", - "gpu", - "image-to-video", - "keyframes", - "python", - "runpod", - "sdxl", - "serverless", - "stable-diffusion", - "video-generation", - "vivijure", - "wan" - ] - }, - { - "owner": "skyphusion-labs", - "repo": "vivijure-com", - "family": "vivijure", - "topics": [ - "agpl", - "ai-film", - "ai-video", - "cloudflare-workers", + "docker-compose", "filmmaking", "generative-ai", "homelab", - "landing-page", - "open-source", - "portfolio", - "promotional-site", + "module-host", + "nodejs", "self-hosted", - "serverless", - "showcase", - "static-site", + "sqlite", + "storyboard", "typescript", - "vanilla-js", "video-generation", - "vivijure" + "vivijure", + "vivijure-studio" ] }, { @@ -525,6 +547,25 @@ "vivijure-module" ] }, + { + "owner": "skyphusion-labs", + "repo": "vivijure-mcp", + "family": "vivijure", + "topics": [ + "agents", + "agpl", + "ai-agents", + "ai-film", + "cloudflare-workers", + "mcp", + "model-context-protocol", + "self-hosted", + "typescript", + "video-generation", + "vivijure", + "vivijure-studio" + ] + }, { "owner": "skyphusion-labs", "repo": "vivijure-musetalk", @@ -573,26 +614,5 @@ "vivijure", "vivijure-module" ] - }, - { - "owner": "skyphusion-labs", - "repo": "crew-bus", - "family": "infra", - "topics": [ - "agent-coordination", - "agents", - "agpl", - "claude-code", - "cloudflare-workers", - "crew-bus", - "cursor", - "d1", - "mcp", - "message-bus", - "model-context-protocol", - "open-source", - "self-hosted", - "typescript" - ] } ]