Skip to content

udhawan97/PDFold

Repository files navigation


PDFold app icon

PDFold

A native macOS workspace for turning scattered documents into one organized PDF workflow.

Import, arrange, annotate, sign, search, save, and export without sending your files anywhere.

macOS 14+ Β Β  Version 3.0 Β Β  Zero compile installer

SwiftUI Β Β  PDFKit plus PDFium Β Β  One line setup

Release hardened Β Β  Multi-format export Β Β  MIT License

⚑ Setup Β Β Β  ✨ Features Β Β Β  πŸ—οΈΒ Architecture Β Β Β  🚒 Release Β Β Β  βœ…Β Quality Β Β Β  🧰 Help


Quick Start

Paste this into Terminal:

curl -fsSL https://raw.githubusercontent.com/udhawan97/PDFold/main/install.sh | zsh

The installer downloads the latest prebuilt app, places it in ~/Applications/PDFold.app, and adds Desktop commands for launching/updating and clean uninstall.

No Xcode. No GitHub account. No compile step. Just paste, install, and get back to the documents.

How to open Terminal

Open Applications -> Utilities -> Terminal, paste the command above, and press Return.


The Short Version

PDFold is a local-first Mac app for the moment when "just send me the PDF" turns into six PDFs, two screenshots, a Word document, a form, and one file named final_final_revised_ACTUAL.pdf.

It gives those files a calm place to live. Drop in documents, combine them into one workspace, reorder pages, add notes and markup, place signatures, search the full set, save your project, and export the result in the format you need.

Everything happens on your Mac. No account, no upload queue, and no mystery cloud detour.

At A Glance

Signal Why It Matters
πŸ–₯️ Native macOS Built with SwiftUI, PDFKit, document-based app architecture, and sandboxed file access
πŸ“₯ Broad import support Handles PDFs, Word documents, HTML, Markdown, text files, structured data, and images
🧭 Real workflow tools Combine, reorder, rotate, delete, annotate, tag, comment, sign, search, save, print, and export
πŸ”’ Local-first privacy Files stay on the user's Mac instead of being uploaded to a service
⚑ Simple installation One pasted command installs the prebuilt app and creates Desktop launch/update and uninstall commands
🧱 Release-minded engineering Includes installer automation, crash hardening, import safety, export checks, and CI coverage

Who This Is For

Audience What to Notice
πŸ“Ž People with document chaos Pull scattered files into one workspace, clean them up, and export something usable
πŸ§‘β€πŸ’Ό Recruiters and hiring teams A polished desktop product with clear user empathy, practical scope, and visible product judgment
πŸ§‘β€πŸ’» Engineers SwiftUI, PDFKit, PDFium-backed validation, file conversion, document persistence, undo-aware page operations, export pipelines, sandboxing, and installer automation

What It Does

Capability Details
πŸ“₯ Import PDFs, Word docs, HTML, RTF, Markdown, plain text, CSV, JSON, XML, and common image formats
πŸ—‚οΈ Organize Combine files, reorder source documents, move pages, rotate pages, delete pages, and keep navigation aligned
πŸ“– Read Native PDF canvas, generated section banners, table of contents, sidebar navigation, inspector views, and workspace search
✍️ Mark up Highlight, note, editable text overlay, ink, underline, strikeout, and drawn signature placement
🏷️ Track Workspace tags, workspace comments, document metadata, and an inspector list for reviewing annotations
πŸ’Ύ Save Persistent .pdfoldproj workspaces with metadata, comments, tags, signatures, page order, and source PDF data
πŸ“€ Export PDF, Word .docx, Markdown .md, plain text, HTML, PNG pages, JPEG pages, or print-ready output
πŸ”‘ Unlock Password-protected PDF prompt using native PDFKit behavior
πŸ›‘οΈ Protect Local-first design with sandboxed file access, local PDF validation, and no document upload pipeline

Product Flow

PDFold workspace overview showing imports, native workspace tools, markup, metadata, update flow, uninstall command, and export artifacts

Bring in messy inputs, work with them as one local workspace, and export a clean result.

Architecture

flowchart LR
    Files["Source files<br/>PDF, Word, HTML, Markdown, text, images"]
    UI["SwiftUI app<br/>sidebar, reader, inspector"]
    State["Workspace state<br/>documents, pages, tags, comments"]
    Engine["Processing backend<br/>PDFium validate, PDFKit compose"]
    LocalState["Local document state<br/>metadata and PDF data"]
    Export["Export artifacts<br/>PDF, DOCX, MD, TXT, HTML, PNG, JPG"]

    Files --> UI
    UI --> State
    State --> Engine
    Engine <--> LocalState
    Engine --> Export
