From 9e7f0186ee2463a9da66d93efcac6e8f5c920332 Mon Sep 17 00:00:00 2001 From: Yejin Kelly Joo Date: Thu, 25 Jun 2026 21:10:48 +0900 Subject: [PATCH 1/4] Add workflows for automatic OpenAPI updates and tagging Signed-off-by: Yejin Kelly Joo --- .github/workflows/tag-on-openapi-merge.yaml | 56 ++++++++ .github/workflows/update-openapi.yaml | 139 ++++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 .github/workflows/tag-on-openapi-merge.yaml create mode 100644 .github/workflows/update-openapi.yaml diff --git a/.github/workflows/tag-on-openapi-merge.yaml b/.github/workflows/tag-on-openapi-merge.yaml new file mode 100644 index 000000000..639c26e56 --- /dev/null +++ b/.github/workflows/tag-on-openapi-merge.yaml @@ -0,0 +1,56 @@ +name: tag on openapi merge + +# When an openapi-auto-update PR (from update-openapi.yaml) is merged, tag the merge +# commit with the matching Bee version (vX.Y.Z). That tag is what gh-pages.yaml deploys on. +# +# Requires the BOT_PAT secret (same token as update-openapi.yaml). It is used so the tag +# push triggers gh-pages.yaml — a tag pushed with the default GITHUB_TOKEN does NOT trigger +# other workflows. The job fails loudly if BOT_PAT is missing/expired. + +on: + pull_request: + types: [closed] + +permissions: + contents: write + +jobs: + tag: + if: >- + github.event.pull_request.merged == true && + contains(github.event.pull_request.labels.*.name, 'openapi-auto-update') && + startsWith(github.event.pull_request.head.ref, 'bot/update-openapi-') + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.base.ref }} + fetch-depth: 0 + token: ${{ secrets.BOT_PAT }} + + - name: Derive tag from branch + id: tag + env: + HEAD_REF: ${{ github.event.pull_request.head.ref }} + run: | + set -euo pipefail + NEW_TAG="${HEAD_REF#bot/update-openapi-}" + if ! echo "$NEW_TAG" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then + echo "Refusing to tag: '$NEW_TAG' is not a vX.Y.Z tag" >&2 + exit 1 + fi + echo "new_tag=$NEW_TAG" >> "$GITHUB_OUTPUT" + + - name: Create and push tag + env: + NEW_TAG: ${{ steps.tag.outputs.new_tag }} + run: | + set -euo pipefail + if git rev-parse -q --verify "refs/tags/${NEW_TAG}" >/dev/null; then + echo "Tag ${NEW_TAG} already exists — nothing to do." + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag "$NEW_TAG" + git push origin "$NEW_TAG" diff --git a/.github/workflows/update-openapi.yaml b/.github/workflows/update-openapi.yaml new file mode 100644 index 000000000..7c03dd561 --- /dev/null +++ b/.github/workflows/update-openapi.yaml @@ -0,0 +1,139 @@ +name: update openapi + +# Detects a new STABLE ethersphere/bee release tag, pulls its OpenAPI specs into +# openapi/, bumps the Bee version strings in the install docs, and opens (or updates) +# a PR. Prereleases (-rc*, -beta, v2.7.1a, v2.5.0-v8, ...) are ignored. +# +# Requires the BOT_PAT secret (a classic PAT with public_repo scope, or a fine-grained PAT +# with contents + pull-requests write). It is used so the auto-PR triggers build.yaml CI — +# PRs opened with the default GITHUB_TOKEN do NOT trigger other workflows. The job fails +# loudly if BOT_PAT is missing/expired rather than silently skipping CI. + +on: + schedule: + - cron: "0 6 * * *" # daily 06:00 UTC + workflow_dispatch: + inputs: + tag: + description: "Force a specific Bee tag (e.g. v2.9.0); blank = latest stable" + required: false + +concurrency: + group: update-openapi + cancel-in-progress: true + +permissions: + contents: write + pull-requests: write + +jobs: + update-openapi: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Resolve latest stable Bee tag + id: resolve + run: | + set -euo pipefail + if [ -n "${{ github.event.inputs.tag }}" ]; then + NEW_TAG="${{ github.event.inputs.tag }}" + else + NEW_TAG="$(git ls-remote --tags --refs https://github.com/ethersphere/bee.git \ + | awk '{print $2}' | sed 's#refs/tags/##' \ + | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \ + | sort -V | tail -1)" + fi + if [ -z "$NEW_TAG" ]; then + echo "Could not resolve a stable Bee tag" >&2 + exit 1 + fi + NEW_VER="${NEW_TAG#v}" + echo "new_tag=$NEW_TAG" >> "$GITHUB_OUTPUT" + echo "new_ver=$NEW_VER" >> "$GITHUB_OUTPUT" + echo "Latest stable Bee tag: $NEW_TAG (version $NEW_VER)" + + - name: Determine current docs version + id: current + run: | + set -euo pipefail + OLD_VER="$(grep -oE 'TAG=v[0-9]+\.[0-9]+\.[0-9]+' docs/bee/installation/quick-start.md \ + | head -1 | sed 's/^TAG=v//')" + if [ -z "$OLD_VER" ]; then + echo "Could not determine current docs version anchor" >&2 + exit 1 + fi + echo "old_ver=$OLD_VER" >> "$GITHUB_OUTPUT" + echo "Current docs version: $OLD_VER" + + - name: Fetch OpenAPI specs from the tag + env: + NEW_TAG: ${{ steps.resolve.outputs.new_tag }} + run: | + set -euo pipefail + for f in Swarm.yaml SwarmCommon.yaml; do + curl -fsSL \ + "https://raw.githubusercontent.com/ethersphere/bee/${NEW_TAG}/openapi/$f" \ + -o "openapi/$f" + done + + - name: Bump Bee version strings in docs + if: ${{ steps.current.outputs.old_ver != steps.resolve.outputs.new_ver }} + env: + OLD_VER: ${{ steps.current.outputs.old_ver }} + NEW_VER: ${{ steps.resolve.outputs.new_ver }} + run: | + set -euo pipefail + FILES=( + docs/bee/installation/build-from-source.md + docs/bee/installation/docker.md + docs/bee/installation/quick-start.md + docs/bee/installation/shell-script.md + docs/bee/working-with-bee/bee-api.md + docs/bee/working-with-bee/configuration.md + docs/bee/working-with-bee/staking.md + ) + # Literal substring swap of the semver. This deliberately also rewrites the + # vX.Y.Z, bee:X.Y.Z and X.Y.Z- forms (the version is a substring of each), + # and is safe because the old version never appears inside an unrelated number + # in these files. ESC_OLD escapes the dots so they match literally. + ESC_OLD="${OLD_VER//./\\.}" + sed -i "s/${ESC_OLD}/${NEW_VER}/g" "${FILES[@]}" + + - name: Detect changes + id: changes + run: | + set -euo pipefail + if git diff --quiet; then + echo "changed=false" >> "$GITHUB_OUTPUT" + echo "No changes — already up to date with the latest stable Bee release." + else + echo "changed=true" >> "$GITHUB_OUTPUT" + fi + + - name: Create or update PR + if: ${{ steps.changes.outputs.changed == 'true' }} + uses: peter-evans/create-pull-request@v6 + with: + token: ${{ secrets.BOT_PAT }} + branch: bot/update-openapi-${{ steps.resolve.outputs.new_tag }} + commit-message: "chore: update OpenAPI specs and version refs to Bee ${{ steps.resolve.outputs.new_tag }}" + title: "Update OpenAPI specs to Bee ${{ steps.resolve.outputs.new_tag }}" + labels: openapi-auto-update + delete-branch: true + body: | + Automated update to Bee **${{ steps.resolve.outputs.new_tag }}**. + + Source: https://github.com/ethersphere/bee/tree/${{ steps.resolve.outputs.new_tag }}/openapi + + ## What changed + - `openapi/Swarm.yaml` and `openapi/SwarmCommon.yaml` pulled from the tagged commit. + - Bee version strings bumped `${{ steps.current.outputs.old_ver }}` → `${{ steps.resolve.outputs.new_ver }}` in the install docs. + + ## ⚠️ Please review before merging + The version-string replacement is **best-effort** (literal semver swap in a fixed set + of doc files) and can miss or over-match. Skim the doc diff. Merging this PR triggers + the `tag-on-openapi-merge` workflow, which tags the merge commit `${{ steps.resolve.outputs.new_tag }}` + and (with a PAT configured) kicks off the gh-pages deploy. From f32869803175e3a5631a7afb56ffd54ec0795ca3 Mon Sep 17 00:00:00 2001 From: Yejin Kelly Joo Date: Thu, 25 Jun 2026 21:11:03 +0900 Subject: [PATCH 2/4] Add CLAUDE guidance file Signed-off-by: Yejin Kelly Joo --- .gitignore | 4 ---- CLAUDE.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 CLAUDE.md diff --git a/.gitignore b/.gitignore index c36860a79..62066d1d6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ examples .docusaurus .claude -CLAUDE.md node_modules .DS_Store build @@ -15,6 +14,3 @@ docs/references/awesome-list.mdx *.zip *.csv link-reports/ -CLAUDE.md - - diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..4e8e758ef --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,62 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this is + +Documentation website for the [Swarm Bee client](https://github.com/ethersphere/bee), built with **Docusaurus 3** and deployed at [docs.ethswarm.org](https://docs.ethswarm.org). Content lives in `docs/` as Markdown/MDX; everything else is site config, build tooling, and a few React components. + +## Commands + +```bash +npm ci # install exact deps (preferred over npm install) +npm start # local dev server with live reload +npm run build # production build into build/ (runs prebuild first) +npm run build:quiet # build with noisy Node deprecation warnings suppressed +npm run serve # serve a built site locally + +npm run check:links # check links against an existing local build +npm run build:check # build + check links in one step +``` + +Link checker flags pass through after `--`: + +```bash +npm run check:links -- --mode local --no-external --threads 16 +npm run check:links -- --mode live --site-domain docs.ethswarm.org +``` + +Node >=20, npm >=9.6 (see `.nvmrc` / `package.json` engines). + +There is **no test suite and no linter** — validation is the build, the `llms.txt` validator (runs in `prebuild`), and the link checker. + +## Build pipeline gotchas + +The `prebuild` npm hook runs automatically before `build` and does three things, in order: +1. Copies `openapi/Swarm.yaml` → `static/openapi.yaml`. +2. `scripts/fetch-awesome-swarm.mjs` — fetches external content at build time. +3. `scripts/validate-llms-txt.mjs` — validates `static/llms.txt` coverage (informational, **always exit 0**, never blocks the build). + +`onBrokenLinks: 'warn'` — broken internal links warn rather than fail the build. Use the link checker to catch them. + +## Architecture / where things live + +- **`docs/`** — all documentation content, grouped into top-level sections: `bee/`, `concepts/`, `desktop/`, `develop/`, `references/`. Page ordering and the sidebar tree are defined manually in **`sidebars.js`** (not auto-generated) — adding a doc file requires adding it to `sidebars.js`. +- **`docusaurus.config.mjs`** — single source of site config: plugins, presets, redirects (`@docusaurus/plugin-client-redirects`), the OpenAPI integration (`redocusaurus`), and three `docusaurus-plugin-llms` slice configs (`llms-api.txt`, `llms-node-ops.txt`, etc.). +- **`openapi/`** — `Swarm.yaml` + `SwarmCommon.yaml`. The API reference page is compiled from these at build time via redocusaurus. These are **manually kept in sync** with the [OpenAPI specs in the Bee repo](https://github.com/ethersphere/bee/tree/master/openapi) — they do not auto-update. +- **`src/components/`** — interactive calculators embedded in docs via MDX (e.g. `AmountAndDepthCalc.js`, `RedundancyCalc.js`, `VolumeAndDurationCalc.js`). `src/config/globalVariables.js` holds shared constants. +- **`src/theme/SearchBar/`** — a **swizzled** component (ejected from the theme). See the README: upgrading the Docusaurus theme does NOT upgrade swizzled components and can break search; re-swizzle after theme upgrades. +- **`scripts/`** — TypeScript (`tsx`, no separate install) build/CI helpers: link checkers (`check_links.ts`, `check_live_links.ts`) and the build-time `.mjs` scripts above. + +## llms.txt (AI-agent docs) + +- `static/llms.txt` — **hand-curated** index of every doc page, one line each. Edit by hand when pages are added/renamed/deleted. +- `/llms-full.txt` and the sliced variants — **auto-generated** at build time; do not hand-edit. +- When the prebuild validator warns about a stale link or missing coverage, fix `static/llms.txt` (update the path or add a `- [Title](url): description` line in the right section). A few navigation-only landing pages are intentionally excluded — those warnings are expected. + +## Content conventions (from CODING.md) + +- **Wrap long lines** with newlines — keeps git diffs small and reduces merge conflicts. +- **Minimize unrelated edits** (e.g. don't reflow a whole paragraph to fix one typo) for the same reason. +- **`Swarm` vs `swarm`**: capital `Swarm` = the project / main network; lowercase `swarm` = a swarm of bee nodes (Bee supports running multiple). Capital `Bee` = the Go client; lowercase `bee` = any Swarm-protocol client. +- **Version bumps**: find-and-replace the version number across the whole `docs/` folder. From b9416adca6a13a779d60329f0575580bb85232ba Mon Sep 17 00:00:00 2001 From: Yejin Kelly Joo Date: Thu, 25 Jun 2026 21:18:54 +0900 Subject: [PATCH 3/4] Document automated Bee release sync Signed-off-by: Yejin Kelly Joo --- CLAUDE.md | 5 +++-- README.md | 13 +++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 4e8e758ef..ffaa0afaf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -43,7 +43,8 @@ The `prebuild` npm hook runs automatically before `build` and does three things, - **`docs/`** — all documentation content, grouped into top-level sections: `bee/`, `concepts/`, `desktop/`, `develop/`, `references/`. Page ordering and the sidebar tree are defined manually in **`sidebars.js`** (not auto-generated) — adding a doc file requires adding it to `sidebars.js`. - **`docusaurus.config.mjs`** — single source of site config: plugins, presets, redirects (`@docusaurus/plugin-client-redirects`), the OpenAPI integration (`redocusaurus`), and three `docusaurus-plugin-llms` slice configs (`llms-api.txt`, `llms-node-ops.txt`, etc.). -- **`openapi/`** — `Swarm.yaml` + `SwarmCommon.yaml`. The API reference page is compiled from these at build time via redocusaurus. These are **manually kept in sync** with the [OpenAPI specs in the Bee repo](https://github.com/ethersphere/bee/tree/master/openapi) — they do not auto-update. +- **`openapi/`** — `Swarm.yaml` + `SwarmCommon.yaml`. The API reference page is compiled from these at build time via redocusaurus. Kept in sync with the [OpenAPI specs in the Bee repo](https://github.com/ethersphere/bee/tree/master/openapi) by the `update-openapi` workflow (see below) — they are **not** edited by hand. +- **`.github/workflows/`** — `build.yaml` (build on push/PR), `gh-pages.yaml` (deploy on `v*.*.*` tag push), and two Bee-sync workflows: `update-openapi.yaml` (daily; pulls openapi specs + bumps version strings from the latest stable Bee tag and opens a PR labelled `openapi-auto-update`) and `tag-on-openapi-merge.yaml` (tags the merge commit `vX.Y.Z` when that PR merges, triggering the deploy). Both need the `BOT_PAT` secret and fail loudly without it. - **`src/components/`** — interactive calculators embedded in docs via MDX (e.g. `AmountAndDepthCalc.js`, `RedundancyCalc.js`, `VolumeAndDurationCalc.js`). `src/config/globalVariables.js` holds shared constants. - **`src/theme/SearchBar/`** — a **swizzled** component (ejected from the theme). See the README: upgrading the Docusaurus theme does NOT upgrade swizzled components and can break search; re-swizzle after theme upgrades. - **`scripts/`** — TypeScript (`tsx`, no separate install) build/CI helpers: link checkers (`check_links.ts`, `check_live_links.ts`) and the build-time `.mjs` scripts above. @@ -59,4 +60,4 @@ The `prebuild` npm hook runs automatically before `build` and does three things, - **Wrap long lines** with newlines — keeps git diffs small and reduces merge conflicts. - **Minimize unrelated edits** (e.g. don't reflow a whole paragraph to fix one typo) for the same reason. - **`Swarm` vs `swarm`**: capital `Swarm` = the project / main network; lowercase `swarm` = a swarm of bee nodes (Bee supports running multiple). Capital `Bee` = the Go client; lowercase `bee` = any Swarm-protocol client. -- **Version bumps**: find-and-replace the version number across the whole `docs/` folder. +- **Version bumps**: automated by the `update-openapi` workflow on each new stable Bee release (literal find-and-replace of the semver in the install docs). Only bump by hand for out-of-band corrections, across the whole `docs/` folder. diff --git a/README.md b/README.md index 123caee00..c13429fb3 100644 --- a/README.md +++ b/README.md @@ -122,8 +122,17 @@ Reports are written to `link-reports/` (gitignored). ## Bumping Version -Don't forget to find and replace the version number for the whole of the docs folder. +When a new stable Bee version is released, the version number across the `docs/` folder is bumped automatically — see [Keeping in sync with Bee releases](#keeping-in-sync-with-bee-releases) below. ## API Reference -The OpenAPI reference docs are compiled at build time from the OpenAPI yaml files in the `/openapi` directory using the [redocusaurus plugin](https://www.npmjs.com/package/redocusaurus) for Docusaurus. They must be manually updated to stay up to date with the [OpenAPI specs in the Bee repo](https://github.com/ethersphere/bee/tree/master/openapi). \ No newline at end of file +The OpenAPI reference docs are compiled at build time from the OpenAPI yaml files in the `/openapi` directory using the [redocusaurus plugin](https://www.npmjs.com/package/redocusaurus) for Docusaurus. They are kept in sync with the [OpenAPI specs in the Bee repo](https://github.com/ethersphere/bee/tree/master/openapi) automatically — see below. + +## Keeping in sync with Bee releases + +Two GitHub Actions workflows keep the docs aligned with [ethersphere/bee](https://github.com/ethersphere/bee) releases: + +- **`.github/workflows/update-openapi.yaml`** runs daily (and on manual `workflow_dispatch`). It finds the latest **stable** Bee tag (prereleases like `-rc*` are ignored), pulls `Swarm.yaml` + `SwarmCommon.yaml` from that tag into `openapi/`, bumps the Bee version strings in the install docs, and opens (or updates) a PR labelled `openapi-auto-update`. The version-string replacement is best-effort — **review the doc diff before merging**. +- **`.github/workflows/tag-on-openapi-merge.yaml`** runs when such a PR is merged. It tags the merge commit with the matching Bee version (`vX.Y.Z`), which triggers the existing `gh-pages.yaml` deploy. + +Both require a repository secret named **`BOT_PAT`** (a classic PAT with `public_repo` scope, or a fine-grained PAT with contents + pull-requests write). The PAT is necessary to allow CI for the auto-PRs and deployment for the auto-release tags. If the token is missing or expired, the workflows fail loudly rather than silently degrading. Renew BOT_PAT in such case. From b4944094517a85c7deff2adce8e4c4aa72b80054 Mon Sep 17 00:00:00 2001 From: Yejin Kelly Joo Date: Thu, 25 Jun 2026 21:20:54 +0900 Subject: [PATCH 4/4] docs(github): add pull request template - add PULL_REQUEST_TEMPLATE.md with what/details/checklist sections - checklist adapted to this repo's build, link-check, and llms.txt conventions Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Yejin Kelly Joo --- .github/PULL_REQUEST_TEMPLATE.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..8ed0c7904 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,17 @@ +# What does this PR resolve? 🚀 + + + +# Details 📝 + + + +# Checklist ✅ + +- [ ] Merged latest `master` and resolved conflicts +- [ ] `npm run build` succeeds +- [ ] Links checked (`npm run check:links`) where relevant +- [ ] `static/llms.txt` updated if pages were added / renamed / deleted +- [ ] Content follows [CODING.md](../CODING.md) conventions (wrap long lines, `Swarm` vs `swarm`) +- [ ] Self-reviewed the diff +- [ ] Commits are signed off (`git commit -s`)