We're live on Product Hunt 🚀

Upvote us
OxygenPDF
Back to Home

Changelog

Every feature, improvement, and fix — tracked as we build OxygenPDF.

v2026.07.09-01

Latest
July 9, 2026

Forgot your password? You can reset it yourself now

The sign-in form has a 'Forgot password?' link. We email you an 8-digit code, you pick a new password, and you're signed in. No support ticket needed. One thing worth knowing if you bought a license: your license key already works as your password. It starts with OPDF- and sits in your purchase receipt email, so you may not need a reset at all. The sign-in form, the reset screen, and the reset email all point this out now.

All changes in version 2026.07.09-01

  • New
    Reset a forgotten password with a code sent to your email
  • New
    Sign-in reminds license buyers that their license key doubles as their password

v2026.06.17-01

June 17, 2026

The app reloads itself after an update instead of throwing an error

If you kept a tab open while we shipped a new version, OxygenPDF could reach for a file from the old build that no longer exists and show a 'Something went wrong' screen — the loading-animation stylesheet was the usual culprit. It now catches that case and quietly refreshes to the current version, dropping you back where you were. Sign-in got a fix too: password managers like iCloud Passwords now put your saved email and password straight into the login form.

All changes in version 2026.06.17-01

  • Fixed
    Stale tabs reload on their own after a deploy instead of crashing with 'Unable to preload CSS'
  • Fixed
    Saved logins from iCloud Passwords and other password managers now autofill the sign-in form

v2026.06.15-02

June 15, 2026

Type any language into your PDFs — umlauts, accents, and non-Latin scripts now work

Adding a watermark, header, footer, or page stamp — or turning text, Markdown, Word, and CSV into a PDF — used to quietly break on characters outside basic Latin. German umlauts typed on a Mac were the worst offender: the diacritic comes through as a separate combining mark that the old font could not encode, so the whole export failed. The text tools now embed real Unicode fonts and normalize your text first, so umlauts, accented names, Cyrillic, Greek, and CJK (Chinese, Japanese, Korean) render properly. Arabic, Hebrew, Hindi, and Thai are supported too, with right-to-left and complex-script shaping handled on a best-effort basis. The same fix reaches the PDF editor and chat form-filling, and scanned documents in non-Latin scripts now keep a searchable text layer instead of dropping it. Fonts for non-Latin scripts download only when needed and are cached; your files never leave your browser.

All changes in version 2026.06.15-02

  • Fixed
    Decomposed umlauts (ä, ö, ü typed on macOS) no longer break PDF text export
  • New
    Watermarks, headers, footers, page numbers, and Bates stamps accept any-language text
  • New
    Text, Markdown, Word, and CSV to PDF render Latin, Cyrillic, Greek, and CJK scripts
  • New
    OCR keeps non-Latin scripts in the searchable text layer instead of stripping them
  • New
    PDF editor annotations and chat form-filling accept umlauts and non-Latin scripts

v2026.06.15-01

June 15, 2026

Speed read Markdown, text files, and pasted text — not just PDFs

The RSVP speed reader now opens .md and .txt files alongside PDFs, or you can paste raw text straight in from a new tab. Markdown gets its syntax stripped first — headings, links, bold, lists — so you read the actual prose instead of flashing past # and ** one word at a time. Plain text is split into sections so the preview panel and jump-to-page keep working on long documents. It all still runs in your browser; nothing is uploaded.

All changes in version 2026.06.15-01

  • New
    RSVP speed reader accepts Markdown (.md) and plain text (.txt) files
  • New
    Paste raw text directly into the RSVP speed reader
  • New
    Markdown syntax is stripped to clean prose before reading

v2026.05.13-01

May 13, 2026

Switch tiers when you regenerate a visual webpage

The regenerate button on a visual-HTML chip used to silently re-run with the same quality tier you originally picked, which meant if Basic came out flat you had to start a new conversation to try Best. The button is now a small menu — pick Basic, Quality, or Best directly from the chip and the new build runs at the tier you chose (and the chip subtitle updates to match so you can tell at a glance which tier produced the result). The cache is always busted on regenerate, so a tier you already tried genuinely re-runs against the model rather than handing back a stale result.

Memory chips don't pop up on pleasantries anymore

The assistant occasionally over-extracted a "Save to thread memory?" chip when you replied with just "thanks" or "ok cool" — fabricating a preference you never actually stated. The chat prompt now hard-bans memory suggestions on social acks and explicitly forbids inventing facts the user hasn't spoken, and a server-side filter drops any memory chip that lands on a pleasantry-shaped turn regardless of what the model emitted. Saying thanks no longer triggers a memory pill.

All changes in version 2026.05.13-01

  • New
    Chip regenerate menu lets you re-run the visual HTML at Basic / Quality / Best
  • New
    Memory chips suppressed on short pleasantry messages (thanks, ok, hi, etc.)
  • Fixed
    Regenerate at a different tier now updates the chip subtitle to reflect the new tier

v2026.05.11-14

May 11, 2026

Pick your quality tier when converting a PDF to a visual webpage

Visual HTML recreation now asks one extra question after you pick 'Visual recreation': Basic, Quality, or Best? Each level runs through a different AI model behind the scenes — Basic is fastest and cheapest, Best is slowest but reads design-heavy pages the most carefully. The chip subtitle shows which tier produced the result so you know what you're paying for, and the regenerate button reuses the same tier you originally picked. Replaces the previous three-pass refinement loop (which was producing modest gains for a lot of extra cost). The underlying prompt also got a full rewrite — the AI now produces Tailwind-CDN-based responsive HTML with semantic tags and proper design fidelity instead of hand-rolled blocky CSS with US-Letter page dimensions.

Chat clarifications never dead-end on generic fallback chips anymore

When you asked the assistant to convert a PDF to Word or HTML, it sometimes wrote "let me ask a couple of quick questions" but forgot to actually emit the wizard — the bubble would just sit there with the four generic follow-up chips (Explain more / Give an example / …) underneath, which read as a broken UI. The model now gets a hard prompt rule against promising clarifications without emitting the matching directive, and a server-side safety net catches the misfire by inferring the right wizard format from your message and recovering the wizard inline.

