# Kindle Desktop Automation: Session Findings

**Date:** 2026-08-08  
**Machine:** Apple silicon Mac, macOS 26.5.2 (build 25F84)  
**Scope:** Read-only inspection of the installed Kindle application, its macOS Accessibility surface, local catalog/cache metadata, document rendering, and OCR integration possibilities. No book text is reproduced in this report.

## Executive summary

The installed Kindle for Mac is highly automatable through native macOS Accessibility (`AXUIElement`) and targeted keyboard events. It exposes stable semantic controls for the library and reader, explicit per-book download states, ASIN-based identifiers, and clear plaintext for the currently rendered reading page.

The strongest conclusions are:

1. **A robust Kindle reader/download driver is feasible.** Native AX is substantially better than coordinate-based clicking for this application.
2. **Bulk downloading approximately 2,200 ebooks is technically feasible as a resumable per-title job.** Kindle for Mac has no documented global “Download All” command.
3. **Audible downloading is promising but needs a controlled canary test.** The UI exposes `Download with Audible`, but “Audible companion available” does not necessarily prove ownership or entitlement. Automation must never purchase automatically.
4. **Kindle exposes genuine clear Unicode for the current page.** This is post-render runtime plaintext, not ciphertext, and it aligns strongly with independent OCR.
5. **AX does not expose rich publication structure.** Figures, tables, block hierarchy, link targets, styles, and reliable visual reading order are absent or flattened.
6. **AX plaintext can materially improve OCR.** A hybrid pipeline should use AX as a transcription/lexical authority for aligned prose while Docling or another vision system remains responsible for geometry, layout, figures, and tables.
7. **The underlying publication remains DRM-protected.** Clear AX output does not make the stored KFX package DRM-free.

## 0. Ecosystem context supplied at the start of the session

The session began with a user-supplied survey of Kindle desktop automation projects. Those ecosystem observations were not independently re-audited during the local probe, so they should be kept separate from the machine-specific evidence below.

The supplied survey’s main conclusions were:

- No mature, dedicated, cross-platform Kindle Desktop automation framework had been identified.
- Windows had more existing Kindle-specific examples than macOS.
- AutoHotkey examples demonstrated directed input to Kindle for PC by window handle, including background left/right key delivery without coordinate clicking.
- PyAutoGUI examples demonstrated repeated page turning and screenshot capture across desktop platforms.
- Existing personal-library download scripts showed that large Kindle-for-PC workflows had been automated in practice.
- Windows was proposed as the easiest first platform through AutoHotkey, Win32, and UI Automation.
- macOS was proposed as an `AXUIElement` Accessibility driver rather than a Kindle-specific AppleScript library.
- The recommended cross-platform fallback hierarchy was native AX/UIA, then keyboard events, then coordinates/image matching, then a vision agent.

The local work in this report directly validates the macOS half of that proposal: Kindle’s native Accessibility surface is sufficiently semantic for a focused driver.

## 1. Installed application

| Property | Observed value |
|---|---|
| Application | `/Applications/Amazon Kindle.app` |
| Display name | Amazon Kindle |
| Process name | Kindle |
| Bundle ID | `com.amazon.Lassen` |
| Version | `7.64` |
| Build | `1.461753.10` |
| Architectures | `arm64`, `x86_64` |
| Minimum macOS | 13.0 |
| Distribution | Mac App Store |
| Runtime | Hardened, sandboxed |
| Implementation | Mac Catalyst / UIKit with WebKit and native Kindle components |

### Static automation surfaces

- No Kindle-specific AppleScript dictionary is present.
- `sdef` returns error `-192`; there is no `.sdef`, script suite, or scripting terminology resource.
- Generic AppleScript/System Events can still launch the app and inspect its Accessibility tree.
- A custom `kindle://` URL scheme is registered, but the private deep-link grammar was not dynamically validated.
- The bundle contains App Intents corresponding to **Read Current** and **Play Current**. These can resume current content but do not provide a documented arbitrary-title API.
- Static symbols and localized strings indicate commands for next/previous page, next/previous chapter, bookmark, font sizing, search, copy selection, close book, and location navigation.