Loading

PDFold architecture diagram showing the SwiftUI app layer, local PDFium processing backend, PDFKit document engine, local artifacts, update and uninstall commands, and stability guards

SwiftUI handles the workspace experience, PDFKit powers document composition and annotation, and local persistence keeps projects editable.

Layer Responsibility
πŸ–₯️ SwiftUI app Presents the document workspace, sidebar, reader, annotation tools, search, inspector, and export actions
βš™οΈ Document engine Converts imports, validates PDFs through the processing backend, composes PDFs, manages page state, preserves annotations, and writes export formats
πŸ’Ύ Local storage Saves workspace metadata, page order, source PDF data, comments, tags, signatures, and generated output

Why It Matters

Most PDF tools live at one of two extremes: too tiny to handle a real workflow, or so large that opening them feels like clocking in for a shift. PDFold aims for the useful middle.

It is built for document assembly as a workflow, not just PDF viewing as a feature. The goal is simple: take the pile, make sense of it, mark what matters, and send out one clean artifact.

For reviewers, the interesting part is not just that PDFold works. It is that the app ties together product thinking, native Mac engineering, file handling, persistence, export reliability, and distribution polish into one coherent project.

Release Status

PDFold v3 is a release-hardened local-first macOS app for collecting scattered documents, turning them into one editable workspace, marking them up, tracking context, and exporting clean deliverables.

Detail Status
🚒 Version 3.0
🧾 App metadata CFBundleShortVersionString 3.0, CFBundleVersion 3
⚑ Install path One-line installer downloads the latest prebuilt GitHub release
πŸ§ͺ Smoke test ./scripts/install-mac.sh --no-open
πŸ” Signing Local ad-hoc signing for source and release packaging
πŸ“¦ Distribution style Prebuilt release zip, with source build fallback for developers

What Changed In v3

Area Release Update
πŸ”„ Automatic updates The Desktop PDFold.command launcher checks the latest GitHub release every time it opens the app
🧹 Clean uninstall The installer now creates Uninstall PDFold.command for removing the app, generated commands, installer cache, and PDFold app data
πŸ§ͺ PDF processing backend PDF imports pass through an injectable PDFProcessingEngine, with PDFium validation and a PDFKit fallback path
🧭 Simpler setup The old separate update command is treated as a legacy artifact and cleaned up by install/update/uninstall scripts
πŸ“ Release docs README setup, update, uninstall, quality, and troubleshooting guidance now match the v3 install flow

Carried Forward From v2

Area Release Hardening
🏷️ Workspace context Tags and workspace comments persist with saved projects and appear in dedicated inspector tabs
✍️ Text editing The text tool can create clean free-text boxes or convert selected PDF text into editable overlays
πŸ“ Markdown export Workspaces export .md files with a summary, comments, document sections, and extracted PDF text
πŸ–ŠοΈ Ink stability Ink annotations use PDFKit-native paths, with malformed legacy ink data sanitized before display
πŸ›‘οΈ Import safety Import failures show actionable messages, oversized files are rejected early, and selected files use security-scoped access
πŸ” Protected PDFs Password-protected documents unlock from the already-loaded PDF instance for safer sandbox behavior
↩️ Undo reliability Page deletion and reordering undo restore serialized PDF state, not just sidebar metadata
πŸ—‚οΈ Page order Reordered pages rebuild the workspace page map so navigation, export, signatures, and saved projects stay aligned
πŸ“€ Export reliability PDF and multi-format exports report write failures instead of failing quietly
🧯 Crash hardening Reordering, page operations, PDF serialization, HTML rendering, image export, and signature storage guard failure cases

Simplest Local Setup

Paste one command into Terminal:

curl -fsSL https://raw.githubusercontent.com/udhawan97/PDFold/main/install.sh | zsh

The installer downloads the latest prebuilt PDFold.zip from GitHub Releases, installs PDFold.app to ~/Applications, creates self-updating launch and uninstall Desktop commands, removes download quarantine metadata, and opens the app.

The normal path does not require Xcode, Apple's Command Line Tools, a package manager, or a GitHub account. The installer is intentionally uneventful, which is exactly how installers should behave.

Important release note: the zero-compile installer depends on a published GitHub release containing PDFold.zip. If no prebuilt release is available, the installer falls back to a source build and macOS may ask for Apple's free Command Line Tools.

For detailed install diagnostics, run the same command with verbose logging enabled:

PDFOLD_INSTALL_VERBOSE=1 curl -fsSL https://raw.githubusercontent.com/udhawan97/PDFold/main/install.sh | zsh
Developer source install
git clone https://github.com/udhawan97/PDFold.git
cd PDFold
./scripts/install-mac.sh

