Skip to content

catalog-refresh

catalog-refresh #3

# Refresh the committed site catalog from live AgentFront conformance.
#
# tools.culture.dev (M3) is hosted on Cloudflare Pages via git-integration, which
# builds site-astro/ from the *committed* catalog.json. So as sibling tools change
# versions or cross the conformance line, the live index goes stale until the
# catalog is regenerated. This job does that regeneration on a schedule (and on
# demand) and opens a PR — it never commits to main directly, so a human reviews
# the version/conformance diff before a merge triggers the CF rebuild.
#
# Status: needs a first `workflow_dispatch` run to validate in CI.
# Secrets (both optional):
# SIBLING_REPOS_TOKEN read-access PAT to clone *private* siblings; public
# ones clone with the default GITHUB_TOKEN. Without it,
# private siblings are reported as excluded.
# CATALOG_REFRESH_PR_TOKEN write PAT / App token for opening the refresh PR.
# Only needed if you want that PR to trigger CI — PRs
# opened by the default GITHUB_TOKEN do not. Falls back
# to GITHUB_TOKEN (which can still open the PR).
name: catalog-refresh
on:
schedule:
- cron: "0 6 * * 1" # Mondays 06:00 UTC
workflow_dispatch: {}
permissions:
contents: write
pull-requests: write
concurrency:
group: catalog-refresh
cancel-in-progress: false
jobs:
refresh:
runs-on: ubuntu-latest
steps:
- name: Checkout culture-tools
uses: actions/checkout@v4
- name: Set up uv + Python
uses: astral-sh/setup-uv@v5
with:
python-version: "3.12"
- name: Install culture-tools (+ dev deps)
run: uv sync
- name: Install the AgentFront auditor
run: |
uv tool install agentfront
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: Clone candidate sibling repos (from the manifest)
env:
GH_TOKEN: ${{ secrets.SIBLING_REPOS_TOKEN || secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
mkdir -p _siblings
# Keep the token out of clone URLs and the cloned repos' git config: feed
# it through GIT_ASKPASS instead, so the URL carries only the
# x-access-token *username* (not a secret) and nothing is persisted.
askpass="$RUNNER_TEMP/askpass.sh"
printf '#!/bin/sh\necho "$GH_TOKEN"\n' > "$askpass"
chmod +x "$askpass"
export GIT_ASKPASS="$askpass" GIT_TERMINAL_PROMPT=0
# The manifest is the single source of truth for what to fetch — emit
# "<owner/repo>\t<dir>" rows so this never drifts from the Python list.
uv run python - > _siblings/manifest.tsv <<'PY'
from culture_tools.index import candidates
for tool in candidates():
print(f"{tool.repo}\t{tool.repo_dir}")
PY
while IFS=$'\t' read -r repo dir; do
[ -z "${repo:-}" ] && continue
echo "::group::clone $repo -> _siblings/$dir"
git clone --depth 1 \
"https://x-access-token@github.com/${repo}.git" \
"_siblings/$dir" \
|| echo "skip: could not clone $repo (private/missing) — it will be excluded"
echo "::endgroup::"
done < _siblings/manifest.tsv
rm -f _siblings/manifest.tsv
- name: Enrich (best-effort) — install conformant tools for `learn --json`
continue-on-error: true
run: |
# Optional layer: populates each listed tool's purpose + command map.
# If a tool can't be installed the catalog still builds; that entry just
# carries no command surface. Never fails the job.
for pkg in agentfront colleague culture-tools; do
uv tool install "$pkg" || echo "skip install $pkg"
done
- name: Regenerate the catalog
run: |
set -euo pipefail
uv run culture-tools index build --out _stage --repos-dir _siblings
cp _stage/catalog.json site-astro/src/data/catalog.json
rm -rf site-astro/public/simple
cp -r _stage/simple site-astro/public/simple
cp _stage/_redirects site-astro/public/_redirects
rm -rf _siblings _stage
- name: Open a PR if the catalog changed
uses: peter-evans/create-pull-request@v7
with:
# PR creation needs *write*. SIBLING_REPOS_TOKEN is documented read-only
# (cloning private siblings), so it must NOT be reused here. The default
# GITHUB_TOKEN works via the permissions: block above; note that a PR it
# opens does not itself trigger CI — set CATALOG_REFRESH_PR_TOKEN (a PAT
# or App token) if you want the refresh PR to run checks automatically.
token: ${{ secrets.CATALOG_REFRESH_PR_TOKEN || secrets.GITHUB_TOKEN }}
base: main
branch: bot/catalog-refresh
delete-branch: true
commit-message: "chore(index): refresh catalog from live conformance"
title: "chore(index): refresh tools.culture.dev catalog"
body: |
Automated catalog refresh from live AgentFront conformance
(`culture-tools index build --repos-dir <cloned siblings>`).
**Review the version / conformance diff before merging** — merging to
`main` triggers a Cloudflare Pages rebuild of tools.culture.dev. If a
tool's command surface looks stripped, its package likely failed to
install in the enrichment step (non-fatal) — re-run or hold.
Generated by `.github/workflows/catalog-refresh.yml`.