Skip to content

Repository files navigation

ByeTex

A LaTeX → Typst converter built for the AI era.

ByeTex pairs a fast, deterministic core with a native agent loop. The core does the reproducible heavy lifting — no LLM inside, no network, no guessing — and for the last mile it can't finish alone, it hands off to an AI agent with surgical, source-mapped repair instructions. The Typst it emits is good enough to trust: hand-rolled native math and class-faithful layout. It works best on academic papers today — where its fidelity is tuned — and the approach generalizes outward.

curl -fsSL https://raw.githubusercontent.com/zeyuyang42/ByeTex/main/install.sh | sh
byetex convert ./my-paper --project     # a folder, an arXiv tarball, or a single .tex
typst compile my-paper.typst-project/main.typ

Math is hand-rolled to native, editable Typst — not delegated to an external engine, not rasterised to images:

\begin{align}
  \mathcal{L}(\theta) &= \mathbb{E}_{x \sim p_{\text{data}}}\bigl[\log p_\theta(x)\bigr] \\
                      &\leq \sum_{i=1}^{n} \alpha_i \|\nabla f(x_i)\|_2^2
\end{align}
$ cal(L)(theta) &= bb(E)_(x tilde.op p_("data"))[log p_(theta)(x)] \
 &<= sum_(i=1)^(n) alpha_i ||nabla f(x_i)||_2^2 $

LaTeX original next to the ByeTex-converted Typst render

arXiv:2605.31499 — two-column IEEE-style layout, title block, abstract, vector figure and body text carried across. The dropped author emails and the heading style are real, current gaps.

New here? docs/getting-started.md is a guided tour. CONTRIBUTING.md covers the dev loop (TDD, the acceptance and fidelity gates), fetching the corpus, and how to add a repair skill.

What it won't do. TikZ pictures become a marked placeholder (Typst has no TikZ; use cetz or embed an image), .eps figures become a grey box because Typst can't read EPS, and page density often differs from the LaTeX original. Nothing is dropped silently — every gap is a structured warning in warnings.json.

Why ByeTex

  • Natively AI-in-the-loop. Not a wrapper around an LLM — a deterministic tool designed to be finished by one. When the output doesn't compile, byetex diagnose maps every Typst error back to the exact LaTeX fragment that caused it and names the repair skill that fixes it: the agent gets a worklist, not a stack trace. It ships as an agent-first CLI, 14 bundled repair skills, and an AGENTS.md cold-start — drop it into Claude Code or Cursor with no glue.
  • Best-in-class math. ByeTex hand-rolls LaTeX → Typst math instead of delegating to an external engine — ~450 symbols/operators, coverage gated against the entire KaTeX command set, emitting native, editable Typst math (not images). Hand-rolling wins on fidelity: correct accents, no split digits, real Typst you can keep editing.
  • Deterministic & pure. The core is a pure function — same input, same output, every time, with no model inside the binary. The AI only touches clearly-marked edges. That's what makes the loop trustworthy: AI leverage without AI unpredictability where it counts.
  • Fidelity, measured. Beyond "it compiles": a per-class StyleProfile (NeurIPS, ICML, ICLR, IEEE, ACM, LNCS, …) reproduces title/abstract/heading styling, and a vision agent grades the render against an explicit rubric. Compile-rate is the gate; visual fidelity is the driver.
  • Never hard-fails. Anything ByeTex can't translate becomes a visible placeholder plus a structured warning — it always produces usable output and exits 0, so a pipeline never breaks on a surprise.
  • Real-project aware. Multi-file \input, asset copying, .bib preprocessing, and macro pre-scan across every .tex/.sty/.cls — it converts real arXiv tarballs, not just toy single files.

How it works

A conversion is a single deterministic forward pass — there is no intermediate IR, and it never hard-fails:

