A lightweight Python CLI that syncs accepted LeetCode submissions into an existing GitHub repository.
It uses:
- LeetCode GraphQL with your local LeetCode session cookies.
- GitHub API commits using a GitHub token.
- A TOML config file for non-secret settings.
- A git-ignored
.envfile for secrets.
- How It Works
- Install
- Quick Start: Try It Safely
- Configure
- Getting LeetCode Cookies
- Getting A GitHub Token
- Commands
- Repository Output
- Behavior
- Uninstall Or Reset
- Tests
LeetCode GraphQL
|
v
Accepted submissions
|
v
Sync planner
|
v
Generated solution files + metadata
|
v
GitHub Commit API
The tool reads accepted submissions from LeetCode using your browser session cookies, then compares them against the generated files already present in the configured GitHub repository.
Before writing anything, the sync planner builds a file-level plan: create, update, or skip. sync --dry-run prints that plan without creating a commit. A real sync uses the GitHub Commit API to write one all-or-nothing commit to the configured branch.
After the first backfill, sync becomes incremental automatically. The tool reads existing metadata.json files from the target repository, finds the latest synced submitted_at_unix, applies a one-day lookback buffer, and asks LeetCode only for recent submissions. sync --full-sync bypasses this optimization when you want a complete rescan.
User-owned notes are protected: notes.md is created once if missing, then never overwritten by the tool. Secrets stay local in .env and are never written into generated files.
macOS/Linux:
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"Windows PowerShell:
py -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e ".[dev]"Windows Command Prompt:
py -m venv .venv
.venv\Scripts\activate.bat
pip install -e ".[dev]"Use dry-run mode before writing anything to GitHub.
- Make sure your target GitHub repository already exists and has a
mainbranch. - Activate the local environment:
macOS/Linux:
source .venv/bin/activateWindows PowerShell:
.\.venv\Scripts\Activate.ps1Windows Command Prompt:
.venv\Scripts\activate.bat- Edit
leetcode-sync.tomlwith your GitHub owner, repo, and branch. - Create
.env.
macOS/Linux:
cp .env.example .envWindows PowerShell:
Copy-Item .env.example .envWindows Command Prompt:
copy .env.example .env- Add your LeetCode cookies and GitHub token to
.env.- Need LeetCode cookies? See Getting LeetCode Cookies.
- Need a GitHub token? See Getting A GitHub Token.
- Check that authentication works:
leetcode-sync status- Preview the sync without writing to GitHub:
leetcode-sync sync --dry-run- If the preview looks right, run the real sync:
leetcode-sync syncEdit leetcode-sync.toml:
[github]
owner = "your-github-username"
repo = "your-target-repo"
branch = "main"Create .env from .env.example:
macOS/Linux:
cp .env.example .envWindows PowerShell:
Copy-Item .env.example .envWindows Command Prompt:
copy .env.example .envFill in:
LEETCODE_SESSION: your LeetCode session cookie.CSRFTOKEN: your LeetCode CSRF token, if present.GITHUB_TOKEN: a GitHub token with read/write contents access to the target repository.
Do not commit .env. This project ignores it by default.
The CLI reuses your existing browser login. You do not need to type your LeetCode password into this tool.
- Go to leetcode.com and make sure you are logged in.
- Open DevTools:
- macOS:
Cmd + Option + I - Windows/Linux:
Ctrl + Shift + I
- macOS:
- Go to the Application tab.
- In the left sidebar, open Storage → Cookies → https://leetcode.com.
- Find these cookie names:
LEETCODE_SESSIONcsrftoken
- Copy their Value fields into
.env:
LEETCODE_SESSION=paste_the_LEETCODE_SESSION_value_here
CSRFTOKEN=paste_the_csrftoken_value_here
GITHUB_TOKEN=paste_your_github_token_here- Enable developer tools if needed: Safari → Settings → Advanced → Show features for web developers.
- Open LeetCode and make sure you are logged in.
- Open Web Inspector.
- Look under storage or cookies for
leetcode.com. - Copy
LEETCODE_SESSIONandcsrftokeninto.env.
Treat LEETCODE_SESSION like a password. Anyone with it can act as your logged-in LeetCode session. If sync stops working later, your LeetCode session probably expired; copy a fresh cookie value from your browser.
The CLI uses a GitHub token to create commits through the GitHub API.
Use a fine-grained personal access token:
- Go to GitHub Personal Access Tokens.
- Click Generate new token.
- Choose Fine-grained token.
- Set Repository access to only your LeetCode sync repository.
- Under Repository permissions, set:
- Contents: Read and write
- Metadata: Read-only
- Generate the token and copy it.
- Put it in
.env:
GITHUB_TOKEN=github_pat_your_token_hereThis token does not need Actions, Issues, Pull Requests, Administration, or full account access. Treat it like a password and never commit it.
Check setup:
leetcode-sync statusRun full setup diagnostics:
leetcode-sync doctorShow non-secret config and secret presence:
leetcode-sync config showPreview changes without writing to GitHub:
leetcode-sync sync --dry-runSync accepted submissions:
leetcode-sync syncAfter the first backfill, plain sync automatically uses repository metadata to fetch only recent submissions, with a one-day lookback buffer.
Sync submissions since a date:
leetcode-sync sync --since 2026-01-01Force a complete LeetCode rescan:
leetcode-sync sync --full-syncCreate starter local files in another directory:
leetcode-sync initSynced files are written to the target GitHub repository like this:
problems/
0001-two-sum/
solution.py
solution.java
metadata.json
notes.md
solution.* and metadata.json are generated. notes.md is created once and never overwritten.
- Only Accepted submissions are synced.
- The latest accepted submission is kept per problem and language.
- Multiple languages for the same problem are preserved.
- The first sync performs a full backfill; later syncs automatically use
metadata.jsontimestamps to reduce LeetCode API calls. - Re-running sync is idempotent and creates no commit when nothing changed.
sync --dry-runprints planned creates, updates, and skips without writing.sync --full-syncbypasses incremental mode and scans all accepted submissions.doctorvalidates setup and reports actionable failures.config showprints config and whether secrets are set without printing secret values.syncandsync --dry-runfinish with a concise summary showing repo, mode, fetched submissions, planned files, and commit status.- GitHub writes are all-or-nothing through a single commit.
- Secrets are redacted from error messages.
Local cleanup is manual and non-destructive:
macOS/Linux:
rm -rf .venv .pytest_cache
rm -f .envWindows PowerShell:
Remove-Item -Recurse -Force .venv, .pytest_cache
Remove-Item .envWindows Command Prompt:
rmdir /s /q .venv
rmdir /s /q .pytest_cache
del .envTo remove synced files from GitHub, delete them in the target repository yourself so you can review exactly what will be removed.
pytestRun the full local verification suite:
ruff check src tests
mypy
pytest