Skip to content

Keep the owid/public-skills mirror in sync automatically - #22

Merged
danyx23 merged 2 commits into
mainfrom
mirror-sync-workflow
Sep 15, 2026
Merged

danyx23 merged 2 commits into
mainfrom
mirror-sync-workflow

Conversation

@danyx23

@danyx23 danyx23 commented Sep 14, 2026

Copy link
Copy Markdown
Member

GH repo owid/public-skills is a private mirror of this repo. It exists because an org-level plugin in Claude Desktop / Claude Web has to be installed from a repo inside the owid org and it has to be private, so this repo’s content is republished there.

This adds .github/workflows/mirror-to-public-skills.yml, which on every push to main:

  1. checks out owid/public-skills,
  2. runs that repo’s own sync-upstream.sh — merge this repo’s main, regenerate the mirror’s README, push.

All the sync logic lives in the mirror; this workflow only triggers it. Nothing about this repo’s own content or CI changes.

Before merging

Add a repository secret MIRROR_SYNC_TOKEN: a fine-grained PAT scoped to owid/public-skills only, with Contents: read and write. The default GITHUB_TOKEN cannot reach another repository. Without the secret the first step fails with an explanation instead of an opaque checkout error.

Notes

  • The mirror’s README.md is derived (.mirror/readme-notice.md + this repo’s README.md, regenerated each sync), so it can never drift or need a manual merge resolution.
  • sync-upstream.sh fails loudly on a conflict in any file other than that README — which should not happen unless someone commits to upstream-owned files in the mirror.
  • A weekly cron repairs drift if a push-triggered run ever fails; the sync is idempotent, so no-op runs are free. workflow_dispatch allows a manual re-run.
  • Actions are disabled on the mirror, so mirrored copies of this repo’s workflows do not run there and the push does not trigger anything.

🤖 Generated with Claude Code

owid/public-skills is a private mirror of this repo, republished inside the org
so the skills can be installed as an org-level plugin in Claude Desktop/Web.
Until now it had to be synced by hand.

This workflow checks the mirror out on every push to main and runs the mirror's
own sync-upstream.sh, which merges this repo, regenerates the mirror README
(upstream README + a "this is a mirror" notice) and pushes. The sync logic stays
in the mirror; this only triggers it. A weekly cron repairs drift if a run ever
fails, and it can be re-run by hand via workflow_dispatch.

Needs a MIRROR_SYNC_TOKEN secret: a fine-grained PAT scoped to
owid/public-skills with Contents: read and write. Without it the first step
fails with an explanation rather than a confusing checkout error.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@danyx23
danyx23 force-pushed the mirror-sync-workflow branch from 445f1b9 to f1934e1 Compare September 15, 2026 14:59
The first live run failed with a bare "Not Found" from actions/checkout,
which reads as though the mirror repo did not exist when in fact the token
could not see it. A preflight call names the likely cause instead.

checkout@v5 also drops the Node 20 deprecation warning.
@danyx23
danyx23 force-pushed the mirror-sync-workflow branch from 5556404 to 1d6e084 Compare September 15, 2026 15:01
@danyx23

danyx23 commented Sep 15, 2026

Copy link
Copy Markdown
Member Author

Tested end to end against the real mirror before merge, by temporarily letting the workflow fire on this branch.

To prove the token can write and not merely read, the mirror’s README.md was deliberately clobbered first; the run repaired it:

MIRROR_SYNC_TOKEN can reach owid/public-skills.
==> fetching upstream
==> already up to date with upstream/main
==> regenerating README.md from .mirror/readme-notice.md + upstream README
[main 3465dcb] Re-apply mirror notice to README
==> pushing to origin/main
   6d1cbe3..3465dcb  main -> main

The resulting README was byte-identical to notice + upstream README, committed as github-actions[bot]. All test commits and the temporary branch trigger have been removed from both repos; the mirror is back to a clean history.

The first attempt failed with a bare Not Found from actions/checkout because the token could not see the private repo — which reads as though the repo does not exist. That is why the preflight step in the second commit exists: it now names the likely cause (expired, wrong resource owner, approval pending, repo not selected) instead.

@danyx23
danyx23 merged commit a51baae into main Sep 15, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant