Reference
Keybindings
| Key | Action |
|---|---|
r | Regenerate the pairing token (Pairing screen) |
s | Show the Devices screen (from Pairing) |
x | Revoke the highlighted device (Devices screen) |
p | Show the Pairing screen (from Devices) |
j | Open the TUI switcher modal |
q | Quit |
Screens
Pairing
- Generates a one-time 256-bit token via
secrets.token_urlsafe(32). - Detects the LAN IPv4 and builds the URI per
aidocs/applink/protocol.md§Pairing flow. - Embeds the server’s TLS-certificate fingerprint (SHA-256 of the DER cert, base64url) so the mobile client can pin it at pairing time.
- Renders the URI as a QR code using
segno, displayed with half-block Unicode for compact terminal output. The raw URI is not shown on screen to avoid leaking the pairing token to bystanders.
Regenerate semantics
r rotates only the unused pairing token. Devices that have already
paired carry their long-lived bearer and keep their connection IDs across
a regenerate action. To deliberately disconnect a device, revoke it from
the Devices screen (below) — regenerating a QR never drops live sessions.
Devices
Lists every paired device, one row per bearer session, with its
name/model, platform, connection state (Connected / Suspended), pairing
time, last-seen age, and coarse location when the device supplies one.
Press x to revoke the highlighted device: its bearer is invalidated and
any live socket is closed immediately. The list refreshes automatically.
Listener
On launch the TUI starts a wss:// WebSocket server (TLS via a persistent
self-signed certificate generated on first run). It accepts the pair
verb, issues a session bearer under the selected permission profile, and
routes subsequent command verbs into the shared monitor core, gating each
verb against the session’s profile. See aidocs/applink/protocol.md for
the envelope and pairing flow, aidocs/applink/permissions.md for the
permission profiles, and aidocs/applink/monitor_port_design.md for the
command-verb inventory.
While at least one paired device is streaming, the App Linker reads pane
status from the background monitor status server, the one ait monitor and
ait minimonitor share, instead of scanning every pane itself. With no
device connected it holds no subscription. Set AITASKS_MONITOR_SERVER=0 to
make it scan the panes itself; it also does so whenever that server cannot be
reached.
Permission profiles live in aitasks/metadata/applink_profiles/*.yaml
(read_only, monitor_control, full). Validate a profile with:
./.aitask-scripts/aitask_applink_validate_profile.sh <profile.yaml>
Per-device bearer sessions and the TLS certificate are stored under
aitasks/metadata/applink_sessions/ (gitignored, per machine).
URI grammar
applink://<lan-ip>:<port>/pair?t=<base64url(token)>&fp=<fingerprint>[&name=<urlencoded(hostname)>]
See aidocs/applink/protocol.md for the canonical definition, including
the JSON envelope, version handshake rules, and the connection state
machine.
Python module layout
.aitask-scripts/applink/
├── __init__.py
├── applink_app.py # Textual App + Pairing/Devices screens + runtime
├── server.py # wss:// WebSocket transport + connection lifecycle
├── router.py # pure frame router: parse, auth, gate, dispatch
├── sessions.py # pairing tokens + bearer session table (persisted)
├── profiles.py # permission-profile loading + verb gating
├── tls.py # self-signed cert, fingerprint, SSL context
├── pairing.py # token, IP detection, URI builder
├── paths.py # runtime/profile path resolution
└── qr_widget.py # TerminalQR(Static) — compact half-block renderer
Dependencies
textual>=8.2.7,<9segno>=1.5,<2(chosen overqrcodefor built-in Micro QR support)websockets>=12,<17(WebSocket transport)openssl(system binary; generates the self-signed TLS certificate)
The Python packages are installed by ait setup.