bingran.you
← Skills
Engineering

overleaf-paper-sync

overleaf-paper-sync

Description

Manage Overleaf-backed LaTeX papers mirrored to GitHub with bidirectional GitHub Actions sync. Use for Overleaf git tokens, paper version control, GitHub mirrors, divergence or merge conflicts between Overleaf and Git, repos with sync-overleaf/pull-from-overleaf workflows or sync helpers, collaborator onboarding, and named paper instances listed in references/instances.md.

SKILL.md

Overleaf Paper Sync

Manage a LaTeX paper that lives on Overleaf by mirroring it on GitHub, with both directions kept in sync automatically by two GitHub Actions workflows. The point is to get Overleaf's editor + preview while keeping GitHub's version control, PR review, and tooling — without paying for Overleaf's built-in GitHub integration.

The mental model

Overleaf is a great editor (live preview, real-time collab, browser-based). It's a weak version control system. GitHub is the inverse. This setup keeps Overleaf as the editor of record and GitHub as the source of version truth, connected by two automated paths:

  1. GitHub → Overleaf (push trigger). Every push to GitHub's master runs .github/workflows/sync-overleaf.yml, which git pushes to Overleaf's git endpoint within seconds.

  2. Overleaf → GitHub (cron + on-demand). .github/workflows/pull-from-overleaf.yml runs hourly on a cron and on manual trigger. It fetches Overleaf, compares HEADs, and:

    • if Overleaf has new commits (a web edit), fast-forwards GitHub master onto them and pushes,
    • if GitHub is already ahead, does nothing — the other workflow handles that direction,
    • if both sides have unique commits, fails loudly with resolution instructions, because automated merges of LaTeX produce silently-broken papers.

Local clones also get a sync.ps1 / sync.sh helper that the user runs before each editing session: it triggers the pull workflow, waits for it to finish, and fast-forwards the local working copy. This catches collaborator web-edits without waiting up to an hour for the next cron tick.

That's the whole system. Everything else in this skill is one of: setup, conflict resolution, or troubleshooting.

Recognizing an already-wired-up paper

When stepping into an unfamiliar paper repo, these signals mean this skill applies:

  • .github/workflows/sync-overleaf.yml and/or .github/workflows/pull-from-overleaf.yml exist
  • Two git remotes — one with a git.overleaf.com URL (often named origin), one with a github.com URL (often named github)
  • A sync.ps1 / sync.sh in the repo root
  • An OVERLEAF_TOKEN secret configured on the GitHub repo

If 2+ of these are present, treat the repo as already set up — skip the setup section and go to Daily editing workflow below.

Daily editing workflow

This is the most-used section. Walk the user through it whenever they're about to work on the paper.

Step 1 — Before editing: pull Overleaf changes

From the paper repo root:

# Windows
.\sync.ps1
# Mac / Linux
./sync.sh

Takes ~10–30 seconds. It triggers the pull workflow on GitHub, waits for it, then fast-forwards the local clone. After this, the local working copy reflects whatever the latest collaborator web-edit on Overleaf left behind.

If the script reports "diverged" or the workflow run failed, see Conflict resolution below — don't keep editing on top of a divergent state.

Step 2 — Edit normally

VS Code, Cursor, vim, whatever. The paper repo is a regular git repo from here.

Step 3 — After editing: commit and push to GitHub only

git add .
git commit -m "<message>"
git push github master

The sync-overleaf workflow fires within seconds and pushes to Overleaf automatically. The user does not need to git push origin (Overleaf) — pushing manually is redundant and racy.

Sanity-check the workflow ran:

gh run list --workflow=sync-overleaf.yml --limit 1

What about commits made directly on Overleaf web?

Those reach GitHub via:

  • The hourly cron of pull-from-overleaf (worst case ~60 min latency — GitHub Actions cron is delayed by 5–15 min in practice on top of the schedule)
  • The user running sync.ps1 / sync.sh (fastest — usually under a minute)
  • A manual gh workflow run pull-from-overleaf.yml

The commit on GitHub will be authored by github-actions[bot] since the workflow does the push — that's expected.

Conflict resolution

The pull-from-overleaf workflow is fast-forward only. If GitHub and Overleaf have each grown commits the other doesn't have, the workflow fails on purpose. Auto-merging LaTeX between two unrelated edits would produce subtly broken output that nobody notices until the figure is upside down in the final PDF.

Full playbook, including the exact commands to detect each case and recover, is in references/conflict-resolution.md. The short version:

cd <paper-repo>
git fetch origin master        # origin = Overleaf
git fetch github master
git checkout master
git pull github master --ff-only    # bring local up to GitHub
git merge origin/master              # merge Overleaf in; resolve conflicts
git push github master               # triggers sync-overleaf to push back to Overleaf

If the local clone doesn't have credentials cached for the Overleaf remote, fetching from origin will prompt. The username is the literal string git; the password is the OVERLEAF_TOKEN.

Setting up sync for a new paper

