Hosted web editor
Open `editor.latexdo.org` to create a cloud project in the browser. The hosted editor stores projects by browser session and uses the cloud API for files, sharing, compilation, and PDF retrieval.
Complete product and maintainer reference
LatexDo is a LaTeX writing system made of a desktop editor, a local browser editor launched by a CLI, a public marketing and downloads site, and a Cloudflare-hosted editor backend. These docs explain the boundaries between those pieces and the workflows that keep them in sync.
System Overview
The core product lives in the `latexdo` repository. It contains the Electron desktop shell, the shared React and Monaco editor frontend, local file/project operations, LaTeX compilation through `latexmk`, PDF preview, diagnostics, Git tools, importers, and the source for the CLI and website assets that are synced downstream.
Source of truth rule: product behavior starts in `latexdo`. Published site/download files and hosted editor frontend builds are downstream artifacts unless a repository-specific backend or deployment file owns the behavior.
Quickstart
Open `editor.latexdo.org` to create a cloud project in the browser. The hosted editor stores projects by browser session and uses the cloud API for files, sharing, compilation, and PDF retrieval.
Install the `latexdo` command. It clones the app source into `~/.latexdo/app`, installs npm dependencies, starts Vite on localhost, and opens a browser.
Use the desktop app when you need local folders, `latexmk`, PDF preview, SyncTeX, terminal access, Git tools, DOCX import, or Markdown import.
curl -fsSL https://latexdo.org/install.sh | bash
latexdo doctor
latexdo
Product Matrix
| Capability | Desktop app | Local browser editor | Hosted editor |
|---|---|---|---|
| Project storage | Local folders selected through Electron dialogs. | `localStorage` browser workspace. | Container filesystem under `LATEXDO_DATA_ROOT`, keyed by browser session. |
| LaTeX compilation | `latexmk` with `pdflatex`, `xelatex`, or `lualatex`. | Not available. Shows a desktop-required diagnostic. | Cloud backend runs `latexmk` with no shell escape. |
| PDF preview | Available from local build output with PDF.js and SyncTeX. | No generated PDF. | Available after cloud compilation through the PDF API. |
| Terminal | Real project shell through `node-pty` with a pipe fallback. | Placeholder only. | Disabled. |
| Git | Status, stage, unstage, commit, diff, discard, history. | Disabled with explanatory fallbacks. | Disabled until auth and storage are hardened. |
| DOCX and Markdown import | Available through local import handlers. | Disabled. | Backend route exists, but the current cloud frontend adapter marks import disabled. |
| Collaboration links | Not available. Desktop tells users to use the hosted editor. | Not available. | Available through share tokens and presence heartbeats. |
User Guide
LatexDo is organized around a source-to-preview workflow. Open or create a project, edit `.tex` and `.bib` files in Monaco, choose the root `.tex` file and engine, compile, inspect diagnostics, then use the PDF preview and side panels to resolve paper-level issues.
The editor builds an index from project `.tex` and `.bib` files for completions, labels, bibliography entries, citation commands, and project-aware analysis.
Compiler diagnostics are parsed from `latexmk` output and enriched with source context. Additional checks inspect structure, citations, conference rules, reproducibility, acronyms, notation, and PDF compliance.
Reviewer mode can create anchored review threads. Rebuttal mode tracks reviewer comments, author answers, manuscript changes, and can generate a rebuttal letter from tracked items.
LatexDo includes a TikZ canvas, table-to-TikZ generation, equation and notation helpers, citation stubs, project search, history snapshots, and import helpers.
| Tool | What it checks |
|---|---|
| Conference checker | Margins, font size, abstract length, keywords, figure/table references, bibliography style, page limit, author information, anonymous review, image resolution, embedded fonts, compiler suitability. |
| Citation assistant | Missing citations, unused BibTeX entries, duplicate references, broken links, citation key suggestions, metadata gaps, old citations. |
| Structure assistant | Abstract shape, introduction structure, related-work length, reproducibility in methods, results discussion, conclusion claims. |
| Reproducibility | Code links, dataset links, license mentions, hyperparameters, hardware details, random seeds, evaluation metrics. |
| PDF compliance | Page count, unreferenced figures, uncited citations, citation-free sections, Type 3 fonts, abstract word count. |
Desktop App
The desktop app is an Electron shell around the shared React frontend. It exposes a secure preload API at `window.latexdo` and a terminal API at `window.terminalApi`. The renderer never reaches directly into Node APIs; project operations go through IPC handlers in `electron/main.ts`.
`electron/compiler.ts` searches for `latexmk`, preferring common
macOS paths such as `/Library/TeX/texbin/latexmk`. It creates an
isolated build directory under `.latexdo/build/job-
latexmk -pdf|-xelatex|-lualatex \
-g \
-synctex=1 \
-interaction=nonstopmode \
-file-line-error \
-halt-on-error \
-outdir=.latexdo/build/job-<uuid> \
main.tex
npm install
npm run dev
npm run typecheck
npm test
npm run build
npm run package
npm run dist
Web Editor
The shared frontend installs browser APIs when Electron does not provide `window.latexdo`. The runtime is selected by `VITE_LATEXDO_RUNTIME`. Without the cloud flag, the editor uses a browser workspace stored in `localStorage`. With `cloud`, it uses HTTP APIs served by `editor.latexdo.org`.
Stores projects in `latexdo.browser.workspace.v1` inside `localStorage`. It supports basic file and folder operations but cannot compile, run a shell, use Git, or import documents.
Stores session, client, and share token IDs in `localStorage`. It sends `x-latexdo-session`, `x-latexdo-client`, and `x-latexdo-client-name` headers to the backend.
The `editor.latexdo.org` repository deploys a Cloudflare Worker named `editor-latexdo-org`. Static assets come from `dist/`, and all `/api/*` requests are proxied to a Cloudflare Container running the Fastify backend. The Container image is built from `Dockerfile` and includes Node 22, `latexmk`, Pandoc, and TeX Live packages.
The current cloud backend has import routes for DOCX and Markdown, but the current cloud frontend adapter intentionally reports those features as unavailable. Treat them as backend-ready but not exposed in the hosted UI.
Command Line
The CLI installs one shell command. Running `latexdo` keeps a cached checkout of `https://github.com/latexdo/latexdo.git` in `~/.latexdo/app`, updates it unless disabled, installs npm dependencies when `package-lock.json` changes, starts Vite, and opens the localhost URL.
| Command | Purpose |
|---|---|
| `latexdo` or `latexdo open` | Start the local browser editor and open it. |
| `latexdo update` | Fetch the configured branch and install dependencies. |
| `latexdo doctor` | Print cache paths and check Git, Node, npm, curl, and `latexmk`. |
| `latexdo path` | Print the cached app path. |
| `latexdo reset` | Remove the cached app checkout and dependency state hash. |
| Variable | Default | Use |
|---|---|---|
| `LATEXDO_HOME` | `~/.latexdo` | Base cache directory. |
| `LATEXDO_APP_DIR` | `$LATEXDO_HOME/app` | Checkout location for the app source. |
| `LATEXDO_APP_REPO` | `https://github.com/latexdo/latexdo.git` | Source repository to clone and update. |
| `LATEXDO_APP_BRANCH` | `main` | Branch to check out and reset to. |
| `LATEXDO_HOST` | `127.0.0.1` | Local Vite bind host. |
| `LATEXDO_PORT` | `5173` | Preferred local port. The CLI scans upward if busy. |
| `LATEXDO_NO_OPEN` | `0` | Set to `1` to print the URL without opening a browser. |
| `LATEXDO_SKIP_UPDATE` | `0` | Set to `1` to use the cached checkout as-is. |
Website
The website repository is the published static site. The source version also lives under `latexdo/website`. The main app sync script builds the TypeScript website, copies the CLI install script and command into the website, formats the generated assets, and rsyncs the result to the website repository.
{
"schemaVersion": 1,
"product": "LatexDo",
"version": "0.1.0",
"publishedAt": "ISO timestamp",
"commit": "git sha",
"repository": "latexdo/latexdo",
"downloadsPage": "https://latexdo.org/downloads/",
"files": [
{
"id": "macos-arm64",
"platform": "macos",
"arch": "arm64",
"filename": "LatexDo-macos-arm64.dmg",
"sha256": "..."
}
]
}
The currently checked-in published website manifest has empty `files` and null version fields. That is expected before release artifacts are published by the release workflow.
Architecture
`latexdo` is the active development repository. It can run as an Electron desktop application or as a Vite web application. The hosted editor is a cloud deployment of the same frontend built with `VITE_LATEXDO_RUNTIME=cloud`, paired with a backend in `editor.latexdo.org`.
| Path | Owner | Purpose |
|---|---|---|
| `src/` | `latexdo` | React app, Monaco editor, panels, checks, runtime adapters, tests. |
| `electron/` | `latexdo` | Electron main process, preload bridge, compiler, terminal, imports, SyncTeX. |
| `cli/` | `latexdo` | Source for the published `latexdo` command and installer. |
| `website/` | `latexdo` | Source for the published marketing/downloads website. |
| `server/src/index.ts` | `editor.latexdo.org` | Fastify backend for cloud projects, files, imports, sharing, compile, PDF. |
| `src/worker.ts` | `editor.latexdo.org` | Cloudflare Worker entry point that serves assets and proxies `/api/*`. |
| `dist/` | `editor.latexdo.org` | Committed hosted editor frontend assets built from `latexdo`. |
Cloud API
Cloud API requests are JSON unless the PDF route returns `application/pdf`. Most routes require the `x-latexdo-session` header. Collaboration-aware project routes can also accept `x-latexdo-share-token`.
| Method | Route | Purpose |
|---|---|---|
| GET | `/api/health` | Returns `{ "ok": true }`. |
| POST | `/api/projects/open` | Open the current session project or create one. |
| POST | `/api/projects` | Create a project. Optional body: `{ "folderName": "Paper" }`. |
| GET | `/api/projects/:projectId/files` | Return the project file tree. |
| GET | `/api/projects/:projectId/files/content?path=main.tex` | Read a text file. |
| PUT | `/api/projects/:projectId/files/content?path=main.tex` | Write a text file with `{ "content": "..." }`. |
| PUT | `/api/projects/:projectId/files/blob?path=figure.png` | Write binary content with `{ "contentBase64": "..." }`. |
| GET | `/api/projects/:projectId/files/exists?path=main.tex` | Return whether a path exists. |
| POST | `/api/projects/:projectId/files` | Create a file or directory with `{ "relativePath": "...", "type": "file" }`. |
| POST | `/api/projects/:projectId/files/move` | Move a file or directory. |
| POST | `/api/compile` | Compile a project root file with `pdflatex`, `xelatex`, or `lualatex`. |
| GET | `/api/projects/:projectId/pdf?path=main.pdf` | Return a generated PDF. |
| POST | `/api/import/:kind` | Backend DOCX or Markdown import through Pandoc. `kind` must be `docx` or `markdown`. |
| GET/POST | `/api/projects/:projectId/share` | Read or create a project share token. |
| POST | `/api/shares/:token/open` | Open a shared project from a token. |
| POST | `/api/shares/:token/presence` | Heartbeat collaborator presence and current file. |
{
"projectId": "project-id",
"rootFile": "main.tex",
"engine": "pdflatex"
}
{
"ok": true,
"pdfPath": "main.pdf",
"durationMs": 1240,
"output": "latexmk output",
"diagnostics": [],
"error": null
}
Development
Use Node.js 20 or newer for the app, website, and cloud backend. The app CI uses Node.js 22, so match that locally when debugging build or native-module issues.
cd /Users/omar/Desktop/Github/latexdo
npm install
npm run dev
cd /Users/omar/Desktop/Github/latexdo
npm run web
cd /Users/omar/Desktop/Github/editor.latexdo.org
npm install
LATEXDO_DATA_ROOT=./storage/dev npm run server:dev
| Repository | Commands |
|---|---|
| `latexdo` | `npm run format:check`, `npm run lint`, `npm run typecheck`, `npm test`, `npm run test:coverage`, `npm run build`. |
| `latexdo.org` | `npm run typecheck`, `npm run build`, then ensure compiled `assets/site.js` is committed. |
| `editor.latexdo.org` | `npm run typecheck`, `npm run build`, `npm run dev`, or `npm run server:dev`. |
| `docs.latexdo.org` | `npm run typecheck`, `npm run build`, then open `index.html`. |
Run `npm run sync:downstream` from the main app repository after changes to CLI, website source, or hosted frontend behavior. The script syncs `../latexdo-cli`, `../latexdo.org`, and `../editor.latexdo.org` by default. Override target paths with `LATEXDO_CLI_REPO`, `LATEXDO_WEBSITE_REPO`, and `LATEXDO_EDITOR_REPO`.
Release And Deploy
The main app has two relevant workflows: `latexdo-ci` for validation and installer artifacts, and `latexdo-release` for publishing direct downloads to the website repository.
| Secret | Purpose |
|---|---|
| `LATEXDO_WEBSITE_TOKEN` | Write access to publish website downloads. |
| `MACOS_CERTIFICATE_P12` | Developer ID certificate as base64 or configured package link. |
| `MACOS_CERTIFICATE_PASSWORD` | Password for the macOS signing certificate. |
| `APPLE_API_KEY_P8` | Base64-encoded Apple notarization `.p8` content. |
| `APPLE_API_KEY_ID`, `APPLE_API_ISSUER`, `APPLE_TEAM_ID` | Apple API and team metadata for notarization. |
The current `editor.latexdo.org` repo is configured for Cloudflare Workers Builds. Build command: `npm run build`. Deploy command: `npx wrangler deploy`. If the build logs say Docker is unavailable, push a prebuilt image and update the container image in `wrangler.jsonc`.
Security
LaTeX compilation can execute complex toolchains and consume large amounts of CPU, memory, and disk. Treat compile services as untrusted-input execution environments.
The user runs compilation on their own machine against their own local TeX distribution. Electron renderer access is mediated through preload APIs and IPC handlers.
The container runs as a non-root user and the cloud compile command injects `-no-shell-escape` into engine commands. Compile timeout is 45 seconds, and output buffer is capped at 10 MB.
Before a broad public cloud launch, add authentication, per-user quotas, rate limits, abuse monitoring, reviewed memory/disk limits, durable storage design, and a clear project retention policy.
Backend project paths are normalized to relative paths, reject `..`, and are resolved under the project root before file operations. Project IDs and session/share tokens are constrained to safe character sets and lengths.
Troubleshooting
Install a TeX distribution and restart the app. On macOS, MacTeX normally provides `/Library/TeX/texbin/latexmk`.
The CLI checks the preferred port and scans upward when busy. Set `LATEXDO_PORT` or pass `--port` to choose a different starting point.
Add `CLOUDFLARE_ACCOUNT_ID` and a deploy-capable `CLOUDFLARE_API_TOKEN` to the Cloudflare Worker build configuration.
The checked-in manifest can be empty before release artifacts are published. Run the release workflow and ensure `LATEXDO_WEBSITE_TOKEN` is configured.
Git is intentionally disabled in the hosted editor. Use the desktop app for repository operations.
The backend compile timeout is 45 seconds. Reduce document complexity, remove expensive TikZ/pgfplots passes, or move the project to the desktop app for local compilation.
Maintenance
Update these docs whenever a command, API route, runtime capability, release artifact, or deployment requirement changes. The safest maintenance pattern is to update docs in the same branch as the product change, then verify that all documented commands still match `package.json`, workflow files, and runtime adapters.
This docs site is static, with browser behavior authored in TypeScript under `src/site.ts`. Run `npm run build`, then open `index.html` directly in a browser from the `docs.latexdo.org` repository.