Skip to content

Release History

Nabeel Wasif edited this page Sep 29, 2026 · 1 revision

Release History

Everything Anonify has shipped, fixed and hardened, release by release, with the reason each change was made. The authoritative, per-release changelog is CHANGELOG.md, and each release's notes are on the Releases page. This page adds context and links each change to the wiki page that explains it.

Current release: v1.10.0 (2026-09-29).


At a glance

Version Date Headline
1.10.0 2026-09-29 Batch downloads in the original format (a mailbox comes back as a mailbox) or as processed files in provenance folders. Batches over 50 documents are exported whole. Non-Latin-1 filenames download correctly.
1.9.3 2026-09-28 pnpm bench:models verifies each model before benchmarking it.
1.9.2 2026-09-28 pnpm bench:models and pnpm bench:charts: models benchmarked on the labelled corpus.
1.9.1 2026-09-28 A synthetic, labelled PII corpus and a scorer (pnpm corpus:*).
1.9.0 2026-09-27 Search, RegEx rules, global rules, the Hush review assistant, a shortcut sheet, word-level click-to-redact.
1.8.0 2026-09-27 OpenRouter, Synthetic, LM Studio, llama.cpp, any OpenAI-compatible endpoint, ChatGPT subscription sign-in, the pnpm ai command. The standalone build no longer copies the working tree.
1.7.0 2026-09-27 Streaming I/O, part 2: a page-at-a-time editor, ranged reads of Office and PDF files, streamed downloads.
1.6.3 2026-09-23 OCR misconfiguration fails at once and names a misspelled Mistral key.
1.6.2 2026-09-23 Local vision models (Qwen3-VL through Ollama) work: regions on a 0–1000 grid.
1.6.1 2026-09-23 CI tests the model pass with a scripted provider and OCR against a pinned model.
1.6.0 2026-09-23 Chunked encryption (1 MB authenticated chunks) and streamed uploads, mailboxes, email and text. Each stored file is bound to its own name.
1.5.0 2026-09-23 Multi-copy exports fixed and downloadable as one zip. PDF redaction box placement security fix (GHSA-h3hv-rpqw-7p84). Dependency advisories cleared.
1.4.0 2026-09-23 pnpm setup pages large model catalogs, shows list prices, and can finish a local install for you.
1.3.0 2026-09-12 Bring your own AI provider: official AI SDK adapters, Azure, Bedrock, Vertex, local Ollama. MinIO replaced by RustFS.
1.2.0 2026-09-08 Release notes written from changelog.d/ fragments.
1.1.1 2026-09-08 HTML email bodies analysed as markdown; a message folds into its parts. Releases cut by a workflow.
1.1.0 2026-09-06 MBOX mailboxes accepted; each opens as a batch with one document per message.
1.0.0 2026-09-06 First release: ten formats, batches, presets, anonymisation methods, reports, durable processing, verified exports.

Upgrades that need a database migration (pnpm db:migrate:deploy; the container image runs it for you): 1.6.0, 1.7.0, 1.9.0. Every migration in prisma/migrations/ is listed under Data Model.


1.10.0 — the batch comes back in the shape it went in

2026-09-29 · #143, PR #147

Added

  • The batch download asks what to deliver.
    • Original format (the default) returns what was uploaded. A mailbox comes back as inbox-redacted.mbox. It is rebuilt from its messages' verified exports, with the From separator lines written fresh rather than copied, and the whole mailbox is verified again before it is sent. A message comes back carrying its redacted attachments. A single file comes back as itself.
    • Processed files is every document's own output, in folders that mirror where it came from. Folders are named by message number and MIME part path, never by subject or filename, because both are routinely the personal data being removed.
    • Both puts the two layouts side by side in one zip.
  • A message left out of a rebuilt mailbox is named in the batch report. So is the check a mailbox failed when its own verification withholds it.
  • An expanded mailbox in the workspace offers Download redacted mailbox directly.

Changed

  • The batch archive is no longer flat. GET /api/batches/:id/download takes output=original|processed|both (default original), and a single upload comes back as that one file rather than a zip.

