01 / ingest
Read stable local copies.
Import Messages and optional Contacts data without opening the source databases for mutation.
messagelikeme ingest imessageLocal-first agent tooling for macOS
Turn your private iMessage history into contact-aware style profiles an agent can use to draft unsent replies in your voice.
$ messagelikeme ingest imessage
✓ corpus stored locally
$ messagelikeme inspect tempo <contact-id>
✓ response shape ready
Read-only ingest. Stable copies, never source mutation.
Bring your own agent. No model account or API key.
Drafts only. Nothing sends, reacts, or schedules.
How it works
01 / ingest
Import Messages and optional Contacts data without opening the source databases for mutation.
messagelikeme ingest imessage02 / understand
Inspect prose, response tempo, bubble sequences, multiple incoming points, and explicit reply use.
messagelikeme inspect tempo <id>03 / draft
Install the bundled Agent Skill and produce contact-aware, unsent drafts through the agent you already use.
messagelikeme skill installA behavioral profile
Word choice matters. So do the pauses, the bursts, the afterthought, and the decision to answer three things in one message or three.
The private boundary
1bun add --global github:hraness/message-like-me#v0.1.0
2messagelikeme skill install
3messagelikeme ingest imessage
A local-first CLI and Agent Skill for studying your private iMessage history and drafting messages that sound like you.
Message Like Me turns a local Messages database into deterministic conversation metrics, bounded study packets, and reusable style profiles. Its Agent Skill teaches Codex, Claude, and other coding agents how to interpret those local artifacts and draft unsent replies in your voice.
The CLI does not call an AI service, authenticate with a product account, send messages, or operate Messages. The agent already running the skill supplies the semantic analysis and drafting judgment.
Message Like Me requires Bun 1.3.14 or newer. Install the immutable public release from GitHub, then install the Agent Skill:
bun add --global github:hraness/message-like-me#v0.1.0
messagelikeme skill install
Start a new agent session after installing the skill. The default target is Codex at user scope. Other supported targets and project-local installation are available explicitly:
messagelikeme skill install --target claude
messagelikeme skill install --target agents --scope project
messagelikeme skill path
Message Like Me is distributed directly through GitHub and is not published to npm.
Initialize the private data store and inspect its location:
messagelikeme init
messagelikeme doctor --json
On macOS, the default store is:
~/Library/Application Support/Message Like Me/
The directory is private to the current user. It contains a local SQLite
database, stored profiles, and a private installation key used to derive
stable pseudonymous IDs. Study packets are written only to the explicit path
you choose. You can put the store elsewhere by placing
--data-dir /absolute/private/path before the command.
Import the current user's iMessage database:
messagelikeme ingest imessage --json
The default source is the current user's Messages chat.db. Use --database
only to name another caller-owned physical database:
messagelikeme ingest imessage --database /absolute/path/to/chat.db --json
Ingestion validates the source schema and ownership, makes a stable private
copy of the database and its transactional sidecars, and opens only that copy
with SQLite. It does not change Messages, chat.db, or its sidecars. macOS may
require permission for the terminal or agent host to read Messages data.
Optionally enrich direct conversations with private labels from macOS Contacts:
messagelikeme ingest contacts --json
The default source is the current user's AddressBook directory. An explicit
absolute AddressBook root, Sources directory, store directory, or
AddressBook-vN.abcddb file can be selected with --addressbook:
messagelikeme ingest contacts \
--addressbook /absolute/path/to/AddressBook \
--json
Contacts ingest may run before or after iMessage ingest. It reads only bounded
name, email, and phone fields from a stable private copy. Exact normalized
email or phone handles can label direct conversations. Shared handles remain
ambiguous, local phone numbers never gain a guessed country code, and groups
are never collapsed to one contact. Contact labels have their own revision, so
a rename does not stale a messaging-style profile. messagelikeme doctor
reports local aggregate state without asking for an account or credential.
Contact listings and aggregate views omit private labels, handles, and message bodies by default:
messagelikeme contacts list --min-outgoing 20 --json
messagelikeme contacts show <contact-id> --json
messagelikeme inspect tempo <contact-id> --json
messagelikeme inspect sessions <contact-id> --limit 20 --json
The metrics cover conversation start and end, message counts, incoming and outgoing turns, response latency, single-message versus multi-message replies, surface prose features, multi-point response contexts, and explicit reply use. Incoming messages establish what you were responding to; they are never counted as examples of your writing style.
Pass --private to contacts list or contacts show only when you need to
resolve a pseudonymous contact to its local private label or participants.
When you already know the complete Contacts label, resolve only that exact private name instead of listing every label:
messagelikeme contacts resolve "Exact Contact Name" --private --json
Resolution is normalized for case and Unicode representation, but it does not perform prefix, substring, phonetic, or fuzzy matching. It returns only direct conversation IDs and labels, never handles or message bodies.
Aggregate metrics cannot explain why a short burst works in one context or why a longer single message appears in another. For that semantic work, prepare a small, diverse study packet at an explicit private path:
messagelikeme study prepare <contact-id> \
--output /absolute/private/path/study.json \
--limit 24 \
--json
This is the only command that writes bounded message bodies outside the private
database. The output is mode 0600. It contains incoming context and outgoing
responses selected across different response shapes; it is not a full
transcript export. By default, each body is capped at 4 KiB, each example keeps
at most 12 text messages per direction, and the entire packet keeps at most
256 KiB of body text. Packet coverage fields report every truncation or
omission explicitly.
Keep the JSON receipt with the analysis. Its packetSha256 binds the finished
profile to these exact packet bytes; the packet does not contain its own digest.
Invoke $message-like-me in your agent and ask it to analyze that contact. The
skill separates measured facts from inferred patterns, covers prose and tempo,
studies how several inbound points are handled, and treats reply links and
tapbacks separately from written text.
The agent writes a schema-version-one profile and asks the CLI to validate and store it:
messagelikeme profile apply /absolute/private/path/profile.json --json
messagelikeme profile show <contact-id> --json
A profile is bound to the exact corpus revision and study-packet SHA-256. A new ingest can therefore mark an earlier profile stale instead of silently applying it to changed evidence.
Export a profile only when you need an explicit private copy:
messagelikeme profile export <contact-id> --output /absolute/private/path/profile.json
Ask an agent with the installed $message-like-me skill to draft for a
pseudonymous contact. The compact deterministic context is available through:
messagelikeme context <contact-id> --json
The skill preserves your intended meaning, selects the applicable profile, and can express the result as one message or a realistic sequence of separate bubbles. It uses explicit replies only when your evidence and the current context support them.
Drafting ends with text in the agent task. Message Like Me has no send, react, schedule, or messaging-application command.
Run messagelikeme --help for the checked grammar. The public surfaces are:
messagelikeme init [--json]
messagelikeme ingest imessage [--database PATH] [--json]
messagelikeme ingest contacts [--addressbook PATH] [--json]
messagelikeme contacts list [--min-outgoing N] [--limit N] [--private] [--json]
messagelikeme contacts show CONTACT_ID [--private] [--json]
messagelikeme contacts resolve QUERY --private [--limit N] [--json]
messagelikeme inspect tempo CONTACT_ID [--json]
messagelikeme inspect sessions CONTACT_ID [--limit N] [--json]
messagelikeme study prepare CONTACT_ID --output FILE [--limit N] [--json]
messagelikeme profile apply FILE [--json]
messagelikeme profile show CONTACT_ID [--json]
messagelikeme profile export CONTACT_ID --output FILE [--json]
messagelikeme context CONTACT_ID [--json]
messagelikeme skill path [--json]
messagelikeme skill install [--target codex|claude|agents]
[--scope user|project] [--project PATH] [--force] [--json]
messagelikeme doctor [--json]
Place global --data-dir PATH before the command.
chat.db and AddressBook databases remain authoritative.
SQLite opens only stable private copies, never the source files or sidecars.Read SECURITY.md before integrating the library into another tool or handling a private study packet outside the CLI.
The package exports the versioned corpus, metrics, study-packet, and profile types plus deterministic canonical JSON and SHA-256 helpers:
import type { ContactMetrics, StyleProfileV1 } from "@hraness/message-like-me"
import { canonicalJson, sha256 } from "@hraness/message-like-me"
The library does not start the CLI, inspect Messages or Contacts, connect to a network, or send a draft merely because it is imported.
bun install --frozen-lockfile --ignore-scripts
bun run check
Tests use synthetic Messages and AddressBook databases plus synthetic conversations. Never add a real message, handle, group title, attachment, contact record, private path, or derived profile to a fixture.
The canonical repository is
hraness/message-like-me.
The informational project page is
messagelikeme.com. The CLI does not connect to
the site, and the site never receives message or contact data.
MIT.