Updating The App

Double-click PDFold.command on the Desktop. The launcher checks for the latest release, refreshes the installed app when needed, and then opens PDFold.

You can also paste the installer command again:

curl -fsSL https://raw.githubusercontent.com/udhawan97/PDFold/main/install.sh | zsh

If PDFold is already installed, the updater closes the running app if needed, replaces ~/Applications/PDFold.app, refreshes the Desktop launcher, removes quarantine metadata, and opens the updated app.

Uninstalling The App

Double-click Uninstall PDFold.command on the Desktop to remove the installed app, generated Desktop commands, installer cache, and PDFold app data.

Saved .pdfoldproj workspace files are not removed. To keep app support, preferences, caches, and sandbox data too, run:

curl -fsSL https://raw.githubusercontent.com/udhawan97/PDFold/main/scripts/uninstall-mac.sh | zsh -s -- --keep-user-data
Developer source update
git pull
./scripts/install-mac.sh

Useful terminal options:

./scripts/install-mac.sh --clean
./scripts/install-mac.sh --no-open
./scripts/install-mac.sh --verbose
./scripts/install-mac.sh --help

The local script can install a release build, package a release zip, or build from the current source checkout.

Requirements

Requirement Version
🍎 macOS 14 Sonoma or newer
πŸ“¦ Normal install Published PDFold.zip release
🧰 Source build fallback Apple Command Line Tools with Swift 5.9+
Why might Command Line Tools appear?

The normal installer downloads a prebuilt .app. If no release artifact is available, PDFold falls back to a source build with SwiftPM, which requires Apple's free Command Line Tools. Full Xcode is not required.

Daily Workflow

  1. Launch PDFold.
  2. Drag in PDFs, Word documents, text files, web exports, data files, or images.
  3. Reorder documents and pages until the workspace matches the story you need to tell.
  4. Highlight, annotate, add notes, tag the workspace, capture comments, or place a drawn signature.
  5. Search across the combined document set when the one detail you need is hiding on page 37.
  6. Save the workspace if you want to keep editing later.
  7. Export a PDF, Word document, Markdown file, text file, HTML file, or page images.

Technical Layout

PDFold/
  App/             App entry point and command wiring
  Document/        macOS document package read/write support
  Engine/          PDF loading, conversion, composition, manifests, export helpers
  Models/          Workspace, page, annotation, comment, and signature data models
  Resources/       App metadata, entitlements, and asset catalogs
  ViewModels/      Workspace state, document operations, search, export, undo
  Views/           SwiftUI interface components
scripts/
  install-mac.command  Compatibility double-click installer
  install-mac.sh       Release-first installer, source builder, and release packager
  uninstall-mac.sh     Clean uninstaller for installed app artifacts and PDFold app data
install.sh
  Hosted one-line bootstrap
Install or Update PDFold.app
  Finder installer/updater that bypasses Terminal shell startup
Install or Update PDFold.command
  Compatibility Terminal installer/updater
Uninstall PDFold.command
  Compatibility Terminal uninstaller

Developer Notes

Open the project in Xcode:

open PDFold.xcodeproj

Build with SwiftPM:

swift build

Create the same release zip used by GitHub Releases:

./scripts/install-mac.sh --package-only --package /tmp/PDFold.zip

Install from the current source checkout without opening the app:

./scripts/install-mac.sh --no-open

Privacy & Security

PDFold is local-first by design. Documents are opened, edited, saved, and exported on your machine.

The app uses macOS sandboxing and file access through user-selected documents. Its new PDF processing backend runs locally for import validation; it is not a remote upload service. In plain English: PDFold works with the files you hand it, not your entire digital attic.

Release v3 also includes practical guardrails around failure-prone paths:

  • A supplemental PDFium processing backend performs a non-blocking validation smoke check before PDFKit proceeds with the normal import path.
  • Files larger than 512 MB are rejected before loading to avoid memory pressure from accidental giant imports.
  • PDF serialization failures preserve existing package data or report an actionable import error instead of writing broken workspace state.
  • Malformed legacy ink annotations are rebuilt before display so PDFKit does not crash while drawing them.
  • Markdown exports include workspace metadata, comments, document headings, and extracted document text.
  • HTML rendering, image export, page operations, and signature storage guard invalid or unavailable state.
  • Export failures are surfaced to the user, including failed writes and image-rendering errors.
Sandbox details

The app enables:

  • com.apple.security.app-sandbox
  • com.apple.security.files.user-selected.read-write

These entitlements allow sandboxed read/write access to files selected by the user.

Quality Checks

Before shipping a build, verify both the developer path and the human-with-documents path.