### Permissions and local tooling

The current execution context passed all relevant preflight checks:

- Accessibility trusted: `true`
- Targeted event posting: `true`
- Screen capture: `true`
- Event listening: `true`
- System Events UI access: enabled

Installed development tools include Swift, Xcode, and Accessibility Inspector. Python did not have PyObjC, PyAutoGUI, or `atomacos`; `cliclick` and Hammerspoon were also absent. A native Swift driver is therefore the cleanest implementation on this Mac without additional dependencies.

## 2. Reader Accessibility surface

The reader exposed stable semantic identifiers and labels including:

- `SceneWindow`
- `ReaderView`
- `Close Book`
- `Table of Contents`
- `In-book Search`
- `Annotations`
- `Brightness`
- `More options`
- `BookmarkButton`
- `Bird's Eye View`
- `PageLocationText`
- Transient `Next Page`

Most interactive reader controls advertise `AXPress`. The toolbar and page-turn controls are dynamic: they appear and disappear depending on reader chrome state. A driver must re-query the tree before every operation and keep keyboard events as a fallback.

### Current-page text

The reading surface exposes its current page as an `AXGenericElement` under `ReaderView`. Its `AXValue` is an ordinary string.

Two books were observed during the session:

- **Statistical Thinking** was later identified by the user as a PDF. Its sampled reading surface exposed 5,942 characters / 863 whitespace-separated words. This proved readable text availability, not rich PDF object or annotation exposure.
- **Winning at New Products** is a non-PDF KFX title. Its sampled page exposed 1,841 characters / 255 whitespace-separated words (283 normalized alphanumeric tokens in the OCR comparison).

Selection text and selection range can be read, but `AXSelectedTextRange` and `AXValue` were not settable. Page text supports advertised range-related APIs, although several of those APIs are stubs in the KFX reader, as detailed below.

### Practical reader primitives

```text
get_current_page()
  SceneWindow -> ReaderView -> AXGenericElement -> AXValue

get_progress()
  PageLocationText -> AXDescription / AXValue

next_page() / previous_page()
  transient semantic button when present
  -> fallback: CGEventPostToPid(Right / Left)

screenshot()
  CoreGraphics / ScreenCaptureKit
```

No page-turn test was performed during this session.

## 3. Library Accessibility surface

The library is a virtualized `AXGroup` with identifier `LibraryGridView`.

### Visible grid behavior

- One snapshot exposed 42 cells in a 7×6 grid, with the final row partially visible.
- Normal book cells are childless `AXButton` elements.
- Each normal cell has a stable identifier of the form `Cell(asin:<10-character ASIN>)`.
- ASIN is the best deduplication and checkpoint key.
- Titles and authors appear together in `AXDescription` / `AXUserInputLabels`; they are not separate semantic fields.

Every normal cell exposed:

- `AXPress`
- `AXShowMenu`
- `AXScrollToVisible`
- `AXScrollDownByPage`
- `AXScrollUpByPage`
- `AXCancel`

### Download semantics

In the sampled viewport:

- 28 cells reported exactly `Book Not Downloaded`.
- 13 cells reported `Book Downloaded. Reading is N percent completed`.
- One remaining cell represented a periodical/issues aggregate and requires separate handling.
- 12 of 42 descriptions contained `Audible companion available`.

The help text was explicit:

- Undownloaded: `Downloads book. Has context menu`
- Downloaded: `Opens book. Has context menu`

Therefore, `AXPress` on an undownloaded normal cell is a semantic ebook download action rather than an ambiguous coordinate click.

### Audible menu action

A transient, non-destructive context-menu probe found an enabled button:

- Label: `Download with Audible`
- Identifier: `BookDownloadAction`
- Role: `AXButton`
- Action: `AXPress`

The menu was dismissed without invoking the download action, and the book’s download state remained unchanged.

### Scrolling and enumeration