Fixed

  • A batch of more than fifty documents (so any mailbox of more than fifty messages) was exported, downloaded and listed as only its first fifty. From the 51st document on, the workspace also lost its place in the batch. Every document is now included and navigable.
  • Downloading or restoring a file whose name is outside Latin-1 (收件箱.mbox, Отчёт.pdf, an emoji) no longer fails, and the file saves under its real name.

Detail: Batches and Mailboxes · Export and Anonymisation.


1.9.x — measuring the claim

The architecture has always claimed that running patterns first, asking a model only the contextual question and expanding repeats locally costs far fewer tokens at comparable quality. This series built the tooling to test that claim.

1.9.3 — 2026-09-28 · #59

  • Fixed: pnpm bench:models verifies each model before its first phase, the way pnpm ai verify does, for that run only. Before, a model other than the one verified in .env was treated as unsupported, and every document was scored on the pattern detectors alone.

1.9.2 — 2026-09-28 · #59, #55

  • Added: pnpm bench:models benchmarks the models in .env (or a BENCH_MODELS list) on the labelled corpus. It measures recall per category, tokens and cost per document, throughput as concurrency rises, and the tokens the deterministic pass saves against the same model with it switched off. pnpm bench:charts draws light and dark charts into the README. A model benchmarked later is added beside the earlier ones without changing their results.

1.9.1 — 2026-09-28 · #57

  • Added: pnpm corpus:generate builds a synthetic, labelled PII corpus through the Claude Code or Codex CLI you are already signed in to. Every email address and phone number comes from a range reserved for fiction, and so does every card and ID where such a range exists. A document containing a real-looking email, phone, URL or IP is rejected. pnpm corpus:validate has a model from another family review the labels. CI fails if a committed corpus file holds a value outside the reserved ranges. pnpm corpus:score measures precision, recall and a weighted cost (a missed ID costs more than a false alarm), with patterns alone or with the configured model. --format pdf|docx|eml|csv|xlsx|txt renders the corpus and measures it through the same extraction an upload goes through.

Detail: Testing and Benchmarks.

1.9.0 — the review screen grows up

2026-09-27 · #142, PR #146 · needs a migration

Added

  • Search (Ctrl/⌘+F or /). A find strip docked above the document searches the whole document on the server, not just the loaded pages, in every format. It offers match case, whole word and RegEx, an "N / M" counter announced to screen readers, amber highlights, a results panel grouped by page, and hit counts on page thumbnails. From a hit, Redact this or Redact all (which opens a rule), with optional counts across the batch. Searches and rule previews have their own rate limit, ANONIFY_RATE_LIMIT_SEARCH.
  • RegEx rules on a linear-time engine (RE2): a pattern cannot hang the server. Backreferences and lookaround are refused, and a rule that matches too much applies nowhere rather than partway. Every rule is previewed with its count and matches in context before anything is written.
  • Global rules apply to every document you upload from now on. The pattern is encrypted at rest and deleted after 30 days unused. The session cookie now renews when you upload or change a rule, so rules in use are not lost when the cookie turns 30 days old. Global rules export and import as JSON.
  • A Rules tab in the inspector: switch off, edit with a fresh preview, or remove with everything the rule redacted.
  • Hush (Ctrl/⌘+K), a review assistant that reads, searches and scans the document with tools. It lists where a value occurs and whether each occurrence is covered, finds what the detectors can see that nothing covers yet, explains suggestions, and proposes rules and redactions. Every change is a card that waits for Approve. Approvals are signed by the server and re-checked before they run. Hush asks once before it first reads a document, renders replies as Markdown that cannot load links or images, stays within the spend cap, and has a per-visitor daily token allowance, ANONIFY_QUOTA_ASSISTANT_TOKENS. It also offers rules locally, with no provider, once you have hand-redacted the same shape of value a few times.
  • ? lists every keyboard shortcut, and zoom has a slider.
  • A new failure code, rule-too-broad: a batch or global rule that matches too much of a newly processed document fails that document. It can still be reviewed, and it retries once the rule is narrowed.

