SkillAgentSearch skills...

Madrid

Swift package for reading your iMessage® database, with support for Apple's typedstream format

Install / Use

/learn @mattt/Madrid
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Madrid

Madrid is a Swift package that provides read-only access to your iMessage® chat.db database.

It comprises the following two modules:

Requirements

  • Xcode 16+
  • Swift 6.0+
  • macOS 13.0+

Installation

Swift Package Manager

Add Madrid as a dependency to your Package.swift:

dependencies: [
    .package(url: "https://github.com/mattt/Madrid.git", from: "0.4.0")
]

Then add the modules you need to your target's dependencies:

targets: [
    .target(
        name: "YourTarget",
        dependencies: [
            .product(name: "iMessage", package: "Madrid"),
            .product(name: "TypedStream", package: "Madrid")
        ]
    )
]

Usage

Fetching Messages

import iMessage

// Create a database (uses `~/Library/Messages/chat.db` by default)
let db = try iMessage.Database()

// Build a predicate-style request
let pastWeek = Date.now.addingTimeInterval(-7 * 24 * 60 * 60) ..< Date.now
let request = FetchRequest<Message>(
    predicate: .and([
        .participantHandles([
            "johnny.appleseed@mac.com",
            "+18002752273",
        ]),
        .dateRange(pastWeek),
    ]),
    sortDescriptors: [.date(.descending)],
    limit: 10
)

// Execute request
for message in try db.fetch(request) {
    print("From: \(message.sender)")
    print("Content: \(message.text)")
    print("Sent at: \(message.date)")
}

[!TIP] Legacy convenience APIs (fetchMessages(for:with:in:limit:), fetchChats(with:in:limit:)) are still available, but are deprecated in favor of fetch(_:).

Decoding TypedStream Data

import TypedStream

let decoder = TypedStreamDecoder()
let data = // ... your typedstream data ...
let result = try decoder.decode(data)
print(result.stringValue)

FAQ

"Database Disk Image is Malformed"

If you get the error message "database disk image is malformed" when attempting to connect to your iMessage database, it typically indicates corruption in the SQLite file. The error most often occurs when attempting to read the database while another process (like the Messages app) is actively using it.

To check if the database file is corrupt, you can use SQLite's built-in integrity check`:

sqlite3 ~/Library/Messages/chat.db "PRAGMA integrity_check;

If the original database file is corrupt, restore from a Time Machine backup or other backup source.

The most reliable way to prevent this error is to operate on a copy of the iMessage database:

  1. Quit Messages: Ensure the Messages app is completely closed.

  2. Copy All Database Files:

    # Create destination directory
    mkdir -p ~/imessage_db_copy
    # Copy main database and supporting files
    cp -p ~/Library/Messages/chat.db ~/imessage_db_copy/
    # Copy WAL and shared memory files if they exist
    cp -p ~/Library/Messages/chat.db-* ~/imessage_db_copy/ 2>/dev/null || true
    

    Always include the -shm and -wal files when copying a SQLite database using WAL mode

  3. Use the Copied Database:

    let homeURL = FileManager.default.homeDirectoryForCurrentUser
    let dbURL = homeURL.appendingPathComponent("imessage_db_copy/chat.db")
    let db = try iMessage.Database(path: dbURL.path)
    

Acknowledgments

Legal

iMessage® is a registered trademark of Apple Inc. This project is not affiliated with, endorsed, or sponsored by Apple Inc.

License

This project is available under the MIT license. See the LICENSE file for more info.

Related Skills

View on GitHub
GitHub Stars90
CategoryData
Updated6d ago
Forks8

Languages

Swift

Security Score

100/100

Audited on Mar 27, 2026

No findings