Check What To Verify
βœ… Build swift build completes
πŸ§ͺ Installer smoke test ./scripts/install-mac.sh --no-open installs the release or builds, signs, installs, and refreshes Desktop commands
πŸ“¦ Release package ./scripts/install-mac.sh --package-only --package /tmp/PDFold.zip creates the release artifact
πŸ“₯ Import Drag-and-drop works with supported file types
πŸ§ͺ Processing backend PDFium validation runs when available, and PDFKit fallback remains usable
πŸ”‘ Protected PDFs Password-protected PDFs show the unlock flow
πŸ’Ύ Persistence Saved workspaces reopen with metadata, markup, comments, signatures, and document data intact
πŸ”Ž Search Search results navigate across the combined workspace
🏷️ Inspector Tags, comments, info, and markup tabs reflect workspace state
✍️ Annotation Highlight, note, editable text, ink, underline, strikeout, and undo behavior work
πŸ—‚οΈ Pages Page rotation, deletion, and reordering stay aligned with navigation and export
πŸ“€ Export PDF, Word, Markdown, text, HTML, PNG, and JPEG exports complete successfully
πŸš€ Launch/update Desktop launcher updates and opens the installed app
🧹 Uninstall ./scripts/uninstall-mac.sh --help prints usage and the Desktop uninstaller removes install artifacts

For v3 release preparation, the local verification pass should include:

plutil -lint PDFold/Resources/Info.plist
plutil -lint PDFold/Resources/PDFold.entitlements
zsh -n install.sh
zsh -n scripts/install-mac.sh
zsh -n scripts/uninstall-mac.sh
zsh -n scripts/install-mac.command
zsh -n "Install or Update PDFold.command"
zsh -n "Uninstall PDFold.command"
plutil -lint "Install or Update PDFold.app/Contents/Info.plist"
swift build
./scripts/install-mac.sh --package-only --package /tmp/PDFold.zip

Roadmap

  • Richer signature management.
  • More export presets.
  • Improved document thumbnails and faster page navigation.
  • Automated UI smoke tests.
  • Developer ID signing and notarized release builds for the smoothest possible macOS install path.

Contributing

Contributions are welcome when they keep the product focused and the workflow calm.

  1. Create a focused branch.
  2. Keep changes scoped.
  3. Run the local verification checks.
  4. Include screenshots or notes for UI changes.
  5. Open a pull request with the problem, approach, and verification steps.

Troubleshooting

Clicking the installer opens a GitHub page instead of installing

That is expected on GitHub. README links open files in the browser; they do not execute Mac installer scripts.

Use the Quick Start command from Terminal, or download the repository first and run the installer from Finder.

Double-clicking the installer says it cannot be opened

Open Terminal in the project folder and run:

chmod +x "Install or Update PDFold.command" "Uninstall PDFold.command" "Install or Update PDFold.app/Contents/MacOS/PDFoldInstaller" scripts/install-mac.sh scripts/install-mac.command scripts/uninstall-mac.sh

Then double-click Install or Update PDFold.app again from Finder.

The installer says Command Line Tools are needed

The normal installer uses a prebuilt app and does not need developer tools. This message means a prebuilt release was not available, so the installer fell back to a source build.

Install Apple's free Command Line Tools from the macOS prompt, then run the installer again. Full Xcode is not required.

The Desktop launcher does not open the app

Run the installer again. It refreshes ~/Applications/PDFold.app and recreates the Desktop launcher.

For more detail, run the installer with verbose logging:

PDFOLD_INSTALL_VERBOSE=1 curl -fsSL https://raw.githubusercontent.com/udhawan97/PDFold/main/install.sh | zsh
macOS warns the app is from an unidentified developer

PDFold release builds are ad-hoc signed but not notarized. The installer removes download quarantine from the installed app. If macOS still warns, open it from Finder, then use Open from the security prompt.

Fully silent Gatekeeper behavior requires Apple Developer ID signing and notarization, which is listed on the roadmap.

The app did not update

Double-click PDFold.command on the Desktop, or paste the Quick Start command again.

For a fully fresh developer source build:

./scripts/install-mac.sh --clean
The build fails and the terminal window closes too fast

Open .build/install.log in the project folder. It contains the latest installer/build output.

When using the README install command, the prebuilt release attempt is also logged at ~/.pdfold/prebuilt-install.log. If PDFold opens and immediately exits, the installer records recent macOS launch diagnostics in the install log before failing.

You can also run the installer from Terminal to keep the output visible:

./scripts/install-mac.sh --verbose

License

PDFold is available under the MIT License.

About

PDFold is a native macOS PDF workspace for combining, reading, annotating, and signing multiple PDFs in one clean view.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors