Thanks for considering a contribution.
git clone https://github.com/hanlulong/overleaf-sync-now
cd overleaf-sync-now
python -m venv .venv && source .venv/bin/activate # or `.venv\Scripts\activate` on Windows
pip install -e .
overleaf-sync-now --versionAfter editing src/overleaf_sync_now/cli.py, the editable install picks up changes immediately — just rerun the CLI:
overleaf-sync-now status
overleaf-sync-now doctorTo install the changes back into your everyday uv tool install (so the Claude Code hook picks them up):
uv tool install --reinstall --from . overleaf-sync-nowThe unit test suite under tests/ covers the project resolver, marker handling, atomic-write concurrency, POSIX file perms, the version-match refresh decision, the zip-slip + recent-mtime guards in _extract_files, the cmd_hook exit-code contract, get_session auth/retry behavior, and save-cookie normalization. No external dependencies — just unittest (HTTP/cookie paths are monkeypatched):
python -m unittest discover testsTests must pass before opening a PR; CI (.github/workflows/ci.yml) runs them across Python 3.8–3.13. Anything touching _atomic_write_text, _extract_files, the resolver (_resolve_by_name, _autolink_resolve, _disambiguate_by_fingerprint), refresh_project, cmd_hook, the install/uninstall hook surgery, or the index format should add a test.
- Python 3.8+ compatible. Avoid 3.9+ syntax/stdlib (
match,|type unions,str.removeprefix/removesuffix,Path.is_relative_towithout a 3.8 fallback, etc.). - Standard library where possible. New runtime deps need a justification in the PR.
- Errors raised by
refresh_project/fetch_updates/download_zipshould be one of:AuthExpired,RateLimited, or aRuntimeErrorwith a user-actionable message including the path / URL / next step. - Anything written to disk should go through
_atomic_write_text(writes to.tmp+os.replace) — particularly~/.claude/settings.json. - Anything that reads cookies / makes HTTP calls should be skippable (try/except around imports of optional deps; cheap-existence checks before expensive operations).
- Hot paths (the hook, anything called from it) must avoid network calls when avoidable. Use the validation cache (
_cookies_recently_validated) rather than calling_validate_cookieswithuse_cache=False.
| Area | Why |
|---|---|
| macOS / Linux end-to-end testing | Developed on Windows. CI runs the install + unit-test matrix on Linux/macOS/Windows, but there's no real Overleaf round-trip (the suite is hermetic). |
| Self-hosted Overleaf / Server Pro | The BASE URL is hardcoded to https://www.overleaf.com. Needs a --base-url (or env var) and a way to flow it through every HTTP call. |
| Background poller | A daemon mode that polls Overleaf periodically and triggers Dropbox sync, for users who want fresh files without an active AI session. |
| PyPI publishing | Currently install is git-only. PyPI makes pip install overleaf-sync-now work for users who don't want uv. |
Standalone .exe build (PyInstaller) |
For users who don't want any Python tooling. Multi-platform build complexity. |
| Multi-account support | Cache currently holds one session. Switching accounts means clearing and re-auth. |
| Bash / zsh / PowerShell completion | Subcommand + flag completion. |
Small focused PRs are easier to review than large ones. If you're touching the auth chain or the install logic, please:
- Run
overleaf-sync-now doctorbefore and after your change and paste both outputs in the PR. - Bump
__version__insrc/overleaf_sync_now/__init__.py— the single source of truth;pyproject.tomlderives its version from it via[tool.setuptools.dynamic]. Also bumpCITATION.cff(a test pins the two together). - Add a CHANGELOG.md entry under a new version header.
- Bump
__version__insrc/overleaf_sync_now/__init__.py(single source) and theversion/date-releasedinCITATION.cff. - Update CHANGELOG.md with the date.
git tag v<version> && git push --tags.- CI runs the test + build matrix; users get the new version with
uv tool install --reinstall --refresh.