`LibraryGridView` directly supports page-wise scrolling. One reversible test produced:

- 42 visible identifiers before scrolling
- 49 visible identifiers after one page-down action
- 7 overlapping identifiers
- 42 newly observed identifiers
- Exact restoration after one page-up action

There is no exposed total-count, scrollbar range, or end-position attribute. Full enumeration should:

1. Re-query after every scroll.
2. Deduplicate by ASIN.
3. Expect at least one row of overlap.
4. Stop only after repeated pages yield no new ASINs.
5. Use a stable sort such as title or author so downloads do not reorder the working set.

Relevant toolbar identifiers include:

- `OOBLibrary.AllButton`
- `OOBLibrary.DownloadedButton`
- `OOBLibrary.FilterMenu`
- `OOBLibrary.SortViewButton`
- `LibraryGridView`
- Library search field

## 4. Local catalog and storage inventory

The following was obtained through read-only database, plist, and filesystem inspection. Databases should be used as inventory/verification sources only; downloads should still be initiated through Kindle’s UI.

### Containers

| Location | Approximate size |
|---|---:|
| `~/Library/Containers/com.amazon.Lassen` | 981 MB |
| `~/Library/Group Containers/group.com.amazon.Lassen` | 136 KB |

The data volume had approximately **2.6 TiB free**.

### Catalog

Primary catalog database: `Data/Library/Protected/BookData.sqlite`

| Category | Count |
|---|---:|
| Total `ZBOOK` rows | 2,900 |
| Ebook/dictionary rows | 2,268 |
| Archivable ebook rows | 2,226 |
| Non-archivable dictionary-like rows | 42 |
| Audio/Audible rows | 632 |

“Archivable” is the strongest local indicator for cloud/library books, but it should not be treated as a formal proof of purchase entitlement without an Amazon-side check.

### Current local download state

| Content | Catalogued/candidate | Locally downloaded | Approximate remaining |
|---|---:|---:|---:|
| Archivable ebooks | 2,226 | 16 | 2,210 |
| Linked Audible candidates | 632 | 3 | Up to 629 |

Additional observations:

- Downloaded ebook bundles totaled about 359 MB.
- Declared ebook file sizes totaled approximately 25.6 GiB, implying roughly 25.3 GiB remained.
- Ebook bundles are stored below `Data/Library/eBooks/` as KFX/AZW8-style resources, with one legacy AZW bundle observed.
- Audio state is represented by `assets.plist`, `downloads.plist`, `syncFileMetadata.plist`, and managed assets below `Data/Library/com.apple.UserManagedAssets.../`.
- Three downloaded audio packages totaled about 551 MB.
- Audio payloads were FairPlay HLS fragmented media, not portable standalone audiobook files.
- The KSDK asset database contained linked BOOK and AUDIOBOOK nodes. The 632 audio records were linked to book parents, but the database’s download-state field was not reliable; plists and filesystem assets are better verification sources.
- Total audiobook size was not available. Current free disk space makes capacity unlikely to be the immediate blocker, but actual audio entitlement and download size must be measured during a canary run.

## 5. Bulk download feasibility

### Ebook conclusion

Bulk ebook downloading is technically feasible through a sequential, resumable AX automation job. It is not a supported one-click Kindle-for-Mac workflow.

Recommended state machine:

1. Refresh/sync the Kindle catalog.
2. Build a read-only ASIN inventory from the local catalog.
3. Set the library to **All** and use a stable sort.
4. Enumerate visible cells and deduplicate by ASIN.
5. For `Book Not Downloaded`, invoke `AXPress`.
6. Verify completion using database state plus local bundle existence.
7. Checkpoint ASIN, status, attempts, timestamps, and error category.
8. Scroll by page and continue.
9. Stop after the queue is complete or repeated end-of-grid detection.
10. Retry transient failures with backoff and conservative concurrency.

Special cases include periodical/issue aggregates, collections, dictionaries, removed titles, borrowed titles, authentication prompts, and network failures.

### Audible conclusion

