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

10 · The Tutor

This is where the AI layer begins. Everything so far (drilling, scheduling, workspaces) runs entirely offline. From here on alix shells out to the configured model CLI, and the first place it does is the most useful: a tutor on any card.

(One reminder: every AI feature shells out to the configured model CLI, so it needs the CLI installed and logged in. See chapter 2. The flashcard core never calls it.)

Asking about a card

On any post-answer screen (a revealed flip card, the feedback after a typed answer, an answered choice) an Ask button (or the a key) opens a chat panel without leaving the session: type a question, Send, Make this a note, Close. alix hands the tutor the card (its front, answer, note, and deck name) as context, and you can ask “why is that the answer?”, “what’s a simpler way to see this?”, or anything else, and follow up. The server runs the model CLI on a background thread and the page polls for the reply, so the single-threaded server never blocks and the session stays responsive while it works.

In the web panel, Enter inserts a newline and Shift-Enter sends. Closing a tutor that contains a conversation moves the caret out of the chat box and asks for confirmation: Enter chooses Leave anyway, while Escape chooses Stay and returns the caret to the chat box. Moving on to the next card drops the conversation and a question still being answered, but a note still being made lands on the card you asked it on: the panel says the tutor is still working on the previous card until it does, a note saved after you closed the panel is announced on the page, and the next card’s tutor waits for that slot.

Tutor replies use the same content grammar as a card. Ordinary explanation stays prose, backticks mark inline code, and multi-line code arrives in a fenced block that the panel renders as code rather than showing the fence markers. The raw reply is still kept for follow-up questions and for making a note or card.

One conversation spans the whole review run. For Claude, alix uses --session-id for the first question and --resume for each follow-up, so the model remembers earlier cards and questions efficiently. Other backends re-inline the accumulated Q&A transcript into each prompt, so the context carries over, at the cost of a growing prompt rather than a resumed session. Either way you can ask how the current card relates to one from ten minutes ago, and the tutor knows.

Ask is available wherever you serve, including over --lan, but the request runs the model CLI on the host machine, so, like --lan in general, only enable it on a network you trust.

Saving what you learn: Make this a note

When an exchange clears something up, press Make this a note: the tutor extracts up to three key points from the exchanges since the last note, one short line each, and appends them, addressed to the card, to the deck’s personal sidecar (<deck>.local.md); the deck file itself is untouched. It does not repeat what the card’s existing notes already say, and saves nothing when those notes cover every new point. Each point has to stand on its own with only the card in front of you: an example that exists only in the conversation is either carried into the note as a short code block or left out, so a saved note never points at a chat that is gone. Notes aren’t part of the card’s identity, so its progress is untouched: you just keep the insight. The action has no default key; bind one with make_note in [keys.review] (see Configuration).

Make this a note and Make this a card stay disabled until the tutor has answered something newer than the last note or card made from the conversation. They disable again while any tutor call is running and after a note is saved or a card draft lands, then re-enable on the next answer.

A deck can point the tutor at background reading with a link: list in its frontmatter:

---
link:
  - https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html
  - https://tokio.rs/tokio/tutorial
---

These are handed to the tutor with your first question as material to consult when useful: fetched once and remembered for the rest of the run. They’re tutor-only: unlike exam: (the exam’s ground truth, covered next chapter), a link: never becomes exam material. And like every directive, they don’t affect a card’s identity.

Grounding a frozen card: exam: and cite:

A frozen workspace card is grounded in its deck-owned assets/deck-<token>/ evidence. The tutor receives the exact excerpt shown during review, so deleting or editing the live source cannot silently change its ground truth.

The deck’s exam: (and a workspace’s exam) is listed to the tutor as context. A URL entry is fetched when the selected backend can use WebFetch. The tutor always receives the frozen excerpt first; current source context can explain the surrounding material or detect drift, but never silently replaces the captured evidence.

Local file browsing is opt-in with [ask] source_access = true, and a workspace’s alix.toml may carry its own top-level source_access key, which overrides the global setting in either direction for that workspace’s decks. The manifest travels when a workspace is shared, so inspect a received workspace’s alix.toml before making an AI call over it. With access on, the tutor browses one local cite: root, chosen per card:

  • the root of the first locator (in card order) whose key names a local root;
  • for a card without such a locator, the deck’s only local root, when the deck and its manifest declare exactly one;
  • otherwise none. A URL root is never browsed, and an exam: entry never grants browsing.

This keeps every live-source grant reviewable: the grant is on in your config or a manifest you can read, and the folder is a root the deck declares.

With the Claude backend, the tutor reads only inside that root: its file tools are allowed under the root’s resolved path alone, and the call loads none of your Claude settings files, whose own allow rules would otherwise widen it. A root whose path contains (, ), *, ?, [, ], { or }, or any root on Windows, gets no file tools. Gemini, Codex and Copilot do not confine reads to the root this way.

When no usable source is available, the tutor still works from the frozen excerpt and card context. The Ask status warns that it lacks the full current source, so the learner can distinguish an evidence-grounded explanation from a freshness check against the live source.

How it’s sandboxed

Because the CLI runs headless, it can’t show interactive permission prompts: an unanswerable prompt would just hang the call. So alix runs it locked down with a locked permission mode plus an exclusive tool allowlist (WebFetch, WebSearch by default). On the Claude backend that list is exclusive in both directions: the listed tools work without prompting, and no other tool exists for that call, so a malicious page behind a deck link can’t make the tutor run shell commands or touch your files. The other backends get the same list, but there alix can only pre-approve it, not bound it, so that backend’s own defaults and your provider configuration still decide what else it could reach. Both the permission mode and the allowlist live in the [ask] section of the config, along with the command, a --model override, and the timeout.

alix also runs the CLI without your instructions for it. Claude Code reads CLAUDE.md, Codex reads AGENTS.md, Gemini reads GEMINI.md, and those instructions would otherwise shape a reply alix parses strictly: a rule as ordinary as “end every answer with a timestamp” is enough to break exam grading. So alix asks each CLI to skip them, along with your hooks, skills and MCP servers. Gemini offers no way to do that, so a GEMINI.md in scope still applies on that backend.

Make this a card

During an Ask exchange, if the tutor’s reply answers a question about a concept you’d like to drill, click Make this a card. The tutor distills the conversation into a draft front/back for you to edit. Once you’re satisfied, click Add to land it as a new card on the current deck. It works the same during a walk; the new card joins the deck’s next walk.

The card goes into the deck’s personal file (<deck>.local.md), not the deck itself, so the authored .md is left byte-identical. It joins your sessions from then on as a new card: the drill introduces it, then grades and schedules it like any other card. It is a plain Markdown block in a file you can open and edit.

This is an adult-review feature only; it’s not available in the kids interface. If the tutor’s draft can’t be parsed as a valid front/back pair, alix reports the error plainly rather than inventing a card, so you can ask for a clearer format.