.tex ─┐
      ▼
  parse      tree-sitter-latex → concrete syntax tree                 parser.rs
      ▼
  prepass    harvest the doc class, \newcommand/\def/\newif, title,
             authors, abstract, \label/\ref targets, bib keys         emit.rs::prepass_collect
      ▼
  emit       single forward walk; each node dispatched to a
             specialized emitter — math, tables, figures, sections,
             bibliography, … (15 emit/ submodules)                    emit.rs + emit/*.rs
      ▼
  finish     prepend a self-contained neutral preamble + a per-class
             StyleProfile (title / abstract / heading sizes)          emit/preamble.rs, style_profile.rs
      ▼
  project    --project: copy assets, preprocess .bib, resolve
             \input                                                    project.rs
      ▼
 .typ  +  warnings.json   (+ agent_brief.md, + diagnostics.json)

Anything outside the supported subset degrades gracefully: the construct becomes a visible placeholder (e.g. #text(red)[\chemfig…]) plus a structured warning — never a crash. byetex convert exits 0 even with warnings, so callers inspect the sidecar, not the exit code.

Agent-in-the-loop

ByeTex does the deterministic majority of the work and hands the residual off to an external AI agent (Claude Code, Cursor, …) over two feedback loops. No model runs inside the binary — ByeTex stays a pure tool; the agent drives.

1. Compile-repair loop — make it compile.

byetex diagnose paper.tex      # convert → typst compile → map each error back to its
                               # LaTeX fragment + a repair skill
                               #   → paper.typ + paper.diagnostics.json

diagnostics.json is a content-anchored source map: each typst error carries the originating LaTeX fragment and a skill_name. The agent reads the skill (byetex skills read <name>), edits paper.typ, and re-runs typst compile until clean. (Don't re-run diagnose mid-edit — it re-converts and overwrites your edits.)

2. Visual-fidelity loop — make it look right.

Rasterize the rendered PDF, then have a vision agent grade it against an explicit rubric (docs/fidelity-rubric.md) — title/abstract styling, citation forms, float placement, page density — emitting a per-dimension verdict. Findings roll up into the ranked docs/fidelity-backlog.md. This loop catches typography and layout defects that compile-only and word-recall metrics are blind to.

If you're an agent, start with AGENTS.md — the cold-start orientation.

What it converts

A condensed view; see docs/architecture.md and docs/conversion-logic.md for the exhaustive per-command list.

  • Document classesarticle/report/book, IEEEtran/IEEEconf, acmart, revtex4-*, elsarticle, llncs/svmult (Springer), and NeurIPS/ICML/ICLR (detected via style packages). ByeTex emits a self-contained neutral preamble that compiles on stock Typst with no @preview imports; the detected class drives a per-class StyleProfile (title size/weight/rules, abstract style + in-column placement, heading sizes, citation form, bibliography style, body font).
  • Sectioning & inline — every heading level incl. starred forms; emphasis, \texttt, sub/superscripts, \textcolor, links (\href/\url), boxes, text symbols.
  • Listsitemize, enumerate, description.
  • Math — every AMSMath display environment + starred variants, the matrix family, subequations, inline $…$ / \(…\) / \[…\]; ~450 symbols/operators, full Greek, \mathbb/\mathcal/\mathfrak/\mathscr, accents, extensible arrows, and layout primitives. Hand-rolled — not delegated to an external math engine.
  • Tablestabular/array/tabularray/tabularx with full column specs, booktabs rules, \multicolumn/\multirow/\makecell.
  • Figures & floatsfigure/table/algorithm, wrapfigure (degrades to a standard float), \includegraphics + \caption + \label, multi-caption subfigure grids via #subpar.grid.
  • Theorems — built-in kinds plus user kinds harvested from \newtheorem/\newtcolorbox/ \newmdenv.
  • Code listingslstlisting/verbatim/minted/\verb#raw.
  • References & citations\label/\ref/\eqref/\cref/\Cref; natbib/biblatex \cite/\citet/\citep, .bib preprocessing for Hayagriva, .bbl fallback, and \bibliographystyle mapping.
  • Custom macros\newcommand/\renewcommand/\def/\newcommandx/\newif, pre-scanned from every .tex/.sty/.cls in the project tree before conversion.

Anything else produces a structured warning categorised as unsupported_command, unsupported_environment, drop_only, tikz, custom_macro, ambiguous_math, or needs_manual_review.

Install

The byetex binary is the same across channels; the Claude Code plugin (which bundles the repair skills) is a separate artifact that needs the binary on PATH.

# Claude Code plugin — bundles the repair skills.
claude plugin marketplace add zeyuyang42/ByeTex
claude plugin install byetex@byetex

# Install script — prebuilt binary → ~/.local/bin.
curl -fsSL https://raw.githubusercontent.com/zeyuyang42/ByeTex/main/install.sh | sh

# From source via cargo (needs Rust 1.84+).
cargo install --git https://github.com/zeyuyang42/ByeTex byetex

Self-contained binaries are attached to each release for macOS (arm64/x86_64), Linux musl (arm64/x86_64), and Windows x86_64 — each archive bundles the byetex binary and the skills/ directory; verify against SHA256SUMS. See packaging/README.md and docs/plugin-setup.md (Claude Code / Cursor).

CLI

The byetex binary's subcommands are the surface. convert is the workhorse; diagnose is the headline path when the goal is "make it compile".

# Convert a LaTeX project FOLDER (recommended for real papers): auto-detects the entry
# .tex, pre-scans every .tex/.sty/.cls for \newcommand/\def, then converts.
byetex convert ./paper-source
#   → paper-source.typ, paper-source.warnings.json, paper-source.agent_brief.md

# Single file, custom output, skip the brief, or fold a real compile log into the brief:
byetex convert paper.tex
byetex convert paper.tex --output /tmp/out.typ
byetex convert paper.tex --no-brief
byetex convert paper.tex --compile          # also runs typst; equivalent to `agent-brief`

# Compile-repair loop: map each typst error back to its LaTeX fragment + repair skill.
byetex diagnose paper.tex                    # add --project (or pass a dir) for multi-file papers
#   → paper.typ + paper.diagnostics.json

# Stage-0 input oracle: is the INPUT LaTeX itself valid (compiled with tectonic)?
# Distinguishes "the input is broken" from "ByeTex has a bug". Skips cleanly if
# tectonic isn't installed.
byetex doctor paper.tex                       # --strict to fail hard; --full to also check the .typ

# Bundled repair skills (start with byetex-getting-started):
byetex skills list
byetex skills read byetex-repair-loop

# Inspect the warnings:
cat paper.warnings.json | jq '.[].category.kind' | sort | uniq -c

byetex agent-brief <input> is a documented shorthand for convert --compile: it runs typst compile and folds the real log into the brief (--no-compile to skip).

Project mode

For real-world LaTeX projects with figures, bibliography files, and \input sub-files, --project produces a self-contained Typst project directory that compiles end-to-end. The input can be the entry .tex file or the project folder; for arXiv tarballs, point at the unpacked folder and ByeTex picks the entry and harvests all sibling .sty/.cls macros before converting.

byetex convert ./paper-source --project
# Writes paper-source.typst-project/ containing:
#   main.typ        — the converted Typst body
#   fig/foo.pdf     — asset files copied from the source project
#   refs.bib        — bibliography copied as-is (Typst reads it natively)
#   warnings.json   — structured warnings sidecar
#   agent_brief.md  — portable Markdown brief (skip with --no-brief)

byetex convert ./paper-source --project --project-out /tmp/my-project --force
typst compile /tmp/my-project/main.typ

Output contract

byetex convert always writes, next to the input:

  • <stem>.typ — the converted Typst document.
  • <stem>.warnings.json — an array of warnings, always written (even if empty) so downstream tools can rely on the file existing.
  • <stem>.agent_brief.md — a portable Markdown brief for LLM patching (skip with --no-brief).

byetex diagnose additionally writes <stem>.diagnostics.json — the content-anchored map of each typst compile error to its LaTeX fragment and repair skill.

The warnings.json schema is fully documented at docs/warnings.schema.json and locked by a regression test (crates/byetex-core/tests/warnings_schema.rs). A representative warning:

{
  "range": {
    "start_line": 42, "start_col": 1,
    "end_line": 47,  "end_col": 18,
    "byte_start": 1023, "byte_end": 1184
  },
  "category": { "kind": "unsupported_command", "name": "\\chemfig" },
  "severity": "warning",
  "message": "...",
  "snippet": "\\chemfig{...}",
  "suggested_skill": "byetex-using-warnings-json"
}

severity is info | warning | error. The exit code of byetex convert is always 0 when conversion succeeds — even with warnings — so callers inspect the sidecar rather than the exit code. (byetex doctor --strict is the one exception: it returns non-zero on a broken input.)

For AI agents

Start with AGENTS.md — the cold-start orientation for the repair loop. docs/for-agents.md is the deeper technical reference. The short version:

  1. byetex convert input.tex is non-destructive and idempotent. Read input.warnings.json — empty means a clean conversion.
  2. Each warning's suggested_skill points to one of the 14 bundled skills in skills/ that documents how to resolve that category. Reach them via byetex skills read <name> or by opening skills/<name>/SKILL.md.
  3. When the .typ doesn't compile, byetex diagnose input.tex maps each typst error back to its LaTeX fragment + repair skill — the compile-repair loop. Edit the .typ, re-run typst compile, repeat.
  4. To grade visual fidelity, the byetex-visual-grading skill drives a vision agent against docs/fidelity-rubric.md — the visual-fidelity loop.

Project layout

New contributors: start with docs/architecture.md for the code map and a bird's-eye view of how a conversion flows through the crates.

ByeTex/
├── crates/
│   ├── byetex-core/        # the library — pure, no I/O
│   │   ├── src/
│   │   │   ├── parser.rs        # tree-sitter-latex frontend
│   │   │   ├── emit.rs          # the Emitter forward walk
│   │   │   ├── emit/            # 15 specialized emitters (math, tables, figures, …)
│   │   │   ├── style_profile.rs # per-class fidelity (title/abstract/headings/cites)
│   │   │   ├── project.rs       # project mode: plan + materialize
│   │   │   ├── diagnose.rs      # compile-error → LaTeX-fragment mapping
│   │   │   └── skills.rs        # skills embedded at build time
│   │   └── vendor/             # vendored tree-sitter-latex (MIT, Patrick Förster 2021)
│   └── byetex-cli/         # the `byetex` binary (all filesystem/process I/O)
├── corpus/                 # arXiv regression corpus (manifest.json; payloads gitignored)
├── scripts/                # corpus_sweep.sh, acceptance.sh, visual_test.py, … (see scripts/README.md)
├── skills/                 # 14 bundled Markdown repair skills (+ INDEX.md)
├── tests/                  # corpus/ fixtures/ visual/ (outputs gitignored)
├── vendor/katex/           # KaTeX submodule — math-coverage TEST oracle, not a runtime dep
└── docs/
    ├── getting-started.md      # a beginner's tour — start here if you're new
    ├── architecture.md         # the code map — start here if you're reading the code
    ├── conversion-logic.md     # emitter behavior in prose
    ├── for-agents.md           # the agent contract
    ├── fidelity-rubric.md      # the visual-grading oracle
    ├── fidelity-backlog.md     # ranked fidelity issues from the vision audit
    ├── scorecard.md            # corpus quality history (gate + driver)
    └── warnings.schema.json

Status

Compile-rate — the gate. 59/59 ByeTex-attributable arXiv papers compile (100%, 0 BYETEX_FAIL), tracked in scripts/acceptance_baseline.json. The acceptance gate (scripts/acceptance.sh) blocks any merge that regresses a known-passing paper.

Visual fidelity — the driver. Corpus composite fidelity score 0.821, graded against docs/fidelity-rubric.md. The fidelity gate (scripts/fidelity_gate.sh, baseline scripts/fidelity_baseline.json) flags render regressions; remaining gaps are tracked and ranked in docs/fidelity-backlog.md. Full history: docs/scorecard.md.

The supported subset grows incrementally; compile-rate is held at its ceiling while each release pushes fidelity.

Synthetic snippet corpus (secondary). A separate set of synthetic doc snippets tracks coverage breadth (a different measure from the arXiv compile gate above):

Last updated: 2026-07-26 (commit 20172e2)

Corpus pass-rate (clean + warnings): 87% — 431/495 files.

Bucket Count
Total 495
Clean 207
Warnings (≥1, no parse error) 224
Parse errors 64
Warning category Count
unsupported_command 407
drop_only 70
unsupported_environment 47
ambiguous_math 27
needs_manual_review 6
tikz 4

License

Dual-licensed under MIT or Apache 2.0 — your choice.

Vendored and third-party dependency licenses are documented in NOTICE. The only vendored source is crates/byetex-core/vendor/tree-sitter-latex/ (MIT, Patrick Förster 2021). All 150 transitive cargo dependencies are MIT, Apache-2.0, Unlicense, or Zlib.

About

Convert your legacy LaTeX documents to Typst because life is strictly too short to compile the exact same file three times just to update a single citation.

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages