The problem

Everything else in this project translates one system's idea of something into another's: a battery, a clipboard, a keyboard. Accessibility is the same shape of problem with a much worse failure mode, because getting it wrong does not degrade the experience, it removes it. A blind user turning on VoiceOver over this desktop today hears nothing useful, no matter how well the desktop underneath is working.

The good news is that neither side is missing information. Linux apps publish their widget tree over AT-SPI: GTK4 has a native backend for it, Qt 6 has its own bridge inside QtGui, and GNOME Shell exposes its whole shell chrome the same way. iOS has a rich accessibility API on the other side. Nothing connects them.

The bridge

A daemon, xios-a11yd, sits on the accessibility bus and walks the AT-SPI tree of whatever is running. It streams what it finds over a local socket as newline-delimited JSON records: an initial hello, a reset, a window, then upserts as elements appear and change. The schema is versioned, because both ends ship separately and a mismatched pair is exactly the sort of thing that fails silently.

On the iOS side, Xios.app consumes that stream and publishes real accessibility elements over its Metal view, so VoiceOver has something to focus, speak and activate. The same publisher exists in the per-window host used by native mode, since a Linux app living in its own iPadOS window has the same problem in a smaller frame.

The wirea11y v1.1

hello · reset · window · upsert, as NDJSON over a Unix socket, with per-connection filters so a client can subscribe to one app instead of the whole desktop.

Off by default, on with VoiceOver

The accessibility stack costs memory and startup time, and on a device this size that is not free, so GTK's accessibility backend is disabled by default and the bus is not started. The gate is VoiceOver itself: when the app sees UIAccessibility.isVoiceOverRunning change it tells ioscd, which persists that as a flag the session launchers read. Turn VoiceOver on, and the next app launch brings up the accessibility bus, the registry, and the daemon with it.

There is a force flag for smoke tests, so the path can be exercised without toggling VoiceOver on a device you are also trying to read logs from.

Where it actually stands

The pieces exist and talk to each other. On-device smoke tests have brought up the bus against a real GTK app, walked its tree, and seen the daemon publish window and element records for it. The AT-SPI packages and xios-a11y-tools ship, the opt-in XIOS_ENABLE_A11Y=1 launch path works, the Xios app mirrors VoiceOver state, and the launchers honour the gate.

Built, not yet proven with a screen reader

The part that matters most has not happened: nobody has driven a GTK or Qt control with real VoiceOver gestures on a device and confirmed it behaves. Until that validation exists, read this page as a description of a bridge that is built, not of a desktop that is usable with a screen reader. xios-a11yd is also not in any flavor's package set yet, so it is something you run deliberately, not something an install turns on.

Orca, and why it is not the plan

Linux already has a screen reader. Orca could run here and read the desktop in its own voice, with its own key bindings, and for the X11 flavor that is a reasonable complement. It is not the primary design, because it would mean a VoiceOver user learning a second screen reader with a second gesture language to use one app on their iPad. The bridge aims at the opposite: the desktop should answer to the screen reader the person already uses.