# olcli — Overleaf CLI
**Command-line interface for Overleaf** — Sync, manage, and compile LaTeX projects from your terminal.
[](https://www.npmjs.com/package/@aloth/olcli)
[](https://www.npmjs.com/package/@aloth/olcli)
[](https://github.com/aloth/olcli)
[](https://opensource.org/licenses/MIT)
[](https://agentskills.io)
Work with Overleaf projects directly from your command line. Edit locally with your favorite editor, version control with Git, and sync seamlessly with Overleaf's cloud compilation.
## Features
- 📋 **List** all your Overleaf projects
- ⬇️ **Pull** project files to local directory for offline editing
- ⬆️ **Push** local changes back to Overleaf
- 🔄 **Sync** bidirectionally with smart conflict detection
- 🔀 **Git remote** — use Overleaf as a native git remote ([docs](docs/GIT-REMOTE.md))
- ✌️ **Two-way deletions** — files removed locally are deleted on Overleaf on next sync
- 🗑️ **Delete** and ✏️ **rename** remote files by path
- 🚫 **Smart ignore** — LaTeX build artifacts and OS noise filtered automatically; extend with `.olignore`
- 📄 **Compile** PDFs using Overleaf's remote compiler
- 📦 **Download** individual files or full project archives
- 📤 **Upload** files to projects
- 💬 **Review comments** — list, add, resolve, reopen, delete, and reply to threads
- 🗂️ **Preserve folder structure** when pushing nested files
- ⏱️ **Configurable timeout** for slow connections
- 🔑 **Password login** for self-hosted instances (no browser required)
- ⚙️ **Self-hosted Overleaf/ShareLaTeX** support
- 📊 **Output** compile artifacts (`.bbl`, `.log`, `.aux` for arXiv submissions)
- 🤖 **MCP server** for AI assistants ([docs](docs/MCP.md))
**Perfect for:**
- Editing LaTeX in your preferred text editor (Vim, VS Code, Emacs, etc.)
- Version control with Git while using Overleaf's compiler
- Automating workflows and CI/CD pipelines
- Offline work with periodic sync
## Installation
### Homebrew (macOS/Linux)
```bash
brew tap aloth/tap
brew install olcli
```
### npm (all platforms)
```bash
npm install -g @aloth/olcli
```
Or use with `npx` without installation:
```bash
npx @aloth/olcli list
```
### For AI agents (via AgentSkills)
```bash
npx skills add aloth/olcli
```
## Quick Start
### 1. Authenticate
**Session cookie** (overleaf.com and self-hosted):
```bash
olcli auth --cookie "your_session_cookie_value"
```
**Email/password** (self-hosted without reCAPTCHA):
```bash
olcli auth --email "you@example.com" --password "your_password"
```
### 2. List Projects
```bash
olcli list
```
### 3. Pull, Edit, Push
```bash
olcli pull "My Thesis"
cd My_Thesis/
vim main.tex
olcli push
```
### 4. Compile PDF
```bash
olcli pdf
```
### 5. Or use native git commands
```bash
git clone overleaf::https://www.overleaf.com/project/
cd
# edit, commit, push — standard git workflow
git push
```
See [Git Remote Helper docs](docs/GIT-REMOTE.md) for details.
## Commands
All commands auto-detect the project when run from a synced directory (contains `.olcli.json`).
| Command | Description |
|---------|-------------|
| `olcli auth` | Set session cookie or login with email/password |
| `olcli whoami` | Check authentication status |
| `olcli logout` | Clear stored credentials |
| `olcli list` | List all projects |
| `olcli info [project]` | Show project details and file list |
| `olcli pull [project] [dir]` | Download project files to local directory |
| `olcli push [dir]` | Upload local changes to Overleaf |
| `olcli sync [dir]` | Bidirectional sync (pull + push) |
| `olcli upload [project]` | Upload a single file |
| `olcli download [project]` | Download a single file |
| `olcli delete [project]` | Delete a remote file or folder (alias: `rm`) |
| `olcli rename [project]` | Rename a remote file or folder (alias: `mv`) |
| `olcli compile [project]` | Trigger PDF compilation |
| `olcli pdf [project]` | Compile and download PDF |
| `olcli output [type]` | Download compile output files |
| `olcli zip [project]` | Download project as zip archive |
| `olcli comments list [project]` | List comments (`--status`, `--context`) |
| `olcli comments add ` | Add a comment to selected text |
| `olcli comments reply ` | Reply to a comment thread |
| `olcli comments resolve ` | Resolve a comment thread |
| `olcli comments reopen ` | Reopen a resolved thread |
| `olcli comments delete ` | Delete a comment thread |
| `olcli ignored [dir]` | List ignore patterns in effect |
| `olcli config set-url ` | Set self-hosted base URL |
| `olcli config set-cookie-name ` | Set session cookie name |
| `olcli config set-timeout ` | Set default HTTP timeout |
| `olcli check` | Show config paths and credential sources |
### Global Options
| Flag | Description |
|------|-------------|
| `--verbose` | Print HTTP requests and responses to stderr |
| `--base-url ` | Override Overleaf instance URL |
| `--cookie-name ` | Override session cookie name |
| `--timeout ` | Override HTTP timeout (default: 10000) |
## Sync Behavior
### Pull
- Downloads all files from Overleaf
- Skips local files modified after last pull (won't overwrite your changes)
- Use `--force` to overwrite local changes
### Push
- Uploads files modified after last pull
- Preserves nested folder structure
- Filters out LaTeX build artifacts and OS noise
- Use `--all` to upload all files, `--dry-run` to preview
### Sync
- Pulls remote changes, then pushes local changes
- Local modifications win if newer
- **Propagates local deletions** — use `--no-delete` to opt out
- Use `--dry-run` to preview without applying
#### How deletion propagation works
`olcli` records a manifest of remote files in `.olcli.json`. On next sync:
- File missing locally + still on remote → deleted on Overleaf
- File new locally → uploaded
- File modified locally → uploaded (local wins)
- File only on remote → downloaded
First-time syncs skip the deletion phase (no prior manifest to compare).
## Ignoring Files
### Three layers
| Layer | Source | Purpose |
|---|---|---|
| 1 | Built-in | LaTeX intermediates, OS noise, build dirs. Always on. |
| 2 | `.olignore` | Project-level patterns (gitignore syntax). |
| 3 | `.olignore.local` | Machine-specific patterns. |
Later layers override earlier ones. Negation (`!important.aux`) is supported.
### Special PDF rule
`X.pdf` is ignored only if `X.tex` (or `.ltx`) exists in the same folder.
### Inspecting and overriding
```bash
olcli ignored # list patterns in effect
olcli push --show-ignored # see what was skipped
olcli sync --no-default-ignore # only .olignore applies
olcli sync --no-ignore # upload everything
```
## Configuration
Credentials are checked in order:
1. `OVERLEAF_SESSION` environment variable
2. `.olauth` file in current directory
3. Global config: `~/.config/olcli-nodejs/config.json`
### Self-hosted Overleaf
```bash
olcli config set-url https://latex.example.org
olcli config set-cookie-name overleaf.sid
```
Or pass per-command: `olcli --base-url https://latex.example.org list`
### Timeout
```bash
olcli config set-timeout 60000 # persist
olcli --timeout 60000 pull "Big Thesis" # one-off
export OVERLEAF_TIMEOUT=60000 # env var
```
Precedence: `--timeout` > `OVERLEAF_TIMEOUT` > config > default (10000ms).
## Examples
```bash
# Daily thesis workflow
olcli pull "PhD Thesis" thesis && cd thesis
vim chapters/methods.tex
olcli sync && olcli pdf -o draft.pdf
# Quick PDF download
olcli pdf "Conference Paper" -o paper.pdf
# Upload figures
olcli upload figures/diagram.png
# arXiv submission prep
olcli output bbl -o main.bbl
olcli zip -o arxiv-submission.zip
# Backup all projects
for proj in $(olcli list --json | jq -r '.[].name'); do
olcli zip "$proj" -o "backups/${proj}.zip"
done
```
## Programmatic Usage (Library API)
`@aloth/olcli` exposes `OverleafClient` and all public interfaces as a library.
### Install
```bash
npm install @aloth/olcli
```
### Basic example
```ts
import { OverleafClient } from '@aloth/olcli';
const client = await OverleafClient.fromSessionCookie(cookie);
const projects = await client.listProjects();
const info = await client.getProjectInfo(projectId);
const zipBuf = await client.downloadProject(projectId);
const pdfBuf = await client.downloadPdf(projectId);
await client.uploadFile(projectId, null, 'main.tex', readFileSync('main.tex'));
const comments = await client.listComments(projectId, { status: 'open' });
```
### Available exports
```ts
import {
OverleafClient,
// Types
Project, ProjectInfo, FolderEntry, DocEntry, FileEntry,
CommentMessage, ProjectComment, CommentContext, CommentStatus,
ListCommentsOptions, AddCommentOptions, Credentials, SessionCookiePair,
// Config utilities
getBaseUrl, setBaseUrl, getSessionCookie, setSessionCookie,
getSessionCookieName, setSessionCookieName, getCsrf, setCsrf,
getLastProject, setLastProject, clearConfig, getConfigPath, saveOlAuth,
getTimeout, setTimeout, getPasswordCredentials, setPasswordCredentials,
clearPasswordCredentials, type PasswordCredentials,
// Ignore utilities
DEFAULT_IGNORE_PATTERNS, loadIgnore, shouldIgnore, buildTexSiblingSet,
IgnoreContext, LoadIgnoreOptions,
} from '@aloth/olcli';
```
## Further Documentation
- [MCP Server](docs/MCP.md) — AI assistant integration (Claude, Cursor, Windsurf)
- [Git Remote Helper](docs/GIT-REMOTE.md) — use Overleaf as a native git remote
## Troubleshooting
**Session expired** — Get a fresh cookie from the browser and run `olcli auth` again.
**Compilation fails** — Check the Overleaf web editor for detailed error logs (missing packages, syntax errors, missing bibliography files).
## Contributing
Contributions are welcome! Please open an issue or submit a pull request.
## License
MIT © [Alexander Loth](https://alexloth.com)