Own your PDFs.
A powerful, open-source PDF workbench for desktop, web, mobile, and CLI.
Pure-Rust backend. No account. No database. No document storage.
Download desktop · Run with Docker · Use the CLI · Explore every feature
RustlingPDF brings a broad PDF toolkit into one local-first application. Use the
visual React interface, install the Tauri desktop app, self-host the web service,
scan from a phone, call the REST API, or automate local files with the
rustlingpdf CLI.
The processing service is written in Rust and exposes 166 /api/v1/...
endpoints. There is no Java or JVM at build or run time.
| Private by design | No login, account, database, or durable server-side document storage. Temporary request files are swept automatically. |
| One toolbox, many surfaces | Desktop app, self-hosted web UI, Docker image, installable mobile scanner PWA, REST API, and local CLI. |
| Built for real workflows | Go beyond merge and split: design forms, batch-fill records, check accessibility, OCR scans, sign documents, redact content, and compose pipelines. |
| Automation without a server | The typed rustlingpdf CLI runs the same processing pipeline in-process against local files. |
| AI only when you choose it | Summary, extraction, and translation are optional, stateless, disabled by default, and support BYOK or local Ollama. |
| Honest dependency handling | Optional native tools are detected at startup. Missing tools disable only the features that require them. |
| Area | What you can do |
|---|---|
| Page workshop | Merge, reorder, rotate, crop, rescale, overlay, remove blanks, add page numbers, and split by page, size, count, chapter, section, tile, or QR divider |
| Visual editing | Edit structured text, add images and stamps, replace text, annotate, recolor for dark mode, manage bookmarks, and flatten content |
| Forms at scale | Visually draw and resize accessible fields, align or duplicate them, edit properties and tab order, fill forms, and batch-fill CSV/XLSX rows into PDFs |
| Accessibility | Inspect language, tags, reading structure, figure alternative text, form labels, and tab order; apply bounded, user-reviewed remediation |
| Scan, OCR, and repair | Capture and clean multi-page scans from a phone, correct perspective, reorder pages, add searchable OCR text, compress files, and repair damaged PDFs |
| Convert almost anything | Convert images, Office files, HTML, Markdown, email, eBooks, SVG, and comic archives to PDF; export PDF to images, text, Word, PowerPoint, HTML, Markdown, CSV/XLSX, EPUB, video, and more |
| Protect and sign | Set passwords and permissions, sanitize metadata, redact content, add watermarks, sign with X.509 or hardware/smart-card certificates, timestamp, and validate signatures |
| Inspect and manage | Review fonts, pages, annotations, forms, encryption, attachments, and metadata, and report a file that declares no PDF/A profile. Validating a file that does declare PDF/A, PDF/UA or WTPDF needs veraPDF installed; without it that request is refused rather than answered |
| Automate | Build multi-step pipelines visually, drag and drop to reorder steps, save or exchange them as JSON, run typed CLI operations, call the REST API, or submit asynchronous jobs |
| AI-assisted, optional | Produce page-cited summaries, schema-driven extraction, ordered translation, edit plans, review comments, generated documents, math audits, and classification |
The detailed, code-derived reference lists every registered route and dependency requirement in What RustlingPDF can do.
| Surface | Best for | Notes |
|---|---|---|
| Desktop app | Private day-to-day use | Windows (-setup.exe/.msi) and Linux (.deb); macOS and AppImage: coming soon. Native Tauri shell; desktop packages bundle qpdf and Tesseract with English OCR data |
| Docker | Home lab, team network, or server | Web UI and REST API in one container |
| From source | Development and customization | Rust backend plus Vite/React frontend |
| CLI | Shell scripts, CI, and batch jobs | Processes local files directly; no server or account |
| Mobile scanner PWA | Capturing paper documents | Local multi-page capture and PDF export, with optional temporary phone-to-desktop transfer |
docker pull ghcr.io/hairbui76/rustlingpdf:latest
docker run --rm -p 8080:8080 ghcr.io/hairbui76/rustlingpdf:latestOpen http://localhost:8080.
For Compose, local builds, configuration mounts, and the optional AI sidecar, see Running RustlingPDF.
Prerequisites: Rust, Task, and Node.js with npm.
task rust:install # fetch Cargo dependencies and install pinned PDFium
task dev # start the Rust backend and web UIThe UI opens on the address printed by Task. To include the optional stateless AI engine, use:
task dev:allYou can also run each component separately:
task backend:dev # http://127.0.0.1:8080
task frontend:dev # http://127.0.0.1:5173, proxies /api to the backendSmoke check:
curl http://127.0.0.1:8080/api/v1/info/statusrustlingpdf is a first-class local automation CLI. It generates its operation
bindings from the same catalog used by the HTTP pipeline, validates parameters
against the catalog JSON Schemas, and invokes the processing runtime in-process.
It does not start a listener, upload files to a RustlingPDF server, require
an account, or create durable server state.
Install it from a source checkout:
task rust:install
cargo install --path rust/crates/rustling-cli --lockedDiscover operations and inspect their parameters:
rustlingpdf operations
rustlingpdf operations --json
rustlingpdf describe general-rotate-pdfRun one operation:
rustlingpdf run general-rotate-pdf \
--input report.pdf \
--output report-rotated.pdf \
--param angle=90Compose repeatable workflows in pipeline.json:
{
"pipeline": [
{
"operation": "general-rotate-pdf",
"parameters": { "angle": 90 }
},
{
"operation": "misc-compress-pdf",
"parameters": { "optimizeLevel": 2 }
}
]
}rustlingpdf pipeline \
--spec pipeline.json \
--input report.pdf \
--output report-ready.pdfCLI behavior is designed for safe scripting:
- explicit output paths are required;
- existing files are preserved unless
--forceis supplied; --output -is the only binary-stdout mode;- diagnostics go to stderr; and
- stable exit codes distinguish usage, I/O, processing, dependency, and internal failures.
See the CLI contract for JSON parameters, repeated inputs, pipeline semantics, stdout rules, optional dependencies, and exit codes.
RustlingPDF has one server mode: stateless and account-free.
- No analytics, telemetry, or tracking pixel is shipped, in the web app or the service. There is no vendor SDK, no opt-in prompt, no consent banner, and no setting that enables one — the code does not exist.
- The web app makes no outbound request of its own. It does not fetch icons or fonts from a CDN, and contacts no third-party host at any point. The web app talks to your RustlingPDF backend and to nothing else. Nothing about you — not your IP, not your version, not the fact that you run RustlingPDF — is disclosed to anyone by the software running.
- The desktop app makes exactly one outbound request of its own, and you can
turn it off. At startup it asks the GitHub releases page once whether a
newer version exists (a fetch of
latest.json; like any HTTP request it discloses your IP and a user agent to GitHub, and nothing else — no version report, no identifier). Settings → General → "Check for updates at startup" disables it, after which the desktop app is as silent as the web app. - Fallback fonts ship with the app. When a PDF names a font it does not embed, the viewer substitutes one from a set bundled into the build and served from your own origin — never fetched. The bundled set is Noto Sans (which covers Latin, Cyrillic, Greek and Vietnamese), Noto Naskh Arabic, and Noto Sans Hebrew, about 11 MB in total. CJK is deliberately not bundled: the Japanese, Korean and Chinese sets are roughly 141 MB together, an order of magnitude more than the rest of the application, so a CJK document that does not embed its fonts renders no glyphs for those runs. That is a real limitation, and it is the deliberate trade — no document, in any script, causes a request to a third party.
- The compiled JavaScript still contains a few
cdn.jsdelivr.netstrings: they are unused constants left in a vendored library by tree-shaking, and no code path reaches them. This is verified rather than assumed — seenoRemoteAssetDefaults.test.ts, plus the ESLint rule and the singleuseLocalPdfiumEnginewrapper that make a remote default unreachable. If an audit greps the bundle and finds those strings, this is what they are. - Updates install only when you ask. When the startup check finds a newer version, the desktop app shows a dismissible banner; nothing downloads until you click, and every download is verified against the project's signing key before it is installed. With the check turned off (or on the web app, which never checks), watch the releases page yourself. Desktop builds are signed, so you can also verify a download you fetched by hand.
- No authentication, users, teams, database, audit log, or durable document store exists in the application.
- Requests use bounded temporary workspace and result storage that expires.
- The
/api/v1/info/*request counters are in-memory, reset when the process restarts, and are served only to whoever asks those routes. - The optional AI engine is disabled by default. When enabled, dedicated document-understanding requests keep PDF bytes in the processing service and send only bounded extracted text to the configured provider.
- Because the service has no built-in authentication, expose it only on a trusted network or behind your own authenticated reverse proxy.
Most processing is implemented in the Rust workspace. Some conversions require specialized external programs:
- LibreOffice for Office ↔ PDF. Office → PDF also has a built-in pure-Rust
engine that handles
.docx,.xlsx, and.pptxwith nothing installed, so that direction always works; LibreOffice is used when present because its fidelity is better, and it is required for every other input format and for PDF → Office; - WeasyPrint for HTML, Markdown, email, and URL → PDF;
- Tesseract or OCRmyPDF for OCR;
- Calibre for eBook conversion;
- FFmpeg for PDF → video;
unrar/7-Zip andrarfor CBR workflows; and- qpdf and Poppler for selected repair/conversion assistance.
Each dependency is probed at startup. A missing tool reports its feature as unavailable instead of crashing the service or silently producing a different result. Desktop packages bundle qpdf and Tesseract; the Docker image includes the common conversion toolchain. See the operator guide for versions and command overrides.
| Path | Purpose |
|---|---|
rust/crates/rustling-processing |
Axum processing service and in-process pipeline runtime |
rust/crates/rustling-ai-engine |
Optional stateless AI document-understanding and orchestration engine |
rust/crates/rustling-cli |
Local rustlingpdf automation binary |
rust/crates/rustling-operation-catalog |
Typed operation-catalog generator |
rust/contracts |
Behavior contracts for processing surfaces |
frontend/editor |
Vite, React, TypeScript, and Mantine application |
SwaggerDoc.json |
OpenAPI snapshot used for catalog and type generation |
Crate names use the rustling-* namespace and product environment variables
use the RUSTLING_* prefix.
