Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

19 · Pairing a device

alix’s web server can lend a paired phone its AI backend for the tutor, the exam, deck generation, and note-taking, over /api/remote/*: the phone keeps its own decks and progress, the desktop only computes answers.

The pairing token changes on every restart

alix --lan prints a fresh, random pairing token each time the server starts. This is the single biggest papercut in pairing a device: if an app that paired fine yesterday suddenly can’t reach the server, the token most likely changed on the last restart. Re-pair with the freshly printed URL, or pin one that never changes:

[serve]
token = "pick-your-own-fixed-token"

With token set, --lan reuses it instead of generating a new one, so a saved pairing survives restarts. A pinned token (or a --token value) must be at least 16 characters; --lan refuses a shorter one before it binds.

What the remote surface does

Nothing under /api/remote/* writes the server’s own progress store, session, decks, or recent list; it only computes an answer and hands it back. A tutor question re-sends the whole conversation with every call, since the server keeps no session for a remote client. When the stable deck and card ids match what the desktop serves, the tutor uses the desktop’s assembled card, notes, links, frozen evidence, and allowed live source root, just like the desktop tutor. When either id cannot be matched, the reply is marked card_only and uses only the card text the phone sent; the phone names that limit as “Answered from the card alone: the paired desktop could not match this card.” An AI exam sitting is graded on the server, but the result, any remediation cards, and what counts as mastered stay the phone’s to keep. A deck generation call hands back the full deck text and a suggested file name; a note condense hands back up to three lines. Either way the phone decides where they land: the decks folder or the deck file, never the server.

The server side of this ships from 0.6.0; see docs/API.md, section 4.11, for the wire contract if you’re building against it.

Pairing the mobile app

On your computer, run alix --lan and note the URL it prints (the same one [serve] token can pin, above). On the mobile app:

  1. Open Settings (the ☰ button on the deck list) and tap Connected devices.
  2. Paste the printed URL into the sheet and tap Pair.

The app checks the server before saving anything, so a bad paste or an unreachable desktop never gets stored silently. It shows one inline line naming what went wrong:

  • an unparseable paste: that does not look like an alix pairing URL
  • a desktop it can’t reach: no alix answered at <host>:<port>
  • a desktop too old for this app’s remote surface: alix <version> found, this app needs 0.6.0 or newer
  • a desktop that answers but rejects the token (most often a server that restarted, and minted a fresh token, since the URL was printed): alix answered but refused this token. Copy a fresh pairing URL from the server.

On success the sheet closes with a note of which host you paired with. The same Connected devices row reopens the sheet later, now showing the current host:port and an Unpair button; unpairing only clears the saved config, nothing else on the phone changes.

What’s borrowed once paired

Once paired, review gains things it doesn’t have offline:

  • An Ask chip, shown once you’ve attempted the current card (revealed it, picked a choice, submitted a typed answer, or walked all its lines) but not before: the same attempt-first rule the web tutor follows. It opens the same question/answer flow as the desktop tutor: replies render with the card’s own content grammar (code blocks, checklists, tables, quotations), and Make this a card and Make this a note enable once an answer exists that nothing was made from yet. A note condenses the exchanges since the last note into key points and appends them to the deck’s personal sidecar, <deck>.local.md, on the phone and, when the desktop serves that deck, on the desktop too, so the next sync pull carries the same note back rather than a sidecar without it (an empty result says so rather than doing nothing silently). A card you add from a draft is minted on the desktop the same way when it serves the deck, and the phone records it under the id the desktop hands back, so the next pull keeps it. Pressing Add locks the draft’s fields. A refusal (a duplicate, or a malformed card) adds nothing on the phone, says so, and unlocks the draft for editing. When no answer arrives, the phone says the card may already be on the desktop and keeps the fields locked: tapping Add again sends the same card, and if the desktop already kept it, it hands that card back and the phone records it. For a deck the desktop does not serve, the card is minted on the phone alone and stays there. Every question re-sends the whole exchange to the paired desktop (the server keeps no session of its own for a remote turn). The conversation belongs to the card, not the sheet: closing the sheet while the desktop is still working loses nothing, the answer or note lands anyway, a note saved with the sheet closed is announced on the review screen, and reopening the sheet shows the whole transcript and a question you had typed but not yet sent. Moving to another card starts a fresh conversation; while the previous card’s note or card draft is still being made, the new card’s tutor says so and waits, since the desktop makes one thing at a time. A desktop restarted mid-call forgets the call; the phone reports it as failed (the question goes back into the chat box) rather than waiting for a result that will never come.
  • An Exam row on a deck’s launch sheet, for a fact deck that declares exam material, with an “Only what needs work” switch (on by default, disabled once every section has passed). It opens a full-screen exam: one question at a time, then the points count, each section’s count, a Pass/Partial/Fail breakdown per question and, when an answer missed key points, a Turn the gaps into cards button. Every sitting’s results and any remediation cards land in the phone’s own progress store, exactly like an offline grade, matching the rule above: the server computes, the phone keeps.

A trace deck runs entirely on-device: predict, reveal, and self-grade each checkpoint. It has no AI exam or paired-only capstone.

The Settings page also gains a Generate deck row: give it a URL and optional guidance, the desktop generates the deck text the same way alix deck generate does, then the phone asks where to save it (an in-app folder browser) and writes it under a collision-free file name. It follows the same liveness rule as the two chips: the row appears only while the phone has confirmed the paired desktop is reachable and new enough, and is simply absent otherwise.

The Ask chip and the Exam row both depend on the phone having confirmed the paired desktop is reachable and running at least version 0.6.0; there is no retry chrome for a dead or too-old server: the Ask chip simply is not there, and the Exam row is disabled with a short hint.

If the desktop answers but rejects the token partway through a review, an exam, a note, or a generation (the restart case above, caught mid-session instead of at pairing time), the phone shows one SnackBar: “Pairing expired. Pair again from Settings → Connected devices.” On the review and exam screens it carries a Re-pair action that reopens the pairing sheet directly; the tutor sheet shows the same line inside the sheet instead, so there you follow the message’s own instruction. Pinning [serve] token is what stops this from happening in the first place.

Security posture

This is plain HTTP on your local network. The bearer token guards against someone stumbling onto the server by accident, not against a hostile network: anyone already on your LAN who gets hold of the token can use it. For anything beyond your own LAN, put alix behind a VPN or a reverse proxy; alix itself will not grow TLS or accounts.