15 · The web app
alix is a web app: review, browse, and the exam all run here. alix opens a
small local web server and shows you its URL, writing to the same progress
store that alix stats/alix list read: what you grade here is exactly
what they show. It’s especially handy on a tablet or
phone, where touch (and images) work naturally.
alix # the deck picker, at http://127.0.0.1:7777
alix --port 8080 # a different port
alix --lan # reachable from other devices on your network
alix ~/decks-maria --lan --port 7781 # serve one folder as its own scoped root
Choosing decks in the browser
Run alix and the page opens the deck-selection
screen. Up / down move between
decks; a search box in the header filters the list (focus it with /).
Focus a deck and Learn it with Enter (a facts deck opens a
review, a trace deck opens a trace) one deck per session. Browse
on b opens a read-only, in-page read-through instead: step the cards with
Prev/Next, Esc to leave. A browse leaves no trace: it records no progress and
does not add the deck to your recent decks. Focusing any deck opens an inline focus drawer
beneath it: it shows the deck’s frontmatter description:, if any, and
a per-card tier heatmap: neutral for an untouched card, grey for one merely
seen (met: acknowledged, or answered and got wrong), white once learning
(at least one full or partly pass, not yet graduated), green/yellow/red for a learned card by how well you’d recall it right
now, purple once retired, and an unfilled outline for a
sub-card still gated on its
parent’s graduation. When the deck has a review order that
heatmap splits into named regions you can pick to drill (click one or step
through with ← / →); otherwise it is a single whole-deck bar. On a workspace row instead,
→ enters it, and Esc or Backspace backs out. After a session, Leave (on the summary)
or Esc (also the footer’s Back chip while inside a drill-in) returns
here, so you can switch decks without restarting. Every review starts from
this screen; there’s no direct deck launch. A focused deck’s split
Depth… button opens the depth menu (Scheduling)
without starting it.
A fact deck with an exam has one separate Take exam action (x).
Learn and Enter still start a drill when the exam is due; they never
start the exam. Take exam fills with the accent color only when the exam
is due and unlocked. A locked exam stays unfilled and disabled with a lock
glyph. The Depth menu does not repeat the exam action, and a session summary
does not offer an exam. An only what needs work tick always follows
Take exam, ticked by default; untick it to take a full sitting. It is
disabled while the exam is locked or every section has passed, since the
sitting then covers every section either way. Results show the point
total, each section’s count and status, and the shape of every question.
mastered appears only after a perfect full sitting.
A workspace row that has a personal deadline set shows a
small chip: a date, days left, and ready percent, colored to flag urgency
inside the last week or past due; the same readout sits inline behind the
title once you drill in. Press d (or the row’s Ready by… action) to
set, move, or clear it from an inline date prompt.
A deck whose own progress document cannot be read shows a red error line
and refuses to start: reviewing it would write fresh progress over the
document alix could not read. Its siblings are unaffected. alix doctor
names the damaged file; fix or remove it (alix reset <deck> removes an
unparseable document after confirming) and the row heals on the next
listing.
Walking a deck
A walk reads a deck once, card by card, with an attempt before each
answer. You grade each answer, but nothing is scheduled: a walk only
remembers what you missed so the next walk can bring it back. It is meant for
material you want to go through rather than drill: preparing a talk or a code review, or re-reading a deck now and
then. Start it from the focused deck’s Depth… menu with Walk (key
w while the menu is open). After that, the deck’s main button is Walk
until you start a session at a depth again. It is not offered for a trace
deck.
Each item shows its front first. A card with authored choices is answered by
picking (the pick shows right or wrong); every other item is a flip: try to
recall it, then Reveal (space). A reveal: line card shows one answer
line per Reveal next instead. A flip ends with Missed it, Partly
or Got it (1/2/3). A correct pick ends with Next (space) or
the quiet I guessed (1); a wrong pick ends with Continue (space).
A card with an authored hint offers Hint (i) on its front; opening it
turns a Got it on that card into Partly, as in a session. Each direction of
a two-way card and each blank of a cloze is its own item. The section’s
context sheet opens by itself the first time a walk reaches that section, and
the tutor is available once an answer shows.
A walk keeps only the time each item was walked and its last walk grade; it
never touches the schedule or the review history. An item is waiting until
its last walk grade is Got it (or Next on a pick). While any item waits, a
walk serves only the waiting items, in deck order, so a missed card comes
back in the next walk, leaving early and coming back continues where you
stopped, and the counter shows what is left. Adding a card to a deck makes it
waiting. Once nothing waits, a walk is a full pass, the items walked longest
ago first. At the end, Next walk (r) starts the next walk. Walking
counts for the drill too: the drill grades a walked card at first sight
instead of introducing it.
The tutorial
Tutorial in the deck picker’s ☰ menu, or the Tutorial button the picker shows when it finds no decks, opens a short tutorial deck as a walk. Its nine cards each teach one thing by having you do it: grade an answer, open the section’s text and a hint, pick a choice, reveal line by line, fill a blank, hide an answer, and show a cited source. Opening it again continues where you stopped, as any walk does.
The tutorial ships with alix and is kept apart from your library: it is
never listed in the picker or the recent list, and neither it nor its
progress is written into your decks folder. Each open writes the tutorial
and the small sample file its cited card points into a folder of its own,
under the same platform directory as the server log: tutorial/default/,
or tutorial/profiles/<name>/ for a launch of profile <name>. A scoped
alix <dir> launch and a --config launch that names no profile share
tutorial/default/. A file there that differs from the shipped one is
rewritten on the next open, so an update brings the updated tutorial and an
edit you make there does not last. In the tutorial the tutor offers Ask
but not Make this a note or Make this a card, so nothing of yours is
saved there. A kids-profile server refuses /api/tutorial with HTTP 403.
The tutorial is in English only.
Library actions
The picker’s ☰ menu carries six actions that used to be terminal-only:
everything below is an /api/* endpoint, so it’s also on the wire for other
clients (see docs/API.md):
- Add deck…: one sheet, three ways in, all landing in a chosen
destination (the library root or a workspace): generate a deck from a
URL (with optional guidance) the same way
alix deck generatedoes, but URL sources only, a local-file source stays CLI-only, since a LAN token holder must not be able to point the server’s AI at the server’s own filesystem; import an Anki.tsvor an alix.mdfile; or receive: paste a wormhole code, or upload a.zip. - Share…: sends the focused row (deck, folder, or workspace; the served root if nothing’s focused) device-to-device over a wormhole code, or download as .zip as the offline fallback. Personal state (progress, recent list, local pacing) stays home either way.
- Remove from library…: permanently removes a focused loose deck,
workspace member, or whole workspace and its Alix-owned progress, frozen
assets, augmentations, and backup siblings. The sheet first lists the
stakes, then requires the exact row name. Removing a workspace preserves
ordinary source files and uninitialized Markdown, so its folder remains if
either is present. A partial failure stays visible with completed and failed
artifact labels plus the
alix doctorrecovery step. There is no undo. - Reset…: wipes a row’s progress. Gated on typing the row’s name back exactly, since this can’t be undone; needs a focused row.
- Doctor: the free environment checks (config, log, store, decks,
backend, share) as ✓/!/✗ rows, screenshot-able for handing to whoever set up the
instance. The costed
--backendsprobe stays CLI-only. - Pair a device: a QR of the pairing URL plus the URL itself, to scan
from a phone or tablet. Needs
--lan; a localhost-only instance shows a hint instead (nothing reachable to scan).
Augmenting a deck from the picker
Focus a deck and press a (or its Augment button) to open the Augment
screen: the browser face of alix deck augment. Each of six targets,
choices, notes, questions, key points,
format, and order, gets its own card: a short, plain description of what
that augmentation does, a small neutral before/after preview, its coverage
count, and its action. Generate fills only the cards a target is still
missing, run as a background model call while the page polls (a spinner shows
it working); Remove clears a target, and the order card adds or drops
named topologies. Each card has its own compact guidance input, feeding the
same --with steer as the command line, with a kind-specific example as its
placeholder so you can see what a steer is good for; a batch carries each
ticked card’s own guidance. It writes the same
augment/deck-<token>.json document review reads, so this only saves you the
trip to the terminal.
Cached per-card augmentations are tied to the question and answer they were generated from. Editing either makes that card reappear as a gap, so its augmentations regenerate on the next augment run.
The action also works on a workspace or folder row: the same screen opens over all its decks at once, so a Generate fills a target’s gaps across every member, Remove clears it across every member, and an Order generated here is one workspace-wide pedagogical path. A workspace additionally gets an Icon card: Generate draws (or redraws) the small emblem shown on its picker row, steered by the card’s guidance.
Tick several targets and press Generate selected to run them in one batch (a Select all button at the top ticks everything that can run): it shows a rough estimate of how many generations that will take, then walks each ticked card through its own status, queued, generating, done, or failed, as the batch runs. A target failing doesn’t stop the others; a single per-target Generate still works the same way it always did.
On the Claude backend a batch shares one conversation: the first target sends the cards once and every later target refers back to them by index, which is cheaper and a little faster than re-sending the deck per target. Other backends, and single-target runs, keep making one self-contained call per target. A failed target starts a fresh conversation for the rest of the batch.
The format target is a non-destructive reshaping pass: for each plain card whose answer is poorly shaped (a list crammed into prose, a run-on sentence that wants to be lines) it caches a tidier front, split answer lines, an optional note, and a suggested reveal-method: applied at display time without touching the deck file or card identity. Both review and browse show the reshape, so the two views match. It’s an AI heuristic, so it can miss or produce an unhelpful reshape; Remove clears it with no lasting effect.
Every check, at every depth, plus the AI features
Every check works in the browser, at whichever session
depth you picked: a flip or cloze reveal, a line reveal (it auto-scrolls to
the newest line), a typing Reconstruct check (each line marked ✓/✗ with the
correct answer shown, then you grade), an explain Reconstruct check, and the
multiple-choice pick: a new card’s attempt-first on-ramp, or a genuine
Recognize-session question. Pick-one cards submit when you tap an option;
select-all cards let you toggle each answer independently, then submit the
whole set at once. A correct pick offers the quiet “I guessed” undo. A
revealed note uses the same content-column width and text size as the answer
or choices above it. Question and answer prose is left-aligned inside a block
that shrinks to its content and sits centred in the card: a one-word question
or a one-glyph answer lands in the middle, a wrapped paragraph reads as a
left-aligned block, and a block holding code, a table, a checklist or a
quotation spans the whole column. A note is always left-aligned at the full
column width. The note sits at the bottom of the card, directly above
the buttons, and takes only the height its text needs; a long note takes the
room the answer is not using, and room the answer is using only down to a
third of the card, past which the note scrolls inside its own region. When an answer or a note is taller than
its region, a “more below” or “more above” marker appears at that edge;
clicking it scrolls that region by most of its height, so you can walk a long
answer without reaching for the wheel. Controls are big tap targets and
follow your configured key bindings (the page reads them from the server).
A card under a section names the section on its face only through a quiet
Context chip in the bottom row, offered until the answer shows. On the first
card you ever meet from that section, the section sheet opens by itself
once: the page dims at once and the sheet slides up from the bottom of the
page, as on the phone, taking only the room its prose needs; a long section
scrolls inside it. Dismiss it and it stays closed through reveal or answer
input; later cards from the same section, in this sitting or any later one,
do not open it automatically. The full section never appears inline. Click
the Context chip, press c, or use Context beside Ask in the
review menu to open the sheet on demand; a click on the question opens
nothing, and once the answer shows none of these is offered, since the
section is there to help you answer.
While the sheet is open, the card and its review keys are inert; a click on
the dimmed page, the × in the sheet’s top-right corner, c, or Escape
closes it.
A card with hints offers a quiet Hint
chip to the right of the main button (Context sits to its left) for as long
as you are still answering (on a
reveal: line card, until the last line shows). The chip, i, or Hint in
the review menu opens the same sheet with the first hint; Next hint (or
Enter) adds the next one under it until none are left, and reopening shows the
ones you already opened. c and i swap the sheet between the section and
the hints. Opening a hint turns a pass on that card into Partial.
Confidence tracking
The depth menu’s confidence tick-box (f) switches tracking on or off for the
deck; the choice is saved in the deck’s progress (so it syncs with it) and
kept for every later launch until you switch it again. It is off by default.
With tracking on, a graded card asks Sure or Unsure in place of its
first action, as one button split down the centre: Unsure (Space) and
Sure (Enter). Where Space already types or ticks an option (a typed
answer, an explain box, a select-all card), they move to Shift+Space and
Shift+Enter, and plain Enter marks nothing.
Either one performs that action and records your mark with the review
in the card’s history. On a single-answer multiple-choice card a click (or the
number keys) only selects an option, which you can change; Sure or Unsure then
submits it. Introductions, walks, and line-by-line typing (Check) ask
nothing. The mark does not change scheduling.
To set an unanswered card aside for later in the session, use Skip card in
the review menu (skip has no default key; bind one in [keys.review]).
A dim “N left” count in the header shows how many cards the session still
holds; it can tick up when a card you missed cools back in for its retry. The
☰ menu is context-aware: during review it holds Ask and,
when available, Context; a trace holds Ask. On the deck
picker, the library actions above plus keyboard
shortcuts, Tutorial and about, with Theme… and Draw
answers (a per-device toggle, see below) in both. The ⟳ button (also key
r) re-reads your config, so a changed decks_dir takes effect without
restarting (scoped alix <dir> instances stay pinned to their folder), and
re-fetches workspace icon images, so a regenerated emblem shows without a
reload.
Once an answer is on screen you can hide it to self-test before you grade:
press h or click the answer. A cover fills the answer’s space, an eye-off
glyph with “click to reveal” beneath it. The note disappears while the answer
is hidden and comes back when you show it. Nothing on the card moves. h or a
click shows the answer again, and the corner marker names what the next press does; on a
cited card it sits beside the </> source marker. A choice pick, a typed
check and a sketch have nothing to hide. The next card always starts shown.
The AI features come along too: the tutor, the AI exam, and traces all have a web surface, each running its model call on a background thread while the page polls, so the single-threaded server never blocks.
Draw input
A input: draw card, or a flip/explain card with
the ☰ menu’s Draw answers toggle switched on, swaps the usual typed/reveal
input for a small canvas: Pen · Eraser · Undo · Clear, then
Reveal. The drawing stays on screen (frozen, not editable) while you
self-grade against the card’s normal reveal, then it’s discarded; nothing you
draw is saved or sent anywhere beyond rendering it in the browser. It’s
honored on flip/explain cards only, never on a cloze card (the desktop web
app types those regardless of the directive or the toggle), and there’s no OCR
or vision model reading it back: grading is on you, same as any other
self-graded card.
Themes
The web UI ships a gallery of colour themes: the alix Dark/Light
originals and a Kids group (Sunrise, Ocean, and Berry, the
same three themes the kids app offers, so a kid moving up to
the grown-up app can keep the look they grew
attached to), plus crowd-favourite editor/slide palettes
(GitHub, Dracula, Nord, Solarized, Gruvbox, Catppuccin, Tokyo Night, Monokai, One
Dark, Ayu, Rosé Pine, Everforest). Open the Theme… popover from the ☰ menu (a
small bar button on the trace): a grid grouped Light / Dark / Kids that previews
on a sample card as you hover and re-themes the whole app when you click one,
remembering your choice in the browser (kept in localStorage, not the config).
The palette lives in a shared theme.css the
server hosts, so every screen (review, browse, and traces) themes together.
Kids mode
alix can also serve a second, touch-first frontend aimed at kids (roughly
age 10). Set audience = "kids" in [serve] (see
Configuration) and point it at a folder an adult has
already set up:
alix --config kids.toml ~/decks-family --lan --port 7781
A box is a workspace: the home screen shows the boxes as a grid, tap one to see its decks with a ⭐ mastery indicator per deck, tap a deck, then pick that deck’s depth: 👆 Tap the answer (Recognize) or 🗣️ Say it yourself (Recall); a caught-up choice disables itself instead of starting an empty session. On a select-all card, taps mark options instead of answering, and one Done button submits the whole set. Review works the same way underneath as the regular app (reveal, then the mascot says a short “why” instead of a bare note, then self-rate) with a 💬 Ask Alix button that opens a kid-safe tutor overlay scoped to the current card.
v1 is consumption only: it covers reviewing pre-made boxes at Recognize and
Recall depth, plus the tutor. Augmenting a deck, the AI exam, and traces stay
adult-only for now. An adult prepares a box in the regular web app, then
hands the kid a kids.toml and the box to open. It’s the same engine and the
same /api/* contract underneath, just a different page: self-hosted Baloo 2
type, warmer colours, and no keyboard required.
Building a client?
The JSON API the web app itself speaks is a documented, client-agnostic
contract: docs/API.md in the repository (endpoints, DTO field tables, the
flows, and the stability rules) with every response shape pinned by snapshot
tests. Native or alternative clients build against that file.
Local by design
The server is deliberately local-only: no accounts, no database. By default it
binds to 127.0.0.1 (this machine only). --lan binds all interfaces so another
device on your network can reach it: at startup it prints the pairing URL with
the machine’s real IP, plus a scannable QR code, right in the terminal. Serving
with --lan auto-generates a pairing token and requires it on
/api/*, so the network endpoint isn’t wide open; pin your own with --token or
[serve] token. Open the printed …/?token=… URL (or scan the QR) and the page
attaches the token for you. AI requests still run the model CLI on the host, so
only use --lan on a network you trust. The default port lives in the [serve]
config section; --port overrides it.
alix <dir> serves that folder as a self-contained scoped root: its own
catalog, shareable augmentation and assets, plus private per-deck progress and
recent history under its colocated .alix/ directory. Several instances run
happily side by side, one per family
member, say:
alix ~/decks-maria --lan --port 7781.
If a launch misbehaves, alix doctor checks the setup (config, progress
store, decks directory, backend CLI) and prints a one-line remedy per problem.
The Doctor sheet also names this instance’s local log file.
Preparing a bug report
Every running server keeps a small local diagnostic history without requiring
a flag. From the adult web app, open About and choose Prepare a bug
report. From a terminal, run alix bug-report; --out <dir> chooses where
the archive lands. Both paths use the same local ZIP format. Nothing is
uploaded or sent, so open it and review its plain-text files before attaching
it yourself.
The web archive contains the current instance log and its one rollover; the
CLI collects every instance log so it does not have to guess which server had
the bug. The archive also contains version and platform details, a copy of the
active config with every token and AI prompt override removed, and per-deck
counts keyed only by a SHA-256 hash of the stable deck ID. Home-directory and
user names are redacted. By default, no deck text is included. The CLI’s explicit
--include-deck <path> option adds that one deck verbatim, including card text
and authored notes, and names it in report.md. Personal sidecars, AI prompts,
and AI responses are always excluded. The diagnostic log records minted card
IDs plus content-free panic, AI, parser, and HTTP failure classes; verbose
logging can add operational timings. Only known-safe diagnostic fields enter
the archive. Deleting the archive or either log file does not change decks or
progress.