texforge 0.8.0

Self-contained LaTeX to PDF compiler CLI
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
```
 ███████████          █████ █████ ███████████                                     
░█░░░███░░░█         ░░███ ░░███ ░░███░░░░░░█                                     
░   ░███  ░   ██████  ░░███ ███   ░███   █ ░   ██████  ████████   ███████  ██████ 
    ░███     ███░░███  ░░█████    ░███████    ███░░███░░███░░███ ███░░███ ███░░███
    ░███    ░███████    ███░███   ░███░░░█   ░███ ░███ ░███ ░░░ ░███ ░███░███████ 
    ░███    ░███░░░    ███ ░░███  ░███  ░    ░███ ░███ ░███     ░███ ░███░███░░░  
    █████   ░░██████  █████ █████ █████      ░░██████  █████    ░░███████░░██████ 
   ░░░░░     ░░░░░░  ░░░░░ ░░░░░ ░░░░░        ░░░░░░  ░░░░░      ░░░░░███ ░░░░░░  
                                                                 ███ ░███         
                                                                ░░██████          
                                                                 ░░░░░░           
```

<p align="center">
  <a href="https://github.com/UniverLab/texforge/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/UniverLab/texforge/ci.yml?branch=main&style=for-the-badge&label=CI" alt="CI"/></a>
  <a href="https://crates.io/crates/texforge"><img src="https://img.shields.io/crates/v/texforge?style=for-the-badge&logo=rust&logoColor=white" alt="Crates.io"/></a>
  <img src="https://img.shields.io/badge/Status-Active-27AE60?style=for-the-badge" alt="Status"/>
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-2E8B57?style=for-the-badge" alt="License"/></a>
</p>

Texforge is a unified LaTeX workspace — one tool for writing, rendering diagrams (Mermaid, Graphviz), and building PDFs. Set it up once and stay focused on your document.