All changes in version 2026.05.11-14

  • Fixed
    New inferExportWizardFromMisfire safety net in chatPdf.ts runs when no directive was honored. Matches few-shot prose patterns ("let me ask…", "let me walk you through…", "pick the right…", "couple of (quick )?questions to pick") against the user's question (html/website → html, docx/word/.doc(x) → docx) and injects the recovered <export-wizard format/> into the message patch. Telemetry tag wizard-recovered lands on emittedDirectives so we can monitor the rate.
  • Fixed
    System prompt gains an INVERSE-RULE clause forbidding clarification prose without the matching directive. Calls out the exact phrase shapes ("let me ask…", "let me walk you through…", "pick the right…") that must co-occur with <export-wizard/> or <ask-choice>. Also re-asserts that image-based PDFs asked for docx/html STILL route through the wizard, not <ask-choice>.
  • Improved
    Visual HTML rebuild swapped from Gemini Pro to Replicate-hosted openai/gpt-5.4. callReplicateVisionHtml() posts to /v1/models/openai/gpt-5.4/predictions using Replicate's FLAT input schema — `prompt` (text instruction) + `image_input` (array of client-rendered page-image URIs) at the top level, plus reasoning_effort / verbosity / max_completion_tokens sampling knobs. Important gotcha encoded in the comments + memory: Replicate's openai/* wrappers do NOT accept OpenAI's `messages` array or `type: "file"` content parts; sending those gets the entire payload silently dropped by the input validator (symptom: 'I don't have the PDF' replies). Hence the render-pdf-pages.ts + attachVisionHtmlPageImages pipeline that pre-rasterizes to JPEG before upload. awaitReplicateOutput drains via Prefer wait + 2s polling, capped at 180s per pass. Requires REPLICATE_API_TOKEN env var. Hard caps: first 10 pages, 32k output tokens per pass. Bump REPLICATE_VISION_HTML_MODEL to a newer minor revision when Replicate ships one.
  • New
    Client-side PDF rasterization for the visual flow — new render-pdf-pages.ts uses pdfjs-dist at 1.5× scale + JPEG quality 0.85 to render each page (max 10) into a Blob, the VisionHtmlChip uploads each one via Convex generateUploadUrl, and the new attachVisionHtmlPageImages mutation patches the resulting storage IDs onto pdfIndex.visionHtmlPageImageStorageIds. getVisionHtmlDownloadUrl now exposes pageImagesReady + pdfSourceUrl + pageRenderLimit so the chip can skip re-rasterization when the cache is warm. Adds a "Preparing page images for the vision model…" subtitle state to the chip during the prep phase.
  • Fixed
    VisionHtmlChip regenerate button now defensively preps page images when they're not attached. Older pdfIndex rows created before visionHtmlPageImageStorageIds existed in the schema (or any row whose cached status='ready' / 'error' predates the Replicate switch) hit startVisionHtmlPass with no images cached, which threw 'Page images not yet attached'. handleRegenerate now mirrors the auto-start + handleClick guard: if pageImagesReady is false, render+upload+attach first, then force-regenerate.
  • New
    3-tier quality picker for the visual-match flow. VISION_HTML_MODEL_BY_TIER maps each tier to a different Replicate-hosted vision model — basic→prunaai/gemma-4-26b-a4b-fast, quality→google/gemini-3.1-pro, best→anthropic/claude-opus-4.7. New chatMessage.visualQualityTier + pdfIndex.visionHtmlTier schema fields persist the choice per-message and gate cache validity (a tier-mismatch on the cache forces a re-run). Wizard adds a second-step picker after 'Visual recreation' (Basic / Quality / Best with descriptive hints, NEVER showing the underlying model). applyExportWizardChoice / startVisionHtmlPass / runVisionHtmlPass all accept tier args. Chip subtitle now reads 'Building (Quality quality)…' / 'Website · Quality · click to download'. New buildVisionInput(modelSlug, …) helper dispatches the request body shape per provider — each Replicate wrapper has its own flat schema with different field names, so a unified body silently drops fields and the model hallucinates. Verified schemas via scraping each /api page's embedded OpenAPI definition: openai/* uses image_input array + max_completion_tokens + reasoning_effort + verbosity; google/* uses images PLURAL array + max_output_tokens + thinking_level; prunaai/* (Gemma 4) uses message (NOT prompt) + images plural + max_tokens (cap 16384) + max_visual_tokens (pinned to 1120 — without this, images auto-compress to 280 vision tokens and the model hallucinates); anthropic/* uses image singular + max_tokens (cap 64000) + system_prompt + max_image_resolution (set to 2 MP, otherwise images auto-downscale to 0.5 MP). Anthropic and Gemma only accept ONE image per call, so multi-page PDFs on those tiers lose pages 2..N.
  • Improved
    Removed the critique-then-apply iteration loop and its supporting scaffolding (VISION_HTML_CRITIQUE_PROMPT, VISION_HTML_REFINE_PROMPT, VISION_HTML_MAX_ITERATIONS, callReplicateVisionHtmlCritique, callReplicateVisionHtmlApply). Visual-match is now single-pass — one model call per visual recreation. The cost reduction (5x to 1x calls) funds the model upgrades in the tier picker; a High-tier single pass on gpt-5.4 produces materially better single-shot output than 5 stacked passes on gpt-5-mini did.
  • Improved
    VISION_HTML_PROMPT rewritten end-to-end. Old prompt explicitly banned Tailwind and any CSS framework, and framed the task as converting a PDF (no mention of the attached image) — producing hand-rolled CSS with US-Letter 8.5in by 11in page boxes and Open Sans defaults. New prompt opens with a directive that the attached images ARE page screenshots (primes the model to actually look at the inputs), mandates Tailwind CSS via CDN script, semantic HTML5 elements, mobile-first responsive breakpoints, WCAG AA contrast, arbitrary-value Tailwind syntax for off-scale colors and radii. Preserves the two non-negotiable platform contracts: section.pdf-page[data-page=N] wrappers + pN-imgK image placeholder syntax so inlineImagesAsDataUrls still substitutes Mistral-extracted images. Adds placehold.co URL convention for synthetic decorative placeholders that have no source image counterpart.

v2026.05.11-13

May 11, 2026

Inline export wizard replaces the flat ask-choice for Word and HTML conversions

When you asked to convert a PDF to Word or HTML, the chat assistant used to show a flat list of 3-4 options you had to read and commit to in one click. Re-deciding meant editing your message or starting over. The new wizard walks you through 1-2 short questions inline in the bubble — back-navigable, fully frontend (no extra AI round-trips per question), and the final pick writes the right export shape directly to the message. Markdown and text still skip the wizard since there's only one sensible output for those.

All changes in version 2026.05.11-13

  • New
    New <export-wizard format="docx|html|markdown|text"/> directive. Self-closing, mutually exclusive with emit-file/ask-choice/open-tool/fill-pdf/run-action. Parser in chatPdf.ts validates the format against a closed set; the dispatcher places it between run-action and ask-choice in priority order so the model can hedge with the wizard when it would otherwise emit ask-choice.
  • New
    New ExportWizard component (apps/main/src/features/chat-pdf/components/export-wizard.tsx). Renders inline inside the assistant bubble when message.exportWizardFormat is set. 2-step state machine for HTML (priority → edit-style branch), 1-step for DOCX (priority directly to outcome). History stack for back navigation; submit goes through applyExportWizardChoice mutation, no AI round-trip per step.
  • New
    New applyExportWizardChoice mutation clears exportWizardFormat and sets emittedFileFormat/Source/Filename in one patch. Validates format against EMIT_FILE_FORMATS and source against {index, index-visual}; rejects index-visual for non-HTML. Optional proseSummary updates the bubble text so the wizard can leave a contextual note about which chip to click.
  • New
    chatMessage gains exportWizardFormat (optional string). _patchMessage accepts it. Bubble rendering shows the ExportWizard component below EmittedFileChip, hides the FollowUpChips while the wizard is active (matching the existing ask-choice contract).
  • Improved
    System prompt reroutes all docx/html conversion requests through <export-wizard/> instead of direct <emit-file source="index"/> or <ask-choice> trees. The flat 4-option HTML ask-choice and 3-option DOCX ask-choice examples are gone. Markdown and text still emit emit-file directly since there's only one viable output for each.

v2026.05.11-12

May 11, 2026

"Generate a fresh website that visually matches" — fourth option for scanned-PDF HTML

When a scanned PDF gets a 'give me as html' request, the chat assistant now offers four routes instead of three. The new option uses a vision AI pass to rebuild the design as a real webpage with CSS — colors, gradients, custom typography, the works — instead of stripping it down to a semantic export. Click it and the screenshot-to-code pass kicks off automatically: no second click required, the chip shows a spinner while it works, then flips to a download when ready.

All changes in version 2026.05.11-12

  • New
    New EmitFileSource value `index-visual` routes HTML exports straight to the screenshot-to-code chip. parseEmitFilePlan accepts the new value only for format=html — typo-rejects anything else so a model fumble doesn't surface as an empty download. EmittedFileChip renders only the VisionHtmlChip when source is index-visual, with auto-start.
  • New
    VisionHtmlChip gains an `autoStart` prop. When true, a useEffect-guarded by a single-fire ref triggers startVisionHtmlPass on mount as soon as the query resolves and status is null. Strict-mode double-effects can't double-charge; ready/running/error states all skip the auto-fire.
  • New
    System prompt now has an explicit 4-option ask-choice for scanned PDFs requesting HTML, plus follow-up routing rules for each option. Visual-match option emits <emit-file format="html" source="index-visual"/>; OCR-text option emits the standard <emit-file format="html" source="index"/>. Model behavior is now deterministic instead of improvised from the Word pattern.
  • Improved
    Removed the Replicate VLM chip and backend in their entirety — VisionReplicateChip component, runReplicateVisionHtmlPass action, startReplicateVisionHtmlPass mutation, getReplicateVisionHtmlDownloadUrl query, generatePageImageUploadUrl mutation, callReplicateVisionHtml / fetchReplicateLatestVersion / flattenReplicateTextOutput helpers, getReplicateToken, REPLICATE_API_BASE / REPLICATE_DEFAULT_VISION_MODEL constants, and the pdfIndex.visionReplicate* schema fields. The open VLMs on Replicate hard-cap their output at 512 tokens — too small for screenshot-to-code at any quality. Kept the GEMINI path and added the index-visual route in its place.

v2026.05.11-11

May 11, 2026

Replicate-powered Website chip — open VLM as a second opinion

Gemini 2.5 Pro is strong on screenshot-to-code but it makes specific mistakes some PDFs trip over. The new Replicate chip routes the same task through Qwen2.5-VL by default — different model class, different failure modes, sometimes a better fit for a given design. Sits alongside the Gemini chip so you can A/B the two on the same PDF without re-uploading. Backend is parameterized via env vars so swapping to DeepSeek-VL3 or any other Replicate VLM takes a config change, not a redeploy.

All changes in version 2026.05.11-11

  • New
    New runReplicateVisionHtmlPass internal action calls Replicate with one image per page (parallel) and aggregates the resulting fragments into one self-contained .html. Model/version env-overridable via REPLICATE_VISION_MODEL / REPLICATE_VISION_VERSION; defaults to lucataco/qwen2-vl-7b-instruct. Image-inlining reuses the same pN-imgK → base64 data URL post-processor as the Gemini path.
  • New
    New generatePageImageUploadUrl mutation returns Convex signed upload URLs so the frontend can render PDF pages to PNG client-side and stream them up in parallel before kicking off the action. Replicate doesn't ingest PDFs the way Gemini does, hence the extra client-side step.
  • New
    pdfIndex grows visionReplicateStorageId + visionReplicateStatus + visionReplicateErrorMessage + visionReplicateModel. The model name on the index lets the chip display which Replicate model produced the output so users know what they got. Same idempotency contract: cache hit on second click per index.
  • New
    VisionReplicateChip renders alongside VisionHtmlChip for <emit-file format="html" source="index"/> messages. Amber accent, Cpu icon to distinguish it from Gemini's fuchsia Globe. Click → render pages client-side → upload → trigger action → poll → download `<base>-replicate.html`.
  • Improved
    Action drops the uploaded page PNGs from Convex storage after the .html is produced — they served their purpose, the final output is self-contained, no reason to keep them eating storage quota.

v2026.05.11-10

May 11, 2026

Website (visual) chip — screenshot-to-code for design-heavy PDFs

Word documents can't render modern CSS, which means infographics, posters, and Canva-style exports always lose their visual chrome on a Word export — no matter how clever the converter. HTML can carry all of it. The new chip sends the source PDF to Gemini 2.5 Pro and asks for self-contained HTML+CSS that visually recreates the design: gradients, custom typography, decorative shapes, layered illustrations. Cropped images get inlined as base64 data URLs so the .html opens in any browser with nothing broken. Sits next to the standard HTML chip so you can pick semantic-text or visual-reconstruction depending on what you need.

All changes in version 2026.05.11-10

  • New
    New runVisionHtmlPass internal action calls Gemini 2.5 Pro (Pro tier, not Flash — visual reconstruction needs the larger model) with the PDF as inline data and a screenshot-to-code prompt. Output gets code-fence-stripped, then every `<img src="pN-imgK">` reference is replaced with a base64 data URL pulled from the Tier-1 stored images. Self-contained .html is stored in Convex storage.
  • New
    pdfIndex grows visionHtmlStorageId + visionHtmlStatus + visionHtmlErrorMessage, parallel to the existing markdown vision-pass fields. Same idempotent contract: cache hit on second click, charges chat_pdf_vision_html ops only on the first uncached invocation per index.
  • New
    VisionHtmlChip renders alongside the standard HTML chip for any <emit-file format="html" source="index"/> message. Globe icon, fuchsia accent, idle → pending/running → ready/error state machine driven by getVisionHtmlDownloadUrl. Downloaded file is named `<base>-visual.html`.
  • Fixed
    runLayoutPreservedPdfToWord now throws a clear error when the PDF has zero extractable text (Canva / Figma / Illustrator exports outline text into vector paths — pdfjs returns nothing). Message points users at the Website (visual) chip instead of returning a silently empty .docx.
  • Improved
    Gemini call helper extracted from callGeminiVision into callGemini(pdfBytes, model, prompt) so the new HTML pass can reuse the same 20 MB size guard, base64 encoding, and error handling. callGeminiVision becomes a thin wrapper that pins Flash + the markdown prompt.

v2026.05.11-9

May 11, 2026

Word (layout) chip — text in the right positions, editable

The previous "page-perfect" chip just embedded each PDF page as a PNG inside the docx. Better than nothing visually, but you couldn't edit, copy, or search anything. The new converter extracts every text item from the PDF via pdfjs with its real (x, y) coordinates and emits one absolutely-positioned paragraph per item in a docx sized to match the source. Font size and bold/italic come along. Result: text lands where it belongs, and you can edit it. v1 ships text only; image extraction and colors land in follow-ups.

All changes in version 2026.05.11-9

  • New
    New layout-preserved.ts converter walks pdfjs textContent in viewport space (top-left origin), extracts transform[4]/[5] as baseline x/y in points, derives font size from transform[0], and detects bold/italic via fontFamily regex on the styles map. Each item becomes a docx Paragraph with frame.type='absolute' anchored to FrameAnchorType.PAGE. Per-page sections sized to viewport dimensions with zero margins so frame coords map 1:1 to source.
  • Fixed
    PagePerfectChip swapped from runPdfPagesToWord (screenshot-in-docx) to runLayoutPreservedPdfToWord. Subtitle updated to "layout-preserved" so the chip honestly describes the tradeoff: text in the right positions, editable, but v1 doesn't yet carry images or vector chrome.

v2026.05.11-8

May 11, 2026

Word (page-perfect) chip — pixel-identical to the source PDF

Some PDFs are infographics, posters, designed layouts where every arrow, gradient, and font choice matters. Word documents can't reproduce that as vector content — the decorative chrome dies in any text-based conversion. The new chip skips the OCR pipeline entirely: each PDF page renders to a high-resolution image client-side and embeds in the docx as a full-page picture. The result looks identical to the source. Trade-off is honest: editable text is gone, but visual fidelity is total. Sits next to the other two chips so you can pick the one that matches the document.

All changes in version 2026.05.11-8

  • New
    New PagePerfectChip surfaces alongside the standard Word chip for any <emit-file format="docx" source="index"/> message. Fetches the source PDF via getSourcePdfDownloadUrlForMessage, runs runPdfPagesToWord client-side (pdfjs render at 2x DPI → PNG → ImageRun → docx), downloads as `<name>-pages.docx`. Reuses existing infra from the scanned-PDF flow; we just stopped gating it on pdfType.
  • Fixed
    Three-chip layout (Editable / Page-perfect / High quality) gives users an honest tradeoff matrix: editable text vs. visual fidelity vs. better layout reconstruction. Each chip uses a distinct icon and accent (FileText/blue, ImageIcon/emerald, Sparkles/violet) so they read as separate options rather than redundant duplicates.

v2026.05.11-7

May 11, 2026

Chat PDF gets a "Word (high quality)" chip that reads layout the way you do

Mistral OCR is fast and cheap but it flattens multi-column layouts, breaks callout boxes, and treats key-value pairs as random sentence fragments. The new chip hands the whole PDF to Gemini 2.5 Flash and asks for cleanly structured Markdown — heading hierarchy, columns interleaved in reading order, tables reconstructed as tables, callouts as block quotes. It sits next to the standard Word chip so you can pick the cheap fast path or the better slower one depending on the document. Picks up the same embedded images Tier 1 added, so figures still land in the right spots.

All changes in version 2026.05.11-7

  • New
    New runVisionLayoutPass internal action calls Gemini 2.5 Flash with the source PDF as inline data and a structured-Markdown prompt. PDF-native ingest means no per-page rendering on our side; 20 MB inline cap surfaces as a clean user-visible error rather than a half-truncated document.
  • New
    pdfIndex grows visionMarkdownStorageId + visionStatus (pending/running/ready/error) + visionErrorMessage. The vision pass output caches per index, so a second click on the high-quality chip downloads the existing result instead of re-charging the user.
  • New
    startVisionLayoutPass mutation kicks off the action with a charge of pageCount ops against chat_pdf_vision_hq. Idempotent: if a pass is already pending/running/ready, returns the existing status with no re-trigger and no re-charge.
  • New
    VisionHQChip component renders alongside the standard IndexedExportChip for docx exports. Walks through idle → pending/running (spinner) → ready (download) → error (retry) states driven by getVisionMarkdownDownloadUrl. Sparkles icon and violet accent so users see the two chips as distinct options instead of duplicates.
  • New
    Gemini placeholders like ![alt](pN-imgK) get post-processed to point at the Tier-1 image refKey for the K-th image on page N (resolved via the new pageIndex field on pdfIndexImage). Unmatched placeholders fall through and the converter drops them — same contract as the rest of the image pipeline.

v2026.05.11-6

May 11, 2026

Chat PDF exports stop leaking ![img-0.jpeg] text where pictures should be

Convert an infographic-style PDF to Word in chat and you used to get the headings and paragraphs right but every image came out as literal markdown placeholder text like `![img-0.jpeg](img-0.jpeg)` floating between the paragraphs. The OCR pipeline was returning image bboxes but throwing the cropped image bytes away, and the docx converter had no `image` token handler so the marked AST default echoed the raw markdown into the output. Now the OCR pass pulls the cropped image bytes inline, stores them per-image, and the docx/html converters embed them where they belong. Reupload the same PDF and the index gets a free one-time re-OCR so existing chats benefit too.

All changes in version 2026.05.11-6

  • Fixed
    Mistral OCR call now sets include_image_base64: true so cropped pictures come back inline. Each image lands in Convex storage with its bbox dimensions tracked in a new pdfIndexImage table keyed by a globally-unique refKey (page number plus original image id). Per-page collisions on ids like `img-0.jpeg` no longer scramble which page's image gets fetched.
  • New
    runOcr rewrites each page's markdown so image refs become globally unique within an index. `![img-0.jpeg](img-0.jpeg)` on page 3 turns into `![p3-img-0.jpeg](p3-img-0.jpeg)` before the markdown is stored — downstream conversion no longer has to track which page section a ref came from.
  • New
    getIndexedMarkdownDownloadUrl returns signed URLs for every cropped image alongside the markdown URL. The download chip pre-fetches them in parallel and hands the bytes to the docx converter via a resolver callback; HTML export rewrites markdown image hrefs to the signed URLs pre-parse so the resulting <img> tags load.
  • New
    createWordDocumentFromMarkdown grows an optional resolveImage option. The `image` marked token now routes through it instead of falling to the raw-text default, so unresolved refs drop silently rather than echoing `![alt](src)` into the .docx. Image-only paragraphs become standalone ImageRun blocks with generous spacing.
  • New
    New pdfIndex.imagesIngested flag drives a one-time backfill: existing indexes from before image ingest cache-miss on re-upload and re-OCR without a double charge, same contract as the prior needsBlockUpgrade backfill.
  • Fixed
    headless-image-paths.ts canvasToImageRun was missing the required `type` field on docx v9 ImageRun (would've thrown at runtime). Set to 'png' to match the canvasToBlob output.

v2026.05.11-5

May 11, 2026

Chat PDF exports stop ignoring the OCR markdown they already had

Ask Chat to convert a PDF to Word and you used to get a wall of unstyled text — headings flattened, paragraphs collapsed, plus whatever OCR typos were baked into the source PDF's text layer. Meanwhile every PDF you upload already runs through Mistral OCR during indexing, which produces clean markdown with real headings, lists, and tables. The conversion path was just ignoring it. Now it doesn't. Ask for .docx, .html, .md, or .txt and the download chip rebuilds the file from the indexed markdown. Heading 1s stay Heading 1s, tables survive, bold and italic stick, and nothing inherits the broken OCR sitting in the source bytes.

All changes in version 2026.05.11-5

  • New
    New <emit-file source="index"/> directive shape — self-closing, no body. The chat assistant emits it for conversion requests, the chip pulls pdfIndex.markdownStorageId at download time, and conversion to docx / html / markdown / text happens client-side. Replaces the lossy <open-tool slug="pdf-to-word"/> path for TextBased and Mixed PDFs.
  • New
    EMIT_FILE_FORMATS expanded from markdown/text to markdown/text/html/docx. Inline-source emit-file still only accepts markdown/text — the model can't write a docx body inline. Index-source supports all four since the body comes from storage.
  • New
    New getIndexedMarkdownDownloadUrl query returns a signed URL to the indexed markdown, gated by message → conversation → user ownership. The emitted-file chip dispatches on emittedFileSource: inline streams the stored blob as before; index fetches the markdown, strips internal page separators and cite markers, and runs format-specific conversion (marked for HTML, createWordDocumentFromMarkdown for DOCX). Both converters lazy-load so the chat bundle doesn't pay for marked/docx on every page load.
  • Fixed
    Chat system prompt updated: "convert to word" on a TextBased or Mixed PDF routes through <emit-file format="docx" source="index"/> instead of <open-tool slug="pdf-to-word"/>. The OCR-then-Word branch in the scanned-PDF ask-choice routes through the index path too — Mistral OCR already ran during ingest, re-OCRing in a separate tool was duplicate work.
  • New
    Schema: chatMessage gets emittedFileSource ("inline" | "index") so the chip knows whether to stream a stored blob or convert from indexed markdown. Existing inline rows keep working — the field defaults to inline when undefined.

v2026.05.11-4

May 11, 2026

Chat PDF asks before converting a scanned PDF to Word

Ask Chat to convert a scanned PDF to Word and you'd previously get back an empty .docx with no warning. Now Chat notices the source is image-only and asks under the reply: run OCR and pack the text into a fresh Word doc, embed each page as an image (preserves the look, not editable), or do both — text alongside each page image. Click a chip and the file is built and ready to download in the same bubble. No bouncing into a separate tool. No flipping a toggle to enable OCR. Just pick the outcome and the AI delivers it.

All changes in version 2026.05.11-4

  • New
    New <ask-choice> directive the chat assistant emits when running the obvious tool would silently fail. The model writes a prompt and 2–4 labeled options; the bubble renders each option as a button that submits its label as a fresh user turn, so the AI's next response routes on what the user actually picked. Mutex with the other action directives in the same turn — picking the wrong tool is worse than pausing to ask. Reusable: future failure modes like password-protected PDFs or multi-language scans can opt into the same chip-style clarification.
  • New
    Three new chat-only conversion slugs: ocr-pdf-to-word (OCR → editable Word), pdf-pages-to-word (each page embedded as an image — preserves layout), and ocr-pdf-to-word-with-images (both — OCR text alongside each page image). Each has its own headlessRun so the chat chip downloads the right artifact in one shot, no flipping into the standalone tool to toggle settings.
  • Fixed
    The model was leaking the Document profile into its prose ("This PDF contains selectable text, so I can route you directly..."). Renamed the prompt section to "Routing hints (INTERNAL — never mention, quote, or paraphrase in your prose)" and added explicit examples of terse acks. The bubble now reads "Converting to Word." with no meta-commentary on what the AI thinks the PDF is.
  • New
    PDF classification on upload. The chat upload hook fires inspector.classify() in the background after the bytes land and patches pdfType (TextBased / Scanned / ImageBased / Mixed) plus hasExtractableText onto the pdfIndex row. The system prompt renders it as a Document profile block, which is what lets the LLM tell the difference between a text PDF and a scan before it decides which directive to emit.
  • Fixed
    Headless pdf-to-word throws EmptyExtractionError when extraction returns under 8 trimmed characters instead of packing an empty .docx. The chat chip catches it and falls back to the click-to-open CTA so the user can still get into the standalone PDF→Word tool (which has OCR mode in its config panel) rather than walking away with a zero-byte download.
  • New
    Schema additions: pdfIndex gets pdfType, hasExtractableText, pagesRequiringOcr; chatMessage gets askChoicePrompt + askChoiceOptions. New chatPdf.setDocProfile mutation persists the client classification, and a new parseAskChoicePlan parser clamps option counts and label lengths before any chip lands on the message.
  • Fixed
    Cache-hit rows backfill the profile on the fly. Legacy pdfIndex rows from before this field existed pick up the classification the next time they're opened in a chat, so the model eventually sees a profile for every document without a separate migration job.

v2026.05.11-3

May 11, 2026

Chat PDF can fill IRS-style forms now

Ask Chat to fill an IRS Form SS-4 (or any PDF whose AcroForm field names look like topmostSubform[0].Page1[0].f1_1[0]) and it actually works. The server tries to match labels by name first since that path is cheap and handles most forms. If nothing matches, the browser takes over: pdfjs reads the visible label text plus every form-widget rectangle on the page, then pairs each label with the closest empty field nearby. Same chip, same download. The old "I couldn't match any of those labels" failure should be a lot rarer.

All changes in version 2026.05.11-3

  • Fixed
    Chat PDF form fill: when name-based AcroForm matching produces zero hits, hand the labels off to the browser instead of writing an error. A new unresolvedFillFields field on chatMessage stages the unmatched labels, isFilling stays true so the chip keeps pulsing while client-side grounding runs.
  • New
    Client-side spatial grounding for form fields. The new resolve-fill-fields helper reads pdfjs text content and widget annotations per page, finds the label's bbox in PDF user space, and scores nearby unfilled widgets. Same-row pairings (label on the left, field on the right) win; a below-label fallback catches stacked layouts. One widget per label, greedy in input order, threshold-guarded so a label without a plausible nearby widget is left alone.
  • New
    New applyResolvedFill public action on chatPdfFill. Takes {fieldName, value} pairs the browser already resolved, applies them by exact AcroForm name, regenerates appearance streams, and lands the filled blob on the message via the same _setMessageFill mutation runFormFill uses. Idempotent: a duplicate dispatch from React strict-mode hits the alreadyFilled guard and returns early.
  • New
    New useApplyResolvedFill hook in the thread pane. Watches the chat list for messages with unresolvedFillFields set but no filledPdfStorageId yet, downloads the effective source PDF (respecting the conversation's prior fill chain), runs the spatial grounding, dispatches applyResolvedFill. Tracks in-flight message ids so the reactive query re-emitting a row can't spawn a parallel resolve.
  • Fixed
    Chat PDF form fill: route "Yes" / "No" answers to checkboxes instead of leaking them into nearby text fields. The resolver now detects boolean values (yes / y / true / on / 1 — and their negative counterparts) and only considers checkbox widgets for those, while text values are barred from checkbox widgets. Stops the misfill mode where "yes" got written into the "If 8a is Yes, enter number of LLC members" text field on SS-4.
  • New
    Checkbox disambiguation by adjacent option label. Each checkbox widget gets tagged with the nearest "yes" or "no" text item within ~24pt of its center, so the resolver can pair {label: "Is this an LLC?", value: "Yes"} to the checkbox the form actually printed "Yes" next to (not whichever box happens to be closer to the question text). Radio groups still untouched in this pass.
  • Fixed
    Resolver emits a console.warn listing every label it couldn't place — visible per-fill, useful for diagnosing model output drift (e.g. when the LLM emits "Company name" instead of "Legal name" and the form's text layer doesn't carry that synonym).

v2026.05.11-2

May 11, 2026

Chat PDF now has a real memory

Chat PDF carries facts forward across turns. Three scopes: things about you (your name, role, how you like answers), things about the PDF (who the contract is for, what kind of report this is), and things about the chat (bullet-only answers, skip the jargon). The assistant proposes saves itself when something durable comes up — you get a Save/Dismiss chip on the bubble, nothing lands without you saying yes. Or type /remember anything you want kept; /memories opens the panel; /forget cleans up. Memories ride into every future prompt so you stop repeating yourself.

All changes in version 2026.05.11-2

  • New
    Chat PDF memory system. New chatMemory table on the backend with three scopes (user / document / thread), each indexed for ownership-checked retrieval. The chat pipeline pulls the applicable rows on every turn and renders them as a "Saved memories you must respect" section above the document context — within a hard 2000-char injection budget so power users with 50+ memories don't bloat the prompt.
  • New
    Chat PDF: new <remember scope="user|document|thread">FACT</remember> directive. ADDITIVE — the model can emit it alongside any other directive, since saving a fact is orthogonal to whichever action drives the turn. The suggestion stages on the assistant message (pendingMemoryText/Scope) and renders as a Save/Dismiss chip in the bubble; nothing lands in chatMemory until the user clicks Save. Dismiss clears the pending fields with no row written. The model is told to only emit for durable facts about the person, the document, or stable preferences — never for one-off question content.
  • New
    Slash commands: /remember <text> (defaults to user scope, --document and --thread override), /forget <n>, /forget all [scope], /memories. Parsed client-side so they don't burn LLM tokens or count against the monthly operation cap. Synthetic user + assistant turns are inserted so the thread shows what got saved or forgotten. Dedupes against existing exact-match memories at the same scope so spamming /remember can't bloat the table.
  • New
    Memories panel in the workspace top bar. Grouped by scope with inline edit / delete affordances. Pulls from the same Convex query the chip components subscribe to, so accepting a suggestion on a bubble or running /remember updates the panel in the same render.

v2026.05.11

May 11, 2026

Chat PDF now delivers filled markdown as a real downloadable file

Ask "fill this with mock data and give me the markdown file" and you get exactly that: the filled content rendered inline AND attached as a downloadable .md (or .txt) chip — no more misleading "Filled PDF" artifact when you explicitly named a different format. Powered by a new <emit-file> directive on the chat router: when the user names a text output format, the model wraps the synthesized content and the server stores it as a blob, so the download chip lands on the message the same way the PDF chip does. PDF fill requests are unchanged.

All changes in version 2026.05.11

  • New
    Chat PDF: new <emit-file format="markdown|text" filename="…">CONTENT</emit-file> directive. The chat router parses the tag inside the model response, stores the captured content as a blob (text/markdown or text/plain), and attaches it to the assistant message via emittedFileStorageId/emittedFileFilename/emittedFileFormat. A new EmittedFileChip renders alongside FilledPdfChip in the bubble with a Download CTA. emit-file outranks the other three directives in honor priority (emit > run > open > fill) because a named output format is the most specific user intent.
  • Fixed
    Chat PDF: stop emitting <fill-pdf> when the user explicitly asks for a non-PDF output format. The system prompt now routes "markdown file" / ".md" / "save as text" through <emit-file> instead, and word-doc/image requests get a prose-only response with no directive (no path to those formats yet from the chat router).

v2026.05.10-8

May 10, 2026

Filled-form values now land inline with their labels

When you converted a filled fillable PDF, the values you typed showed up at the corner of each form field instead of where the text actually sits — so labels and values collided in weird ways and the checkbox glyphs ended up clustered at the bottom of the doc. Fixed: pdf-inspector now reads each widget's appearance stream (the same data pdftotext extracts) and places the rendered text at its real position. "Please enter your name: Jordan Lee" reads as one line, not two; checkboxes appear next to the option they belong to; values inside tables sit in their cells.

All changes in version 2026.05.10-8

  • New
    pdf-inspector: extract widget appearance streams. New extract_widget_appearance_text walks each page's /Annots, follows every Tx/Ch widget's /AP/N to its Form XObject, computes the placement transform mapping the form's /BBox (post-/Matrix) onto the widget's /Rect, and runs the appearance content stream through the existing extract_form_xobject_text pipeline. Result: form values land at their actual draw position as ordinary positioned text items, the same way pdftotext sees them.
  • Fixed
    pdf-inspector AcroForm /V walker now skips widgets whose appearance stream already produced text (so values aren't double-emitted). Btn fields stay on the /V walker path because their appearance is usually a single Zapf Dingbats glyph; the ☑/☐ rendering reads better than the raw extracted character.
  • Fixed
    Per-page Y-descending re-sort on pages that contain widget annotations. Without it, the line builder's stream-order vs Y-sort heuristic flipped on filled-form pages — appearance items jumping back up to their widget positions read as chaos and form values were emitted at the document tail. Pages without widgets are untouched, so non-form PDFs (where stream order can be load-bearing for footnotes/sidebars) aren't affected.
  • Fixed
    Tables in fillable forms now render as real Word tables, not flat paragraphs. Three fixes that compose: (1) the thin-rect synthesis path now merges co-linear segments before passing to the line-based table detector, so Word's per-cell border stamping (each cell edge as its own 0.48pt rect) reconstructs into the 3 horizontal + 3 vertical lines a 2×2 table needs — previously each 14.64pt fragment was discarded as decoration. (2) the line-based detector skips its capture-ratio gate when cell density is ≥80%, so densely-filled small tables embedded in form pages aren't rejected as chart-axis pseudo-tables. (3) cell assignment iterates column edges right-to-left so items right at a boundary land in the higher column instead of the lower one (the prior find returned the first match, mis-claiming items inside the ±2pt boundary tolerance).
  • New
    pdf-inspector now tracks per-glyph fill color (g/rg/k/sc/scn operators) and propagates it through extraction and the merge pass. TextItem gained a color field exposed to JS via the WASM API, used by two markdown layer changes: (a) force a paragraph break between adjacent lines whose dominant color differs by ≥32 per RGB channel, so blue section labels stay separated from black body values; (b) promote short non-near-black lines to H2 headings, which Word renders in blue by default — restoring the visual style of fillable-form labels without needing inline color spans in the markdown.
  • Fixed
    Checkbox options now render as a bulleted list, one option per paragraph, instead of collapsing onto a single line. Three sub-fixes: (1) is_list_item / format_list_item recognize ☑ and ☐ as list markers; (2) the line builder no longer breaks the link between a glyph and its label when the glyph sits to the left of the label (which routinely happens because the widget's Rect.x is a few points lower than the page-content label's x — the line-builder's reverse-x check now permits single-character items to join their row); (3) the list formatter inserts a space between glyph and label when the source has none.
  • Fixed
    Tightened paragraph spacing on Heading2 (240/120 → 120/60 twips before/after) and body paragraphs (200 → 120 twips after). Form-style PDFs sit labels close to their values; the previous Word defaults pushed them too far apart and made the docx look airy compared to the source.
  • Fixed
    Stop bolding the first table row by default. Markdown table syntax always has a header row, but the dependent-style tables our inspector synthesizes from thin-rect borders don't actually want bold styling — row 1 is just data. Render every row identically; if the source has a real header, the user can bold it in Word.
  • Fixed
    Set Calibri as the docx body font on every TextRun. Word's default fallback is Times New Roman in some renderers; explicit Calibri matches what most Word-generated source PDFs use.
  • Fixed
    Checkbox lines no longer get a Word bullet stacked on top of the ☑/☐ glyph. The list-paragraph generator skips the bullet when an item starts with a checkbox glyph, so each option reads as just ☑ Option 1 — matching the visual style of the source form.
  • Fixed
    Tighter Heading2 spacing — after-spacing zeroed so a blue label sits flush against the value paragraph beneath it, the way form-style PDFs render. Body paragraph after-spacing trimmed from 120 to 80 twips, list-item after-spacing zeroed.

v2026.05.10-7

May 10, 2026

Filled-form PDF to Word: no more "Dropdown2:" in your docx

Convert a filled fillable PDF and the docx came back with internal field identifiers all over it — "Name: Jordan Lee", "Dropdown2: Choice 1", "Option1 Option 1: On", "NameofDependent Name of Dependent: Alex Lee". Those are PDF-internal names that Word users were never meant to see. They're gone now: only the value lands in the doc, at the field's position. Checkboxes also got upgraded — instead of "Option 1: On" you get a real ☑, and unchecked boxes show ☐ instead of being silently dropped. Same fix flows through pdf-to-markdown and the chat-pdf headless converter.

All changes in version 2026.05.10-7

  • Fixed
    pdf-inspector form-field walker (extractor/links.rs): drop the "FieldName: " prefix when emitting AcroForm values. /T names like "Dropdown2", "Option 1", "Name of Dependent" are dev-facing identifiers — they have no place in user-visible output. Page content already has the human label.
  • Fixed
    Btn fields now render as Unicode glyphs: ☑ for /On, ☐ for /Off (and for missing /V). Previously /Off returned early so unchecked boxes left a hole in the output, and /On emitted the literal string "On". Pushbuttons (/Ff bit 17) are skipped — their /V is an action target, not a checkbox state.
  • Fixed
    pdf-inspector markdown post-processor: normalize literal tab characters in extracted text to single spaces. Word/Acrobat-generated PDFs sometimes encode inter-word positioning gaps as \t, which renders as nothing in Word without a tab stop, mashing words together ("Name of Dependent" → "NameofDependent" in the output docx). Replacement happens after table cells are emitted, so markdown tables (which use pipes) are unaffected.

v2026.05.10-6

May 10, 2026

Chat PDF: filled-in form text no longer comes back as gibberish

If you fed Chat PDF a filled form and asked for a Word or Markdown export, the values you actually typed (names, addresses, anything non-trivial) came out as ?? J o r d a n L e e — replacement chars where the BOM should have been, and a space wedged between every letter. That was a UTF-16 BE byte order mark the form-field decoder was reading as raw UTF-8. Acrobat and Preview both write filled values that way, so basically every real-world filled form was hitting this. Fixed: the decoder now handles both PDFDocEncoding and UTF-16 BE, the way the PDF spec says it should.

All changes in version 2026.05.10-6

  • Fixed
    pdf-inspector (Rust/WASM): form-field /T names, /V text values, and link /URI strings now route through decode_text_string instead of String::from_utf8_lossy. Detects the 0xFE 0xFF BOM, decodes the rest as big-endian UTF-16; falls back to PDFDocEncoding for plain bytes.
  • Fixed
    Same path fixes pdf-to-markdown and pdf-to-word in chat (both ran through the inspector) and any tool that reads AcroForm values

v2026.05.10-5

May 10, 2026

Chat PDF: ask, get the file. No tool overlay needed.

Telling the assistant "convert this to a word doc" used to land you on a "Open in PDF to Word" chip — fine, but you still had to click through, wait for the tool to mount, and click Convert. Now: when you ask, the chip pulses with "Converting to Word…" and resolves to a downloadable .docx right in the bubble. Same for JPG, PNG, WebP, BMP, plain text, Markdown, grayscale, color invert, repair, and annotation removal. Everything that has a deterministic transform with no parameters now auto-executes the moment the model suggests it. Tools that genuinely need UI input (sign, redact regions, image watermark, edit-pdf) still show the click-to-open chip — that's where it's actually useful.

All changes in version 2026.05.10-5

  • New
    Tool registry: optional `headlessRun: () => Promise<HeadlessRunFn>` on ToolDefinition lets a tool register a UI-free executor that takes a File and returns a {blob, filename}. Lazy import keeps the conversion deps out of every host bundle.
  • New
    Chat: SuggestedToolChip auto-executes a tool's headlessRun when present. Chip lifecycle: idle → running ("Converting to {tool}…") → ready (download chip with the produced blob). Falls back to the original click-to-open chip if the headless path errors so users are never stuck.
  • New
    Headless wired for ten tools: pdf-to-word, pdf-to-jpg/png/webp/bmp (shared image-export pipeline), pdf-to-text, pdf-to-markdown, repair-pdf, remove-annotations, pdf-to-grayscale, invert-colors
  • Improved
    Extracted shared makePdfToImageHeadless helper for the four pdf-to-image tools — single render-to-canvas-and-zip pipeline, format/quality/extension as params. Per-tool wrappers are 3 lines.

v2026.05.10-4

May 10, 2026

Chat PDF: instant rotate, lock, sanitize, compress, reverse

The chat assistant can now run zero-config transforms directly without bouncing you through a tool. Say "rotate every page 90", "lock the form", "compress this", "remove the metadata", or "reverse the page order" and the result downloads in the bubble — same chip you already get for form fills, no second click required. Anything more involved (conversions, signing, redaction, image watermarks, page extraction) still routes through Open-in-tool, so you only pay the UI tax when there's actually configuration to do.

All changes in version 2026.05.10-4

  • New
    Chat: new <run-action type="..."/> directive lets the AI fire rotate / reverse / flatten / sanitize / compress directly on the source PDF — chip pulses while the transform runs, then resolves to a download chip with the appropriate filename suffix
  • New
    Backend: new chatPdfFill.runInitialAction internalAction loads the conversation's source PDF, applies one of five shared pdf-lib transforms (extracted from the existing follow-up actions), and stores the result via _setMessageFill — same chip semantics as form fill
  • Improved
    Backend: extracted applyFlatten / applySanitize / applyRotate / applyReverse / applyCompress as shared pdf-lib transforms; both the chip's More-menu follow-up actions and the new run-action directive call them. Single source of truth for transform behavior
  • New
    Backend: directive telemetry — every assistant message records emittedDirectives (everything the model tried) and honoredDirective (what we acted on) so prompt-fidelity drift shows up in the data instead of as user-visible bugs
  • New
    System prompt now lists three directives (fill / run / open) with priority rules and 11 few-shot examples covering rotate, reverse, lock, sanitize, compress, convert, extract, redact, sign, add page numbers, and the explicit "no directive" case

v2026.05.10-3

May 10, 2026

Chat PDF: ask in plain English, get the right tool

The chat assistant used to know how to do exactly two things — answer questions and fill forms. Anything else (convert to Word, rotate pages, compress, sign, redact, watermark, crop, extract pages…) it would punt on with "I can't do that." No more. The system prompt now ships with the full catalog of fifty PDF-input tools, and the assistant emits an <open-tool> directive whenever you ask for an action it can't run inline. The reply gets a "Open in PDF to Word" (or whichever tool fits) chip — click it and the tool opens fullscreen over the chat with your PDF already loaded. As a side effect: the model can no longer over-eagerly emit <fill-pdf> on a non-fill turn, because <open-tool> takes precedence when both appear, killing the stray "Filled PDF" chip that used to show up after a botched conversion request.

All changes in version 2026.05.10-3

  • New
    Chat: AI now suggests the right tool for any operation it can't run inline — emits <open-tool slug="..."/> directive that the chip resolves to a one-click "Open in {tool}" CTA, mounting the tool over chat with the indexed PDF pre-staged on continuation
  • New
    Backend: system prompt rewritten with the full PDF-input tool catalog (fifty tools across Organize / Edit / Convert / Security / Optimize), explicit directive rules (mutually exclusive <fill-pdf> vs <open-tool>), and few-shot examples so the model picks the right slug for "convert to Word", "rotate", "redact", etc
  • New
    Backend: new chatMessage.suggestedToolSlug field + getSourcePdfDownloadUrlForMessage query; parseOpenToolPlan validates against the catalog so a hallucinated slug never persists
  • Fixed
    Chat: stray "Filled PDF" chip on conversion requests — when the model over-emitted <fill-pdf> with hallucinated labels even though the user asked to convert, the dispatcher now prefers <open-tool> when both appear and the prompt explicitly forbids fill-pdf as a fallback for unrelated asks

v2026.05.10-2

May 10, 2026

Chat PDF: every tool, one ellipsis away

The More menu on the download chip used to be a fixed shortlist — Edit, Rotate, Reverse, Lock, Sanitize, Compress. Now it has a search input at the top and the full OxygenPDF catalog underneath, grouped by category (Organize, Edit, Convert, Security, Optimize). Pick any tool and it opens fullscreen over the chat with your filled PDF already loaded — no re-upload, no losing the conversation. The original quick actions stay at the top for one-tap operations; the catalog is for when you want the full tool experience (page-by-page rotation, watermark options, redaction, etc).

All changes in version 2026.05.10-2

  • New
    Chat: download chip's More menu picks up a Search input and the full PDF-input tool catalog grouped by category — every tool that accepts a PDF is one click away
  • New
    Chat: new generic ToolOverlay mounts any registry tool fullscreen over chat with the filled PDF pre-staged on the continuation context (mirrors the existing EditPdfOverlay plumbing — useLayoutEffect + staged gate so the tool consumes continuation before its first paint)
  • New
    Chat: catalog items search across title + category + description, so typing 'convert' surfaces every Convert tool and 'compress' finds Compress PDF wherever it lives

v2026.05.10

May 10, 2026

Chat PDF: in-page editor + a fuller More menu

The "Edit in editor" item on the download chip now opens the existing /tools/edit-pdf experience as a fullscreen overlay over the chat instead of navigating away — your conversation stays put underneath. The More menu also picked up three new actions: Rotate 90° (clockwise per click, stacks for 180°/270°), Reverse page order, and Compress (structural). The chip's label and filename track every action you apply, so a fully worked-over PDF reads as e.g. "Filled, rotated, locked, and compressed PDF" — and once an action has been applied, its menu item flips to a "done" state to keep you from doing it twice.

All changes in version 2026.05.10

  • New
    Chat: "Edit in editor" opens the editor inline as a fullscreen overlay (CloseTabProvider trick lets EditorDialog render inline inside our portal'd container instead of stacking another fullscreen Dialog on top)
  • New
    Chat: More menu adds Rotate 90° (composes with prior rotation), Reverse page order, and Compress (structural). Menu now grouped into Continue editing / Structure / Finalize / Optimize
  • New
    Backend: chatPdfFill gains rotateFilledPdf, reverseFilledPdf, and compressFilledPdf public actions sharing the runFollowUpAction helper. Save options gate per-action ({useObjectStreams, objectsPerStream} for compress)
  • New
    Chat: chip filename and label track six action types now (filled, rotated, reordered, locked, sanitized, compressed) with proper Oxford-comma serialization

v2026.05.09-7

May 9, 2026

Chat PDF: ellipsis menu on the download chip — Edit, Lock, Sanitize

The filled-PDF download chip picked up a "More" ellipsis modeled on the continuation tool's tool-picker. Open it on a filled chip and you get three follow-up actions: Edit drops the file into /edit-pdf via the continuation context (no re-upload), Lock flattens the form so the recipient can't change your answers, and Sanitize strips the PDF's identifying metadata (author, title, producer, timestamps). The chip's label and filename update to reflect what's been applied — "Filled and locked PDF", "Filled, locked, and sanitized PDF" — so the user always sees what they're about to download. Each follow-up action is one Convex action call: load the existing filled PDF, transform with pdf-lib, replace the storage blob, patch the message.

All changes in version 2026.05.09-7

  • New
    Chat: download chip gains a More ellipsis (mirrors the continuation tool-picker) with Edit in editor, Lock the form, and Sanitize metadata
  • New
    Chat: Edit action hands the filled PDF to /edit-pdf through the existing continuation context — the editor consumes the blob on mount instead of bouncing the user through the dropzone
  • New
    Chat: Lock action runs pdf-lib form.flatten() on the server and replaces the chip's filled PDF in place; chip label flips to "Filled and locked PDF"
  • New
    Chat: Sanitize action strips Title / Author / Subject / Keywords / Creator / Producer / CreationDate / ModDate from the filled PDF's Info dictionary
  • New
    Backend: new public Convex actions chatPdfFill.flattenFilledPdf and chatPdfFill.sanitizeFilledPdf, plus internal helpers (_getMessageForFollowUp, _replaceMessageFilledPdf, _setMessageFollowUpPending / Error)

v2026.05.09-6

May 9, 2026

Chat PDF: ask the assistant to fill the form, get a downloadable PDF back

Drop a fillable PDF into chat, hand the assistant the values you want plugged in, and a download chip appears in its reply with the form actually filled. The assistant emits a structured fill-pdf directive alongside its prose answer; the server loads the original PDF, fuzzy-matches each label to a real AcroForm field with pdf-lib, applies the values, and stores the filled document. The bubble shows a pulsing chip while it works, then resolves to a tappable card that downloads the result with a sensible filename. Forms without AcroForm fields, or labels we couldn’t match to anything on the page, surface a quiet warning instead of silently failing.

All changes in version 2026.05.09-6

  • New
    Chat: AI can now produce a downloadable filled PDF when the user asks to complete the form — emits a <fill-pdf> directive that the server applies via pdf-lib AcroForm fuzzy-matching and returns as a stored file
  • New
    Chat: assistant bubble gains a download chip for filled PDFs with three states — pulsing "filling…" placeholder, tappable download card with filename, or an inline warning when the form has no fillable fields or no labels matched
  • New
    Backend: new chatPdfFill action (Node runtime) loads the original PDF from Convex storage, runs fuzzy label-to-field matching with bigram similarity, applies values to text/checkbox/radio/dropdown/option-list fields, and stores the result
  • New
    Backend: chatMessage rows gain isFilling / filledPdfStorageId / filledPdfFilename / fillError fields; new getFilledPdfDownloadUrl query returns an ownership-checked signed URL for the bubble

v2026.05.09-5

May 9, 2026

Chat PDF: warm paper canvas, editorial AI replies, deep-teal you

The chat workspace got a top-to-bottom design pass. The flat all-white canvas became a warm paper-and-ink surface system: the gutter behind the PDF is now a soft cream, the page itself stays paper-white as the protagonist, and the chat panel sits on a slightly raised warm offwhite. AI answers no longer wear a chat-bubble — they read as editorial prose on a Newsreader serif body with a subtle accent rail down the side, and citation chips became small italic footnote numerals instead of bright blue badges. Your messages flip to a deep-teal bubble with a pinched corner so the asymmetry visually says "I asked, the document answered." The sidebar recesses into the canvas, active chats get a left bookmark-ribbon and a raised paper card, and the empty-state hero now opens with an oversized italic "a" behind "Ask the document anything." Composer pill picks up an inset highlight, the send button is a circular deep-teal disc that nudges on hover. Same panes, same shortcuts, very different emotional temperature.

All changes in version 2026.05.09-5

  • New
    Chat: warm paper-and-ink surface tokens (chat-pdf-canvas / surface / sidebar / page / accent / accent-soft / accent-rail) with layered warm-tinted shadows and dark-mode equivalents
  • New
    Chat: AI replies render as editorial prose with Newsreader serif body, accent left rail, and italic footnote-style citation chips (no more bubble fill on assistant messages)
  • New
    Chat: user message bubble switches to deep teal with a pinched bottom-right corner so the user/AI asymmetry reads as conversation, not symmetric chat balloons
  • New
    Chat: sidebar drops into the recessed-canvas tone; active conversation now gets a left accent ribbon and a raised paper card; section labels render as Newsreader italic
  • New
    Chat: empty state opens with an oversized italic "a" drop-letter behind "Ask the document anything," prompt cards become outlined paper cards on accent-soft hover
  • Improved
    Chat: composer pill carries an inset highlight on the warm canvas, the send button becomes a circular deep-teal disc with a hover nudge, and the indexing progress bar/status chips switch from bright blue to the new accent system
  • New
    Chat (landing): the upload page rebuilds on the warm paper surface — eyebrow becomes a Newsreader italic line with accent dots, headline gains an italic teal "PDF." accent and a drop-letter motif, and the dashed dropzone becomes a raised paper card with an accent-soft upload medallion that lifts on hover
  • New
    Chat (landing): "Recent chats" gets an italic serif label flanked by a hairline divider, and the list card sits on the canvas with a raised paper shadow
  • Improved
    Chat: conversation row hover swaps to a translucent rule wash so it reads on both the sidebar surface and the lighter landing card without disappearing

v2026.05.09-4

May 9, 2026

All changes in version 2026.05.09-4

  • Fixed
    Chat PDF: tooltips on the selection toolbar (highlight swatches, bookmark) no longer get clipped by the toolbar — the shared Tooltip now portals to the body so it can escape any overflow-hidden ancestor

v2026.05.09-3

May 9, 2026

Chat workspace: top bar with layout switch, theme + sign-in always one click away

A new top bar sits above the preview and chat panes. A three-way switch flips between PDF only, split view, and chat only — picks stick across reloads. Theme toggle and your account live up there too, alongside a keyboard-shortcuts shortcut. The old "Indexed — ask anything about this PDF" line was replaced with a small "✦ Ready" chip beside the filename, and a thin progress bar shows up only while the document is still indexing.

All changes in version 2026.05.09-3

  • New
    Chat: top bar with PDF / split / chat layout switch, theme toggle, account button, and shortcuts hint
  • New
    Chat: layout choice persists across reloads and auto-uncollapses when a citation chip is clicked
  • New
    Chat (mobile): theme toggle and account button now reachable from the mobile header
  • Improved
    Chat: replaced the "Indexed — ask anything about this PDF" status line with a compact chip beside the filename + progress bar that only shows while indexing

v2026.05.09-2

May 9, 2026

Chat workspace: collapsible sidebar, resizable chat pane, fewer keystrokes

The left sidebar now has a collapse button (or ⌘B), and the chat thread on the right is draggable — pull the divider to give the PDF more room or the chat more room. Your width sticks across reloads. The "New chat" shortcut moved off ⌘K (which usually means "search" in apps that have it) to ⌘⇧O, matching ChatGPT and Claude.

All changes in version 2026.05.09-2

  • New
    Chat: draggable vertical divider between PDF preview and chat thread, with the chosen width persisted to localStorage
  • New
    Chat: collapse button on the desktop sidebar and a floating expand button on the left edge when collapsed
  • New
    Chat: highlights and bookmarks track the canvas across viewport resizes — annotations no longer drift off the text on window resize
  • Fixed
    Chat: highlights and bookmarks are now persisted on the indexed PDF and re-render on reload, with a right-margin fallback marker if the bbox cannot be re-resolved
  • Improved
    Chat: replaced ⌘K with ⌘⇧O for "New chat" so ⌘K stays free for a future command palette

v2026.05.09-1

May 9, 2026

Select any passage in a chat PDF to explain, highlight, or bookmark it

Drag across text in the preview and a small toolbar appears above it. Tap Explain or Summarize and the selection goes to the AI as a quoted question. Pick a color to highlight the passage, or drop a bookmark to come back to it later. Both stick to the document, and a "Highlights & bookmarks" button at the top of the preview lists everything you have saved — click any entry to jump straight to its page. Right-click still works the same way for keyboard people. Replies from the AI now end with follow-up chips (Explain more, Give an example, Show source, Summarize this) so you can keep going without inventing a new prompt every turn.

All changes in version 2026.05.09-1

  • New
    Chat PDF: floating selection toolbar with Explain, Summarize, Define, Highlight (4 colors), Bookmark, and a custom Ask, triggered by drag-select or right-click
  • New
    Chat PDF: highlights and bookmarks persist per indexed PDF and render on top of the preview, with a delete affordance on hover
  • New
    Chat PDF: "Highlights & bookmarks" panel in the preview header lists every saved annotation with click-to-jump and inline delete
  • New
    Chat PDF: assistant replies show static follow-up chips so the next question is one tap away

v2026.05.09

May 9, 2026

Chat citations now highlight the cited sentence, not the whole block

Click a citation chip and you used to get the whole chunk, sometimes a multi-paragraph slab full of facts that had nothing to do with the answer. Citations now carry a verbatim quote, and the preview pane lands the highlight on that exact sentence. Two different chips on the same chunk hit two different sentences. When the quote can't be found (paraphrase, image-only PDF), the highlight drops back to the old chunk flash so you still see the right block.

All changes in version 2026.05.09

  • New
    Chat: citation chips highlight the cited sentence. The model attaches a verbatim `q="..."` quote, the preview pane resolves it to a tight bbox instead of the whole chunk.
  • Improved
    Chat: citation tag parsing switched to an order-independent attribute scanner, so new cite attributes survive whatever order the model picks
  • Fixed
    Chat: two chips pointing at the same chunk no longer share one cached bbox. The resolution cache is keyed by `(elementId, quote)`, so sibling citations land on their own sentences

v2026.05.08-13

May 8, 2026

Chat with PDF — mobile, keyboard, and a polished workspace

The chat workspace got a refresh. On phones, a tab toggle at the top swaps between the PDF preview and the chat thread, and tapping any citation chip flips you to the PDF so you actually see the source. The composer is a rounded pill with an embedded send button, an auto-growing textarea, and a kbd-hint footer. The empty state now offers four one-tap starter prompts. Recents in the sidebar bucket into Today, Yesterday, This week, This month, and Earlier. Keyboard shortcuts: ⌘K for new chat, ⌘B to toggle the sidebar, / to focus the composer, ? for the full reference. Hit ? anywhere on the page to see them.

All changes in version 2026.05.08-13

  • New
    Chat: mobile tab switcher between PDF preview and chat thread; citation chips auto-flip to the PDF
  • New
    Chat: rounded-pill composer with auto-growing textarea, embedded send button, and kbd-hint footer
  • New
    Chat: empty state surfaces four starter prompts that pre-fill the composer with one tap
  • New
    Chat: keyboard shortcuts — ⌘K new chat, ⌘B toggle sidebar, / focus composer, ? open shortcut help
  • New
    Chat: recents in the sidebar are now bucketed by Today / Yesterday / This week / This month / Earlier
  • Improved
    Chat: thread pane split into ChatComposer + ChatEmptyState components to stay inside the 100-line component cap
  • Improved
    Chat: workspace shell rebuilt around a mobile-first three-pane layout with a Sheet drawer for the sidebar

v2026.05.08-12

May 8, 2026

Chat with PDF — sidebar, edit, regenerate

The chat workspace now has a left rail with your recent conversations, a one-click way to start a new chat, and a back link to the rest of OxygenPDF — no more URL surgery to switch threads. Hover any user message to edit and resend it, hover the latest assistant reply to regenerate it. Copy lives on every bubble. Both edit and regenerate truncate the thread cleanly at the fork point so the conversation stays coherent.

All changes in version 2026.05.08-12

  • New
    Chat: workspace sidebar with recent conversations, "New chat", and a back link to the home page
  • New
    Chat: edit any user message and regenerate the assistant reply — backend `editAndResend` action truncates the thread at the edited message and re-runs retrieval
  • New
    Chat: regenerate the latest assistant response — backend `regenerateResponse` action finds the preceding user question, deletes the stale reply, and re-runs the prompt
  • New
    Chat: copy any message to clipboard via a hover-revealed action button
  • New
    Chat: delete a conversation from the sidebar (gated behind a confirmation dialog)
  • New
    Chat landing page now lists recent conversations below the dropzone
  • Improved
    Chat thread pane split into `chat-message-bubble`, `chat-message-actions`, and `chat-assistant-body` to stay under the 100-line component cap

v2026.05.08-11

May 8, 2026

Chat with PDF — selection no longer balloons to the top of the page

Selecting a paragraph in the preview was extending the selection up to every paragraph above it. Cause: pdfjs v5's TextLayer doesn't ship the `.endOfContent` anchor element older versions used to, so empty-space clicks (margins, gaps between paragraphs) anchored on the first text span in DOM order — i.e. the top of the page. We now create the anchor ourselves and toggle a `.selecting` class on pointerdown so the anchor expands to cover the whole layer during a drag.

All changes in version 2026.05.08-11

  • Fixed
    Chat: PDF text-layer selection now stays where you started — added the `.endOfContent` anchor element pdfjs v5 doesn't auto-create, plus pointerdown/up listeners that toggle the `.selecting` class to expand the anchor during a drag

v2026.05.08-10

May 8, 2026

Chat with PDF — select text and ask about it

PDF preview pages now have a transparent selectable text layer over the rendered canvas — drag-select like you would on any web page. Right-click on a selection and a small popover pops up with a question input. Type your question, hit Enter, and the selected passage flows into the chat thread as a quoted prefix to your question, so the AI can answer about that exact span.

All changes in version 2026.05.08-10

  • New
    Chat: PDF preview pages are now text-selectable — pdfjs `TextLayer` is rendered transparently over the canvas, so drag-select, double-click-to-word, and copy-to-clipboard all work
  • New
    Chat: right-click a selection in the preview to open an "Ask about this passage" popover; submitting sends the selection (as a markdown blockquote prefix) plus your question to the chat thread

v2026.05.08-9

May 8, 2026

Chat with PDF — citations highlight the actual text

Citations were flashing a vertical band sized to the chunk's share of the page — better than whole-page, still rough. The preview now matches the chunk's text against pdfjs's extracted text layer and flashes the actual text bbox: the exact paragraph or sentences the AI cited. Falls back to the vertical band if the PDF has no text layer (image-only scans).

All changes in version 2026.05.08-9

  • New
    Chat: citation flashes now land on the actual cited text — preview pane resolves the chunk text against pdfjs `getTextContent` on click and caches the resolved bbox by elementId
  • New
    Chat: new `listChunkTextsForIndex` query returns the full chunk text (no embeddings) for client-side bbox resolution

v2026.05.08-8

May 8, 2026

Chat with PDF — block migration actually triggers now

The block-citation migration shipped yesterday relied on `createOrReuseIndex` running on re-upload, but the frontend's `findIndexByHash` shortcut was bypassing it for any non-error cached row — so old PDFs kept getting page-level citations instead of upgrading. `findIndexByHash` now returns null for pre-block-level indexes, forcing the upload to flow through the migration path. Re-upload your PDF and you'll get sub-paragraph citation flashes on the next chat.

All changes in version 2026.05.08-8

  • Fixed
    Chat: `findIndexByHash` now returns null for pre-block-level indexes (chunks with bare page numbers as elementIds), so re-upload actually triggers the block-upgrade migration instead of joining a stale row

v2026.05.08-7

May 8, 2026

Chat with PDF — block-level citations

Citations used to flash the entire cited page when clicked, which was practically useless on dense pages. Each chunk now has its own pdfIndexElement with an approximate vertical-band bbox, so clicking a citation chip flashes the specific paragraph rather than the whole page. The model is told the block id of every chunk in its context (`<!-- block id="3-c-2" page="3" -->`) and cites with `<cite p="3" id="3-c-2"/>`. Existing PDFs auto-upgrade on next re-upload — no double-charge.

All changes in version 2026.05.08-7

  • New
    Chat: citation chips now point at chunks, not pages — clicking flashes the specific paragraph (vertical-band bbox approximation, sized to the chunk's share of the page)
  • New
    Chat: model prompt now teaches the block-id format and instructs `<cite p="N" id="N-c-K"/>` so citations carry sub-page granularity
  • New
    Chat: full-context path (≤50 pages) sends every chunk in chunkIndex order with block markers, so the model can cite the exact paragraph anywhere in the doc
  • Improved
    Chat: createOrReuseIndex auto-detects pre-block-level indexes (chunks whose elementIds are bare page numbers) and re-runs OCR+chunking to backfill block elements — no extra charge for the migration

v2026.05.08-6

May 8, 2026

Chat with PDF — answers render properly, citations actually click

Three rendering bugs collapsed into one bad screenshot: assistant messages were dumping raw markdown (literal `**Helga**`), every bare citation chip was getting a unique number even when it pointed at the same page (so you saw chips numbered 1–42 instead of one per page), and all chips were marked as "missing" so clicking did nothing. Now: messages render with markdown formatting, citation chips dedupe by page, and clicking one scrolls + flashes the cited page in the preview. Also told the model to stop stacking five citations on one claim.

All changes in version 2026.05.08-6

  • Fixed
    Chat: assistant messages now render markdown (bold, italics, lists, headings) instead of dumping raw `**asterisks**` and unbroken text
  • Fixed
    Chat: citation chips now dedupe by elementId — bare `<cite p="N"/>` tags are resolved to the page-cover element so two citations of the same page share one numbered chip
  • Fixed
    Chat: citation chips are now actually clickable — the resolution path was treating bare cites as orphaned, leaving every chip in the disabled / "Citation not found" state
  • Improved
    Chat: tightened the citation prompt — one citation per claim instead of "cite every page where the info appears", which had the model emitting up to 11 chips next to a single character name

v2026.05.08-5

May 8, 2026

Chat with PDF — smarter answers, real citations

Switched the chat model from gpt-4o-mini to Mistral Large for better instruction-following — the model now actually emits the <cite p="N"/> markers the system prompt asks for. For documents up to 50 pages, the entire OCR'd markdown gets stuffed into the prompt instead of vector search, so broad questions like "list all characters" stop missing the long tail. Longer docs use a wider top-20 retrieval (was top-8). Citation chips appear under the answer and clicking one scrolls + flashes the cited page in the preview.

All changes in version 2026.05.08-5

  • New
    Chat: full-document context for short PDFs (≤50 pages) — entire OCR'd markdown is sent to the model, eliminating retrieval misses on broad questions
  • New
    Chat: vector retrieval bumped from top-8 to top-20 for documents longer than 50 pages
  • Improved
    Chat: switched chat model from gpt-4o-mini (OpenAI) to mistral-large-latest (Mistral). Same key as OCR, no extra setup, stronger instruction-following on the citation rules
  • Fixed
    Chat: tightened the system prompt — citations are now framed as non-negotiable with concrete examples, so the model stops dropping <cite p="N"/> markers on broad answers

v2026.05.08-4

May 8, 2026

Chat with PDF — chat works again, preview stays sharp

Switched the chat backend from a flaky Replicate proxy of DeepSeek-V3 (which was rejecting our payload at the SiliconFlow upstream) to a direct OpenAI gpt-4o-mini call — same citation-grounded answers, faster, and one fewer API key to manage. Fixed the blank-white PDF preview by making the shared page renderer wake consumers up when the doc finishes loading. Reworked the indexing scan animation into a softer two-layer sweep that doesn't fight the underlying text.

All changes in version 2026.05.08-4

  • Fixed
    Chat: replaced Replicate DeepSeek-V3 with OpenAI gpt-4o-mini for chat completions — Replicate's SiliconFlow upstream was returning "Message field is required" for our OpenAI-style payload
  • Fixed
    Shared PDF renderer: `renderPage` identity now bumps on internal version change, so consumer effects (PdfPageCanvas) re-fire when the doc finishes loading instead of leaving the canvas blank white
  • Improved
    Chat: redesigned the indexing scan animation — soft tint pulse + thin gradient line tracer
  • Improved
    Backend: dropped REPLICATE_API_TOKEN dependency from the chat path — only MISTRAL_API_KEY (OCR) and OPENAI_API_KEY (embeddings + chat) are needed now

v2026.05.08-3

May 8, 2026

Chat with PDF — preview pane polish

Fixed the blank white preview that hit when the page-dimension load raced the canvas renderer — pages now paint as soon as they're ready. Added a soft cyan scanner-pass animation that sweeps each page while the index is being built, so the wait feels intentional. Cleaned up the redundant per-page "Failed" pill that was just repeating the doc-wide status on every card.

All changes in version 2026.05.08-3

  • Fixed
    Chat: PDF preview no longer renders blank white — page dimensions are now read from the same pdfjs document the canvas paints from, eliminating a race that left the canvas unrendered
  • Fixed
    Chat: re-uploading a PDF that previously failed to index now actually retries — the cache-hit shortcut was joining errored rows and silently inheriting the old failure
  • Fixed
    Chat: thread pane shows the actual indexing error instead of a misleading 'Starting up…' message when the index is in an error state
  • New
    Chat: scanner-pass animation overlays each page while the index is being OCR'd or embedded
  • Improved
    Chat: dropped the per-page status pill from the preview — the doc-wide indexing state already lives in the header, repeating it on every page was noise

v2026.05.08-2

May 8, 2026

Chat with PDF — indexing is fast now

Replaced the per-page vision-OCR loop with a single Mistral OCR call. A 50-page PDF now indexes in ~10–20 seconds instead of ~3 minutes. Chat unlocks the moment the first chunks are embedded — you can start asking questions while the rest of the document is still being processed in the background.

All changes in version 2026.05.08-2

  • Improved
    Chat: switched OCR provider from DeepSeek-OCR (per-page Replicate predictions) to Mistral OCR (single whole-document API call) — kills the ~5s/page latency tax
  • New
    Chat: 'partial' index status — chat input unlocks after the first batch of chunks is embedded; remaining chunks finish in the background
  • Improved
    Chat: browser no longer renders or uploads page images — only the original PDF is uploaded, Mistral fetches it directly

v2026.05.08

May 8, 2026

Chat with PDF — rebuilt around persistent indexing

Reload-safe, regenerate-safe, no re-OCR. Upload a PDF once and we index it in the background — content-hashed, so re-uploads of the same file are instant. The chat is now subscription-aware (free tier with monthly cap) and runs entirely on our infrastructure: server-orchestrated DeepSeek-OCR with proper rate-limit retry, OpenAI text-embedding-3-small for chunked retrieval, DeepSeek-V3 over only the relevant chunks. Grounded citations with click-to-source preserved.

All changes in version 2026.05.08

  • Improved
    Chat: moved OCR + chat off the browser onto Convex actions — pages are no longer re-indexed on reload, regenerate, or new questions
  • New
    Chat: content-hash dedup so re-uploading the same PDF skips the entire pipeline and reuses the existing index
  • New
    Chat: vector retrieval (top-8 chunks per question) instead of stuffing the full markdown into every prompt — flat input cost regardless of doc length
  • New
    Chat: upload-first /chat UI with PDF preview on the left and chat on the right, replacing the previous chat-input-as-landing flow
  • Fixed
    Chat: 429 rate-limit hell — Replicate calls now run server-side, sequentially, with Retry-After-aware exponential backoff
  • Improved
    Chat: removed the BYOK Replicate proxy, the local Gemma fallback, the in-browser bbox cache, and the IndexedDB chat-files layer in favor of a single auth-gated cloud path

v2026.05.07

May 7, 2026

Cloud Chat with Click-to-Source Citations

Bring your own Replicate token and the chat sidebar gains a cloud mode powered by DeepSeek-OCR + DeepSeek-V3. OCR indexes every page with bounding-box grounding so answers come with citation chips you can click to jump straight to the highlighted region on the source page. Same conversation, same slash commands — but with cited answers and an extensible provider layer so we can swap in Kimi or Claude later without touching the UI.

All changes in version 2026.05.07

  • New
    Chat: new Cloud AI mode (BYOK Replicate) — DeepSeek-OCR indexes pages with bbox grounding, DeepSeek-V3 chats over the index with native tool-calling into the existing PDF processors
  • New
    Chat: citation chips appear under cloud answers; clicking a chip opens the cited page with the bbox highlighted
  • New
    Cloud AI: abstract `CloudAiProvider` layer with Replicate proxy through Convex — adding new providers (Kimi, Claude direct, OpenAI) is one new file

v2026.05.06

May 6, 2026

Workspace Size-Limit Errors Now Tell You What To Do

Drop a file bigger than the free workspace cap and you used to get a dead-end "exceeds 10MB limit" banner. Hard tier blocks now pop an Upgrade to Pro dialog directly, with the cap spelled out and a one-click checkout path.

All changes in version 2026.05.06

  • New
    Workspace: hitting the free file-size or file-count cap now opens the Upgrade to Pro dialog directly instead of showing a passive banner
  • Fixed
    Workspace: size-limit error no longer prints the filename twice and no longer fires an infra-failure analytics event for what is really a tier limit

v2026.05.05

May 5, 2026

Tools Open Cleanly From Any Entry Point

Edit PDF, Compare, Compress, Redact, Remove Watermark, the PDF→Text/Word/Markdown family, and several shared rendering paths could all throw "No GlobalWorkerOptions.workerSrc specified" if you opened them as your first tool in a session. Every pdfjs entry point now configures its own worker instead of relying on a different code path to do it first.

All changes in version 2026.05.05

  • Fixed
    PDF tools: "No GlobalWorkerOptions.workerSrc specified" error on direct tool entry across the fleet

v2026.05.03

May 3, 2026

Two New Alternative Guides on the Blog

Deep-dive comparisons for people searching "Sejda alternative" and "Wondershare PDFelement alternative" — what each product actually is in 2026, what their free tiers really do, and where their privacy stories hold up or fall apart.

All changes in version 2026.05.03

  • New
    Blog: Sejda PDF Editor alternative — pricing, the 3-task wall, watermarks on Edit and Sign
  • New
    Blog: Wondershare PDFelement alternative — the cloud AI behind the desktop UI, the 2025 RepairIt CVE incident, and the trial that watermarks everything

v2026.04.30

April 30, 2026

Crisp PDF Pages at Any Zoom

Edit PDF and PDF Reader now paint pages straight onto a canvas sized to your actual device pixels, so text stays sharp on Retina and at high zoom instead of going through a PNG that the browser had to smooth out.

All changes in version 2026.04.30

  • Fixed
    Edit PDF: text no longer looks blurry on Retina or at high zoom
  • Fixed
    PDF Reader: render scale now tracks devicePixelRatio × zoom, and the pdfjs document is loaded once per file instead of on every page or zoom change
  • Fixed
    Edit PDF: navigating between pages no longer flashes a tiny stretched thumbnail — adjacent pages are pre-rendered and the fallback uses a sharper 400px thumbnail
  • Improved
    New shared PdfPageCanvas component and usePdfPageRenderer hook so every tool that displays a PDF page renders it crisply by default

v2026.04.17

April 17, 2026

Unified Action Bar Across Every Tool

Every PDF tool now shares the same action bar — workspace, mobile, and desktop. Big accent-colored primary button with a ⌘↵ shortcut, plus a Start over button with ⌘⌫ on standalone pages.

All changes in version 2026.04.17

  • Improved
    Every tool now uses the same ToolWorkspaceActionBar in the workspace and on its standalone page
  • New
    Cmd/Ctrl+Enter fires the primary action in every tool
  • New
    Cmd/Ctrl+Backspace triggers Start over on standalone tool pages
  • Improved
    Dropped the one-off inline action bars from compress, OCR, split, sign, and remove-watermark
  • Improved
    SVG to PDF preview restyled to match the shared action bar pattern
  • Improved
    Batch file tabs now follow the tool color — sticky count pill and accent underline on the active tab

v2026.04.15

April 15, 2026

Intelligent Text Extraction

New Rust→WASM engine for smart PDF text extraction with layout analysis. PDF to Word, PDF to Markdown, and PDF to Text now produce significantly better output with proper headings, lists, and structure.

Rich Tool Pages

Every tool page now features in-depth articles, FAQs with structured data, and visual diagrams — making it easier to understand each tool and boosting discoverability.

All changes in version 2026.04.15

  • New
    Rust→WASM PDF text extraction engine with intelligent layout analysis and content classification
  • New
    PDF to Word now uses markdown-aware extraction for better structure preservation
  • New
    PDF to Markdown and PDF to Text upgraded with the new extraction engine
  • New
    Article sections and FAQ sections with structured data (SEO) on all tool pages
  • New
    Collapsible article and FAQ sections for cleaner tool page layout
  • New
    Visual SVG diagrams across 15+ tool pages — Merge, Split, Sign, Protect, Edit, and more
  • New
    New blog articles: Convert PDF to JPG, Create Fillable PDF, Best Free PDF Reader, PDF to Text
  • New
    Blog link added to header and footer navigation
  • New
    License key management for purchasers via Polar integration
  • Improved
    Home page copywriting refreshed for clarity and conciseness
  • Improved
    Blog cover images converted to WebP for faster loading
  • Improved
    Tool conversion card simplified — removed Pro upsell for authenticated users
  • Fixed
    SEO improvements — robots.txt rules, canonical links, and updated sitemaps

v2026.04.13

April 13, 2026

Split Scanned Pages

New tool for splitting two-up scanned pages into individual pages. Handles booklets, side-by-side scans, and A3-to-A4 splitting with guided configuration.

Advanced PDF Compression

Compress PDF now handles huge files (up to ~1 GB). Set a target file size and let the tool auto-optimize, convert to grayscale for line drawings, or use the new Extreme preset.

All changes in version 2026.04.13

  • New
    Split Scanned Pages tool for separating two-up scans into individual pages
  • New
    Target file size mode — specify a size limit and auto-find optimal compression settings
  • New
    Grayscale option for massive savings on architectural drawings and line art
  • New
    Extreme compression preset (72 DPI, 35% quality) for screen-only viewing
  • New
    Loading progress bar with real-time feedback when opening large PDFs
  • New
    Large file upload nudge — guides free users toward Pro when processing big files
  • New
    Contextual upgrade prompts within tool pages for free users
  • Improved
    PDF processing switched from ArrayBuffer to blob URLs for better memory management across all tools

v2026.04.10

April 10, 2026

Cleaner Navigation

Streamlined top navigation bar — secondary links collapsed into a compact "More" menu for a cleaner, less cluttered header.

All changes in version 2026.04.10

  • Improved
    Top navigation decluttered — Download, Changelog, and Feedback collapsed into a "More" dropdown
  • Improved
    Header internals reorganized into smaller extracted components
  • New
    Announcement banner now has a dismiss button (persists per session)

v2026.04.07

April 7, 2026

Chat (Beta)

Ask questions about your PDFs using on-device AI. Upload a file and chat — all processing stays local. Slash commands coming soon.

All changes in version 2026.04.07

  • New
    Chat feature now available to all users (Beta) — no feature flag required
  • New
    Ask AI questions about PDF content with on-device vision models
  • Improved
    Renamed "Chat PDF" to "Chat" across navigation and UI
  • Improved
    Slash commands temporarily disabled — coming soon

v2026.04.03

April 3, 2026

Typography Refresh

New font system with DM Sans, Fraunces, and IBM Plex Mono for sharper, more consistent typography across all platforms.

Desktop Auto-Updates

The desktop app now checks for and installs updates automatically with a splash screen and status notifications.

All changes in version 2026.04.03

  • New
    Auto-update with IPC communication, status notifications, and install prompts
  • New
    Splash screen with theme-aware styling and fade-out transition
  • Improved
    Font families updated to DM Sans, Fraunces, and IBM Plex Mono across all apps
  • Improved
    Responsive layout improvements for file dropzone, tool cards, and announcement banner
  • Improved
    Grid structure and alignment overhaul for tool pages across devices
  • Improved
    Rotate PDF layout standardized with consistent padding and spacing
  • Improved
    Merge PDF layout and styling enhanced for mobile and desktop
  • Improved
    Replaced 'embedPages' with 'embedPdf' method across background color, fix page size, and booklet tools
  • Improved
    Dynamic gradient IDs using useId hook to prevent SVG conflicts
  • New
    Revamped download instructions with detailed macOS installation guide
  • Improved
    Tool upload card badge positioning and flex properties improved
  • Improved
    Padding and spacing standardized across all tool components

v2026.03.31

March 31, 2026

Electron Desktop

Rebuilt desktop app on Electron with native tabbed editing, platform detection, and improved build pipelines.

License & Accounts

License validation API, account-based activation, and rate-limited validation endpoints for Pro users.

Tools Browse & Pinning

Pin your favorite tools, filter by category, and browse the full toolkit from a redesigned tools page.

All changes in version 2026.03.31

  • New
    Electron desktop app with native window controls and platform detection
  • New
    Tab bar with drag-and-drop reordering, search params, and window controls
  • New
    License validation API with rate limiting (5 per minute per IP)
  • New
    Account-based activation and sign-in flow
  • Improved
    Streamlined license validation logic and error handling
  • New
    Tool pinning in the browse page with persistent favorites
  • Improved
    Enhanced tool filtering with additional category support
  • Improved
    Pricing details, descriptions, and comparison metrics updated
  • New
    Early bird spots API for tracking claimed spots
  • Improved
    Early bird data migrated from hardcoded values to API integration
  • Improved
    Download manifest simplified with static asset mapping
  • Fixed
    PDF compatibility utilities for older browsers
  • Fixed
    Undefined page sizes and positions handled across multiple tools

v2026.03.26

March 26, 2026

Edit PDF

Full annotation toolkit — add text, drawings, stamps, symbols, callouts, and freehand highlights with undo/redo and draft auto-save.

Desktop App

OxygenPDF now runs natively on macOS, Windows, and Linux with tabbed editing, keyboard shortcuts, and drag-and-drop tab reordering.

Workflow Builder

Chain multiple PDF operations into reusable workflows — build once, run on any file.

All changes in version 2026.03.26

  • New
    Edit PDF tool with text, image, and drawing annotations
  • New
    Stamp and symbol presets with drag-and-drop placement
  • New
    Callout annotations with click-to-place and drag-to-place
  • New
    Freehand highlighter with customizable stroke width and dash patterns
  • New
    Unified undo/redo history for annotations and page operations
  • New
    Draft auto-save and restore for in-progress annotations
  • New
    Fit-to-page, fit-to-width zoom, and zoom presets
  • New
    Dynamic floating panels for pages and layers with resizable widths
  • New
    Native desktop app for macOS, Windows, and Linux
  • New
    Tabbed editing with drag-and-drop reordering and close guards
  • New
    Global keyboard shortcuts for undo, redo, save, and load
  • New
    Dirty tab tracking with unsaved-changes indicators
  • New
    Workflow builder with visual tool chaining and save/load
  • New
    Free workflow save limits with upgrade prompts for Pro
  • New
    OCR PDF tool with Tesseract, Florence-2, and SmolVLM engines
  • New
    OCR progress display with live preview, cancellation, and stuck detection
  • New
    OCR history tracking and engine selection across tools
  • New
    AI OCR support in PDF to Markdown, PDF to Text, and PDF to Word
  • New
    Insert Watermark tool with text, image, and pattern modes
  • New
    Remove Watermark tool with detection and before/after preview
  • New
    Create PDF tool with blank, template, and HTML modes
  • New
    Expandable template gallery with state management
  • New
    PDF to Form tool for converting fillable PDFs into web forms
  • New
    PDF Merge interleave and interleave-reverse modes with blank page option
  • New
    Page range support for delete, extract, and split operations
  • New
    Command palette for quick navigation and tool search
  • New
    Account-based activation and sign-in with OxygenPDF accounts
  • New
    Pricing page and early bird spots tracking
  • New
    Feedback dialog for collecting user input
  • New
    Inline file renaming in the workspace
  • New
    Floating action bars and bottom sheet settings across all tools on mobile
  • Improved
    Standardized password-protected PDF decryption across all tools
  • Improved
    Terminology updated from "upload" to "select" for privacy clarity
  • Fixed
    File input cleanup to prevent stale hidden inputs after selection or cancellation

We use analytics to understand how our tools are used and improve the experience. No personal files are ever sent.