Fixed

  • Clicking text redacts the value under the pointer (an ID, an email, a name) instead of the whole span. In a text file a span is a whole line, so one click used to redact the line. Grouped values (card numbers, spaced IBANs, phone numbers) are taken whole; names are taken a word at a time. Dragging redacts exactly the selection. PDFs get the same word-level click from their measured character positions.
  • The canvas shows suggestions and accepted redactions over exactly the characters they cover. Before, any line with a redaction on it was drawn fully blacked out, which overstated what the export removes.
  • Plain-text, RTF and slide pages have thumbnails, and changing page opens the new page at its top.

Detail: Search and Rules · Hush Assistant · Review Workspace.


1.8.0 — any model, and a safer standalone build

2026-09-27 · #126, #139, #140

Added

  • Setup and the new pnpm ai command offer OpenRouter, Synthetic, LM Studio, llama.cpp, and any OpenAI-compatible endpoint by AI_BASE_URL. Each gets the same model discovery, verification and visible "unsupported" degradation as the existing providers, and adding a vendor is one row in a table. LM Studio and llama.cpp are treated like Ollama: no spend, one request at a time, reachable from Docker.
  • pnpm ai login --provider openai signs in with a ChatGPT subscription. The token is sealed in the database, never written to .env. Read the caveat first: it uses Codex CLI's public client, and OpenAI's terms decide whether a plan may be used this way. Prefer an API key for anything deployed. There is no Anthropic subscription sign-in, because Anthropic's terms do not allow it.
  • pnpm ai verify verifies a model and writes it to .env without running the rest of setup. pnpm ai status shows what is in force.
  • A model that fails verification now says why: which check failed, the HTTP status, and what the provider said, with credentials redacted.

Fixed

  • Link previews of a self-hosted instance point at its own address. Set ANONIFY_PUBLIC_URL and rebuild the image.
  • The expiry sweep no longer fails with "No record was found for a delete" when a document is removed while the sweep is running. A document already gone counts as deleted, and one document that cannot be purged no longer stops the rest of the run.

Security

  • A standalone build (NEXT_OUTPUT=standalone) no longer copies the working tree into its server output. Before, it copied the source, tests, docs, every document in local storage (.anonify-storage), downloaded OCR models, and .env with the key that opens those documents. Container images and Vercel deployments were not affected. If you built standalone on a machine that stores documents locally and copied .next/standalone elsewhere, delete that copy's .anonify-storage.

Detail: AI Providers · Deployment.


1.7.0 — read only what you need

2026-09-27 · #129 · needs a migration (adds Document.normalizedIndex)

Changed

  • Documents are read a piece at a time instead of whole. The editor loads the pages you look at (an outline, then ≤ 24 pages kept). Word, PowerPoint, Excel and PDF files are read by ranged reads, and pictures and other media are no longer unpacked. Emails are parsed without holding their attachments. Downloads, single and batch, stream while their checksum is verified. Output is unchanged. Documents processed before the upgrade keep working and are read whole.

Fixed

  • A download the browser abandoned partway no longer leaves the stored file's handle or storage connection open.

Detail: Streaming IO.


1.6.x — chunked encryption and a working local model

1.6.3 — 2026-09-23 · #134

  • Fixed: a document that needs OCR fails at once as a configuration problem when OCR_PROVIDER=mistral has no MISTRAL_API_KEY. Before, it was retried five times and reported as an unknown error with a retry button. A Mistral key set under another name (such as MISTRAL_AI_KEY) is named in the error.

1.6.2 — 2026-09-23 · #132

  • Fixed: image and PDF-page analysis works with local vision models such as Qwen3-VL through Ollama. Regions are requested as whole numbers on a 0–1000 grid, the convention those models answer in. Before, they were asked for 0–1 fractions, which they ignored, so validation failed and every image had no suggestions. An over-long region explanation is shortened rather than discarding the region.

1.6.1 — 2026-09-23 · #30, #33

  • Added: the model-assisted analysis pass is tested in CI without an API key or a network call (a scripted provider). The tests cover the rule that a value the model reports but the document does not contain is discarded, and that a failing provider still leaves the pattern detections.
  • Added: scanned images are tested against the real OCR engine in CI, including where each word's redaction box lands.

