diff --git a/AGENTS.md b/AGENTS.md index a71573b8..b669f268 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,42 +1,23 @@ # Bluefin Documentation — Agent Instructions -**Repository:** `castrojo/documentation` (fork of `projectbluefin/documentation`) -**Deployed at:** -**Local path:** `/var/home/jorge/src/documentation` +**Deployed at:** https://docs.projectbluefin.io/ **Framework:** Docusaurus 3.10.x (TypeScript), React 19, Node 24 ---- - ## Quick Start ```bash -# Install dependencies npm install - -# Start dev server (fetches data automatically, hot-reload) -npm run start - -# Full production build -npm run build - -# Type check -npm run typecheck - -# Lint -npm run lint +npm run start # dev server at http://localhost:3000/ (fetches data, hot-reload) +npm run build # full production build +npm run typecheck # TypeScript check +npm run lint # ESLint ``` -Dev server: - ---- - ## Git Workflow -**Never push directly to main.** Always work on a topic branch: - +**Never push directly to main.** Work on a topic branch: ```bash git checkout -b / -git add git commit -m "type(scope): description" git push -u origin / # Then open a PR — do not merge @@ -44,350 +25,36 @@ git push -u origin / Types: `feat`, `fix`, `docs`, `refactor`, `perf`, `ci`, `chore` -AI agent attribution (required in every commit footer — exactly ONE trailer, no Co-authored-by): +### Attribution footer (required in every commit) ``` -Assisted-by: Claude Sonnet 4.6 via GitHub Copilot +Assisted-by: [Model] via [Tool] ``` -**Fork sync:** This is a fork of `projectbluefin/documentation`. Keep in sync: - -```bash -git fetch upstream -git checkout main -git reset --hard upstream/main -git push origin main --force-with-lease -``` - ---- - -## Validation Gates (all required before committing) +## Validation Gates | Check | Command | Blocking? | |---|---|---| | TypeScript | `npm run typecheck` | YES | | ESLint | `npm run lint` | YES | -| Prettier | `npm run prettier-lint` | No (warnings only in CI) | +| Prettier | `npm run prettier-lint` | No (warnings only) | | Build | `npm run build` | YES | -CI enforces TypeScript and ESLint as hard failures. Prettier is warnings-only. - ---- - -## Repository Structure - -``` -docs/ # User documentation (Markdown/MDX) -blog/ # Blog posts with frontmatter + authors.yaml -reports/ # Monthly auto-generated report MDX posts -src/ - components/ # React components (see Components section) - config/ # packageConfig.ts — centralized package tracking - pages/ # Custom Docusaurus pages - changelogs.tsx # /changelogs page — only custom page, all others are docs/ MDX - types/ # TypeScript type definitions - sbom.ts # SBOM attestation types - sbom-attestations.d.ts # Ambient module declaration (allows missing file at tsc time) - data.d.ts # General data types - theme.d.ts # Docusaurus theme type augmentations - css/ # custom.css - theme/ # Swizzled Docusaurus components - DocItem/Footer/ # Adds PageContributors to every doc page -scripts/ # Data-fetch and utility scripts (see Data Pipeline section) - lib/ # Shared library modules for generate-report -static/ - data/ # Auto-generated JSON (gitignored — except sbom-attestations.json and sbom-attestations-frontend.json) - feeds/ # Auto-generated release feeds (gitignored) - img/ # Static images -.github/ - workflows/ # CI/CD workflows (see CI/CD section) - agents/ # GitHub Copilot agent definitions - prompts/ # Copilot prompt files -docusaurus.config.ts # Main Docusaurus configuration -sidebars.ts # Sidebar navigation -Justfile # build, serve recipes -``` - ---- - ## Data Pipeline -### How data reaches the site - -The site fetches all data at **build time** via npm scripts. No runtime API calls from the browser (except `GnomeExtensions.tsx` which fetches live from extensions.gnome.org, and the `ProjectCard.tsx` runtime fallback for missing repo stats). - -#### Standard data pipeline (`npm run fetch-data`) - -Runs automatically during `npm run start` and `npm run build`. - -| Script | Output | What it fetches | -|---|---|---| -| `fetch-feeds.js` | `static/feeds/bluefin-releases.json`, `static/feeds/bluefin-lts-releases.json` | GitHub Atom release feeds from ublue-os/bluefin and ublue-os/bluefin-lts | -| `fetch-playlist-metadata.js` | `static/data/playlist-metadata.json` | YouTube playlist thumbnails/descriptions | -| `fetch-github-profiles.js` | `static/data/github-profiles.json` | GitHub user profiles (~80 users for donations page) | -| `fetch-github-repos.js` | `static/data/github-repos.json` | GitHub repo stars/forks for projects page | -| `fetch-contributors.js` | `static/data/file-contributors.json` | Per-file git contributors (used by DocItem/Footer) | -| `fetch-gnome-extensions.js` | `static/data/gnome-extensions.json`, `static/img/extensions/` | GNOME extension metadata + screenshots for `/tips/` page | -| `fetch-pin-state.js` | `static/data/stream-pins.json` | Current pinned stream versions | -| `fetch-github-driver-versions.js` | `static/data/driver-versions.json` | Kernel/Mesa/NVIDIA/GNOME version history per stream from GitHub releases | -| `fetch-github-images.js` | `static/data/images.json` | OCI image catalog — streams, versions, bootc switch commands, download counts. Reads `sbom-attestations.json` and overlays package versions from SBOM data | -| `fetch-firehose.js` | `static/data/firehose-apps.json` | Flatpak/app release data from castrojo/bluefin-releases; enriched with SBOM OS release entries | - -All scripts use a **24-hour file-mtime cache**: if the output JSON is younger than 24 hours, the fetch is skipped. Pass `--force` to bypass. - -Requires `GITHUB_TOKEN` (or `GH_TOKEN`) env var for authenticated GitHub API requests: - -```bash -export GITHUB_TOKEN=$(gh auth token) -npm run fetch-data -``` - -The fetch-data chain runs in three phases (see `package.json`): - -```bash -# Phase 1 (parallel): feeds, playlists, profiles, repos, contributors -# Phase 2: pin-state (depends on feeds) -# Phase 3 (parallel): driver-versions, images, firehose -npm run fetch-data -``` - -Run individual scripts: - -```bash -npm run fetch-feeds -npm run fetch-playlists -npm run fetch-github-profiles -npm run fetch-github-repos -npm run fetch-contributors -npm run fetch-gnome-extensions -npm run fetch-pin-state -npm run fetch-github-driver-versions -npm run fetch-github-images -npm run fetch-firehose -``` - -#### SBOM attestation pipeline (separate nightly workflow) - -The SBOM pipeline runs **only in `.github/workflows/update-sbom-cache.yml`**. It is NOT part of `fetch-data` — it requires `cosign` and `oras` which are not installed in the standard build environment. - -| Script | Output | What it does | -|---|---|---| -| `fetch-github-sbom.js` | `static/data/sbom-attestations.json` | Uses cosign to verify SLSA attestations and oras to download Syft SBOMs. Extracts RPM package versions (kernel, gnome, mesa, podman, systemd, bootc, fedora) per stream/release. | - -Run with `npm run fetch-sbom` — requires cosign and oras on PATH. Uses `github.token` only — no PAT required. - -**Data flow:** - -``` -update-sbom-cache.yml (nightly 04:00 UTC) - cosign verify-attestation → GHCR OCI images - oras discover/pull → Syft SPDX JSON - → static/data/sbom-attestations.json - → saved to GHA cache (key: github-data-sbom-RUN_ID) - -pages.yml (every build) - restore-keys: github-data-sbom- ← picks up SBOM data from nightly cache - npm run fetch-github-images ← reads sbom-attestations.json, overlays versions - → static/data/images.json -``` - -**NVIDIA sources:** GDX stream (`bluefin-gdx-lts`) includes nvidia-driver in its SBOM. Bluefin stable and LTS nvidia variants use release feed fallback — akmod packages are built outside the OCI image. Dakota nvidia uses `dakota-nvidia-latest` SBOM stream. - -#### Seed file note - -Both `static/data/sbom-attestations.json` and `static/data/sbom-attestations-frontend.json` are **committed with populated SBOM data** and tracked by gitignore exceptions: - -```gitignore -!/static/data/sbom-attestations.json -!/static/data/sbom-attestations-frontend.json -``` - -These files are updated by the nightly `update-sbom-cache.yml` workflow and committed when needed. Do NOT commit stale or locally-fetched versions — only CI-generated data should land here. - -All other `static/data/*.json` and `static/feeds/*.json` files are gitignored and must never be committed. - ---- - -## CI/CD Workflows - -### `pages.yml` — Build and deploy - -Triggers: PR to main, push to main, merge_group, workflow_dispatch, schedule (daily 07:00 UTC) - -Key steps: -1. Restore `node_modules` cache (key: `npm` cache from setup-node) -2. **Restore GitHub data cache** — key `github-data-{scripts-hash}`: artwork-versions, driver-versions, file-contributors, firehose-apps, github-repos, images, playlist-metadata, stream-pins -3. **Restore GitHub profiles cache** — key `github-profiles-v1-` (populated by separate weekly workflow) -4. **Restore SBOM attestation cache** — key `github-data-sbom-` (populated by nightly 04:00 UTC workflow) -5. **Fetch SBOM on cache miss** — runs `fetch-github-sbom.js` directly if SBOM cache didn't hit (uses `github.token` only) -6. `npm ci` (install) -7. `npm run fetch-data` (uses `github.token` — no PAT required) -8. **Restore card image cache** — key `card-images-{template-hash}` -9. `npm run generate-card-images` -10. `npm test` (unit tests) -11. TypeScript + ESLint + Prettier validation (TS and ESLint are BLOCKING) -12. Build (`npm run build:ci`) -13. E2E Playwright tests — **only on `pull_request` and `merge_group`** (not on push to main) -14. Upload pages artifact → deploy to GitHub Pages (main only) - -### `e2e-tests.yml` — Standalone E2E CI - -Triggers: PR to main, **push to main** (separate from pages.yml E2E step) - -Runs a full build + Playwright test on every push to main and every PR. Uploads `playwright-report/` artifact on failure. Uses `github.token` only. Does NOT deploy. - -### `update-sbom-cache.yml` — Nightly SBOM fetch - -Triggers: schedule (04:00 UTC nightly), workflow_dispatch - -Steps: checkout → setup-node → restore existing SBOM cache (incremental) → install cosign → install oras → `npm run fetch-sbom` → save cache - -Permissions: `contents:read` only — no file commits, cache-only data flow. - -Required secret: none — `github.token` is sufficient (`fetch-github-sbom.js` uses the public Releases API and anonymous GHCR bearer tokens). - -### `monthly-reports.yml` — Monthly report generation - -Triggers: first Monday of each month 10:00 UTC, workflow_dispatch - -Permissions: `contents:write`, `pull-requests:write` - -Generates a report MDX in `reports/`, commits to a branch, creates a PR with auto-merge. - -### `pdf.yml` — Weekly PDF export - -Triggers: Sundays 5:50 UTC, workflow_dispatch - -Generates `pdf/bluefin.pdf` via Prince XML from the live site, uploads to GitHub Release `0.1`. - -### `renovate-validate.yml` — Renovate config validation - -Triggers: PRs touching `renovate.json` - -Runs `renovate-config-validator --strict`. - ---- - -## Components - -| Component | Page/Location | Data source | -|---|---|---| -| `FeedItems.tsx` + `CommunityFeeds.tsx` | `changelogs.tsx` | `static/feeds/*.json` + `sbom-attestations.json` | -| `PackageSummary.tsx` | `changelogs.tsx` | Derived from feeds via `src/config/packageConfig.ts` | -| `FirehoseFeed.tsx` + `OsReleaseCard.tsx` | `changelogs.tsx` | `firehose-apps.json` (static import) + `sbom-attestations-frontend.json` (lazy) + `bluefin-releases.json`/`bluefin-lts-releases.json` (lazy) | -| `ImagesCatalog.tsx` | `docs/images.md` (`/images` route) | `static/data/images.json` (includes SBOM version overlays) | -| `DriverVersionsCatalog.tsx` | `docs/driver-versions.mdx` | `static/data/driver-versions.json` | -| `ArtworkGallery.tsx` | `docs/artwork.mdx` | `fetch("/data/artwork.json")` — client-side fetch after hydration | -| `GitHubProfileCard.tsx` | `docs/donations/*.mdx` | `static/data/github-profiles.json` | -| `ProjectCard.tsx` | `docs/donations/projects.mdx` | `static/data/github-repos.json` (build-time) + GitHub API (runtime fallback) | -| `GnomeExtensions.tsx` | `docs/extensions.mdx` | Live fetch from extensions.gnome.org at runtime | -| `MusicPlaylist.tsx` | `docs/music.md` | `static/data/playlist-metadata.json` | -| `PageContributors.tsx` | DocItem/Footer (all doc pages) | `static/data/file-contributors.json` | -| `GiscusComments/` | Blog posts | GitHub Discussions via Giscus | - -### Changelog package tracking - -Package versions shown in changelog cards are centrally managed in `src/config/packageConfig.ts`. The `PACKAGE_PATTERNS` array defines regex patterns matched against release body HTML. - -To add a tracked package: add an entry to `PACKAGE_PATTERNS`, run `npm run build`, verify on `/changelogs`. - -Currently tracked: Kernel, HWE Kernel, GNOME, Mesa, Podman, NVIDIA, Docker, systemd, bootc. - ---- - -## Content Guidelines - -- Documentation should be consumable in one sitting. Link upstream docs; don't duplicate. -- Avoid "simply", "easy", "just" — see -- Imperative tone: "Run this command" -- Never create new pages unless explicitly instructed. -- Blog posts: use MDX with frontmatter tags; add author to `blog/authors.yaml` (fields: name, page, title, url, image_url, optional socials: bluesky, mastodon, github, linkedin, youtube, blog). -- Images: place in `static/img/`, reference as `/img/filename.ext` -- Music page: `MusicPlaylist` component requires 1:1 thumbnail aspect ratio and consistent album sizes. -- Donations/contributors page: uses `GitHubProfileCard` — distinguished contributors get foil effects via the `highlight` prop. - ---- - -## Monthly Reports System - -Auto-generated by `.github/workflows/monthly-reports.yml` on the first Monday of each month. - -### Library modules (in `scripts/lib/`) - -| Module | Purpose | -|---|---| -| `graphql-queries.mjs` | GitHub GraphQL client, fetches PRs from monitored repos | -| `monitored-repos.mjs` | List of repos to include in report | -| `contributor-tracker.mjs` | New vs repeat contributor tracking, bot filtering | -| `markdown-generator.mjs` | MDX formatting and templates | -| `build-metrics.mjs` | CI success rates from tracked workflow IDs | -| `label-mapping.mjs` | Static label color/category map | -| `github-sponsors.mjs` | Sponsor data | -| `tap-promotions.mjs` | Homebrew tap promotion data | - -**Planned work source:** Merged PRs from `projectbluefin/common` -**Opportunistic work source:** Merged PRs from all other monitored repos - -### Contributor tracking - -- `static/data/contributors-history.json` — gitignored, managed by the workflow -- First-time contributors get `highlight={true}` on their `GitHubProfileCard` (gold foil) -- Bots are excluded from human contributor counts - -### Manual generation - -```bash -export GITHUB_TOKEN=$(gh auth token) -npm run generate-report -npm run start # preview at http://localhost:3000/reports -``` - ---- - -## ProjectCard component - -`src/components/ProjectCard.tsx` — used on `docs/donations/projects.mdx`. - -Props: `name`, `description`, `sponsorUrl?`, `packageName?`, `icon?`, `githubRepo?` - -To add a new project: -1. Add `` to `docs/donations/projects.mdx` -2. Add the repo to `GITHUB_REPOS` in `scripts/fetch-github-repos.js` -3. Test: `npm run fetch-github-repos && npm run start` - -Icon URLs: use `https://github.com/org-name.png` or `https://github.com/username.png`. - ---- - -## Active Worktrees (2026-05-12) - -| Worktree path | Branch | Purpose | -|---|---|---| -| `.worktrees/blog-spring` | `feature/blog-f44-update-2` | Spring 2026 blog series — parts 2, 3, 4. Parts 1–3 published. Part 4 (`making-our-own-fate`) still `draft:true`. | - ---- +Data is fetched by `npm run fetch-data` which chains: `fetch-images` → `fetch-docs` → `fetch-contributors` → `generate-report`. This runs automatically before `npm run build` and `npm run start`. ## Known Issues -### SBOM committed files (load-bearing tracked JSON) - -Both `static/data/sbom-attestations.json` and `static/data/sbom-attestations-frontend.json` are committed to git and tracked via gitignore exceptions. These are populated files (not empty seeds). They are required at build time because `FeedItems.tsx` uses a static TypeScript import — the bundler needs the file to exist. The TypeScript ambient declaration in `src/types/sbom-attestations.d.ts` satisfies `tsc`. Do not remove or rename either file from git until a build-time fallback is implemented. - -### cosign/oras not in standard build environment - -Do not add `fetch-sbom` to the `fetch-data` chain. `pages.yml` installs cosign/oras **only** in the nightly `update-sbom-cache.yml`. The `pages.yml` build handles cache miss with a direct `fetch-github-sbom.js` call but cosign+oras must still be present — this is handled by the workflow step, not by developers locally. +- **SBOM files are load-bearing**: `static/data/sbom-attestations.json` and `static/data/sbom-attestations-frontend.json` are committed to git (via gitignore exceptions). Required at build time — do not remove or rename. +- **cosign/oras not in standard build env**: don't add `fetch-sbom` to the `fetch-data` chain. It's handled by the nightly `update-sbom-cache.yml` workflow only. +- **`npm install` may need `--legacy-peer-deps`** due to React 19 peer dependencies. ---- +## Troubleshooting quick fixes -## Troubleshooting - -| Symptom | Cause | Fix | -|---|---|---| -| `npm install` fails with peer conflicts | React 19 peer dep | Use `npm install --legacy-peer-deps` | -| Build fails on missing `sbom-attestations.json` | Gitignore misconfigured or file accidentally deleted | Verify `!/static/data/sbom-attestations.json` and `!/static/data/sbom-attestations-frontend.json` in `.gitignore`; restore from git if deleted (`git checkout HEAD -- static/data/sbom-attestations.json static/data/sbom-attestations-frontend.json`) | -| `images.json` missing SBOM package versions | SBOM cache not yet populated | Run `update-sbom-cache.yml` via workflow_dispatch on upstream | -| TypeScript deprecation error on `baseUrl` | TypeScript 6 change | `tsconfig.json` has `"ignoreDeprecations": "6.0"` — already handled | -| Prettier warnings on existing files | Pre-existing style drift | Non-blocking in CI; run `npm run prettier` to fix all at once | -| `contributors-history.json` corrupt | File corruption | Delete and re-run `npm run generate-report` to rebuild | -| Build fails on missing component after blog PR | Blog post published without its supporting `src/` files | Run `git diff upstream/main --name-only` on the worktree branch and copy ALL changed `src/`, `scripts/`, and `static/` files — not just the MDX. Never include `.github/workflows/*.yml` in the same PR. | -| Post not visible after merge | `draft: true` still in frontmatter | `grep -r "draft: true" blog/` — remove the line and push a fix PR | +| Symptom | Fix | +|---|---| +| Build fails on missing `sbom-attestations.json` | `git checkout HEAD -- static/data/sbom-attestations.json static/data/sbom-attestations-frontend.json` | +| TypeScript deprecation on `baseUrl` | Already handled — `tsconfig.json` has `"ignoreDeprecations": "6.0"` | +| Post not visible after merge | `grep -r "draft: true" blog/` — remove the line and push a fix PR | +| Blog PR breaks build | Run `git diff upstream/main --name-only` on worktree; copy ALL `src/`, `scripts/`, `static/` files, not just MDX |