Work on Overleaf projects locally, with safe synchronization and native Jujutsu history.
简体中文 · Releases · Architecture · Agent skill
JujuLeaf brings an Overleaf project into a real local working directory. Use any editor or coding agent, keep recoverable local checkpoints with the embedded Jujutsu engine, and synchronize changes deliberately. JujuLeaf translates text edits back into Overleaf collaboration events instead of replacing whole files.
Important
JujuLeaf is pre-1.0 software built on private Overleaf APIs. Start with a non-critical project or keep a backup. v0.4.1-rc.3 is a cross-platform preview; the current stable v0.1.3 release provides a Linux AMD64 binary only.
- Your editor, your tools. Work in Neovim, VS Code, Zed, an IDE, or with a coding agent while collaborators remain in Overleaf.
- Safe synchronization. Local and remote changes are compared against a confirmed baseline; JujuLeaf stops on conflicts instead of silently overwriting work.
- Built-in local history. Checkpoint, undo, and redo through an embedded Jujutsu repository. A separate jj executable is not required.
- Native collaboration. Exact edits, tracked changes, comments, compilation, PDFs, project history, and live events use Overleaf collaboration features.
- Human and machine friendly. The default output is readable and colorful;
compact JSON is available for scripts, while
jujuleaf bridgeexposes a stable, versioned process protocol for long-lived integrations.
With cargo-binstall installed, install the current stable release:
cargo binstall --strategies crate-meta-data jujuleafThe stable v0.1.3 binary targets Linux AMD64 and is fully static, so it does not
depend on the host's glibc version. For unattended environments, add
--no-confirm.
Install or upgrade specifically to the release candidate:
cargo binstall --strategies crate-meta-data --force jujuleaf@0.4.1-rc.3
jujuleaf --versioncargo-binstall automatically selects the matching archive:
| Platform | Architecture | Rust target | Package |
|---|---|---|---|
| Linux | AMD64 | x86_64-unknown-linux-musl |
Fully static .tar.gz |
| Linux | ARM64 | aarch64-unknown-linux-musl |
Fully static .tar.gz |
| macOS | Apple Silicon | aarch64-apple-darwin |
Single-binary .tar.gz |
| macOS | Intel | x86_64-apple-darwin |
Single-binary .tar.gz |
| Windows | AMD64 | x86_64-pc-windows-msvc |
Static-CRT .zip |
macOS binaries use Apple system libraries, and the Windows executable uses
Windows system libraries. No separate jj, Git, OpenSSL, or SQLite installation
is required.
Download the archive for your target and SHA256SUMS from the
v0.4.1-rc.3 prerelease.
Linux and macOS archives contain jujuleaf; the Windows ZIP contains
jujuleaf.exe. Put that executable in a directory on your PATH.
JujuLeaf requires Rust 1.92 or newer:
cargo install --locked jujuleafThe executable contains a versioned, self-describing Agent Skill bundle. Run the guided terminal installer to detect local Agent commands and configuration directories, choose a project, current-directory, user, or custom installation, and then select one or more targets:
jujuleaf skill installUse ↑/↓ to move, Space to toggle targets, Enter to confirm, and Esc to cancel.
For the final confirmation, use ←/→ to choose, Enter to accept, or y/n
directly.
JujuLeaf supports Codex, Claude Code, Kimi Code CLI, Pi, Gemini CLI, GitHub
Copilot, Cursor, OpenCode, and the portable .agents/skills convention. It
writes each Agent's native directory, while keeping one standard SKILL.md
source. Codex also receives its optional agents/openai.yaml interface file.
Every choice is available as an argument for scripts and unattended setup:
# Install for two Agents in the nearest project root.
jujuleaf skill install --agent codex,claude-code --scope project --yes
# Install in native Agent directories under the current directory.
jujuleaf skill install --agent kimi-code --scope current --yes
# Treat another directory as a shared skills root.
jujuleaf skill install --agent portable --to ./agent-skills --yesInspect detected Agents and manage every registered installation:
jujuleaf skill detect
jujuleaf skill status
jujuleaf skill update
jujuleaf skill uninstallUpdates compare file digests before writing. JujuLeaf refuses to overwrite local
changes unless --force is supplied, in which case it creates a timestamped
backup first. Use --raw, explicit target arguments, --yes, and optionally
--dry-run for non-interactive automation.
Sign in, find a project, and clone it into a new or empty directory:
jujuleaf login --preset overleaf
jujuleaf projects
jujuleaf clone PROJECT_ID paper
cd paper
jujuleaf status
jujuleafThe login command opens Chrome or Chromium and saves the authenticated session locally. After cloning, JujuLeaf records the project ID and profile in the workspace. From that directory or any child directory, commands automatically use the current project:
jujuleaf files
jujuleaf read main.tex --content-only
jujuleaf compile
jujuleaf compile --log-output output.logOverleaf's compile endpoint returns only after the server-side build finishes.
JujuLeaf then downloads output.log and parses its diagnostics. The default
command does not create a local log file; use --log-output PATH to save one
or --show-log to include it in the command output.
Edit files with your usual tools, record a local checkpoint, then synchronize:
jujuleaf checkpoint -m "rewrite introduction"
jujuleaf syncUse this for changes that should appear in Overleaf as ordinary edits:
jujuleaf sync
# Edit files locally.
jujuleaf status
jujuleaf checkpoint -m "update experiment results"
jujuleaf syncA one-shot sync pulls remote changes and then pushes safe local changes. Use jujuleaf sync --watch to keep synchronizing in the foreground.
Use this when collaborators should accept or reject your changes in Overleaf:
jujuleaf sync
jujuleaf begin -m "rewrite the introduction"
# Edit files locally.
jujuleaf review diff
jujuleaf review submit
jujuleaf review statusAfter collaborators resolve the tracked changes in Overleaf:
jujuleaf review finishJujuLeaf keeps the review anchored to its synchronized baseline and reports foreign or partially resolved changes before closing it.
| Goal | Command |
|---|---|
| List projects | jujuleaf projects |
| Inspect project files | jujuleaf files |
| Read a document | jujuleaf read main.tex --content-only |
| Search a project snapshot | jujuleaf search "bibliography" |
| Replace exact text | jujuleaf replace main.tex --old "draft" --new "final" |
| Submit one tracked edit | jujuleaf suggest main.tex --old "draft" --new "final" |
| View comment threads | jujuleaf threads |
| Integrate an external worker | jujuleaf bridge describe, jujuleaf bridge comments watch |
| Install or update the Agent Skill | jujuleaf skill install, jujuleaf skill update |
| Compile and inspect diagnostics | jujuleaf compile |
| Download the compiled PDF | jujuleaf pdf -o paper.pdf |
| Compare local and remote state | jujuleaf status |
| Pull, push, or synchronize | jujuleaf pull, jujuleaf push, jujuleaf sync |
| Inspect and resolve conflicts | jujuleaf conflict list, jujuleaf conflict show PATH, jujuleaf conflict resolve PATH |
| Inspect local history | jujuleaf local log, jujuleaf local show REVISION, jujuleaf local diff |
| Show the current commit graph | jujuleaf |
| Share through Git | jujuleaf git remote add origin URL, jujuleaf git fetch, jujuleaf git push |
| Check setup and authentication | jujuleaf doctor, jujuleaf auth status |
| Restore local history | jujuleaf undo, jujuleaf redo |
Run jujuleaf --help or jujuleaf COMMAND --help for the complete command list and examples.
Exact-text commands reject ambiguous matches by default. Locate the text first, preview the collaboration operations, and then apply the edit:
jujuleaf locate main.tex --text "Related work"
jujuleaf replace main.tex \
--old "Related work" \
--new "Background and related work" \
--dry-run
jujuleaf replace main.tex \
--old "Related work" \
--new "Background and related work"For repeated text, select a match with --occurrence or --position, or explicitly apply the edit to every match with --all. Positions use CodeMirror UTF-16 units, matching Overleaf.
Named profiles keep accounts and endpoints separate:
jujuleaf login --profile official --preset overleaf
jujuleaf login --profile lab --base-url https://overleaf.example.org
jujuleaf login --profile cstcloud --preset cstcloud
jujuleaf profile list
jujuleaf profile use official
jujuleaf --profile lab projectsA clone remembers the profile that created it, so normal commands do not need a repeated --profile option. Authentication data stays in the user configuration directory and is never written into the project.
Human-readable output is the default. Colors are enabled only for an interactive terminal.
jujuleaf status
jujuleaf status --no-color
NO_COLOR=1 jujuleaf status
jujuleaf projects --raw
jujuleaf projects --prettyBoth --raw and --pretty produce ANSI-free JSON, so an additional --no-color is not needed. Agents can use the bundled SKILL.md as a compact command guide.
--raw follows JujuLeaf's internal command output and may grow with the CLI.
External workers that need a compatibility contract should use the dedicated
bridge instead:
jujuleaf bridge describe
jujuleaf bridge comments list --protocol 1
jujuleaf bridge comments get THREAD_ID --protocol 1
jujuleaf bridge comments watch --protocol 1Bridge commands always emit compact, ANSI-free JSON. comments.watch emits
NDJSON and starts with an authoritative comment snapshot before live events.
It periodically emits another full snapshot, reconnects automatically, and
uses events only as wake-up notifications. A worker should replace its known
state on comments.snapshot and fetch comments.get after a comment.event.
The bridge normalizes thread messages, multi-range anchors, detached anchors, document paths, UTF-16 source and visible ranges, and content hashes. It does not expose Overleaf's private event names or history-OT payloads. Every record contains protocol identity and version; failures use stable error codes and a non-zero process exit status. See the bridge protocol for the complete contract and stream lifecycle.
For each document or uploaded file, JujuLeaf compares the local copy and the current Overleaf copy with the last confirmed checkpoint:
| Local state | Remote state | Result |
|---|---|---|
| Unchanged | Changed | Pull the remote version |
| Changed | Unchanged | Push the local version |
| Changed | Changed | Stop and report a conflict |
| Unchanged | Unchanged | Do nothing |
Remote versions and content hashes are checked again before updates are sent and after confirmation. New files and destructive operations are handled explicitly; conflicting remote content is preserved for manual recovery.
Pull and push record unresolved conflicts without overwriting the working copy. Inspect both sides, merge if needed, and make the choice explicit:
jujuleaf conflict list
jujuleaf conflict show main.tex
jujuleaf conflict resolve main.tex --ours
jujuleaf conflict resolve main.tex --theirs
jujuleaf conflict resolve main.tex --merged ./main.merged.tex--ours keeps the local file, --theirs accepts the preserved remote copy,
and --merged installs a file you prepared. Resolution creates a recoverable
Jujutsu checkpoint and advances the observed remote baseline; the next push
still verifies the live remote state before writing.
JujuLeaf exposes the embedded Jujutsu operation history directly:
jujuleaf local log
jujuleaf local show OPERATION_ID
jujuleaf local diff
jujuleaf local restore OPERATION_IDlocal show accepts an operation or commit ID prefix, or @ for the current
operation. local restore restores that tree as a new operation, so the restore
itself can be undone and does not erase later history. JujuLeaf embeds jj-lib;
installing or invoking the separate jj executable is not required.
Inside a clone, running jujuleaf without a subcommand snapshots pending
working-copy changes and displays a compact, colored first-parent commit graph,
similar to the default jj view. It shows up to 10 commits; use local log for
operation history and jujuleaf --raw for the full structured commit data.
The compact graph uses jj-style 8-character display IDs. Elsewhere,
human-readable output abbreviates Jujutsu operation, commit, and change IDs to
a 12-character prefix. These prefixes can be passed back to local show and
local restore; if one is ever ambiguous, JujuLeaf asks for a longer prefix.
--raw and --pretty JSON always retain the complete IDs.
Every JujuLeaf clone is already backed by a bare Git repository inside .jj.
Configure and use it through JujuLeaf without creating a second .git working
tree:
jujuleaf git root
jujuleaf git remote add origin git@github.com:OWNER/REPOSITORY.git
jujuleaf git push --branch main
jujuleaf git fetch --remote origin
jujuleaf git remote listgit push snapshots pending files and publishes the current Jujutsu
working-copy commit under the selected branch (default: main). It uses the
last fetched remote position as a lease, so an unexpected remote update is
rejected instead of overwritten. Run git fetch first when updating an
existing branch. Fetch imports remote branches and tags into Jujutsu history;
it does not replace the working copy.
Remote configuration also supports remote remove, remote rename, and
remote set-url. Use -R PATH when running outside the clone. Create the
workspace with jujuleaf clone, not jujuleaf git clone or git init. A
separate jj executable is unnecessary; network fetch and push use the system
Git executable and its normal SSH or credential-helper configuration.
Create .jujuleafignore at the clone root to prevent matching generated or
private files from being discovered for upload or first tracked by Jujutsu. It
uses gitignore syntax:
/build/
*.aux
*.log
.envThe rule does not untrack a file that was already checkpointed or an Overleaf
entity that is already synchronized.
.jj, .git, .jujuleaf, and .jujuleafignore are always private and are
never considered for upload.
jujuleaf auth status
jujuleaf doctor
jujuleaf doctor --offline
jujuleaf auth logoutdoctor checks the selected profile, credential permissions, browser,
endpoint, project binding, Jujutsu workspace, and pending sync state. The
offline form skips the network check. auth status never prints the cookie;
auth logout removes the selected local profile and its credentials.
- v0.4.1-rc.3 is a macOS, Windows, and Linux ARM64 preview; use it first on a non-critical project and report platform-specific issues.
- Browser login requires Chrome, Chromium, or Edge, unless an existing session cookie is supplied.
- Synchronization is foreground-only; there is no background service.
- Overleaf private APIs may change without notice, especially on self-hosted installations.
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets --lockedSee the architecture document for protocol, storage, conflict, and review details.
JujuLeaf is inspired by overleaf-cli and builds on ideas from the wider Overleaf command-line community.
JujuLeaf is an independent, unofficial project and is not affiliated with or endorsed by Overleaf or the Jujutsu project.