Audio automation is promising because Kindle exposes both an availability suffix and an enabled `Download with Audible` action. However:

- “Audible companion available” may mean that a companion edition exists, not that it is owned.
- The 632 linked local audio records are candidates, not proven entitlements.
- Automation must never purchase, confirm payment, or accept a trial automatically.
- Any purchase/paywall/entitlement dialog must be classified as `not_owned` or `requires_user_action` and skipped.
- One ordinary ebook and one Audible candidate should be tested as canaries before a full job.

The safest initial concurrency is one active audio download and a small ebook queue, increasing only after state verification is reliable.

## 6. Why “Download all items” is not visible on this Mac

Amazon’s documented `Download all items` command applies to a **physical Kindle e-reader** and to a **specific Collection**, not to Kindle for Mac and not to the entire account library.

The documented hardware path is:

```text
Kindle e-reader Home
  -> Library
  -> Sort by Collections
  -> menu on one Collection
  -> Download all items
```

The installed Mac app exposes individual downloads, Audible-assisted downloads, All/Downloaded filters, sorting, and search. It does not expose the collection-level hardware command.

Official references:

- [Download Collections to Your Kindle E-Reader](https://digprjsurvey.amazon.com/csad/help/node/GQNG5LCNAE6JYM45)
- [Amazon page mentioning Kindle for Mac downloads](https://kdp.amazon.com/en_US/help/topic/G200735130)

## 7. Rich document semantics: PDF versus KFX

### Statistical Thinking (PDF)

The PDF sample demonstrated that Kindle’s reader could expose readable page text. It did **not** establish that Kindle exposed native PDF annotations, figures, link targets, paragraph structure, or geometry. “Readable text layer” and “rich document semantics” are separate claims.

### Winning at New Products (KFX)

The currently tested non-PDF title was confirmed as KFX:

| Property | Observed value |
|---|---|
| ASIN | `B06X1F836K` |
| Package size | 47.61 MiB |
| Files | 19 |
| Main content | One `.azw8` |
| Metadata | One `.azw9.md` |
| Resource pieces | Eleven `.azw9.res` |
| DRM | Voucher present; main/metadata use a `DRMION` envelope |

There was no plaintext EPUB ZIP, OPF, XHTML, CSS, navigation tree, SVG, or URL structure on disk.

Metadata-only resource inspection found 134 structurally valid JPEG payloads. Most were high-resolution and landscape-oriented, but metadata alone cannot identify their roles or placement. The protected KFX content graph contains reading order, styles, anchors, captions, alt text, figure placement, and link targets.

### Visual page versus AX page

The sampled page visibly contained:

- Three prose blocks
- One boxed callout
- One large table-like figure
- Approximately six blue cross-reference spans
- One blue footnote-like marker

AX exposed the page as exactly one childless `AXGenericElement` with 1,841 UTF-16 code units.

| Feature | Visible | Exposed by ordinary AX reads |
|---|---|---|
| Body prose | Yes | Yes, as flattened text |
| Paragraph boundaries | Yes | No |
| Boxed callout | Yes | Text present, but flattened and placed out of visual order |
| Cross-reference labels | Yes | Mostly present as ordinary text |
| Link role/target URL | Yes visually | No |
| Large figure/table | Yes | Omitted from AX |
| Image node/attachment | Yes visually | No |
| Fonts/colors/underline | Yes visually | No |
| Heading/list/block hierarchy | Conceptually present | No semantic nodes |
| Text geometry | Visible | Range/bounds APIs return empty sentinel values |

`AXAttributedStringForRange` returned the same 1,841 characters as one run with **zero attributes**: no font, color, paragraph style, link, attachment, heading, list, or quote metadata.

The reader advertises custom rotor descriptors named `Link` and `Heading`, but AX exposes only rotor labels/types. It does not expose rotor item lists, ranges, URLs, targets, or heading levels. These descriptors show that Kindle retains some internal semantics, but they are insufficient for ordinary cross-process extraction.

### Reconstruction conclusion

- Plain reflowed EPUB from sequential AX page text: feasible.
- Richer derived document using AX text plus screenshots, OCR, layout detection, and heuristics: feasible but lossy.
- Faithful source EPUB with original hierarchy, styles, figure placement, and link targets: not recoverable from AX alone.
- Direct protected-package parsing would encounter the DRM-enveloped KFX content graph and was not attempted.

## 8. Plaintext and DRM distinction

The AX page value is genuine clear Unicode at the Accessibility boundary. It is not ciphertext and is not Apple-generated OCR output. Kindle has already authorized, decrypted, laid out, and rendered that page before supplying its accessible value.

This does **not** make the publication DRM-free:

| Boundary | Status |
|---|---|
| Runtime Accessibility value | Clear Unicode plaintext |
| Stored KFX publication | DRM-protected package with voucher |
| Licensing/distribution rights | Unchanged |

The correct term is **post-render accessibility plaintext**, not “DRM-free book.” It is suitable as a local transcription side-channel for content the user is authorized to read, without bypassing the stored package protection.

References:

- [Apple `AXValue` attribute](https://developer.apple.com/documentation/applicationservices/kaxvalueattribute)
- [Amazon explanation of DRM-free EPUB/PDF availability](https://kdp.amazon.com/en_US/help/topic/GDDXGH9VR22ACM8U)
- [Kindle Store Terms](https://digprjsurvey.amazon.com/csad/help/node/201014950)

## 9. Independent OCR validation

The current KFX page was captured temporarily and processed with Apple Vision OCR. No book text was printed or retained; the temporary image was deleted.

### AX text quality

| Measurement | Result |
|---|---:|
| Unicode characters | 1,841 |
| UTF-16 code units | 1,841 |
| Normalized alphanumeric tokens | 283 |
| UTF-8 encodable | Yes |
| Printable-character ratio | 100.0% |
| Replacement characters | 0 |
| Null characters | 0 |
| Unexpected control characters | 0 |
| Dominant language | English |
| Language confidence | 99.6% |

### AX versus independent OCR

These measurements cover one rendered page only. They depend on the chosen tokenizer and alignment method and should not be generalized to every Kindle title without a broader benchmark.

| Measurement | Result |
|---|---:|
| Vision OCR observations in reading region | 117 |
| OCR characters | 4,326 |
| OCR normalized tokens | 649 |
| AX tokens found in OCR, ignoring order | 97.2% |
| AX tokens preserved in ordered LCS | 88.0% |
| OCR tokens also present in AX | 42.4% |
| Ordered LCS tokens | 249 |

Interpretation:

- The 97.2% AX-token match strongly validates that AX contains real rendered prose rather than encrypted or garbled data.
- The lower ordered overlap is consistent with flattened callout/block ordering.
- OCR contains much more text because it sees figure/table pixels that AX omits, plus possible OCR noise.
- These figures are a cross-check between two imperfect channels, not formal ground truth.

## 10. Docling integration

Docling does not document a direct `external_text=` or “trusted transcript” option. Its supported extension point is a custom OCR plugin implementing `BaseOcrModel` with an `OcrOptions` subclass and `allow_external_plugins=True`.

Recommended hybrid pipeline:

1. Capture the Kindle screenshot and AX transcript from the exact same reader state.
2. Let Docling/OCR detect word or line boxes.
3. Let Docling detect layout regions, tables, figures, and reading order.
4. Normalize and locally align AX tokens with OCR `TextCell` tokens.
5. Replace only confidently aligned OCR strings with AX strings.
6. Retain Docling’s geometry, confidence, and OCR provenance.
7. Keep OCR-only regions, especially tables and figures.
8. Preserve unmatched AX spans for secondary alignment rather than forcing them into incorrect boxes.

The best division of responsibility is:

| Channel | Authority |
|---|---|
| AX plaintext | Spelling, punctuation, lexical transcription for aligned prose |
| OCR / Docling | Bounding boxes, visual reading order, tables, figures, visual-only text |
| Heuristics / VLM | Block classification, callouts, figure-caption matching, uncertain reading order |

This should materially improve prose transcription accuracy. It will not independently recover link targets, figure semantics, paragraph hierarchy, or faithful styling.

Official Docling references:

- [OCR engines](https://docling-project.github.io/docling/concepts/OCR/)
- [Plugin system and custom OCR factory](https://docling-project.github.io/docling/concepts/plugins/)
- [`BaseOcrModel` source](https://github.com/docling-project/docling/blob/main/docling/models/base_ocr_model.py)
- [`TextCell` page model](https://github.com/docling-project/docling-core/blob/main/docling_core/types/doc/page.py)
- [Pipeline options](https://docling-project.github.io/docling/reference/pipeline_options/)

Docling’s `force_backend_text` option is not an AX injection hook; it only chooses native text already supplied by a supported document backend.

## 11. Recommended implementation architecture

```text
Kindle MCP / local service
  |
  +-- Swift macOS AX driver
  |     +-- library enumeration and download actions
  |     +-- reader controls and progress
  |     +-- current-page AX plaintext
  |     +-- targeted keyboard fallback
  |
  +-- Read-only catalog verifier
  |     +-- ASIN inventory
  |     +-- ebook download state
  |     +-- Audible candidate mapping
  |     +-- filesystem/plist completion checks
  |
  +-- Visual extraction pipeline
        +-- synchronized screenshots
        +-- Docling layout/table/figure detection
        +-- OCR word/line boxes
        +-- AX-to-OCR alignment and correction
        +-- confidence/provenance tracking
```

Suggested public primitives:

```text
kindle.list_books()
kindle.open_book(title_or_asin)
kindle.next_page()
kindle.previous_page()
kindle.search(text)
kindle.goto(location)
kindle.get_current_page()
kindle.get_progress()
kindle.screenshot()
kindle.download_book(asin)
kindle.download_with_audible(asin)
kindle.get_download_status(asin)
kindle.close_book()
```

Fallback order:

```text
1. Native Accessibility semantics
2. Targeted keyboard events
3. Coordinates / image matching
4. Vision agent
```

## 12. Reliability and safety constraints

- The AX tree is dynamic; never retain element references longer than necessary.
- Kindle sometimes kept its process alive with zero windows. The driver should detect this and reopen the scene before probing.
- Stable identifiers can change in a future Kindle release; probe capabilities at startup.
- Use read-only database access. Never mark content downloaded by editing Kindle databases.
- Verify UI-triggered downloads with independent database/plist/filesystem evidence.
- Use checkpoints and make every operation idempotent.
- Throttle downloads and back off on authentication, network, service, or storage failures.
- Maintain a disk reserve and monitor managed-asset growth.
- Never automate purchases, trials, payment confirmation, or destructive deletion.
- Do not interpret accessibility plaintext as permission to redistribute protected content.

## 13. Actions deliberately not performed

During this session:

- No ebook or audiobook download was started.
- No purchase or entitlement action was confirmed.
- No page was turned.
- No full book was extracted.
- No DRM was bypassed or decrypted outside Kindle’s authorized rendering path.
- No Kindle database or plist was modified.
- A context menu was opened and dismissed without invoking its actions.
- One library page-down/page-up test was performed and exactly restored.
- Temporary screenshots used for structural inspection/OCR comparison were deleted.
- Book text and private library titles were not included in this report.

## 14. Recommended next step

Build a canary-mode Swift driver that stops after:

1. Enumerating the catalog and library without changing state.
2. Downloading one ordinary undownloaded ebook.
3. Verifying the ebook through AX, database state, and filesystem state.
4. Attempting `Download with Audible` on one candidate only when the menu explicitly offers it.
5. Aborting and logging if any ownership, purchase, trial, or payment UI appears.
6. Verifying the audio through managed-asset plists and files.
7. Capturing one page screenshot and AX transcript, then producing an AX-assisted Docling result with provenance and alignment metrics.

Only after those canaries pass should the full resumable download or extraction job run.
