Repository navigation
0.4.0: real anonymization, stable IDs, nothing dropped silently
LembicKit 0.4.0 makes exports safer to share and harder to get wrong. Anonymize now hides real names, saved data survives renames, and no message is dropped or shown wrong without a trace. It is also much faster.
This is a pre-1.0 minor release with breaking changes. Read Upgrading from 0.3.1 before you update.
Highlights
Anonymize hides names everywhere, not only in labels. Contact, owner, and member names, and each part of them, are replaced in message text too. Enabled scrubbers also reach the header, group name, roster, labels, and event lines, so a phone number used as a group name is not left behind.
Saved data stays attached. Conversation.id is now stable (chat: plus the smallest chat.guid). A contact rename, a group rename, a member change, or a Contacts grant no longer moves it, so per-conversation settings and redactions stay with the right chat.
Redactions follow the message. A RedactionAnchor saves a keyed fingerprint of the hidden text. If the message changes, you can move the redaction or hide the whole message. A redaction that no longer fits hides the whole message: it fails closed.
Nothing leaks, nothing vanishes. Unsent text never appears. Failed sends and pending Send Later messages no longer read as sent. A damaged message is tagged [message may be incomplete], never shown as normal. Skipped rows are reported with a reason, not dropped.
More secrets flagged. New categories for ID numbers (passports, licenses, national and health IDs), recovery keys and backup codes, and Invisible Ink messages. Password and private key flags now cover the whole value.
macOS 14 works again. The schema check fails only on the core columns. A missing optional column turns off one feature, not the whole export.
Faster, same output. Secret detection is about 15 times faster on a 22,000-message thread (666 ms to 42 ms). On a 200,000-message thread, extraction drops from 4.5 s to 1.7 s and the text transcript from 1.8 s to 1.15 s.
Upgrading from 0.3.1
- Saved data keyed by
Conversation.id: look up old keys in the newConversation.legacyIDsand move the data to the newidonce. - Exhaustive
switchonSecretCategory: addidNumber,recoveryKey, andinvisibleInk. - Renamed APIs:
Export.records,Export.preparedRecords, andRendered.recordsare nowunredactedRecords,unredactedPreparedRecords, andRendered.unredactedRecords. The old names still compile, with a deprecation warning. - If you parse the output: the header now says "Messages transcript" (SMS and RCS export too), the header names its time zone, and JSONL
"d"carries the UTC offset (2026-11-01T01:10:00-06:00). - If you call the static prepared-record APIs with anonymize on: pass
Export.knownNames(for:labels:)inscope.knownNames, asrender(_:)does. Otherwise names in message text are not hidden.
Also fixed
- Old rows stored in seconds show their real date (2016, not 2000-12-31). DST fall-back hours read correctly.
- Group rosters are complete. Different groups no longer merge, and one group no longer splits when a member uses a second handle. Group events no longer tell a false story.
- Stickers, Genmoji, voice-note transcriptions, Apple Pay, polls, and other app messages render. Placeholders sit where they belong.
- Reactions on different parts of one message are counted apart.
- Non-US contacts resolve to names. Business chats keep their real id. A note to self shows each note once.
- Fewer false flags and missed secrets in the detectors and the code, email, and phone scrubbers.
Every change, with details: CHANGELOG.md