Blog

Customer Story

How Lindy shipped an AI assistant into iMessage

July 14, 2026·7 min read

Lindy's founder, Flo Crivello, explains the problem his product solves with an analogy about flying. The most dangerous part of any flight is takeoff and landing. Cruising is safe and easy. A twelve-hour flight is fine because you spend it at altitude, and it would become miserable and dangerous only if you had to take off and land at every city along the way. Work is the same. "You want to cruise at 10,000 feet. You want to think strategically about your business and the things that really matter, but you're forced to take off and land at every city along the way. You got to send that email, and you got to jump on that meeting, and you got to follow up on this thing."

Lindy is the assistant meant to remove those takeoffs and landings. It triages your inbox, takes notes in your meetings, and handles the follow-ups afterward. Crivello wanted people to reach it the same way he reached his own human assistant, by text, because that is "the best way to communicate with your executive assistant." Delivering that over iMessage is the whole experience, and it is also the hardest part to operate. In December 2025, Lindy set out to build iMessage support in-house. Within a month they had built the same integration three times before moving it onto Linq, where it has run since. This is that story, drawn from Lindy's own account, iMessage API: Three Rewrites, One Apple Ban, and What Actually Works.

How Lindy got here

Lindy started with agents before most people were talking about them. The team began working on them in mid-2022, playing with the GPT-3 API, when they realized language models could be coaxed into taking actions and not only generating text. LangChain was a library blowing up on GitHub at the time, and the vision came together: an automated assistant for work, connected to all of your tools.

The models were not ready for that yet. GPT-4 had not shipped, and when it did it still could not run the full assistant reliably. So Lindy handed more and more control to the user: control the prompt, control which tool gets called, control which parameters get passed. Before long they had a no-code tool for people to build their own agents. When they looked at what people actually built, the answer was executive assistants. "That was the plan all along," Crivello says, "and now the models can actually support it." Lindy released its AI assistant in February, delivered over iMessage.

The name came from a teammate. The team had spent a long time brainstorming, and every candidate ran into an unavailable domain or a taken trademark. Someone in the room suggested "Lindy," after a colleague by that name. The domain was available for about seventy dollars a year. They took it.

What Lindy built first

The first version was a Swift daemon on a Mac Mini in a Las Vegas data center. It watched the write-ahead log of the Messages SQLite database (chat.db-wal) for incoming texts and injected outgoing ones through Apple's private frameworks, with AppleScript as a fallback. It worked. It sent and received, handled attachments, and relayed events to Lindy's backend over webhooks.

The tell was in the health check. One field was messagesAppRunning, a boolean for whether Messages.app was still open on a machine in Nevada. That field is the real cost of the approach. A production feature's reliability depended on a desktop app staying launched.

Why the first two versions did not hold

Two problems surfaced, and neither was about code quality.

The first was the bus factor. Only one engineer knew Swift. An iMessage bridge fails on physical hardware, and when it fails at 2am someone has to SSH in and debug a Swift process reading SQLite WAL files. Lindy migrated to BlueBubbles, an open-source JavaScript engine for the same job, so the whole team could maintain it. That move unlocked reactions, markdown formatting, edit and unsend, voice memos transcribed on the way in and generated on the way out, and inbound images fed to a multimodal model. Real progress, same hardware.

The second was that the hardware did not scale. Each phone number needed its own Mac Mini, its own iPhone, and its own Apple ID. The launch RFC estimated 100 to 500 messages per hour per Apple ID and planned for a few hundred messages per day. On launch day, real volume passed those numbers fast. A brand-new account sending high volume to a narrow set of recipients, with a lopsided send-to-receive ratio, tripped Apple's spam detection, and the account was banned after about half a day of live traffic. Buying another iPhone and provisioning another Mac would have reproduced the problem on a delay. Running a compliant fleet of phone numbers is a full-time operational job, and it was not the job Lindy set out to do.

The rebuild on Linq

This is where Lindy moved to Linq. Linq runs the hardware and account layer that Lindy had been operating by hand: the Macs, the iPhones, the Apple IDs, number rotation, and the anti-spam strategy that keeps accounts healthy under load. It exposes iMessage, RCS, and SMS behind one REST API with webhooks, the same shape a developer already knows from Twilio or the WhatsApp Business API.

Because Lindy had built the integration twice already, they understood the routing, the webhook handling, and the attachment processing. What changed was ownership. They stopped running phones. The rebuild took about four hours. The new send path is small:

try {
  return await trySendViaLinq(actor, identity, phoneNumber, message, attachments);
} catch (error) {
  logger.info("Linq send failed, falling back to SMS", { error });
}
return await sendViaSMS(actor, identity, phoneNumber, message);

Try Linq, fall back to SMS. Within days, Lindy had read receipts, attachments, voice memos, reply threading, and contact-card generation running on Linq, plus an onboarding flow where the user texts first so Apple sees a reciprocal conversation. The cleanup PR that removed the old bridge changed 76 files and was mostly deletions. The Mac Mini in Las Vegas was decommissioned.

Making it feel like texting a person

With delivery handled by Linq, Lindy could spend its engineering time on the experience rather than the transport. Two small details did more for that experience than anything below the API line.

The first is the typing indicator. A request like "check my calendar for the week" can take a minute while the agent fetches and filters events. On the user's side, a minute of silence reads as broken. Lindy shows the native typing bubble while the agent works and drops it when the first reply is sent. The obvious alternative, sending "working on it" messages, would have spent messages that are better saved for real answers. The typing indicator costs none. It gives the user feedback for free.

The second is debouncing. People text in bursts: "hey," then "what's my day look like," then "weather in SF," three separate sends. Without buffering, that becomes three agent runs and three disconnected replies. Lindy waits three seconds after each inbound message, resets the timer on any new one, then bundles the burst into a single request. Shorter than three seconds drops the second message in a fast pair. Longer leaves a single-message user staring at nothing.

What changed after the move

The move to Linq turned a fragile, hand-run bridge into a managed channel. There are no Mac Minis to keep alive, no Apple IDs to babysit, no manual number rotation, and no hand-built spam heuristics. Lindy now runs on eight load-balanced numbers with per-number daily caps and monitored send-to-receive ratios, all coordinated through a single API. Adding capacity is a provisioning step, not a hardware order.

That is the point of the whole exercise. Crivello wants people to feel "calm and in control," because "the quality of your work is a direct function of the mindset you have." Lindy delivers that feeling to users by removing the small takeoffs and landings from their day. Linq delivers the same thing to Lindy's engineers, by removing the messaging infrastructure from the list of things they have to fly. The team ships assistant features now, and the channel does what good infrastructure should do: it stays out of the way.

Principles

Do not run infrastructure that is not your product. Lindy's product is an assistant, and every hour spent keeping Mac Minis alive was an hour not spent on it.

Write for the bus factor, not the demo. A bridge only one engineer can debug at 2am is a liability no matter how clean the code is.

Buy the hard infrastructure and build the product. A partner who runs iMessage full time will do it better than a team doing it on the side.

Spend your message budget on the user, not on status. A typing indicator beats three "still working" texts.

Delete aggressively once a layer is owned elsewhere. The best migration diff is mostly deletions.

Your Cart
Your cart's looking a little light.Looks like your cart is empty—it's time to add your
gears and make it unforgettable.
Shop our best sellers
Digital Card
Digital Card$14.99
Hub
Hub$29.99
Badge
Badge$19.99
Mini Card
Mini Card$12.99