Portable LaTeX build and sync toolkit for a split workspace layout.
日本語版は README.ja.md を参照してください。
Clone this repo anywhere. All runtime directories (projects/, .secrets/) live inside the cloned directory and are gitignored.
<anywhere>/latex-devkit/ # git clone git@github.com:YosukeIida/latex-devkit.git
projects/
<project>/ # each TeX manuscript (not committed)
.secrets/.olauth # localleaf cookie (not committed)
WORKSPACE_ROOT defaults to the latex-devkit directory itself. Override if needed:
make up WORKSPACE_ROOT=/some/other/path- Build infrastructure lives in
latex-devkit(this repo). - Manuscripts live in
projects/*inside the workspace root (gitignored). - Local compile uses a long-running Docker service (
texd) based on a prebuilt TeX Live image. - Overleaf sync is primarily git-remote based (
origin+ optionaloverleaf). localleaf (lleaf)remains available as a fallback.
- Docker / Docker Compose
uv(forlleaffallback commands)fswatch(optional, for watch mode)
- Default image repo:
texlive/texlive - Default version tag:
TL2024-historic - Effective image:
texlive/texlive:TL2024-historic - This uses a public image from Docker Hub and avoids local
install-tlbuild overhead. - You can override only the version tag at runtime:
make up TEXLIVE_IMAGE_TAG=TL2024-historic- You can also override repo + tag together:
make up TEXLIVE_IMAGE_REPO=texlive/texlive TEXLIVE_IMAGE_TAG=TL2024-historicApple Silicon note:
- If pull/run fails due to platform mismatch, try:
DOCKER_DEFAULT_PLATFORM=linux/amd64 make upDefaults to <project>/output/. A project's latexmkrc wins if it sets $out_dir.
Builds read rc files as latexmk -norc -r latexmk/defaults.latexmkrc -r <project>/latexmkrc. latexmk processes -r in command-line order, so the project's latexmkrc, read last, can override the defaults.
- Defaults live in
latexmk/defaults.latexmkrc($out_dir, plus theBIBINPUTSsetting it requires). compose.yamlmounts it read-only at/etc/latex-devkit/defaults.latexmkrc. The mount is resolved relative to the compose file, so overridingWORKSPACE_ROOTdoes not break it.
Engine choice (platex / lualatex / …) and $force_mode are per-project decisions and are deliberately not in the defaults.
To override explicitly, pass an out dir as the second argument to bin/latexmk-docker; it becomes -outdir=, which beats latexmkrc.
Note: The long-running
texdcontainer (frommake up) keeps the mount set it was created with, so runmake down && make uponce after adding this mount.make build-localstarts a throwaway container viadocker compose run --rmevery time and needs no restart.
Run these from latex-devkit.
make pull-image
make up
make ps
make build-local PROJ=my-paper MAIN=main.tex
make watch-local PROJ=my-paper MAIN=main.tex
make downBoth the Zed and VS Code templates are designed so that builds run only when you press Cmd+S, never automatically on autosave.
- Zed: pressing
Cmd+Son a.texfile spawns theLaTeX Buildtask. Even with Zed's autosave enabled,Cmd+Sitself does not fire on every keystroke, so builds do not run during normal editing. - VS Code:
latex-workshop.latex.autoBuild.runis pinned to"never", andCmd+Sis bound tolatex-workshop.build. Builds are triggered solely byCmd+S, regardless of whether autosave is on or off.
- Start the daemon container:
make up- Install project settings template:
make vscode-init PROJ=my-paper-
Add
Cmd+Skeybinding (user-scope): VS Code does not support workspace-local keybindings, so append the snippet printed at the end ofmake vscode-initto your User keybindings (~/Library/Application Support/Code/User/keybindings.json). The content matchestemplates/vscode/keybindings.json. -
Open
<WORKSPACE_ROOT>/projects/my-paperin VS Code and pressCmd+Son a.texfile to build.
The configured tool calls latex-devkit/bin/latexmk-docker, which compiles inside texd via docker compose exec.
- Start the daemon container:
make up- Install project settings template:
make zed-init PROJ=my-paperThis deploys three files: .zed/settings.json, .zed/keymap.json, and .zed/tasks.json. Cmd+S is bound to the LaTeX Build task.
-
Open
<WORKSPACE_ROOT>/projects/my-paperin Zed. PressingCmd+Son a.texfile runslatexmk-docker-skim; after the build, Skim is brought to the foreground and jumps to the corresponding line. -
Skim inverse search (Skim → Zed jump): Skim > Preferences > Sync > PDF-TeX Sync support > Custom
Field Value Command openArguments zed://file"%urlfile":%lineThen
Shift+⌘+clickin Skim jumps to the corresponding line in Zed.
This repository bundles a Claude Code skill for operating latex-devkit at
skills/latex-devkit/SKILL.md. It uses the layout gh skill recognizes, so you can
inspect it before adopting it:
gh skill preview YosukeIida/latex-devkit latex-devkitHow you install it is up to you. If you manage your dotfiles with git or Nix, prefer your existing vendor/symlink mechanism. Otherwise:
cp -r skills/latex-devkit ~/.claude/skills/Restart Claude Code and /latex-devkit becomes available.
Inside each manuscript repo:
origin: GitHub (primary)overleaf: Overleaf Git remote (optional)
Push helper:
make git-push-all PROJ=my-paper BRANCH=mainThis pushes to origin first, then overleaf if configured.
Cookie location defaults to:
<WORKSPACE_ROOT>/.secrets/.olauth
Commands:
make lleaf-login
make lleaf-pull PROJ=my-paper
make lleaf-push PROJ=my-paper
make lleaf-download PROJ=my-paperDefaults to <WORKSPACE_ROOT>/projects/. To use an arbitrary location (e.g. a dedicated Overleaf directory), pass PROJECTS_DIR=.
make lleaf-pull PROJ=my-paper PROJECTS_DIR=~/workspace/overleaf-projects
make lleaf-push PROJ=my-paper PROJECTS_DIR=~/workspace/overleaf-projectsTo avoid passing it every time, add it to .envrc:
echo 'export PROJECTS_DIR=$HOME/workspace/overleaf-projects' >> .envrc
direnv allow# Overleaf name: "My Paper 2026", local directory name: "my-paper"
make lleaf-pull PROJ=my-paper NAME="My Paper 2026"See docs/first-import.md for the full first-time setup.