1.6.0 — 2026-09-23 · #102, PR #127 · needs a migration (adds Document.encryptionFormat)

  • Changed: uploads, mailbox and email-attachment expansion, and plain text, CSV and TSV extraction stream instead of holding whole files in memory, so a large mailbox no longer has to fit in memory. New documents are stored in 1 MB authenticated chunks (envelope v1). Documents already stored stay readable exactly as they are (v0). Tuned with ANONIFY_ENCRYPTION_CHUNK_SIZE and ANONIFY_STREAM_MEMORY_BUDGET.
  • Security: each stored file is bound to the name it was written under. Someone with write access to the storage bucket can no longer swap one of a document's encrypted files for another (say, its report for its source). This covers documents uploaded from 1.6.0 on.

Detail: Storage and Encryption.


1.5.0 — fixes from a full walkthrough, and a security advisory

2026-09-23 · #121, PR #124

Added

  • An export with a second copy can be downloaded as one zip holding every copy and its report. The vault is left out on purpose and is still downloaded on its own.

Fixed

  • Exports with a second copy (pseudonymized, tokenized or encrypted) work again. Every one of them had failed with "The export could not be generated". A malformed export request is answered 400, not 500.
  • Accept all leaves ignored suggestions alone instead of redacting them after all. An ignored suggestion is marked and dimmed in the inspector.
  • The export dialog scrolls instead of growing past the screen. With two copies, each copy's checksum and report fold away while its downloads and vault stay in view.
  • The documents list says a review is finished instead of showing "0 accepted" under a full progress bar. The upload panel no longer jumps or sits at 0% when an upload starts.
  • Undo and redo save only the redactions they changed. Before, pressing Ctrl+Z in a tab holding stale decisions could overwrite every decision on the document, and undoing a method change was never saved.
  • PDFs that use the standard fonts without embedding them, or that need the bundled CMaps, render and extract on the server with the right font data again.

Security

  • GHSA-h3hv-rpqw-7p84: PDF redaction box placement. Boxes are now placed from the font's own character widths and reach below the baseline. On a line of proportional text a box could sit a few characters away from its value and leave descenders showing, and the export burned in that same box, so part of an accepted value could survive in the exported PDF. PDFs analysed before 1.5.0 are covered a whole text run at a time instead. Upload them again for boxes that fit the value.
  • Next.js 16.3.6 fixes two critical and several high-severity advisories in 16.2.x. Vulnerable transitive copies of undici, mysql2, nanoid, deepmerge-ts, devalue, uuid, lodash and postcss were replaced, and pnpm audit reports nothing.

1.4.0 — setup that finishes the job

2026-09-23 · #119, #120

  • pnpm setup pages and searches large model catalogs and shows each model's advertised capabilities and context window apart from what setup verified. It can finish a local install for you: start Postgres and RustFS, migrate, warm OCR and start the app, or run everything in Docker, with retry, skip or stop on any step that fails.
  • pnpm setup shows list prices for models on the Vercel AI Gateway, DeepInfra (and, from 1.8.0, OpenRouter), labelled with source and age. It offers, never automatically, to save the chosen model's price to AI_MODEL_PRICES. Model lists are cached in .cache/models (or ANONIFY_MODEL_CACHE_PATH); pnpm models:warm refreshes them.

1.3.0 — bring your own model, and RustFS

2026-09-12 · #115, #117, PR #116

  • Added: AI detection can use official AI SDK providers, including Azure, Bedrock and Vertex, or a local Ollama server. Setup discovers models, blocks incompatible choices, and verifies structured output and image support before saving. Existing AI Gateway configurations keep working.
  • Changed: self-hosted object storage uses pinned RustFS images instead of the archived MinIO Community Edition tooling. It reuses the existing data volume and initialises its bucket idempotently. See Deployment for the one-way migration.