**[univerlab.org/texforge](https://univerlab.org/texforge)** — the project page: what it does and why it exists. Command-level documentation lives in [`docs/`](docs/).

---

## Features

- **🚀 One-command setup** — Install once, everything is included (LaTeX engine, templates, diagram renderers).
- **📊 Diagrams as first-class** — Write Mermaid or Graphviz blocks in your `.tex` files; they render and embed during build.
- **🪄 Guided workflows** — Start a new project or migrate an existing one with a guided init.
- **🔎 Template registry** — Install, manage, and validate templates — with built-in fallback for offline work.
- **🔨 Build and live edit** — Compile once or use watch mode; rebuild automatically as you edit.
- **🧭 Smart linting** — Catch missing files, broken references, bibliography keys, and unclosed environments before build.
- **✨ Format on demand** — Normalize `.tex` files with an opinionated formatter (including `--check` mode).
- **🔄 Placeholders and config** — Reuse project details from configuration without retyping.

---

### Demo with OpenCode 

![Demo OpenCode](demo/dist/demo.gif)

---

## Installation

### Quick install (recommended)

**Linux / macOS:**

```bash
curl -fsSL https://raw.githubusercontent.com/UniverLab/texforge/main/scripts/install.sh | sh
```

**Windows (PowerShell):**

```powershell
irm https://raw.githubusercontent.com/UniverLab/texforge/main/scripts/install.ps1 | iex
```

This downloads and installs `texforge`. No Rust toolchain required. Tectonic (the LaTeX engine) is installed automatically on first build.

You can customize the install:

```bash
# Pin a specific version
VERSION=0.1.0 curl -fsSL https://raw.githubusercontent.com/UniverLab/texforge/main/scripts/install.sh | sh

# Install to a custom directory
INSTALL_DIR=/usr/local/bin curl -fsSL https://raw.githubusercontent.com/UniverLab/texforge/main/scripts/install.sh | sh
```

```powershell
# Pin a specific version (PowerShell)
$env:VERSION="0.1.0"; irm https://raw.githubusercontent.com/UniverLab/texforge/main/scripts/install.ps1 | iex
```

### Via cargo

```bash
cargo install texforge
```

Tectonic (the LaTeX engine) is installed automatically on first build. No extra steps needed.

Available on [crates.io](https://crates.io/crates/texforge).

### From source

```bash
git clone https://github.com/UniverLab/texforge.git
cd texforge
cargo build --release
# Binary at target/release/texforge
```

### GitHub Releases

Check the [Releases](https://github.com/UniverLab/texforge/releases) page for precompiled binaries (Linux x86_64, macOS x86_64/ARM64, Windows x86_64).

### Uninstall

```bash
rm -f ~/.local/bin/texforge  # texforge binary
rm -rf ~/.texforge/           # tectonic engine + cached templates
```

## Skill

If you want Copilot to understand texforge and help with common LaTeX tasks, install the [texforge Skill](https://skills.sh/jheisonmb/skills/texforge):

```bash
npx skills add https://github.com/jheisonmb/skills --skill texforge
```

## Quick Start

```bash
# Interactive wizard — new project or migrate existing
texforge init

# Or directly:
texforge new mi-tesis
texforge build
```

## Documentation

Full documentation lives in [`docs/`](docs/): installation, quick start,
building, diagrams, templates, configuration and the complete CLI reference.

## Workflow

```mermaid
sequenceDiagram
    actor User
    participant CLI as texforge
    participant Tectonic

    User->>CLI: texforge new my-doc
    CLI-->>User: project scaffolded

    alt Existing LaTeX project
        User->>CLI: texforge init
        CLI-->>User: project.toml generated
    end

    User->>CLI: texforge check
    CLI-->>User: errors with file:line + suggestion

    User->>CLI: texforge fmt
    CLI-->>User: .tex files formatted in place

    User->>CLI: texforge build
    Note over CLI: render embedded diagrams to PNG
    CLI->>Tectonic: compile entry .tex
    Note over CLI,Tectonic: auto-installs tectonic on first run
    Tectonic-->>User: my-doc.pdf
```

## `texforge init`

Interactive wizard. Auto-detects the context:

- If a `.tex` file with `\documentclass` is found in the current directory — migrates the existing project (asks for title and author, generates `project.toml`)
- Otherwise — guides creation of a new project (asks for name and template)

```bash
# Existing LaTeX project
cd mi-tesis-existente/
texforge init

# Empty directory
mkdir mi-nuevo-doc && cd mi-nuevo-doc
texforge init
```

---



| Command | Description |
|---|---|
| `texforge new <name>` | Create new project from template |
| `texforge new <name> -t <template>` | Create with specific template |
| `texforge init` | Interactive wizard — new project or migrate existing |
| `texforge build` | Compile to PDF |
| `texforge build --watch` | Watch for changes and rebuild automatically |
| `texforge clean` | Remove build artifacts |
| `texforge fmt` | Format .tex files |
| `texforge fmt --check` | Check formatting without modifying |
| `texforge check` | Lint without compiling (includes spell-check) |
| `texforge spell add <word>` | Add word to personal dictionary (default: global) |
| `texforge spell list` | List personal dictionary words |
| `texforge spell remove <word>` | Remove word from personal dictionary |
| `texforge pdf text` | Extract text as seen by readers / accessibility tools |
| `texforge pdf info` | Report pages, fonts, embedding status, metadata |
| `texforge pdf pages` | List which section opens each page (diff-friendly) |
| `texforge pdf check` | Verify significant source words appear in PDF |
| `texforge outline` | Show document's section tree |
| `texforge stats` | Count words by section (or by file with `--by file`) |
| `texforge preview` | Rasterize PDF to PNG pages |
| `texforge doctor` | Diagnose Tectonic, cache, fonts, dictionaries, project |
| `texforge config` | Interactive wizard to set user details (name, email, institution, language) |
| `texforge config list` | Show all configured values |
| `texforge config <key>` | Show value for key (name, email, institution, language) |
| `texforge config <key> <value>` | Set value for key |
| `texforge template list` | List installed + available in registry |
| `texforge template list --installed` | List only locally installed templates |
| `texforge template add <name>` | Download template from registry |
| `texforge template remove <name>` | Remove installed template |
| `texforge template validate <name>` | Verify template compatibility |

---

## Configuration

Global user details stored in `~/.texforge/config.toml`. These are used as replaceable placeholders in templates.

**Interactive setup:**

```bash
texforge config
```

This launches a wizard asking for:
- **Name**: Your full name
- **Email**: Your email address  
- **Institution**: Your institution/organization
- **Language**: Document language (default: `english`)

**Command-line interface:**

```bash
# View all settings
texforge config list

# Get a specific value
texforge config name

# Set a value
texforge config name "Jheison Martinez"
texforge config email "jheison@example.com"
texforge config institution "University of Tech"
texforge config language "spanish"
```

---

## Templates

Templates are managed through the [texforge-templates](https://github.com/UniverLab/texforge-templates) registry. The `general` template is embedded in the binary and works offline. Run `texforge template list --all` to see all available templates.

---

## Diagrams

`texforge build` intercepts embedded diagram environments before compilation. Originals are never modified — diagrams are rendered in temporary build copies.

### Mermaid

```latex
% Default: width=\linewidth, pos=H, no caption
\begin{mermaid}
flowchart LR
  A[Input] --> B[Process] --> C[Output]
\end{mermaid}

% With options
\begin{mermaid}[width=0.6\linewidth, caption=System flow, pos=t]
flowchart TD
  X --> Y --> Z
\end{mermaid}
```

### Graphviz / DOT

```latex
\begin{graphviz}[caption=Pipeline]
digraph G {
  rankdir=LR
  A -> B -> C
  B -> D
}
\end{graphviz}
```

Both rendered to PNG via pure Rust — no browser, no Node.js, no `dot` binary required.

| Option | Default | Description |
|---|---|---|
| `width` | `\linewidth` | Image width |
| `pos` | `H` | Figure placement (`H`, `t`, `b`, `h`, `p`) |
| `caption` | _(none)_ | Figure caption |

---

## Watch Mode

`texforge build --watch` watches for `.tex` file changes and rebuilds automatically:

```bash
texforge build --watch            # rebuild after 2s of inactivity (default)
texforge build --watch --delay 5  # custom delay in seconds
```

The terminal shows a live session timer, build count, and the result of the last build. Press `Ctrl+C` to stop.

---

## Linter

`texforge check` runs static analysis without compiling:

- `\input{file}` — verifies file exists
- `\includegraphics{img}` — verifies image exists
- `\cite{key}` — verifies key exists in `.bib`
- `\ref{label}` / `\label{label}` — verifies cross-reference consistency
- `\begin{env}` / `\end{env}` — detects unclosed environments

```
ERROR [main.tex:47]
  \includegraphics{missing.png} — file not found

ERROR [main.tex:12]
  \cite{smith2020} — key not found in .bib

ERROR [main.tex:23]
  \begin{figure} never closed
  suggestion: Add \end{figure}
```

---

## Formatter

`texforge fmt` applies opinionated formatting inspired by `rustfmt`:

- Consistent indentation (2 spaces) inside environments
- Collapsed multiple blank lines
- Aligned `\begin{}`/`\end{}` blocks

One canonical output regardless of input style. Git diffs stay clean.

```bash
texforge fmt           # format in place
texforge fmt --check   # check without modifying (CI-friendly)
```

---

## Spell-Check

`texforge check` now includes automatic spell-checking. The language is detected from the document itself:

- `\usepackage[spanish]{babel}` — Spanish (Hunspell dictionary)
- `\usepackage[polyglossia]{...}` — Language extracted from polyglossia
- No language declaration — falls back to configured default (`texforge config language`)

Dictionaries download automatically on first use into `~/.texforge/dicts/`. When a language is unsupported, checking is skipped with a message naming that language (never checks against the wrong dictionary).

### Personal Dictionary

Maintain a personal word list to skip custom terms, proper names, and project-specific jargon:

```bash
# Add words to the global dictionary (applies to all projects)
texforge spell add "MyCompany" "LaTeX" "RGB"

# Add to the current project only
texforge spell add "ProjectCodename" --local

# List current dictionary
texforge spell list

# Remove a word
texforge spell remove "MyCompany"
```

Scopes are unioned at check time — both global and project-local words are respected.

---

## PDF Inspection

`texforge pdf` extracts and inspects the compiled PDF without re-rendering:

### Text Extraction

```bash
# Print all text as a reader or accessibility tool would see it
texforge pdf text

# Keep ligature codepoints (fi, fl, etc.) as separate characters
texforge pdf text --raw
```

### Metadata and Fonts

```bash
# Report page count, fonts, whether fonts are embedded, and metadata
texforge pdf info
```

### Page Map

```bash
# List which section opens each page (one line per page)
# Output designed for version control diffs
texforge pdf pages
```

### Fidelity Check

```bash
# Verify that significant source words survived into the PDF text
# (catches missing fonts, encoding issues, rendering bugs)
texforge pdf check
```

---

## Outline

Print the section tree with LaTeX markup resolved to readable text:

```bash
texforge outline

# JSON output for scripting
texforge outline --json
```

---

## Statistics

Word count by section or by file:

```bash
# Count words per section (default)
texforge stats

# Count words per .tex file
texforge stats --by file

# JSON output
texforge stats --json
```

---

## Preview

Rasterize the compiled PDF to PNG pages:

```bash
# Rasterize all pages (writes to ./preview/ by default)
texforge preview

# Single page
texforge preview --page 1

# Custom output directory
texforge preview --out ./previews

# Scale up for higher resolution (default: 1.0 px per PDF point)
texforge preview --scale 2.0
```

---

## Doctor

Diagnose the managed environment (Tectonic, cache, fonts, dictionaries, and project state):

```bash
texforge doctor
```

Reports:
- Whether Tectonic is installed and functional
- Disk usage of the Tectonic cache and downloaded templates
- Available fonts and dictionaries
- Whether the current directory is a recognized texforge project

---

## Runtime Directory

```
~/.texforge/
  bin/
    tectonic            # LaTeX engine (auto-installed on first build)
  templates/
    general/            # Cached templates
    apa-general/
    ...
```

---

## Platform Support

| Platform | Architecture | Status |
|---|---|---|
| Linux | x86_64 | yes |
| macOS | x86_64 | yes |
| macOS | ARM64 (Apple Silicon) | yes |
| Windows | x86_64 | yes |

---

## Tech Stack

| Concern | Crate |
|---|---|
| CLI parsing | `clap` (derive) |
| Error handling | `anyhow` |
| Serialization | `serde` + `toml` |
| HTTP client | `reqwest` (blocking) |
| Archive extraction | `flate2` + `tar` |
| File traversal | `walkdir` |
| LaTeX engine | `tectonic` (external binary) |
| Mermaid renderer | `mermaid-rs-renderer` |
| Graphviz renderer | `layout-rs` |
| SVG → PNG | `resvg` |

---

## License

MIT

---

An experiment of [UniverLab](https://github.com/UniverLab) — an open computational laboratory.
Made with ❤️ by [JheisonMB](https://github.com/JheisonMB)