Library / SDK
Doriandarko/texts-to-transformer avatar
Doriandarko/texts-to-transformer

texts-to-transformer: a from-scratch iMessage style model on Apple Silicon

Train a tiny Transformer from scratch on your iMessage history, entirely on your Mac.

464 stars43 forksPythonMIT

At a glance

What is it?
Doriandarko/texts-to-transformer is an MIT-licensed Python pipeline that snapshots your Messages database read-only, pseudonymizes it, and trains a tiny decoder-only Transformer with MLX. The README is explicit that the result is a personal style model, not an assistant, and the privacy model depends on you keeping work/ and outputs/ off any shared machine.
Who is it for?
Adopt it if you run an Apple Silicon Mac with macOS 14 or newer, can grant Full Disk Access to your terminal, and want a small style model trained only on your own messages. Do not adopt it if you expect factual question answering, if you cannot keep work/ and outputs/ on a FileVault-protected disk, or if you are on Intel hardware, since the project pins MLX 0.32.0 and lists Apple Silicon as a requirement.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 70 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem: your sent messages are a corpus nobody has a pipeline for

chat.db holds years of your own writing, and it is awkward to use. The schema shifts between macOS releases, message bodies are not always plain text, and the file sits behind Full Disk Access. There is no shortage of fine-tuning scripts for public models, but almost none of them start from an Apple Messages database and end at a runnable local model. This repository targets that gap. Its stated goal is a small personal style model that learns phrasing, rhythm, slang and common responses. The README is blunt about the ceiling: it will not reliably reason or answer factual questions. That framing matters, because it tells you the intended output is a generator that sounds like you, not a knowledge system. The audience is a single technical user on their own Mac, not a team building a product.

The pipeline is nine explicit stages, and each one is a separate command

The README's flowchart runs from Messages chat.db through a read-only SQLite backup, extraction and pseudonymization, conversation sessions, chronological splits, tokenizer training, random Transformer initialization, MLX training, and finally a local reply generator. Nothing is pretrained. The tokenizer and the model both start from zero, which is unusual for a project in this space and is the main reason the parameter counts are so small. The default small preset is a 4-layer, 1.38M-parameter decoder-only Transformer with a 4,096-token byte-level BPE tokenizer and a 256-token context window. A 6.16M-parameter preset exists for unusually large message histories. The README notes an example development run of roughly 8M training tokens that produced a 1.38M-parameter model generating short replies in the owner's writing style. That is a single reported run, not a benchmark, and the repository does not present it as one.

Schema inspection and typedstream recovery are the parts that usually break

Step two is inspect-schema, which writes work/schema/schema.json from the snapshot. The README gives the reason directly: Apple changes the Messages schema between macOS versions, so the extractor inspects the local schema instead of assuming an internet example is correct. That is the right call, and it is also a signal that the extractor is version-sensitive by design. The prepare stage then recovers ordinary text plus Apple typedstream attributedBody text, filters reactions, system events, deleted messages and attachment-only rows, redacts obvious identifiers, and pseudonymizes database identities. It groups messages into six-hour conversation sessions, removes duplicate sessions, and creates chronological 90/5/5 splits with seven-day guard bands. The guard bands exist to keep near-identical conversations out of both train and test, and the command verifies that no duplicate session hash appears across splits. When recovery or privacy checks fail, the command stops rather than continuing. The privacy-audit command is a separate step, so it is easy to skip; the README places it right after prepare, which suggests you should not.

Getting it running: uv, doctor, and the Full Disk Access gate

Installation assumes Homebrew or another way to get uv. The README gives: brew install uv, then uv sync, then uv run imessage-mlx doctor. The doctor command checks Apple Silicon, MLX Metal support, disk space, Git ignore coverage, private directory permissions, and read-only access to the Messages database. If it reports safe_to_snapshot_real_data as false, you open System Settings, Privacy & Security, Full Disk Access, enable the app running the command, fully restart that app, and rerun doctor. The README warns against copying the live database manually or changing its permissions as a workaround. From there the sequence is snapshot with configs/data.yaml, inspect-schema, prepare, privacy-audit, train-tokenizer with --vocab-size 4096 on the train split only, corpus-stats, train with configs/model-1m.yaml, evaluate against the best checkpoint, and export. Training supports resumable checkpoints through --resume-from outputs/runs/my-model/last. Requirements are an M1 or newer Mac, macOS 14 or newer, 16 GB of unified memory recommended, Python 3.11, and a pinned MLX 0.32.0. PyTorch is not required.

