An .fmd file is a binary blob composed of:
┌───────────────────┬───────────────────────────────┐
│ 16-byte IV (hex) │ N-byte ciphertext (hex) │
└───────────────────┴───────────────────────────────┘
-
Initialization Vector (IV)
- Length: 16 bytes
- Purpose: Random per-file seed for AES-CBC
- Location: First 16 bytes of the file
-
Ciphertext
- Length:
file_size − 16 - Contains AES-CBC encryption of a PKCS#7-padded JSON container (see below)
- Length:
- Algorithm: AES-128 in CBC mode
- Key: ASCII string
81e06e41a93f3848(16 bytes, fixed) - Padding: PKCS#7 to a multiple of 16 bytes
- IV Generation:
os.urandom(16)
Encryption steps (export path):
- Serialize JSON container → UTF-8 bytes
- Apply PKCS#7 padding
- Prepend 16-byte IV
- Encrypt padded bytes with AES-CBC(key, iv) → ciphertext
Decryption (import path) is the reverse.
Before encryption, the file payload is a compact JSON object:
- type: Always
"checklist" - payload: The actual checklist data model (see §4)
- Serialization options:
json.dumps(obj, separators=(",",":"))(no extra whitespace)
The payload object follows a 4-level hierarchical schema:
{
"metadata": { … },
"objectId": "<32-char hex UUID>",
"schemaVersion": "1.0",
"groups": [ … ]
}| Field | Type | Description |
|---|---|---|
name |
string | Checklist set title |
tailNumber |
string | Aircraft tail number (registration) |
detail |
string | (Optional) free-text description |
schemaVersion |
string | Must be "1.0" |
- A 32-character lowercase hex UUID (no dashes).
- Used internally for sync/tracking.
- Mirrors
metadata.schemaVersion, currently"1.0" - May be used by ForeFlight to version checks.
An array of categories. Each element:
{
"groupType": "normal" | "abnormal" | "emergency",
"objectId": "<uuid>",
"items": [ … ] // subgroups
}- groupType: Lowercase category name
- items: Array of subgroups (see §4.5)
Each subgroup represents a heading within a category:
{
"title": "<subgroup name>",
"objectId": "<uuid>",
"items": [ … ] // checklists under this subgroup
}- title: The name displayed in ForeFlight (e.g. “Preflight”, “Cabin Check”)
Each checklist is a named list of steps:
{
"title": "<checklist name>",
"objectId": "<uuid>",
"items": [ … ] // step entries
}- title: The checklist’s name within its subgroup
Each step is a challenge-response or detail item:
{
"title": "<challenge text>",
"detail": "<inline detail text>", // optional, may be empty string
"type": "comment" | <absent>, // `'comment'` for detail-only items
"note": "<hint or note text>" // optional
}-
title: The main prompt or challenge
-
detail: Supplemental inline info (often shown to the right of title)
-
type:
- If absent (or any value other than
"comment"), treated as a check item - If
"comment", treated as an info-only / detail item (no checkbox)
- If absent (or any value other than
-
note: A longer hint or explanatory note, shown in ForeFlight’s UI as a popup
payload
├─ metadata
│ ├─ name
│ ├─ tailNumber
│ ├─ description
│ └─ schemaVersion
├─ objectId
├─ schemaVersion
└─ groups [ ← categories (Normal/Abnormal/Emergency)
├─ groupType
├─ objectId
└─ items [ ← subgroups
├─ title
├─ objectId
└─ items [ ← checklists
├─ title
├─ objectId
└─ items [ ← steps
├─ title
├─ detail
├─ type
└─ note
]
]
]
]
{"type":"checklist","payload":{
"metadata":{"name":"TEST","tailNumber":"D-ERFH","description":"","schemaVersion":"1.0"},
"objectId":"a1b2c3d4e5f60718293a4b5c6d7e8f90",
"schemaVersion":"1.0",
"groups":[
{
"groupType":"normal",
"objectId":"11111111111111111111111111111111",
"items":[
{
"title":"Preflight",
"objectId":"22222222222222222222222222222222",
"items":[
{
"title":"Fuel Quantity",
"detail":"CHECK SUFFICIENT",
"objectId":"33333333333333333333333333333333",
"items":[
{
"title":"Left Tank",
"detail":"",
"type":"comment",
"note":"Verify gauge reading matches logbook"
}
]
}
]
}
]
}
]
}}Finally, that JSON is padded and encrypted as described in §1–§2 to produce the .fmd file that ForeFlight consumes.
{ "type": "checklist", "payload": { … } }