A native macOS PDF editor — no frameworks, no dependencies, fully App Store compliant.
Built with SwiftUI, PDFKit, CoreGraphics, and CoreText. Designed to feel at home on macOS 26 with a Liquid Glass toolbar aesthetic.
Welcome screen — drag-and-drop zone with Recent Files grid
Scroll view with thumbnail sidebar and resizable AI Assistant panel
Safari-style tab bar with multiple PDFs open simultaneously
Page organizer grid — drag to reorder, rotate, duplicate, or delete pages
Context-sensitive annotation palette with highlight, underline, and markup tools
Sepia reading mode for comfortable long-form reading
Night mode — inverted dark background for low-light reading
Night mode with the annotation palette active
Settings — General pane with theme and tab style options
- Open multiple PDFs in a Safari-style tab bar — embed tabs inside the toolbar or show a dedicated strip below it (configurable in Settings → General)
- Open via ⌘O, drag-and-drop onto the welcome screen, or New Empty Document (⌘N)
- Welcome screen with drag-and-drop drop zone and a Recent Files list (bottom half)
- Per-tab unsaved-changes indicator (blue dot on the tab thumbnail) and a Save / Don't Save / Cancel alert on close
- Non-blocking background save — PDF serialisation and disk write both run off the main thread; ⌘S returns instantly with a spinner badge on the tab
- Scroll view (continuous) and Page Grid organizer, switchable with ⌘⇧1 / ⌘⇧2 or the segmented picker in the toolbar
- Pinch-to-zoom and keyboard zoom (⌘= / ⌘−) with a live percentage readout in the toolbar zoom menu
- Reading modes — Default · Night · Sepia, selectable from the toolbar dropdown
- Text selection with instant annotation application on mouse-up
| Tool | Shortcut | Description |
|---|---|---|
| Select | E | Move and resize existing PDFKit annotations via native drag handles |
| Markup | M | Grouped picker for highlight, underline, and strikethrough — switch sub-tool in the context palette |
| Comment | C | Click anywhere to place a speech-bubble (freeText) annotation |
| Text Box | T | Click to insert a resizable, styled text box; configure font, size, and colour in the context palette |
| Edit Text | — | Click any line of native PDF text to edit it inline; single-line or paragraph-aware; opens the Content Editor panel automatically |
| Shape | S | Draw rectangle, ellipse, or line overlay annotations; configurable stroke/fill from the palette |
| Stamp | — | Click to place a text stamp (APPROVED, DRAFT, CONFIDENTIAL, etc.) chosen from the context palette |
| Signature | G | Draw a freehand signature on a canvas; committed as a resizable PDFKit annotation |
| Audio Note | — | Embed a voice-recording annotation (microphone) |
- Context-sensitive annotation palette — a pill-shaped,
ultraThinMaterialfloating bar appears at the bottom of the canvas whenever an annotation tool is active, showing colour swatches, opacity sliders, font/size pickers, or stamp choices relevant to the active tool - Highlight · underline · strikethrough colours and opacity are also configurable globally in Settings → Annotations
- Choose which tools appear in the toolbar segmented picker in Settings → Tools (with keyboard shortcut badges)
- Activating the Edit Text tool and clicking a PDF text line opens an
NSTextFieldoverlay positioned exactly over the original text — fonts, size, and colour are matched automatically - Supports single-line replacement and multi-line paragraph reflow via CoreText (
CTFramesetterCreateWithAttributedString+CTFrameDraw) - The Content Editor panel slides in on the right whenever Edit Text is active; it lists all text lines on the current page, lets you select and bulk-edit them, and shows a progress/success indicator after each write
- All text mutations use a bare
CGContextPDF round-trip — no third-party libraries, fully App Store compliant
- Full-document thumbnail grid with page numbers
- Drag-to-reorder via the native
Transferable+.draggable/.dropDestinationAPI - Per-page actions: rotate left / right, delete, duplicate
- Copy (⌘C) and Paste (⌘V) pages across documents or within the same document
- Add a blank page, multi-select with ⌘-click, Select All (⌘A), Deselect
- Preview.app-style single-column layout — thumbnail image on top, page number below
- Thumbnails fill the available width and render at @2x for Retina displays
- Draggable resize handle — drag the divider to adjust sidebar width (120–244 pt)
- Four sections switchable via an icon picker: Thumbnails · Outline · Bookmarks · Annotations list
- Toggle with ⌘⇧S
- OCR — run Vision
VNRecognizeTextRequest(accurate mode, language correction) on any page to extract text from scanned documents - Scan enhancement — CoreImage filter pipeline to improve contrast and readability of scanned pages
- Summarisation hook — pipe extracted text to the configured AI provider for a one-tap page or document summary
- AcroForm detection — automatically discovers PDF widget annotations (text fields, checkboxes, radio buttons) via
PDFAnnotationSubtype.widget - Fill interactive form fields directly; changes are committed back to the PDF on save
- Signature canvas — draw with pressure-sensitive strokes; confirm to embed as a scalable PDFKit annotation
- Toggle with the ✦ sparkles button in the toolbar
- Resizable right-hand panel (drag the handle to adjust width)
- Ask any question about the open document; the current page's text is automatically included as context (capped at 12 000 characters)
- Supports OpenAI (GPT-4o, GPT-4-turbo, GPT-3.5-turbo), Claude / Anthropic (claude-opus-4, claude-sonnet-4, claude-haiku-3), and Groq (llama-3.3-70b, llama-3.1-8b, gemma2-9b, mixtral-8x7b)
- Streaming-style chat history with user/assistant bubbles, animated typing indicator, and one-tap conversation clear
- Configure provider, model, and API keys in Settings → AI
- API keys stored exclusively in the macOS Keychain (
kSecClassGenericPassword,kSecAttrAccessibleWhenUnlockedThisDeviceOnly) — never in UserDefaults or logs
| Pane | Options |
|---|---|
| General → Theme | System / Light / Dark appearance |
| General → Tab Style | In Toolbar (tab pills in title bar) · Tab Bar (dedicated strip below toolbar) |
| General → On Launch | Restore open documents, default reading mode, show sidebar by default |
| Display | Default view mode (Scroll / Grid), default zoom level (25%–400%) |
| Annotations | Default highlight / underline / strikethrough colour and highlight opacity |
| Tools | Toggle which annotation tools are visible in the toolbar segmented picker |
| AI | Provider picker, model picker, per-provider API key management |
[Sidebar] [◀ N/total ▶] [Scroll|Grid] · [─── Tab strip ───] · [Tools] [Zoom▾] [Mode▾] [✦]
- Left zone: sidebar toggle (⌘⇧S), page navigation with live page count, scroll/grid view picker
- Centre zone (In Toolbar mode): scrollable tab strip with thumbnail previews, close buttons, unsaved-changes dots, and a
+new-tab menu - Right zone: annotation tool segmented picker, zoom menu (shows current %), reading mode menu, AI sparkles toggle
- All right-side items collapse gracefully into a
>>overflow menu with proper labelled submenus on smaller windows
| Action | Shortcut |
|---|---|
| Open PDF | ⌘O |
| New Empty Document | ⌘N |
| New Tab | ⌘T |
| Save | ⌘S |
| Close Tab | ⌘W |
| Toggle Sidebar | ⌘⇧S |
| Scroll View | ⌘⇧1 |
| Page Grid | ⌘⇧2 |
| Zoom In / Out / Fit | ⌘= / ⌘− / ⌘0 |
| Select tool | E |
| Markup (highlight / underline / strikethrough) | M |
| Comment | C |
| Text Box | T |
| Shape | S |
| Signature | G |
| Settings | ⌘, |
- macOS 26 or later
- Xcode 26 or later
Folio/
├── FolioApp.swift # @main — WindowGroup, Settings scene, menu commands
├── ContentView.swift # Root layout: resizable sidebars, toolbar, file importer,
│ # auto-open Content Editor on editText tool activation
├── Folio.entitlements # App Sandbox + network.client + user-selected files
├── Models/
│ ├── AppState.swift # @Observable singleton — tabs, active tool, sidebar flags
│ ├── DocumentTab.swift # Per-document state; non-blocking background save
│ ├── ActiveTool.swift # Annotation tool enum with symbol names & shortcut metadata
│ ├── AIProvider.swift # AI provider enum + Keychain API key store
│ ├── ReadingMode.swift # Default / Night / Sepia
│ └── ViewMode.swift # Scroll / Grid
├── Services/
│ ├── AIService.swift # @Observable — OpenAI / Anthropic / Groq HTTPS streaming
│ └── CorePDFEngine.swift # App Store–safe PDF mutation engine (CoreGraphics + CoreText)
│ # • Image insertion via CGContext
│ # • Text replacement via CTFramesetter / CTLineDraw
│ # • Text extraction via PDFPage + line grouping
├── Modules/
│ ├── PDFViewerCore/ # NSViewRepresentable PDFView bridge + inline text editor overlay
│ │ ├── PDFKitView.swift # NSEvent monitors, annotation hit-testing, editText click handling
│ │ ├── PDFViewerView.swift # SwiftUI wrapper — annotation palette, inline editor state
│ │ ├── PDFViewerViewModel.swift # Zoom, display mode, page binding
│ │ ├── PDFTabContainer.swift # DocumentTabBar (toolbar pills) + TabBarRowView (bar strip)
│ │ ├── InlineTextEditorOverlay.swift # NSTextField positioned over the clicked text line
│ │ └── AnnotationResizeOverlay.swift # Selection handles for resizable annotations
│ ├── AnnotationManager/ # Annotation VM + pill-shaped context palette
│ ├── ContentEditor/ # Right-panel bulk text/image editor via CorePDFEngine
│ ├── DocumentIntelligence/ # OCR (Vision), scan enhancement (CoreImage), summarisation
│ ├── PageOrganizer/ # Grid reorder view + VM (copy/paste/add/rotate/delete)
│ └── FormsAndSignatures/ # AcroForm field detection + signature canvas
├── Views/
│ ├── Sidebar/ # ThumbnailSidebarView, OutlineView, BookmarksView, AnnotationsListView
│ ├── AISidebar/ # AIChatSidebarView, chat bubbles, typing indicator
│ ├── Toolbar/ # MainToolbarView, FloatingToolbarView
│ └── Welcome/ # Drop zone + Recent Files empty-state screen
└── Settings/
├── SettingsStore.swift # @Observable UserDefaults-backed preferences
├── SettingsView.swift # TabView shell with icon strip sidebar
└── Panes/ # General · Display · Annotations · Tools · AI
Key patterns:
@Observable+@MainActorthroughout — noObservableObjectorCombineNSViewRepresentablebridge toPDFKit.PDFViewwithNSEventlocal monitors for annotation and inline-edit clicks- Inline text editing:
PDFPage.selectionForLine/NSString.paragraphRangefor structure-aware hit detection;NSTextFieldoverlay positioned in SwiftUI coordinates via GeometryReader - PDF mutation via bare
CGContextPDF output —CTFramesetterCreateWithAttributedString+CTFrameDrawfor paragraph reflow,CTLineDrawfor single-line replacement; no AppKit graphics context required Transferable+.draggable/.dropDestinationfor page reorder in the grid- Security-scoped resource bookmarks held open for the lifetime of each tab
Task.detached(priority: .userInitiated)for non-blocking PDF serialisation and disk write- API keys in
kSecClassGenericPasswordKeychain items,kSecAttrAccessibleWhenUnlockedThisDeviceOnly - No AGPL dependencies — MuPDF fully replaced by CoreGraphics + CoreText + PDFKit; App Store compliant
- Clone the repo
- Open
Folio.xcodeprojin Xcode 26+ - Select your development team in Signing & Capabilities
- Run on macOS 26 (⌘R)
MIT License — see LICENSE for details.
- Open multiple PDFs in a Safari-style tab bar (embedded in toolbar or as a dedicated strip)
- Open via ⌘O, drag-and-drop, or New Empty Document (⌘N)
- Per-tab unsaved-changes indicator (blue dot) and Save / Don't Save / Cancel alert on close
- Non-blocking background save — PDF serialisation and disk write both run off the main thread; ⌘S returns instantly
- Scroll view (continuous) and Page Grid organizer (⌘⇧1 / ⌘⇧2)
- Pinch-to-zoom and keyboard zoom (⌘= / ⌘−) with live percentage readout
- Reading modes — Default · Night · Sepia (toolbar dropdown)
- Text selection with instant annotation application
| Tool | Shortcut | Description |
|---|---|---|
| Select | E | Move/resize existing annotations |
| Markup | M | Grouped picker for highlight, underline, and strikethrough |
| Comment | C | Click to place a speech-bubble annotation |
| Text Box | T | Click to insert an editable, resizable text box |
| Edit Text | — | Click any PDF text to edit it inline — single lines or full paragraphs |
| Shape | S | Draw rectangle, ellipse, or line overlay annotations |
| Stamp | — | Click to place a text stamp (APPROVED, DRAFT, etc.) from the palette |
| Signature | G | Draw a freehand signature; resizable via PDFKit handles |
| Audio Note | — | Embed a voice-recording annotation |
- Highlight · underline · strikethrough colours and opacity configurable in Settings → Annotations
- Choose which tools are visible in the toolbar in Settings → Tools
- Full-document grid with page thumbnails and page numbers
- Drag-to-reorder via native Transferable API
- Rotate left / right, delete, copy pages (⌘C), paste pages (⌘V), add empty page
- Multi-select with ⌘-click · Select All (⌘A) · Deselect
- Preview.app-style single-column layout — thumbnail image on top, page number centred below
- Thumbnails fill the available width and render at @2x for Retina
- Draggable resize handle — drag the divider to make the sidebar wider or narrower (120–244 pt)
- Sections: Thumbnails · Outline · Bookmarks · Annotations list
- Toggle with ⌘⇧S
- Sparkles (✦) toolbar button — toggles a resizable right sidebar
- Ask any question about the open document; the PDF's text is automatically included as context (capped at 12 000 chars)
- Supports OpenAI, Claude (Anthropic), and Groq (llama-3.3-70b, llama-3.1-8b, gemma2-9b, mixtral-8x7b)
- Chat history with user/assistant bubbles, animated typing indicator, and one-tap clear
- Configure provider, model, and API keys in Settings → AI
- API keys stored exclusively in the macOS Keychain — never in UserDefaults or logs
| Pane | Options |
|---|---|
| General | Appearance (System / Light / Dark), default reading mode, sidebar visibility on launch, restore documents on launch, tab bar style (In Toolbar / Tab Bar) |
| Display | Default zoom level, default view mode |
| Annotations | Highlight · underline · strikethrough colours and opacity |
| Tools | Choose which annotation tools are visible in the toolbar (with keyboard shortcut badges) |
| AI | Provider picker, model picker, API key management (OpenAI · Claude · Groq) |
- Left: sidebar toggle, page navigation (◀ N/total ▶), scroll/grid picker
- Centre: tab strip (In Toolbar mode)
- Right: annotation tool picker → zoom menu → reading mode menu → AI sparkles button
- All right-side items collapse gracefully into a
>>overflow menu with proper submenus
| Action | Shortcut |
|---|---|
| Open PDF | ⌘O |
| New Empty Document | ⌘N |
| New Tab | ⌘T |
| Save | ⌘S |
| Close Tab | ⌘W |
| Toggle Sidebar | ⌘⇧S |
| Scroll View | ⌘⇧1 |
| Page Grid | ⌘⇧2 |
| Zoom In / Out / Actual | ⌘= / ⌘− / ⌘0 |
| Select tool | E |
| Markup (highlight / underline / strikethrough) | M |
| Comment | C |
| Text Box | T |
| Edit Text | — |
| Shape | S |
| Signature | G |
| Settings | ⌘, |
- macOS 26 or later
- Xcode 26.4 or later
Folio/
├── FolioApp.swift # @main — WindowGroup, Settings scene, menu commands
├── ContentView.swift # Root layout, resizable sidebars, toolbar, file importer
├── Folio.entitlements # App Sandbox + network.client + user-selected files
├── Models/
│ ├── AppState.swift # @Observable singleton — tabs, active tool, sidebar flags
│ ├── DocumentTab.swift # Per-document state; non-blocking background save
│ ├── ActiveTool.swift # Annotation tool enum with keyboard shortcut metadata
│ ├── AIProvider.swift # AI provider enum + Keychain API key store
│ ├── ReadingMode.swift # Default / Night / Sepia
│ └── ViewMode.swift # Scroll / Grid
├── Services/
│ ├── AIService.swift # @Observable — OpenAI / Anthropic / Groq HTTPS calls
│ └── CorePDFEngine.swift # App Store–safe PDF mutation engine (no third-party libs)
│ # • Image insertion via CGContext
│ # • Text replacement via CTFramesetter / CTLineDraw
│ # • Text extraction via PDFPage.characterBounds + line grouping
├── Modules/
│ ├── PDFViewerCore/ # NSViewRepresentable PDFView bridge, inline text editor overlay
│ ├── AnnotationManager/ # Annotation VM + floating colour/opacity palette
│ ├── ContentEditor/ # Sidebar panel for bulk text/image editing via CorePDFEngine
│ ├── DocumentIntelligence/ # OCR (Vision), scan enhancement (CoreImage), summarisation
│ ├── PageOrganizer/ # Grid reorder view + VM (copy/paste/add-empty/rotate/delete)
│ └── FormsAndSignatures/ # Signature canvas + PDFKit freeText annotation commit
├── Views/
│ ├── Sidebar/ # ThumbnailSidebarView, ThumbnailCardView, OutlineView, etc.
│ ├── AISidebar/ # AIChatSidebarView, chat bubbles, typing indicator
│ ├── Toolbar/ # Tab bar row, tab item views
│ └── Welcome/ # Empty-state welcome screen
└── Settings/
├── SettingsStore.swift # @Observable UserDefaults-backed preferences
├── SettingsView.swift # TabView shell with icon strip
└── Panes/ # General · Display · Annotations · Tools · AI
Key patterns:
@Observable+@MainActorthroughout — noObservableObjectorCombineNSViewRepresentablebridge toPDFKit.PDFViewwithNSEventlocal monitors for annotation + editing clicks- Inline text editing:
PDFPage.selectionForLine/NSString.paragraphRangefor structure-aware hit detection;NSTextFieldoverlay positioned in SwiftUI coordinates - PDF mutation via bare
CGContextPDF output —CTFramesetterCreateWithAttributedString+CTFrameDrawfor paragraph reflow,CTLineDrawfor single-line replacement; no AppKit graphics context required Transferable+.draggable/.dropDestinationfor page reorder- Security-scoped resource bookmarks held open for the lifetime of each tab
Task.detached(priority: .userInitiated)for non-blocking PDF serialisation and disk write- API keys in
kSecClassGenericPasswordKeychain items,kSecAttrAccessibleWhenUnlockedThisDeviceOnly - No AGPL dependencies — MuPDF fully replaced by CoreGraphics + CoreText + PDFKit; App Store compliant
- Clone the repo
- Open
Folio.xcodeprojin Xcode 26.4+ - Select your development team in Signing & Capabilities
- Run on macOS 26 (⌘R)
MIT License — see LICENSE for details.