What the model-selection report actually gates

corpus-stats encodes the splits and writes work/reports/model-selection.json. Two behaviours are worth knowing before you start. First, the project refuses real training below one million tokens, so a short message history will not produce a model through the normal path. Second, it selects the largest preset the corpus supports and marks a low token-to-parameter ratio as a memorization-prone experiment. That second point is the honest part of the design. With a 256-token context window and a 1.38M-parameter model, a small corpus leaves the model with enough capacity to store sequences rather than generalize from them. The evaluation stage then looks for exactly that: the report includes overall and me-turn perplexity, a unigram baseline, exact train n-gram overlap aggregates, and obvious-PII pattern counts. Matching private text is never persisted in the report, which is a deliberate constraint, but it also means you get aggregate overlap numbers rather than the offending strings. Diagnosing a specific leak requires reading the model's own output, not the report.

Pseudonymization is not anonymization, and the README says so

Handles and chat identifiers are replaced with keyed HMAC pseudonyms before JSONL is written, and URLs, email addresses and phone-number-shaped strings are redacted by default. Raw messages are never printed in normal logs. Attachments are never opened or copied. No command uploads data or sends an iMessage; the chat interface only prints a suggestion in the terminal. Those are real controls. The limitation is the one the README states in a single line: pseudonymization is not anonymization. A keyed HMAC is reversible if someone holds the key, and the surrounding message text is unchanged, so names, addresses and medical details that appear inside sentences survive the pipeline intact. The practical consequence is that work/ and outputs/ carry the same sensitivity as chat.db itself, and the README's instruction is to keep them on a FileVault-protected Mac and never commit, upload or share them. Datasets, tokenizers, checkpoints and final weights are excluded from Git, and doctor checks Git ignore coverage, but that check protects against accidental commits, not against copying the directory to a shared drive.

Where it is the wrong tool, and what a fine-tune would do differently

If your goal is an assistant that answers questions about your life, this is the wrong project. The README states plainly that the model will not reliably reason or answer factual questions, and a 1.38M-parameter model trained from random initialization has no world knowledge to draw on. The alternative approach is to fine-tune an existing small instruct model on the same extracted corpus. That route inherits pretrained language ability and factual recall, and it usually needs far less data to produce coherent output. The trade is that you now depend on a base model's licence, its tokenizer and its training data provenance, and the resulting artifact is larger and slower to run locally. texts-to-transformer takes the opposite position: every parameter comes from your messages, the tokenizer is trained on your train split alone, and the byte-level BPE preserves emoji, casing, punctuation, multilingual text, slang and unusual spelling. You get a smaller, fully local artifact with a cleaner provenance story, and you give up general capability in exchange. Neither approach is strictly better; they answer different questions.

Maintenance cost and the MIT licence in practice

The dependency surface is small: Python 3.11, uv, and MLX pinned at 0.32.0. That pin is the main upgrade cost. MLX moves quickly, and a pinned version means you either stay on it or take on the work of validating a bump against the compiled training updates and Metal support that doctor checks for. The other recurring cost is schema drift. Because the extractor reads the local schema rather than assuming a fixed one, a macOS update can change what inspect-schema finds, and the prepare stage is designed to stop rather than proceed when recovery checks fail. Treat each macOS upgrade as a re-validation event. The licence is MIT, which permits commercial and private use and modification. It says nothing about the data you put through the pipeline. Your message history is governed by your own obligations, not by the repository's licence, and the README's instruction to keep work/ and outputs/ private is the operative constraint. This is not legal advice; if you plan to share a model trained on conversations involving other people, that is a question for a lawyer, not for the README.

Editorial conclusion

Adopt it if you run an Apple Silicon Mac with macOS 14 or newer, can grant Full Disk Access to your terminal, and want a small style model trained only on your own messages. Do not adopt it if you expect factual question answering, if you cannot keep work/ and outputs/ on a FileVault-protected disk, or if you are on Intel hardware, since the project pins MLX 0.32.0 and lists Apple Silicon as a requirement. Before training, run uv run imessage-mlx doctor and confirm safe_to_snapshot_real_data is true, then run corpus-stats and read work/reports/model-selection.json, because the pipeline refuses real training below one million tokens and will mark a low token-to-parameter ratio as memorization-prone.

Official sources

  1. Doriandarko/texts-to-transformer on GitHub
  2. Issues
  3. License: MIT
  4. README
Community notes

Community notes