When the user wants to add this pattern to a paper that's currently only on Overleaf (or set up a new mirrored paper from scratch), follow the procedure in references/setup-new-paper.md. It covers:

  1. Generating an Overleaf git token (and the gotcha that the token's username must be the literal string git, not the user's email — Overleaf changed this and the old "email + token" auth gives a 403)
  2. Cloning the Overleaf project to a local working dir
  3. Creating an empty GitHub repo and pushing the contents up
  4. Setting the OVERLEAF_TOKEN secret on the repo
  5. Dropping the two workflow files and the sync.ps1 / sync.sh helper into place (templates are in assets/)
  6. Optional: registering the paper repo as a submodule of a parent monorepo

The templates in assets/ use the literal string __OVERLEAF_PROJECT_ID__ everywhere the Overleaf project ID has to go — search-replace it once during setup.

Common errors and fixes

Quick reference. Full details and recovery commands in references/troubleshooting.md.

Symptom Likely cause Fix
403: Overleaf now only supports Git authentication tokens in workflow Workflow URL uses email as username Use https://git:${TOKEN}@git.overleaf.com/<id> — literal git, not email
fatal: Not possible to fast-forward in pull workflow Histories diverged See conflict-resolution.md
Workflow can't push to GitHub master Missing contents: write permission or branch protection Add permissions: contents: write to the workflow; check branch protection rules
Local push to GitHub succeeds but Overleaf never updates OVERLEAF_TOKEN missing or stale Check gh secret list; reset via gh secret set OVERLEAF_TOKEN --body "<new>"
Cron runs are skipped / very late Normal GitHub Actions backlog Use the sync.ps1 / manual trigger when timing matters
fatal: Unable to create '.git/index.lock' Stale lock from an interrupted git operation (common after WSL/sandbox edits on Windows) Remove-Item .git/index.lock (PS) or rm .git/index.lock (bash)
gh pr merge says "not mergeable" right after a force-push GitHub's mergeability cache hasn't refreshed Wait a few seconds and retry

Architecture notes

Non-obvious details that matter when debugging:

  • Default branch is master (Overleaf's convention). The workflows hardcode master. Don't rename it.

  • Why this doesn't loop infinitely: pull-from-overleaf pushes to GitHub using the default GITHUB_TOKEN. GitHub Actions deliberately does not re-trigger workflow runs on commits made by GITHUB_TOKEN — that's the platform's built-in loop protection. So pull-from-overleaf writing to master does NOT fire sync-overleaf back. User pushes from a personal machine DO fire it, because they authenticate with a personal token, not GITHUB_TOKEN.

  • Concurrency group: both workflows share concurrency: group: sync-overleaf. This serializes them so one doesn't push while the other is mid-fetch. Without this, you can get into states where each workflow sees a stale view of the other side.

  • Two remotes by convention: when cloning from Overleaf and adding GitHub, the natural setup is origin = Overleaf (from the original clone), github = GitHub (added later). Some setups flip these. The workflows don't care — they always construct the Overleaf URL from scratch using the secret.

  • OVERLEAF_EMAIL secret is vestigial. Earlier auth tried email-as-username; Overleaf migrated to requiring the literal git. If the secret is set, it's harmless. New setups don't need it.

Token rotation

Overleaf tokens leak. Rotate them periodically and immediately if exposed:

  1. In Overleaf: Account Settings → Git Integration → revoke the old token, generate a new one
  2. Update the GitHub secret:
    gh secret set OVERLEAF_TOKEN --body "<new-token>" --repo <owner>/<repo>
    
  3. Manually trigger pull-from-overleaf.yml once to confirm the new token works:
    gh workflow run pull-from-overleaf.yml --repo <owner>/<repo>
    
  4. No workflow file changes needed. The next push will also exercise the token via sync-overleaf.

Papers already set up with this pattern

This skill doubles as a memory for the author's own paper instances. Before treating a paper as "new", check references/instances.md — it lists each paper repo wired up with this pattern, the per-paper config that differs from the defaults, and any pending action items (e.g., tokens scheduled for rotation).

If the user mentions a paper by name and it's already listed there, you already know its Overleaf project ID, GitHub repo, parent-submodule path, and collaboration mode — skip the discovery questions and go straight to the daily-workflow guidance. When a new paper joins the pattern, append a section to instances.md so the next session inherits the context.

What this skill explicitly does NOT do

  • It does not build the PDF in CI. If the user wants Actions to compile paper.pdf on every push, add a separate workflow using xu-cheng/latex-action@v3. Not in scope here.
  • It does not support branches other than master. Overleaf's git endpoint only exposes master. If the user wants feature branches, do them on GitHub only and merge to master, which then syncs to Overleaf.
  • It does not replace Overleaf's paid GitHub integration. The paid integration handles divergence in a UI. This setup is more transparent and free but requires sync.ps1 before sessions and occasional manual conflict resolution.
  • It does not rebase commits across the boundary. The pull workflow uses fast-forward only, by design. Anything else is a human decision.

Skill contents