1.2.0 and 1.1.1 — releases and email

  • 1.2.0 (2026-09-08, #105): release notes are written by the people who make the changes. Every version-moving pull request carries a fragment in changelog.d/, and the release workflow assembles them.
  • 1.1.1 (2026-09-08, #101, #104):
    • Added: email bodies written in HTML are converted to markdown before analysis, so detection reads the text a person sees rather than the markup around it. A message folds into its parts (headers, bodies, alternatives, attachments).
    • Changed: releases are cut by a workflow. A merged pull request's labels decide which part of the version moves.

1.1.0 — mailboxes

2026-09-06 · #88, PR #100

  • MBOX mailboxes are accepted as an upload, and open as a batch with one document per message.

1.0.0 — the first release

2026-09-06

  • Support for CSV, TSV, plain text, RTF, EML and PPTX, alongside PDF, DOCX, XLSX and images (#72, #47, #49).
  • An email attachment is a document in its own right, and a message carrying attachments opens as a batch (#74, #75).
  • Anonymisation beyond masking: a method per category, consistent surrogates for a repeated value, variants, and restore (#87, #95).
  • Export reports, batch review, and detection presets named for what they look for (#50, #52, #54, #71).
  • Bounded batch concurrency instead of one document at a time (#94).
  • External services paced and retried, with configurable limits (#96).
  • A document that fails partway reports what actually happened, and only the stages that can succeed are retried (#69).
  • Deployable on Vercel Hobby (#53).

Before 1.0 — the hardening pass

The first release came after a long audit of what was half-wired, insecure or untested. These closed issues are worth knowing because the same failure shapes recur:

Security and correctness

Issue What was wrong What changed
#7 The expiry sweep never ran outside Vercel, so nothing was ever deleted pnpm cleanup and an opt-in Compose scheduler
#14 DOCX headers and footers were swept on export but never shown for review Every text-bearing part is extracted and reviewable
#15 A hidden worksheet was rendered exactly like a visible one Hidden / very-hidden sheets, rows and columns are marked
#17 Fixed-window rate limiting allowed double the rate across a boundary Token buckets that refill continuously
#18, #19 A self-hosted install rationed itself with the demo's quotas and limits Deployment profiles (self-hosted, demo)
#20 Spreadsheet cells were charged by used-range area Only filled cells are charged
#27 YAML read the ENCRYPTION_KEY placeholder as the integer 0 assertMasterKey() refuses to boot on a malformed key
#39 Images inside a PDF were never analysed Analysed
#41 Every spreadsheet export failed once a column was accepted Fixed, with tests
#44 The model proposed columns that do not exist Proposals are located against the sheet
#51 Uploads were refused on the browser's guess at the content type Magic bytes decide, at ingest
#62 Raw internal error messages were stored and shown A fixed table of failure codes
#64 Retry had no backoff and re-ran failures that could not succeed Paced backoff and FatalError
#74 EML attachments were carried through unredacted Attachments become child documents

Getting it to run anywhere

#3 Neon-only database adapter → postgres or neon · #4 migrations committed · #5 pnpm setup · #6 a container image · #8 the Compose stack exercised in CI · #9 .env.example committed · #21 Prisma out of the browser bundle · #22 pdfjs in a bundled server · #24 OCR model no longer committed · #25 an opt-in scheduler no longer breaks Compose · #53 Vercel maxDuration · #60 typecheck on a fresh checkout · #73 tesseract.js in the standalone build.

Finishing what was half-wired

#10 scanned PDFs OCR'd · #11 blur and pixelate reachable · #12 AI cost shown · #13 real page thumbnails · #16 OCR suggestions placed on the image · #26 a scroll area that scrolls · #31, #34, #36 DOCX pagination and rail · #46, #48 the grid shows what export will do · #56 keyboard-reachable redactions · #58 selectable OCR provider · #61 the failure screen and retry reachable.

Project files and docs

#67 Apache-2.0 licence · #68 security policy, code of conduct, templates · #76–#84 API, data model, client state, editor, storage, failure codes, boot sequence and security-internals docs · #91 README and About.


Security advisories

Advisory Fixed in Summary
GHSA-h3hv-rpqw-7p84 1.5.0 PDF redaction boxes placed by a proportional approximation could miss characters of an accepted value, and the export burned in the same box. Boxes now come from font widths and include descenders. Re-upload PDFs analysed before 1.5.0.
(no advisory; release note) 1.6.0 Stored objects were not bound to their logical names, so a party with bucket write access could swap one of a document's objects for another. Chunked v1 objects bind the name into every chunk's AAD.
(no advisory; release note) 1.8.0 A standalone build copied the working tree, including local document storage and .env, into its output.

To report one: Security Model §Reporting.


See also

Clone this wiki locally