Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Sync and manage Overleaf LaTeX projects from the command line
.claude/skills/brycewang-stanford-overleaf-cli-guide/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 39% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 24% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 71% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 131% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 79% | 0% |
Sync, manage, and automate Overleaf LaTeX projects from the command line. Work in your preferred local editor while keeping Overleaf as the collaboration and compilation hub for your research team.
Overleaf is the dominant online LaTeX editor in academia, used by millions of researchers for collaborative paper writing. However, many researchers prefer local editors (VS Code, Neovim, Emacs) for their superior editing capabilities, version control integration, and ability to run custom scripts. The Overleaf CLI bridge enables a hybrid workflow: edit locally with full tooling, then sync changes to Overleaf for collaboration and compilation.
This skill covers three approaches to Overleaf CLI integration: Overleaf's built-in Git bridge (available on paid plans), the open-source overleaf-sync tool (works with free plans), and direct API interaction. Each approach has different trade-offs in terms of cost, features, and reliability.
Beyond simple sync, this guide covers automation workflows that are particularly valuable for research: automated bibliography updates from reference managers, figure regeneration from data analysis scripts, CI-based PDF compilation, and multi-author merge conflict resolution.
Overleaf Server Pro and paid plans include a Git bridge that exposes each project as a Git repository.
bash# Clone your Overleaf project (requires paid plan) git clone https://git.overleaf.com/YOUR_PROJECT_ID my-paper cd my-paper # The remote is already configured git remote -v # origin https://git.overleaf.com/YOUR_PROJECT_ID (fetch) # origin https://git.overleaf.com/YOUR_PROJECT_ID (push)
bash# Pull latest changes from collaborators git pull origin master # Edit locally in your preferred editor vim main.tex # Push changes back to Overleaf git add -A git commit -m "Revise methodology section" git push origin master
When collaborators edit the same section simultaneously:
bashgit pull origin master # If conflicts occur: # 1. Open conflicted files # 2. Resolve LaTeX merge conflicts (look for <<<<<<< markers) # 3. Verify the document compiles git add -A git commit -m "Resolve merge conflict in results section" git push origin master
For free Overleaf accounts without Git bridge access:
bash# Install pip install overleaf-sync # Login (stores credentials securely) ols login # List your projects ols list # Download a project ols download "My Research Paper" --path ./my-paper # Upload local changes ols upload ./my-paper --project "My Research Paper" # Two-way sync (pull then push) ols sync ./my-paper --project "My Research Paper"
bash#!/bin/bash # sync-overleaf.sh - Run periodically or before/after editing sessions PROJECT_DIR="$1" PROJECT_NAME="$2" echo "Pulling latest from Overleaf..." ols download "$PROJECT_NAME" --path "$PROJECT_DIR" --skip-existing echo "Compiling locally to verify..." cd "$PROJECT_DIR" latexmk -pdf -interaction=nonstopmode main.tex if [ $? -eq 0 ]; then echo "Compilation successful. Pushing to Overleaf..." ols upload "$PROJECT_DIR" --project "$PROJECT_NAME" else echo "Compilation failed. Fix errors before syncing." exit 1 fi
pythonimport subprocess from pathlib import Path def sync_bibliography(zotero_lib_id, bib_file, project_dir): """Export Zotero library and sync to Overleaf project.""" # Export from Zotero using Better BibTeX subprocess.run([ "curl", "-s", f"http://localhost:23119/better-bibtex/export/library?/" f"{zotero_lib_id}/library.biblatex", "-o", str(Path(project_dir) / bib_file) ]) print(f"Updated {bib_file} from Zotero library {zotero_lib_id}")
pythonimport subprocess from pathlib import Path def regenerate_figures(scripts_dir, figures_dir): """Run all figure generation scripts and update outputs.""" scripts = sorted(Path(scripts_dir).glob("fig_*.py")) for script in scripts: print(f"Running {script.name}...") subprocess.run(["python", str(script)], cwd=figures_dir) print(f"Regenerated {len(scripts)} figures in {figures_dir}")
yaml# .github/workflows/compile-paper.yml name: Compile LaTeX Paper on: push: branches: [main] paths: ['**.tex', '**.bib', '**.sty'] jobs: compile: runs-on: ubuntu-latest container: image: texlive/texlive:latest steps: - uses: actions/checkout@v4 - name: Compile PDF run: | latexmk -pdf -interaction=nonstopmode main.tex - name: Upload PDF uses: actions/upload-artifact@v4 with: name: paper-pdf path: main.pdf - name: Check for warnings run: | grep -i "warning" main.log | grep -v "Font" || true
Recommended directory structure for CLI-managed Overleaf projects:
my-paper/
main.tex # Main document
sections/
01-introduction.tex
02-related-work.tex
03-methodology.tex
04-results.tex
05-discussion.tex
06-conclusion.tex
figures/
fig1-architecture.pdf
fig2-results.pdf
tables/
tab1-comparison.tex
references.bib
custom.sty # Custom LaTeX macros
scripts/ # Not synced to Overleaf
fig_architecture.py
fig_results.py
sync.sh
.gitignoregitignore# LaTeX build artifacts *.aux *.bbl *.blg *.fdb_latexmk *.fls *.log *.out *.synctex.gz *.toc # Local scripts (don't sync to Overleaf) scripts/ # OS files .DS_Store
Install the "LaTeX Workshop" extension and configure local compilation:
json{ "latex-workshop.latex.tools": [ { "name": "latexmk", "command": "latexmk", "args": ["-pdf", "-interaction=nonstopmode", "%DOC%"] } ] }
lua-- init.lua vim.g.vimtex_compiler_method = 'latexmk' vim.g.vimtex_view_method = 'skim' -- macOS
| Issue | Solution | |-------|----------| | Git push rejected | Pull first, resolve conflicts, then push | | Sync tool authentication error | Re-run login, check 2FA settings | | Compilation differs locally vs Overleaf | Match TeX Live versions; Overleaf uses TeX Live 2024 | | Binary files (images) cause large diffs | Use .gitattributes to mark as binary | | Overleaf rate limiting | Add delays between API calls, use Git bridge if available |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 18,106 | 32,018 | +77% | 1 | 1 | 0% | 3,507 | 4,871 | +39% | 0 | 0 | — |
case-02 | fail→fail | 16,585 | 9,582 | -42% | 1 | 1 | 0% | 3,021 | 3,633 | +20% | 0 | 0 | — |
case-03 | fail→fail | 19,422 | 17,134 | -12% | 1 | 1 | 0% | 3,642 | 5,507 | +51% | 0 | 0 | — |
case-04 | pass→pass | 10,452 | 7,024 | -33% | 1 | 1 | 0% | 1,712 | 3,071 | +79% | 0 | 0 | — |
case-05 | pass→pass | 9,140 | 7,065 | -23% | 1 | 1 | 0% | 1,576 | 2,964 | +88% | 0 | 0 | — |
case-06 | fail→pass | 15,007 | 5,453 | -64% | 1 | 1 | 0% | 2,338 | 2,899 | +24% | 0 | 0 | — |
case-07 | fail→pass | 11,259 | 9,853 | -12% | 1 | 1 | 0% | 2,021 | 3,466 | +71% | 0 | 0 | — |
case-08 | fail→fail | 9,982 | 9,119 | -9% | 1 | 1 | 0% | 1,879 | 3,651 | +94% | 0 | 0 | — |
case-09 | pass→pass | 11,811 | 6,365 | -46% | 1 | 1 | 0% | 1,969 | 3,080 | +56% | 0 | 0 | — |
case-10 | pass→pass | 9,537 | 10,594 | +11% | 1 | 1 | 0% | 1,736 | 3,941 | +127% | 0 | 0 | — |
case-11 | fail→pass | 9,758 | 7,083 | -27% | 1 | 1 | 0% | 1,351 | 3,115 | +131% | 0 | 0 | — |
case-12 | pass→pass | 16,394 | 15,294 | -7% | 1 | 1 | 0% | 2,716 | 4,826 | +78% | 0 | 0 | — |
case-13 | pass→pass | 9,869 | 5,116 | -48% | 1 | 1 | 0% | 1,755 | 2,700 | +54% | 0 | 0 | — |
case-14 | pass→pass | 11,640 | 5,480 | -53% | 1 | 1 | 0% | 2,228 | 2,909 | +31% | 0 | 0 | — |
case-19 | pass→pass | 7,052 | 2,957 | -58% | 1 | 1 | 0% | 974 | 2,403 | +147% | 0 | 0 | — |
case-15 | pass→pass | 11,912 | 10,579 | -11% | 1 | 1 | 0% | 1,994 | 3,617 | +81% | 0 | 0 | — |
case-16 | pass→pass | 3,521 | 3,167 | -10% | 1 | 1 | 0% | 654 | 2,324 | +255% | 0 | 0 | — |
case-17 | pass→pass | 10,902 | 5,864 | -46% | 1 | 1 | 0% | 1,871 | 2,966 | +59% | 0 | 0 | — |
case-18 | pass→pass | 6,642 | 16,472 | +148% | 1 | 1 | 0% | 1,096 | 2,259 | +106% | 0 | 0 | — |
case-20 | pass→pass | 12,145 | 12,309 | +1% | 1 | 1 | 0% | 2,090 | 3,813 | +82% | 0 | 0 | — |
case-21 | pass→pass | 14,418 | 15,081 | +5% | 1 | 1 | 0% | 2,201 | 4,293 | +95% | 0 | 0 | — |
case-22 | pass→pass | 13,245 | 10,898 | -18% | 1 | 1 | 0% | 1,944 | 3,639 | +87% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +18 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.