AI Workstation for Students: Research, Learning, and More

✅ Status: The installation guide is essentially complete and has been tested three times. Feedback (logies@web.de) on successful or problematic installations is nevertheless expressly welcome! Any installation problems that do come up should be something the AI assistant installed below can solve on its own. Although the guide has been checked several times, carrying it out is of course at your own risk.

Audience: Medical students and anyone who wants a productive Linux environment on ChromeOS. Other operating systems such as Linux, macOS, and Windows are possible but have not been tested yet.
Last updated: September 6, 2026
System: Debian 13 (Trixie) via ChromeOS Crostini
License: CC0 — free to use, no attribution required
German version: KI-Arbeitsplatz fürs Studium

Download this guide as a Markdown file:
setup-guide-linux-vm-crostini-en.md (76 KB, SHA256: a5822e9bbab52dfc…, last updated September 6, 2026, license CC0 — free to use without attribution). The Markdown source is included deliberately: any AI can read it and adapt the guide for Windows or macOS.

Tip: All command boxes on this page have a Copy button in the top right corner — click once, then paste into the terminal.




1. Introduction

This guide describes how to set up a ChromeOS Crostini Linux VM as a workstation for your studies. It is written so that you can work through it from start to finish — ideally on a Chromebook with the Linux VM.

Why all the effort is worth it: In the end, you can hand your assistant a complete research assignment that it carries out autonomously — without you having to click anywhere, for example:

Download papers on exam anxiety and coping strategies for it, read the full texts, and critically summarise them in a Zotero note; then convert this note into a PDF file as well, and attach both the note and the PDF to a newly created item of type Document to which you have given a fitting title.

Not a single detail for you to add: that the sources are identified via OpenAlex, that the summary is weighted critically, and which structure and format the note has — all of these are conventions from the memory files that your assistant adopted in §3.2. For the PDF conversion it needs the tools from §6.4.

Note for other operating systems: This guide is written specifically for ChromeOS Crostini. However, an AI can easily transfer it to Windows, macOS, or other Linux variants — just tell it: "Adapt this guide for Windows/macOS and work through it step by step."

Special feature: The setup begins with the AI assistant Qwen Code, because it can help you install the remaining tools. Once Qwen Code and its memory (Memory-MCP) are running, you can ask it to install Zotero, Anki, and the other programs for you — and, optionally (§13), rclone.

What awaits you:

  • AI assistant (Qwen Code) with memory (Memory-MCP)
  • Cloud storage (Google Drive via rclone, optional — §13)
  • University VPN (Cisco Secure Client)
  • Reference management (Zotero)
  • Flashcards (Anki) for your studies
  • Notes & knowledge management (Zotero + Marktext)

2. Initial setup of the Linux VM

2.1 Create the VM

  1. ChromeOS → open the Terminal (Terminal app)
  2. "Set up Linux VM" — Debian is provisioned automatically
  3. Wait until the setup is complete

2.2 Update the system

Open the terminal. Copy the command box below in one go using the Copy button at the top right of the box and paste it in completely — the lines are executed in order. Which keyboard shortcut works for pasting depends on your system — try these:

  • Ctrl+V (ChromeOS terminal, most Linux terminals)
  • Ctrl+Shift+V (some Linux terminals)
  • Right-click → Paste (always works)

Good to know: Under ChromeOS/Crostini, sudo does not ask for a password — the commands start without any prompt.

sudo apt update
sudo apt upgrade -y
sudo apt install -y git

2.3 Install standard programs

The following programs are useful for everyday life and are not included on a fresh Crostini system:

sudo apt install -y firefox-esr firefox-esr-l10n-de
sudo apt install -y keepassxc
sudo apt install -y doublecmd-gtk
sudo apt install -y pavucontrol
sudo apt install -y sqlite3
sudo apt install -y vim
sudo apt install -y python3-venv python3.13-venv

The last line (python3-venv) is the prerequisite for the AI memory (§3.2) — on a fresh Debian, the setup otherwise fails with a cryptic error message.

Where do you find the installed programs? In the ChromeOS app menu (circle icon at the bottom left), in the Linux apps folder — every program from the VM appears there automatically right after installation: the apt programs above just as much as the later Flatpak programs (Anki, Marktext, Zotero).

Note on Double Commander: When copying to Google Drive (native Drive access or the rclone mount, §13), first click the target window so it becomes active — then the copy operation works.

Using Google Drive in the VM — try this first (without rclone): In the ChromeOS Files app (Google Drive manager), activate Google Drive in the left sidebar. Then right-click the folder you want inside Google Drive and share it with Linux — only folders shared this way appear in the VM under /mnt/chromeos/GoogleDrive/. This lets you, for example, keep your KeePassXC password file on Google Drive and open it reliably from the VM, in sync across all your devices. Only if this native sharing turns out to be unstable (sync conflicts, hanging accesses) should you fall back to the more convenient but more involved rclone mounting (§13).

2.4 Set the language to German

sudo apt install -y locales-all
sudo update-locale LANG=de_DE.UTF-8 LANGUAGE=de_DE
sudo apt install -y manpages-de
sudo apt install --no-install-recommends -y task-german-desktop

For the new language to take effect, the Linux VM must be shut down: Right-click the Terminal icon → Shut down Linux — then open the Terminal again (it restarts the VM). Simply closing and reopening the terminal window is not enough: the VM only reads the language setting at startup.

The Linux VM manages its storage dynamically, but the default reserve is too tight for studies and AI tools. Better to set 15–20 GB:

ChromeOS → Settings → Linux → Disk size → 15 GB — the increase takes effect while the VM is running; no restart is needed.

2.6 Zotero.org account + Zotero cloud API key (preparation)

Two building blocks of this guide need your personal Zotero credentials later: the Zotero synchronisation (§6.1) and the cloud backup of the AI memory (§12.3). Create the account and the key now — just like your AI assistant's key (§3.1), the account and the key belong to your personal credentials:

  1. Create the account: free at zotero.org (name + e-mail is enough).
  2. Create the cloud API key: logged in at zotero.org/settings/keys/new: description of your choice (e.g. "AI memory backup"), enable Allow library access with read/write and notes access — that is all this key needs, because it only serves the AI memory backup (§12.3), which writes nothing but notes. Your Zotero content itself — literature including all PDF files — is backed up in full to the cloud by the Zotero synchronisation (§6.1): only that gives you a complete backup of everything in Zotero, and the cloud storage of your account exists exactly for that purpose. Generate the key and keep it at hand.
  3. Store the key: the key will later live in the file ~/.qwen/zotero-api-key (permissions 600) — in §12.3 you ask your AI agent to put it there.

Don't confuse them: this cloud key is only needed for outside access to zotero.org (§12.3). The local Zotero interface from §6.1 works without any key — the two switches in Zotero's configuration are enough there.


3. AI Assistant (Qwen Code)

Now it gets exciting: from here on, the AI assistant helps you set up your learning environment.

Recommended setup: The model deepseek-v4-flash is a pragmatic choice: it is reasonably good and inexpensive, it is offered directly inside Qwen Code, and the installation guide runs through it quite reliably — not necessarily perfectly on the first try. This guide was written with glm-5.3-flash, which thinks more thoroughly and can be particularly recommended for the installation — provided you do not shy away, right from the start, from the extra work of another API key and of switching Qwen Code to OpenRouter or z.ai as the provider for glm-5.3-flash.

3.1 Install Qwen Code

You can find the complete installation guide on the following page — click through there and follow the instructions:

👉 www.logies.de/ki-agent-einstieg.html (German only)

There you will find step-by-step instructions for:

  1. Getting an API token (Alibaba ModelStudio)
  2. Downloading and installing Qwen Code
  3. Starting it and choosing a model
  4. Setting up the memory (Memory-MCP) — that is what you do in the next section

The page is updated regularly as the tools evolve.

On first start: Qwen Code opens a setup dialog ("Connect a Provider"). Choose Alibaba ModelStudioStandard API Key → a region → and paste your API key.

Important — the region: It must match the console your key comes from — for the international console (modelstudio.console.alibabacloud.com) that is Singapore, for the Chinese console (bailian.console.aliyun.com) it is Beijing. A perfectly valid key is rejected with "API key invalid" when the wrong region is chosen — the most common stumbling block. If the sign-in fails, type /auth in Qwen Code and pick the other region.

Important — restart the terminal once after installation: Before you start Qwen Code for the first time, close the terminal and open it again. Otherwise the terminal reports qwen: Befehl nicht gefunden ("command not found") — the installation routine places the command in a location that the terminal only reads on restart. Only then does starting with qwen work (step 3).

Important, before you hand over the assignment — switch on Yolo mode: Press Shift + Tab in the Qwen Code interface until the display at the bottom jumps to yolo, then type /approval-mode yolo --user — this command makes the setting permanent so that it survives restarts. Without this switch, Qwen Code pauses at risky commands — the cron job for the memory backup, for example — and waits for your confirmation, so the assignment cannot run through autonomously. You will recognise such interruptions when Qwen Code shows the next command with a numbered selection: press the digit for the confirmation and then Enter so it keeps working. What this mode is about is explained in §3.5.

Set the default model permanently: The first start wrote a Qwen model as the default. Since Qwen Code 0.23.0, a choice made in the /model menu persists permanently — it is written as model.name into the configuration (tested on Sep 6, 2026), so you can change it again at any time. So that the recommended model is in place from the start, give your assistant this order:

Permanently set deepseek-v4-flash as the default model (model.name) in your configuration (~/.qwen/settings.json). Confirm the entry to me.

Then quit Qwen Code (/exit) and start it again (qwen) — the footer at the bottom must now show deepseek-v4-flash.

Your assistant can do the rest: After the first start, give it this one assignment — the automated setup then takes only about a quarter of an hour:

Read this page and carry everything out. Up to and including point 3.1 I have already done everything myself, including the Google Drive connection: https://www.logies.de/studienarbeitsplatz-linux-vm.html

The following strict rules apply to you:
1. Follow the guide to the letter. Execute the copyable commands and assignments exactly as written — do not reinvent anything, do not simplify anything, do not switch to other sources (no falling back to GitHub, no self-written scripts or SQL schemas).
2. Before each step, check whether it has already been done on this system (e.g. `command -v rclone`). If only part is missing, add only the missing part and briefly report what you skipped.
3. If a command fails: read the error message literally and consult the troubleshooting section (§10) and the step in question. Do not question the guide's design — doubt your own execution, not the guide (e.g. browser policies: create exactly as specified, validate the JSON, restart the browser, then verify).
4. If a step still fails after correct execution: STOP at that point. Report the step, the error message, and what you did — do not muddle through.
5. Do not mix the copy blocks with your own variants. The guide text explains the why — execution comes exclusively from the blocks.

3.2 Memory-MCP (memory for the AI assistant)

Once Qwen Code is running, the assistant should get its memory:

👉 www.logies.de/memory-mcp-for-ai-agents.html

Copy this assignment into the Qwen Code interface — the assistant does everything autonomously: installation of the memory server described there, import of the memory content stored there (usage rules and Zotero knowledge), and finally verification of both (the installation routine automatically writes a verification report, which your assistant evaluates and briefly summarises for you):

Go to the page https://www.logies.de/memory-mcp-for-ai-agents.html, install the memory server described there, and import the memory content stored there. After the setup, verify: Does crontab -l contain the backup cron job (backup_memory.sh), and does the verification report ~/.qwen/memory-install-report.md exist? If either is missing, the setup script aborted early — in that case, add the cron job (13 * * * * ~/.qwen/backup_memory.sh) manually and run verify.sh. Also, permanently add the memory-first rule described in the imported document to your always-loaded instruction file ~/.qwen/QWEN.md — together with these two additional rules:

1. Show the usage notes: After the memory check at session start, use memory_search (tag einsteiger-hinweise) to find the note "Usage notes for working with your AI agent" and show it to the user in full. If it does not exist but the file ~/.qwen/usage-notes.md does, save its content once as a note (the tags are given in the file). If a note with tag nutzungshinweise-deaktiviert exists, do not show the notes; if the user asks you to stop showing them, record that in such a note and confirm briefly; if asked to show them again, delete the deactivation note (memory_delete).
2. Commit to Git autonomously: After every piece of completed work that changes files in the home repo ~/.qwen, commit autonomously — only targeted files (git add <file>), never git add -A or git add . (the .gitignore protects settings.json with the API keys); clear, concise commit message; no push (there is no remote); before risky restructuring, commit the current state first.

Finally, save the file ~/.qwen/usage-notes.md as a memory note (the tags are given in the file). After restarting Qwen Code, verify the success.

So that Qwen Code loads the new memory, it restarts once after the installation: end it with /exitall commands begin with / (type it, scroll down the command list, confirm with Enter). Then start qwen again in the terminal and resume the offered previous session — this way your assistant keeps the context. Tell it briefly that it "was restarted", and it will perform the verification agreed upon in the assignment.

A note on the memory's model: Your AI memory searches its notes semantically with the multilingual model multilingual-e5-small — the same model family that the Zotero semantic search (§6.3) uses. No API key needed, which is why it was set up this way; you can have it changed at any time if you wish.

3.3 Optional: switch the model to GLM-5.3-Flash

GLM-5.3-Flash thinks more thoroughly and is the better choice for literature work with Zotero (cheaper, better for text work), but works noticeably slower than deepseek-v4-flash — for the installation, the trade-off from the "Recommended setup" above applies.

If you want to switch:

  1. Get an API key from OpenRouter.ai
  2. Give your AI assistant this assignment (model name exactly like this, with the z-ai/ prefix):
Configure yourself for OpenRouter with the model z-ai/glm-5.3-flash and my OpenRouter API key.
  1. The assistant sets itself up — you only have to provide the key

Several providers in parallel — the /model menu: Your configuration can hold any number of provider entries at the same time; the /model menu shows them as a selection list, and switching takes effect immediately — reopening the menu is enough, no restart needed. That way, if a provider has a temporary outage (which happens now and then), you switch to the fallback model with two keystrokes. Your assistant will write this selection menu to your specifications — just tell it which providers you want in parallel:

Set up a model menu in your configuration (~/.qwen/settings.json) with two providers stored in parallel that I can switch between in the /model dialog: the ModelStudio default (deepseek-v4-flash) and GLM-5.3-Flash via OpenRouter. Goal: if one of the two providers has a temporary outage, I switch to the other immediately. Briefly explain the entries to me and confirm the state to me.

The convenient option — the OpenRouter Auto Router: If you want to skip the routing fine-tuning, store the model code openrouter/auto instead: OpenRouter then classifies every request (about 30 task types) and picks the model itself — measured against the real usage market of the last 7 days, controlled via a cost band (cost_tier: low, medium, high, xhigh, max; if unspecified, low applies). No surcharge is charged; within a session the router prefers to stay with the model it has chosen. Manually steered routing with a fixed model (below) remains the more controllable variant — but for getting started, the Auto Router is the fastest way.

Routing settings at OpenRouter (decisive for speed and cost): OpenRouter offers the same model at several providers in parallel and picks one per request. From long-term operation, my experience: you work fastest, well, and cheaply by choosing the model yourself — based on external benchmarks (e.g. artificialanalysis.ai), currently z-ai/glm-5.3-flash — and in the OpenRouter routing settings leaving the cost tier at "low (default)" and the default provider sort at "Default (balanced)". OpenRouter then load-balances across providers (weighted by price; providers with outages in the last 30 seconds are skipped) and re-selects continuously; "sticky routing" keeps an active session on the same provider for up to 10 minutes so the prompt cache stays warm (repeated input is charged at a fraction there — in my sessions that is 70–75% of input tokens). Your assistant adds two refinements from its memory: it pins the model to the discount providers (the OpenRouter default provider otherwise costs twice as much) and sets the context size to the provider's value (§3.4).

Beware of "cheapest first" (sort by price): that disables load balancing — OpenRouter then walks the providers strictly in price order, and the cheapest are often the slowest or least stable. It can become very slow (a factor of > 10). Measured myself (Sep 2, 2026): DeepSeek V4 Flash ran over the cheapest OpenRouter route at ~5 tokens/s, while the benchmark level (Artificial Analysis) was 137 tok/s — a factor of ~27. Community reports (including Hacker News, June 2026) likewise document 15–50 tok/s for the same model depending on the provider — plus quantization traps at bargain vendors.

What a work session like this "weighs" — numbers instead of vibes: One DIN A4 page of prose is roughly 700 tokens. While overhauling two website pages plus their download files (Sep 3, 2026), the assistant processed around 60 million tokens ≈ 86,000 A4 pages across 354 model requests — a paper stack nearly 9 meters tall. Each individual request carried, at the end of the session, about 250,000 tokens (≈ 360 A4 pages): standing instructions, loaded memory notes, files, and all tool results. 75% of input tokens came from the cache (price advantage). The assistant wrote ~525,000 tokens (≈ 750 pages, including ~200,000 model "thinking" tokens). Memory was in play throughout: 64 accesses to the Memory-MCP server (20 searches — mostly before starting a task, 14 note reads, 17 updates, 8 stores, more), plus roughly 420 tool calls (shell commands, file edits, Zotero/MCP queries). The cost of this session at GLM-5.3-Flash prices: about 2 US dollars. For comparison: a human chat with an AI chatbot runs in the hundreds to a few thousand tokens per message — the AI agent moves 100–500 times that per request, because it re-carries instructions, memory, files, and all intermediate results in its context at every step. That is why a large context window (§3.4), prompt caching, and the right routing settings are not extras but prerequisites.

3.4 After installation: check the context size (important!)

After the initial setup — and after every model change — you should check whether Qwen Code has correctly stored the context size of your model. It has happened that a far too small context size was configured for glm-5.3-flash — this severely restricts the assistant without any error message appearing.

How to spot the problem in the interface: Qwen Code shows what percentage of the context window is in use. If, for example, it already says "90%" at ~160k tokens, something is wrong — modern models have far more context, and the percentage display is then based on a wrong (too small) total value.

Check and fix it — tell your assistant:

Check the configured context size for the currently selected model in your configuration (~/.qwen/settings.json). Compare it with the model's official context size (for OpenRouter models: on the model page at openrouter.ai). If the value is too small, correct it and confirm to me afterwards that the model now has the correct context window.

Alternatively, you can open ~/.qwen/settings.json yourself and check the context-size entries (contextWindowSize or similar) against the model specifications.

Concrete value for glm-5.3-flash (as of August 30, 2026): The model page on OpenRouter lists 1,310,720 tokens of context — but the provider actually used (top provider) only delivers 1,048,576 tokens (1 million). The correct value for the configuration is therefore 1,048,576. A larger value causes problems; a smaller one wastes context.

Do not set model.baseUrl by hand: Normally only the model name (model.name) belongs in the model block of the configuration — the server address (baseUrl) comes from the respective provider entry. Qwen Code may write model.baseUrl itself to distinguish identically named models; but a stale value set by hand or copied from an old guide can cause requests to go to the wrong provider without any error message. After model changes: have your assistant check the model block — never add values there yourself.

3.5 Enable Yolo mode

On its own, Qwen Code pauses at risky actions and asks for confirmation — during setup just as much as in everyday use. Yolo mode lets the assistant work without such confirmation prompts (only sensible inside your own VM!).

Permanent — you have already done this in §3.1: the command /approval-mode yolo --user saves the setting to your configuration, so that yolo is active on every start. To check, simply restart Qwen Code (/exit, then qwen) — the display at the bottom must show yolo. If it does not: just type the command again.

For the current session only: Press Shift + Tab — the display then shows "yolo". You have to do this again on every start; useful when you only want to switch the mode temporarily.

3.6 Fix terminal flickering

Right after installation, Qwen Code can flicker heavily in the ChromeOS terminal (hterm) — the terminal cannot cope with the default render mode. The assistant solves this itself as well — copy this assignment:

The terminal is flickering. In your configuration (~/.qwen/settings.json), set ui.renderMode = raw and ui.useTerminalBuffer = false, then restart.

After that, the flickering is gone. (Side effect: completion messages stay visible instead of disappearing.)


4. Work tools

Once Qwen Code is running, the rest of the setup is its job. Copy this assignment into the interface — it works through everything autonomously and summarises at the end what remains for you to do:

Work through the rest of this installation guide (§4 through §6) completely on your own. Only ask me when you need an API key, a password, or a confirmation from me. Do not install any programs that are not explicitly required in the guide. Also set up Git version control as described in §4.2. At the very end, create a list of everything I still have to do myself, and save it as a Markdown file named todo.md in my home directory (not on the desktop — ChromeOS doesn't have one). Alongside the todo.md, also write a report on what errors occurred during the installation, what still needs to be added or installed, and where the installation guide could be improved, and save it in the home directory as installationsbericht.md. Precede the report with a short system overview: distribution and version (from /etc/os-release), architecture and kernel (uname -m -r), Qwen Code version (qwen --version), Node.js version (node --version), free disk space (df -h /), and the model you executed the assignment with. Clean the report of any private keys or private data and suggest to me that it be emailed to logies@web.de.

At the end, the list is saved as todo.md in your home directory, with the report next to it as installationsbericht.md. How to open it: ChromeOS app menu (under "Linux apps") → Double Commander → navigate to your home directory in the file pane → select todo.mdEnter — Markdown files open with Marktext (§5.3), which your assistant has installed by now. At the end, your assistant will suggest emailing the cleaned report to logies@web.de — this helps improve the guide for future students.

Why Markdown? Markdown is the format AIs prefer: plain text (any AI can read and write it), yet cleanly structured (headings, lists, code blocks) and also directly readable for humans. For structured assignments to the AI and for the AI's results, it is the best choice — and with Marktext (§5.3), a Markdown file opens with a double click.

Where do I enter the following commands? Not yourself at all — you stay in Qwen Code. The command boxes in the following sections are the working basis for your assistant: it executes them itself once you have given it the assignment above. If you do want to run a command yourself exceptionally, open a second terminal window and paste it there — only assignments to the assistant and / commands belong in the Qwen Code interface.

4.1 University VPN (Cisco Secure Client)

Access to university-internal services (library, learning platforms, campus systems) requires a VPN.

Installation on ChromeOS (recommended):

  1. Open the Google Play Store → search for "Cisco Secure Client" → install
  2. Open the app → set up the VPN connection (VPN gateway and credentials from your university)
  3. Connect — the Android VPN app on ChromeOS also routes the Linux VM's traffic through the VPN (works with current ChromeOS versions; if in doubt, test with the IP check below)

For Linux computers (without ChromeOS): The Cisco Secure Client can be downloaded from your university's website. RWTH Aachen and most other universities provide the client on the VPN portal or the IT service portal for students → download the .deb version for Linux there.

Test whether the VPN is active:

curl -s https://api.ipify.org

→ Shows the IP of the university network (e.g. 134.61.x.x for RWTH Aachen)

4.2 Version control with Git

Git is already installed (step 2.2) and is set up by your assistant as part of the assignment above — version control makes later changes traceable. What gets versioned:

  • This guide (setup-guide-linux-vm-crostini.md)
  • Scripts and configurations (Memory-MCP server, Qwen Code settings)
  • Your own notes and documents (if you store them locally)

Do not version: API keys, passwords, large binary files (images, models), and databases.

Mandatory before the first commit — create a .gitignore: In ~/.qwen there is the file settings.json containing API keys in plain text — a thoughtless git add -A would commit the keys. The assistant therefore first creates this .gitignorethis command creates it in full:

cat > ~/.qwen/.gitignore <<'EOF'
settings.json
usage_record.jsonl
installation_id
memory.db
memory.db-wal
memory.db-shm
models/
backups/
sessions/
todos/
tmp/
file-history/
usage/
extension-store/
extensions/
projects/
skills/
tip_history.json
__pycache__/
EOF

Quick start (your assistant runs this):

cd ~/.qwen           # Memory-MCP directory (as created by the setup script)
git init
git config user.name "Student"      # Required before the first commit — otherwise git aborts
git config user.email "student@local"
git add .gitignore memory_server.py verify.sh
git commit -m "Initial"

# Later, after changes (only targeted files — never git add -A):
git add <geänderte Datei>
git commit -m "Was geändert wurde"

From now on, your assistant commits autonomously after every completed change — you don't need to operate Git yourself (the standing rule for this is in its QWEN.md, set up in §3.2).

Note on office programs: For word processing, spreadsheets, and presentations, Google Docs, Google Sheets, and Google Slides are entirely sufficient. They run in the browser, are always up to date, and require no installation — LibreOffice is therefore not installed, and your assistant must not install it on its own initiative. If you do want to edit local office documents later: just tell your assistant "Install LibreOffice" — that is a one-liner.


5. Learning & Studies

Here too, the same applies: your AI assistant works through the guide for you — just let it know when you are ready.

Prerequisite Flatpak (on fresh Crostini often not yet installed or Flathub not yet set up):

sudo apt install -y flatpak
flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo

Important — always without sudo: Run Flatpak commands as the normal user (user installation). If the assistant accidentally runs them with sudo, a system installation is created — that works, but the two variants are easy to confuse, and flatpak override --user still only applies per user.

Whether you need to do anything after installing: Flatpak apps usually show up in the Linux application menu on their own. If an app doesn't appear there, log out and back in once — that makes the application menu reload.

5.1 Anki (flashcards)

The gold standard for flashcards in medical school — anatomy, pharmacology, clinical subjects.

flatpak install --user flathub net.ankiweb.Anki

Start: launch Anki from the application menu, or:

flatpak run net.ankiweb.Anki

If Anki does not start (only for installations without Flatpak, e.g. the official Linux package from apps.ankiweb.net): Anki 26.x needs the system library libxcb-cursor0 for its graphical interface. If it is missing, startup aborts immediately — with an error message like Could not load the Qt platform plugin "xcb". Remedy:

sudo apt install -y libxcb-cursor0

Afterwards Anki starts normally (verified on August 31, 2026 under Linux Mint 22.3). The Flatpak version described above ships all required libraries itself — this error does not affect it.

⚠️ Important — known Anki bug: crash after the language selection: Anki 26.08.1 (the current version, also as Flatpak) has a startup bug: on the very first launch, it creates its configuration database without a language value and then crashes — the language you chose is never saved, and every subsequent launch crashes again, without you ever reaching the main view. Your assistant fixes this by pre-seeding the database with correct values. Give it this assignment (once):

Anki crashes after the language selection — a known bug in Anki 26.08.1: the configuration database ~/.var/app/net.ankiweb.Anki/data/Anki2/prefs21.db is created on first launch without a language value (defaultLang: None), so every launch crashes. Fix it by deleting this database (including any -journal/-wal/-shm files) and recreating it — important: inside the Flatpak sandbox, e.g. via flatpak run --command=sh net.ankiweb.Anki, not with the host Python — with a _global entry in which defaultLang is set to "en" and firstRun to False, plus a profile named "User 1". Restart Anki afterwards and verify that it boots to the main view without crashing. Warnings about EGL, MESA/ZINK, or Wayland in the terminal are harmless (software rendering in the VM).

Anki then starts directly without the language dialog (English is preselected) — and from then on quite normally from the application menu.

Tip for medical students: The "AnKingMed" deck contains thousands of ready-made flashcards for medical school. Search for it in Anki under "Get Shared". Useful add-ons (AnkiWeb ID in brackets):

  • Image Occlusion Enhanced (1374772155) — mask images to study anatomy
  • Review Heatmap (1771074083) — visualise your learning progress
  • AnkiConnect (2055492159) — for AI integration

Installing Anki add-ons: The GUI route is Tools → Add-ons → Get Add-ons (type in the ID). For the AI assistant, that route is blocked — AnkiWeb rejects simple downloads — so give it this assignment:

Install the Anki add-ons Image Occlusion Enhanced, Review Heatmap, and AnkiConnect for me without the GUI. Important: download them from AnkiWeb — GitHub releases of these add-ons are outdated and unreliable — and follow the download recipe in this guide (section "Installing Anki add-ons without a GUI"): User-Agent "Anki <version>" plus the parameters ?v=2.1&p=<int_version>, otherwise AnkiWeb responds "Your version of Anki is too old". Check each version against minpt and then verify: AnkiConnect responds on port 8765, and all meta.json files have disabled: false.

Installing Anki add-ons without a GUI (working basis for the assistant, verified on September 1, 2026 under Anki 26.08.1):

AnkiWeb only accepts the download with a genuine Anki client profile — two conditions at once:

  1. The User-Agent must be Anki <version> (e.g. Anki 26.08.1) — not anki/…, no browser string
  2. The endpoint requires the parameters ?v=2.1&p=<int_version>, where p must be an integer — the point version year×10000 + month×100 + patch (for 26.08.1 that is 260801), reliably determined from the installed Anki library:
flatpak run --command=python3 net.ankiweb.Anki -c "import anki.utils; print(anki.utils.int_version())"

Download (per add-on):

UA="Anki 26.08.1"          # version string of the installed Anki
P=260801                    # int_version of the same installation
curl -sL -A "$UA" -o addon.ankiaddon \
  "https://ankiweb.net/shared/download/<id>?v=2.1&p=$P"

Installation (Anki may be running during this, but only loads the add-ons at the next start):

  1. Unpack the .ankiaddon file (a ZIP whose manifest.json may be missing — AnkiConnect has none) into ~/.var/app/net.ankiweb.Anki/data/Anki2/addons21/<id>/
  2. Write a meta.json into the same folder — keys: name, mod, conflicts, min_point_version, max_point_version, branch_index, human_version, homepage — plus "disabled": false (otherwise the add-on stays inactive)
  3. Version check: compare only minpt against int_version (must be ≤). A positive maxpt only means "tested with" and is ignored (a negative value would be a hard limit — does not occur with these add-ons). As of September 1, 2026: AnkiConnect minpt 45/maxpt 45 · Image Occlusion Enhanced minpt 50/maxpt 50 · Review Heatmap minpt 49/maxpt 54

Verification without a GUI:

  • AnkiConnect: after Anki starts, curl -s -X POST http://127.0.0.1:8765 -d {"action":"version","version":6} must return {"result": 6, "error": null}. Port 8765 is the default and bound to localhost. There are no add-on management actions over HTTP (a getAddonNames query answers with unsupported action) — management only happens via the files.
  • Load status headless: __pycache__ folders in the add-on directory (ls ~/.var/app/net.ankiweb.Anki/data/Anki2/addons21/<id>/__pycache__) — present = the module was imported by Anki. Proven as a binary, diagnostics-free signal.
  • In every addons21/<id>/meta.json, "disabled": false must be present.

Operating notes for the assistant:

  • Anki only loads add-ons at startup — after installation a restart is required. And because Anki does not handle SIGTERM, the assistant should not quit Anki itself but ask the user to do it (Ctrl+Q).
  • Exit code 255 when closing the window is normal — not a crash signal.
  • Deprecation warnings from Image Occlusion Enhanced (setMod() is deprecated, newField is deprecated) and the conf key hint from Review Heatmap in the log are harmless and are not part of the failure picture.
  • pgrep -f "anki" matches its own command line — use the bracket trick pgrep -f "/app/bin/[a]nki" and finish the verification with an "Anki is running stably" check.

5.2 Knowledge management & PDF annotation: Zotero

For knowledge management, Zotero (§6) is entirely sufficient: it manages not only your literature but can also annotate PDFs, create notes, and be searched by the AI assistant — a separate knowledge-management tool (e.g. Obsidian) or a separate PDF annotation program (Xournal++) is therefore unnecessary.

5.3 Marktext (Markdown editor)

A simple yet powerful editor for notes and documents.

flatpak install --user flathub com.github.marktext.marktext

5.4 Google Chrome in the VM (for browser automation)

The VM already has Firefox (§2.3). So that your AI assistant can also operate web pages autonomously (open pages, fill in forms, take screenshots, run checks), it installs Google Chrome in the VM:

wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install -y ./google-chrome-stable_current_amd64.deb
rm google-chrome-stable_current_amd64.deb

Important: This is a second, separate browser — the Chrome preinstalled with ChromeOS runs outside the VM and is unreachable for the AI.


6. Reference management (Zotero)

6.1 Install Zotero

flatpak install --user flathub org.zotero.Zotero

Start:

flatpak run org.zotero.Zotero

Important for the MCP connection (§6.3): With the Flatpak version, Zotero's database and storage live under ~/Zotero/ (zotero.sqlite, storage/, translators/, styles/), while the browser profile (prefs.js, extensions) lives under ~/.zotero/zotero/<profile>.default/ — the concrete profile directory is listed in ~/.zotero/zotero/profiles.ini. Tools that access file paths directly (e.g. attachment import, full-text search, plugin sideloading) need to know these paths.

⚠️ Important — treat Zotero gently: Zotero is a single-instance application. If an instance is already running (even an invisible one), a new start visibly shows nothing — which looks like "Zotero won't start". And: never kill Zotero with kill -9 — a normal quit (SIGTERM) shuts the database down cleanly. After uncleanly terminated runs, Zotero runs an integrity check at the next start; with an empty library it takes only milliseconds, but together with a bloated WAL it can look like a hang. For diagnostics with log output: flatpak run org.zotero.Zotero -ZoteroDebugText. In an emergency (only with your own/empty library, Zotero closed): sqlite3 ~/Zotero/zotero.sqlite "PRAGMA quick_check;" must return ok; PRAGMA wal_checkpoint(TRUNCATE); empties the WAL.

⚠️ Important — one-time preparation before the first sync sign-in: Zotero stores the sync API key in the system's keyring. In a bare Crostini VM this keyring is missing — the sign-in then hangs forever at "Waiting for sign-in…", even though the sign-in on zotero.org succeeded in the browser. The following preparation is a one-time effort, survives Zotero updates, and takes about 5 minutes. Give your assistant this assignment:

Prepare Zotero for the sync sign-in: install gnome-keyring — mandatory before the sign-in, do not skip this: without a working secret service, the Zotero sync sign-in hangs silently at startup. Allow the Zotero Flatpak access to the secret service (flatpak override --user --talk-name=org.freedesktop.secrets org.zotero.Zotero). Create the unencrypted default keyring: in the directory ~/.local/share/keyrings, create the file default containing the line "login", plus a file login.keyring with the [keyring] section and the entries display-name=login, mtime=0, time=0, lock-on-idle=false, lock-after=false. Then start the secret service with gnome-keyring-daemon --start --components=secrets — the message "couldn't access control socket" is harmless — and check with busctl --user list | grep org.freedesktop.secrets that the service is running. Report the result to me.

How the sign-in then works: Zotero → Edit → Settings → Sync → "Sign In" → Firefox opens. Sign in promptly — the login session expires after about 10 minutes. The Firefox dialog "Open Zotero?" on the success page can be clicked away; it is not part of the sign-in process. The app completes the sign-in by itself within a few seconds, and the sync starts. (The default keyring is unencrypted, but sits with file permissions 600 inside your VM and never leaves it.)

If the sign-in already hangs ("Waiting for sign-in…" forever, although zotero.org confirms the login): do exactly the preparation above, quit Zotero completely and restart it, then start the sign-in again — afterwards it works.

Minor display glitch when deleting: If the confirmation dialog for deleting items appears only as a narrow window fragment: grab the dialog window by its edge with the mouse and enlarge it — then the buttons can be used normally. The dialog does not remember its size, so enlarging is needed again each time (§10.2).

6.2 Zotero plugins

Once Zotero is installed, your AI assistant can install the plugins for you.

Prerequisite: Zotero must have been started at least once before — without that first start, the profile directory (~/.zotero/zotero/<profile>.default) that the plugins are installed into does not yet exist.

Just say:

"Install the Zotero plugins Better BibTeX, Better Notes, Beaver, Zoplicate, Translate, and Zutilo for me."

The current sources (verified on August 31, 2026) — the assistant downloads the respective release asset from the plugin's homepage:

Plugin Version Source (GitHub releases) Asset
Better BibTeX 9.0.63 retorquere/zotero-better-bibtex zotero-better-bibtex-<version>.xpi
Better Notes 3.3.3 windingwind/zotero-better-notes better-notes-for-zotero.xpi
Beaver 0.24.0 jlegewie/beaver-zotero beaver.xpi
Zoplicate 5.1.1 ChenglongMa/zoplicate zoplicate.xpi
Translate 2.4.7 windingwind/zotero-pdf-translate translate-for-zotero.xpi
Zutilo 4.2.2 wshanks/Zutilo zutilo.xpi

How the assistant installs the plugins automatically (without the Zotero GUI, verified under Zotero 10):

  1. Quit Zotero (it must not be running during the installation — otherwise it overwrites the changes) and check that no instance is still running (single-instance behaviour, see §6.1)
  2. Download the XPI and rename it to the add-on ID — the ID is in the XPI's manifest.json under browser_specific_settings.zotero.id (e.g. better-bibtex@iris-advies.com)
  3. Put the renamed file into the profile directory ~/.zotero/zotero/<profile>.default/extensions/ (path see §6.1)
  4. Additionally add to the profile's prefs.js: user_pref("extensions.autoDisableScopes", 0); — without this line the plugins are disabled as "newly discovered" and remain unused
  5. Start Zotero; check success via the fields active, userDisabled, appDisabled in the profile's extensions.json
  6. If plugins get stuck after failed attempts: with Zotero switched off, delete extensions.json and addonStartup.json.lz4 in the profile — Zotero rescans on the next start

Which plugins make sense is also described on the following page:

👉 www.logies.de/zotero-mcp-server-beaver-comparison.html

Zotero Connector in the browsers (assign this to your AI agent): So that you can collect web pages into your library with one click, your assistant sets up the connectors in Firefox and Google Chrome inside the VM via browser policy — each together with an ad blocker: uBlock Origin (Firefox) or uBlock Origin Lite (Chrome). Copy this instruction:

Set up the Zotero connectors in both browsers of this Linux VM via browser policy — Firefox: Zotero Connector (add-on ID zotero@chnm.gmu.edu) and uBlock Origin (uBlock0@raymondhill.net); Chrome: Zotero Connector (ekhagklcjbdpajgpjgmbionohlpdbjgc) and uBlock Origin Lite (ddkjiahejlhfcafbddmgiahcphecmpfh). Procedure:

1. If /etc/firefox/policies/policies.json already exists, show me its contents first. Then create the file with exactly this content (create the directory if needed; sudo works without a password in the VM):

{
  "policies": {
    "ExtensionSettings": {
      "zotero@chnm.gmu.edu": {
        "installation_mode": "normal_installed",
        "install_url": "https://www.zotero.org/download/connector/dl?browser=firefox"
      },
      "uBlock0@raymondhill.net": {
        "installation_mode": "normal_installed",
        "install_url": "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi"
      }
    }
  }
}

2. Create /etc/opt/chrome/policies/managed/zotero-extensions.json with exactly this content (create the directory if needed):

{
  "ExtensionInstallForcelist": [
    "ekhagklcjbdpajgpjgmbionohlpdbjgc;https://clients2.google.com/service/update2/crx",
    "ddkjiahejlhfcafbddmgiahcphecmpfh;https://clients2.google.com/service/update2/crx"
  ]
}

3. Close any running Firefox and Chrome windows properly (Zotero may keep running) and restart both browsers once: Firefox can run in the background (timeout 70 firefox-esr --headless about:blank), Chrome graphically with about one minute of waiting so the Chrome Web Store can install the extensions; then close Chrome again.

4. Verify and report back to me: ~/.mozilla/firefox/*/extensions.json must list zotero@chnm.gmu.edu and uBlock0@raymondhill.net with "userDisabled": false; the folders ekhagklcjbdpajgpjgmbionohlpdbjgc and ddkjiahejlhfcafbddmgiahcphecmpfh must exist under ~/.config/google-chrome/Default/Extensions/. Do not install anything beyond that.

In brief: Firefox gets a policy file (/etc/firefox/policies/policies.json), Chrome a managed extension list (/etc/opt/chrome/policies/managed/zotero-extensions.json). Existing extensions are not touched — duplicate installations are impossible. Chrome will then show a notice that it is "managed by your organization" — that comes from the policy file and is harmless. To verify, your assistant can validate both JSON files with python3 -m json.tool <file> >/dev/null && echo OK; policies take effect on the next browser start, and in Firefox you can see them under about:policies.

The only manual step left: Chrome from ChromeOS (outside the VM) — the VM cannot reach that browser: install the Zotero Connector from the Chrome Web Store.

The Connector only needs Zotero running in the same system (ChromeOS connector: Zotero in the VM; VM browsers: Zotero alongside) — it can be set up even before the sync sign-in. To remove: the Chrome extensions disappear once the AI agent deletes the policy file (on the next Chrome start); the Firefox add-ons remain and can be disabled or removed as usual.

6.3 Connect Zotero to the AI assistant (simplified setup)

Since everything runs in the same Linux VM, the setup is simpler than in the Windows variant on the website — no network between two machines, everything communicates over localhost.

Step 1 — enable the local API in Zotero:

  • Open Zotero → Edit → Settings → Advanced
  • Tick "Allow other applications on this computer to communicate with Zotero" — and in the same view tick the box for use via the local API (Prefs: extensions.zotero.httpServer.enabled and extensions.zotero.httpServer.localAPI.enabled)

Without the GUI (agent route): With Zotero switched off, add the two lines to the profile's prefs.js (~/.zotero/zotero/<profile>.default/prefs.js, path see §6.1) — only edit with Zotero switched off, otherwise Zotero overwrites the file on quit:

user_pref("extensions.zotero.httpServer.enabled", true);
user_pref("extensions.zotero.httpServer.localAPI.enabled", true);

Then test: curl http://127.0.0.1:23119/api/users/0/items?limit=1 must return 200 — with 403 "Local API is not enabled" the second pref is missing.

Step 2 — install the MCP tools (in the Linux VM): The various tools (Zotero MCP server, Zoteus, CLI-anything-Zotero, pyzotero) are described on the comparison page:

👉 www.logies.de/zotero-mcp-server-beaver-comparison.html

The page contains the installation commands and a decision guide for which tool is best suited for which purpose.

For this guide: install only Zoteus. Zoteus covers everything you need (search, metadata, notes, attachments, reference management, OpenAlex research, semantic search) and is faster and more stable than the alternative (Zotero MCP server). You do not need the Zotero MCP server — semantic search (step 4) is handled by Zoteus itself, locally and without a second server.

Prerequisite: Node.js. Zoteus runs on Node.js — on a fresh Crostini system, install it first (the installation route named on the comparison page does this along the way):

sudo apt install -y nodejs npm

Installation and integration: Zoteus is started via npx and entered as an MCP server in the Qwen Code configuration (the actual integration into the configuration is step 3). The entry looks like this:

"zoteus": {
  "command": "npx",
  "args": ["-y", "@oscardvs/zoteus"],
  "transport": "stdio"
}

Two warnings on first start are normal: (1) Without the setup from step 4, semantic search initially only works as keyword search — step 4 sets it up right away, entirely without an API key. (2) Node 20 (Debian 13) has no built-in node:sqlite — Zoteus then falls back to a JSON index backend; for libraries far beyond 250,000 passages, Node 22 would be recommended, irrelevant for getting started with your studies.

Smoke test without a GUI (proves that Zoteus runs and Zotero is reachable): timeout 25 npx -y @oscardvs/zoteus < /dev/null must report MCP server started on stdio and localApi=true.

Step 3 — integrate the MCP server into Qwen Code: The assistant enters the entry shown in step 2 into the Qwen Code configuration (~/.qwen/settings.json). This is not optional: only with MCP servers integrated can the AI control Zotero at all — literature queries like the example in §1 do not work without this step.

Step 4 — Set up semantic search (recommended, entirely without an API key):

Semantic search makes your literature searchable by content: You ask, for example, "Which articles deal with relapse prevention after periodontal therapy?" — and the assistant finds the matching papers, even if the word "prevention" does not appear in the title (for instance because the paper says "recurrence prevention"). It matches by meaning rather than exact words — also across your entire PDF full texts, including 750-page books.

It runs locally with the multilingual model multilingual-e5-small in its quantized variant (q8) — tested against a real library (10,531 entries, 72,554 passages): the q8 variant returns 80.6 % identical hits compared with the unquantized one, with equally good results on German queries. Download: 129 MB, and after that it costs nothing. Tell your assistant:

Set up semantic search in Zoteus locally: in the Zoteus configuration set ZOTEUS_EMBEDDINGS=local, ZOTEUS_EMBEDDING_MODEL=Xenova/multilingual-e5-small and ZOTEUS_EMBEDDING_DTYPE=q8. Important: q8 only works with model names carrying the Xenova/ prefix; Zoteus must be at least version 1.14.0 (starting via npx you automatically get the current one). Afterwards, build the semantic index once in full — with full text, maximum character/token length — and report the result to me.

The first index build runs locally on the CPU and takes a while depending on library size; after that everything is free and cloudless. The model takes up storage and memory — how much of that your Chromebook has to spare is a per-device question: to be safe, have your assistant check how much memory the Linux container actually gets before setting this up (for example with free -h); with about 8 GB or more it should fit comfortably. If you later switch between local and OpenAI, the semantic index is rebuilt once — your PDFs and books themselves remain untouched.

Alternative with an OpenAI API key (for very large libraries): the local first build is slow — with an OpenAI key the build is considerably faster (costs in the cent range). The larger the library, the more interesting this variant.

How to get the key:

  1. Sign in at https://platform.openai.com/api-keys (or create a free OpenAI account) → "Create new secret key"
  2. Top up paid credit (Billing: https://platform.openai.com/usage — even a few dollars last for months)

Which embedding model? Recommendation: text-embedding-3-small. Justification with figures from OpenAI's own documentation:

small large
Price / 1M tokens $0.02 $0.13 (6.5× more expensive)
MTEB quality 62.3% 64.6%
Pages per dollar 62,500 9,615

The quality difference (2.3 percentage points on the standard benchmark MTEB) is practically irrelevant for library search — the price difference is not. The predecessor ada-002 costs as much as large (61.0%) and is worse than both.

Say this during the index build: The assistant should build the semantic index (zotero_index in Zoteus) with text-embedding-3-small and choose the maximum character/token length for full-text indexing, so that even thick books (for example 750-page tomes) end up completely in the index and can be found later. In Zoteus the setting is called fulltext_max_chars — the AI sets it high enough for your longest documents.

Without an OpenAI key, everything else works normally (metadata, annotating, citations, importing literature) — and with the local setup from step 4, semantic search itself also runs without a key.

Good to know: The semantic index reflects the state at the time it was built. Newly added literature is automatically not findable at first — the index needs to be updated occasionally. Sensibly about once a month or after larger collection sessions. You don't have to remember: just tell your assistant:

Create a monthly reminder task: at the beginning of each month, check whether new literature has been added to Zotero since the last indexing. If so, update the semantic index in Zoteus incrementally, with full text — using the configured local embedding model (Xenova/multilingual-e5-small, q8). Briefly report the result to me afterwards.

Your assistant stores the task in its memory (§3.2) and reminds you — you only have to remember to ask it.

A note for your assistant — this concerns only the OpenAI alternative (it knows this from its memory files): Since Zoteus v1.13.0 an index build survives OpenAI rate limits (429) on its own — the server waits and retries automatically — and an interrupted build resumes where it stopped, instead of restarting the full-text phase from scratch. For very large libraries two throttle settings remain useful (ZOTEUS_EMBED_BATCH_SIZE=256, ZOTEUS_EMBED_BATCH_DELAY_MS=8000); since v1.13.0 they are officially documented and are the recommended combination for accounts with tight rate limits. With your initially small collections this is unlikely to matter; as the library grows, your assistant already knows the settings. Details are in the Zotero knowledge export (§3.2).

How does the local model compare to OpenAI? A benchmark on a real, mostly German library (about 10,500 entries, 18 queries): the local search returns about 60 % identical hits compared with the OpenAI route — the remaining hits are "different but also plausible", not broken. The stronger OpenAI model is statistically slightly ahead on dense technical queries; for German-driven retrieval, measurements put e5-small practically on par. The trade-off is not quality alone: OpenAI costs (~1.50–4 USD per full rebuild, cents per day) and sends library text to the cloud; the local route is free and private — for most students, the better deal.

How it runs in my own setup (automatisms instead of manual work): In my agent setup the assistant updates the semantic index daily — the same reminder task as above, just at a daily cadence, because I add literature every day — my index runs locally, no cost. On top of that come a weekly update check for Zoteus, Zotero, and the plugins (§12.2) and the hourly backup of the assistant's memory (§12.3). Once your library grows or you collect regularly, you can turn the monthly task into a daily one at any time — the assistant remembers the new frequency just the same.

6.4 Tools for the note-to-PDF conversion

So that your assistant can output Zotero notes as a cleanly formatted PDF (as in the research assignment from §1), it needs two tools. Your assistant installs them with:

sudo apt install -y pandoc weasyprint fonts-noto-core
  • pandoc converts the Zotero note into clean HTML
  • WeasyPrint prints the HTML as PDF — with German hyphenation (via lang=de-DE), page numbers, and justified text
  • fonts-noto-core provides the fonts so that umlauts and special characters are set correctly

Attention: Under Debian 13 the package is called weasyprint — the formerly common python3-weasyprint no longer exists there, and otherwise the entire apt run (including pandoc!) breaks with "no installation candidate".

How the note must be structured and how the conversion works is described in the imported memory files (§3.2) — your assistant knows the workflow; you have nothing to configure.


7. Installed software (overview)

Installed via apt

# Step 2.2
sudo apt install -y git

# Step 2.3
sudo apt install -y firefox-esr firefox-esr-l10n-de keepassxc doublecmd-gtk pavucontrol vim
sudo apt install -y python3-venv python3.13-venv

# Step 2.4
sudo apt install -y locales-all task-german-desktop manpages-de

# from the installation guide at www.logies.de/ki-agent-einstieg.html
# (Python build tools for Qwen Code and the Memory-MCP server)
sudo apt install -y python3-pip python3-venv python3.13-venv build-essential gcc g++ make patch

# for unpacking the Anki add-ons (§5.1)
sudo apt install -y unzip

# Step 5.4 — Chrome in the VM (browser automation)
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install -y ./google-chrome-stable_current_amd64.deb

# Step 6.3 — Node.js as a prerequisite for Zoteus
sudo apt install -y nodejs npm

# Step 6.4 — tools for the note-to-PDF conversion
sudo apt install -y pandoc weasyprint fonts-noto-core

Installed via Flatpak

flatpak install --user flathub net.ankiweb.Anki           # flashcards
flatpak install --user flathub com.github.marktext.marktext    # Markdown editor
flatpak install --user flathub org.zotero.Zotero           # reference management

8. Restoring on a new system (quick guide)

  1. ChromeOS → Terminal → Set up Linux VM
  2. §2.2 — update the system + install Git
  3. §2.3 — standard programs (Firefox, KeePassXC, Double Commander, Vim, Pavucontrol)
  4. §2.4 — set the language to German
  5. §2.5 — enlarge the disk to 15 GB (works while running)
  6. §3 — install Qwen Code + Memory-MCP (visit the web pages for this)
  7. §3.3 — optional: set up GLM-5.3-Flash + OpenRouter
  8. §3.4 — check the context size in the Qwen Code configuration (important!)
  9. §3.5 — enable Yolo mode
  10. §3.6 — fix terminal flickering (if present)
  11. §4.1 — university VPN (Cisco Secure Client from the Play Store)
  12. §5.1, §5.3 + §5.4 — Anki, Marktext, Chrome in the VM
  13. §6 — Zotero + plugins (including §6.1: sync preparation, before you sign in for the first time; §6.2: Connector in the browsers; §6.4: PDF tools)
  14. §6.3 step 4 — get an OpenAI API key for semantic search (small as the model)
  15. Right after installation: run §10.1 (icon fix)
  16. Optional: §13 — mount Google Drive (rclone — don't forget your own API key!)

9. Asking your AI assistant (after setup)

Once Qwen Code and the Memory-MCP server are running, you can ask your AI assistant for help with all sorts of things:

  • "Install the Anki add-ons Image Occlusion Enhanced, Review Heatmap, and AnkiConnect for me."
  • "What other tools or workflows would you recommend for my medical studies?"
  • "Create a learning strategy with Anki for my first semester."
  • "How do I set up my Zotero with an MCP server in this VM so that you can access it?"
  • "Configure yourself for OpenRouter with the model z-ai/glm-5.3-flash."

The assistant knows your installed environment and can make targeted suggestions that go beyond this guide.


10. Troubleshooting

10.1 Missing icons in the toolbar (empty placeholders)

Cause: A bug in the Debian icon theme makes all icons invisible that exist only in the hicolor theme. Depending on the installation, various applications can be affected (e.g. KeePassXC). The fix, using KeePassXC as an example:

sudo cp /usr/share/icons/hicolor/scalable/apps/keepassxc*.svg /usr/share/icons/Adwaita/scalable/apps/
sudo gtk-update-icon-cache --force /usr/share/icons/Adwaita

Close and restart the affected application once. The same pattern applies to other affected applications: copy their icons from hicolor into the Adwaita theme and rebuild the icon cache.

10.2 Display problems with some apps

If programs are not displayed correctly or cannot be pinned:

  • Close the terminal window and open it again, then restart the affected app
  • That is usually the simplest fix.
  • Zotero: The confirmation dialog when deleting appears only as a window fragment and cannot be operated — grab the dialog window by its edge with the mouse and enlarge it; afterwards the buttons work normally. The dialog does not remember its size: enlarging is needed again every time (observed with Zotero 10.0.1, Flatpak as well as Debian package).

10.3 "API key invalid" — check the region, change the key later

When Qwen Code reports the API key as invalid, it is usually fine — the region is wrong: API keys are bound to the console they were created on (international console modelstudio.console.alibabacloud.comSingapore, Chinese console → Beijing). On the wrong region's server, a perfectly valid key is rejected.

Changing the key later: Start qwen and type /auth — the same dialog as on first start; it overwrites the old configuration: Alibaba ModelStudioStandard API Keyregion → paste the key. Afterwards, /doctor shows whether the sign-in works. If you prefer keeping the key in a file: it lives in ~/.qwen/settings.json under env or in ~/.qwen/.env — the .env file takes precedence.


11. Not yet installed (if needed)

Program Command Purpose
Java sudo apt install default-jre Java applications

(Node.js is no longer in this list since the revision — it is installed in §6.3 as a prerequisite for Zoteus.)


12. What you still have to do yourself

These are the points that no installation script and no guide can take off your hands — they belong to your personal account and your decisions.

12.1 Set up accounts

Account What for? Do it yourself?
Cisco Secure Client University VPN access Install the app from the Play Store, enter your university credentials, test the connection (§4.1)
Zotero.org Synchronisation & backup of your literature Create the account and the cloud API key per §2.6, then sign in in Zotero under Edit → Settings → Sync. Before that, be sure to do the one-time sync preparation from §6.1 — otherwise the sign-in hangs at "Waiting for sign-in…"
Google API key rclone/Google Drive (optional) Create it in the Google Cloud Console (§13.2, step-by-step guide) — afterwards set the OAuth app to "In production", otherwise you have to re-authorise every week
Qwen API token AI assistant Get it at Alibaba ModelStudio (§3.1 → web page)
OpenRouter API key Optional: GLM-5.3-Flash Get it at OpenRouter.ai, then ask the AI assistant to switch itself over (§3.3)

12.2 Do regularly

  • Update the VM: sudo apt update && sudo apt upgrade -y (about once a week)
  • Check storage: if the disk fills up, enlarge it in the ChromeOS settings
  • Maintain memory entries: your AI assistant can do this automatically, but a look into the memory never hurts

12.3 Backups — securing important data

Git is not a backup. Version control in the Git repo serves to trace changes, not for data backup.

What is backed up automatically:

  • Google Docs, Sheets, Slides — live in the Google Cloud, nothing for you to do
  • Zotero literature — synchronised with zotero.org (once the account is set up, §12.1)
  • Your AI memory (the memory database) — the installation package backs itself up: automatically every hour, only on change, 8 days of retention. You have to do nothing.

Additionally recommended: cloud backup of the AI memory via Zotero. Zotero notes do not count against your Zotero account's storage limit, but are fully backed up by the Zotero synchronisation. The memory server mirrors all memory entries as Zotero notes into a dedicated, device-specific collection — one per machine (the collection name carries the device name), so the backups of several devices sharing one Zotero account never collide. A second, external backup that survives even if the VM is lost. Have it set up once:

Prerequisite: Zotero sync on. Your local Zotero should be permanently connected to zotero.org and sync automatically (§6.1) — this not only keeps your library backed up: after restoring an older VM backup, the Zotero sync brings the library back up to date on its own. Your AI memory does not reconstruct itself: the backup notes do come back with the Zotero sync, but the agent's memory has to be rebuilt from them (§12.4 tells your assistant what is missing).

How the backup works: The memory server backs up its contents at most 6 hours after the last backup — on the next use of the memory — as Zotero notes in its own collection "AI-Memory-Backup — ". If you only use the assistant in the mornings, it backs up twice a day automatically; if you close the lid, the next use catches up. You can also trigger it manually at any time: tell your AI agent "synchronise the memory with Zotero".

Set up the Zotero backup of my AI memory. The memory-server package ships the tool memory_zotero_sync. Create the file ~/.qwen/zotero-sync.json with the content {"device": "<device-id>"} (device-id = a short name of this machine, e.g. the hostname) and store my Zotero API key in ~/.qwen/zotero-api-key (I will paste it in a moment; permissions 600). Test afterwards: call memory_zotero_sync with action "status" — it must show device, the collection name "AI-Memory-Backup — <device-id>" and key_present: true. Then trigger the first backup with action "sync": the tool mirrors all memory entries as Zotero notes into the device's own collection (restore protection built in; deleted notes stay in Zotero as an audit trail). Verification: a second call of "sync" reports 0 new / 0 updated; Zotero then contains exactly as many notes in the collection as there are entries in the memory. From now on the backup runs automatically: every time the memory is used, the server checks whether the last backup is more than 6 hours old and, if so, runs it on its own — you have to do nothing. Tell me when the backup runs and how I can trigger it manually at any time ("synchronise the memory with Zotero").

After the first backup, let Zotero sync once and confirm that the collection has arrived at zotero.org.

Weekly update check (recommended): Zotero, Zoteus, and the Zotero plugins keep evolving. Your assistant can check automatically every week whether updates are available — it will report them with a short summary, but install nothing without your approval:

Create a weekly reminder task: at the start of each week, check whether updates are available for Zotero (github zotero/zotero), Zoteus (npm @oscardvs/zoteus), and the installed Zotero plugins (Better BibTeX, Better Notes, Beaver, Zoplicate, Translate, Zutilo — each GitHub releases). Compare with the installed versions (Zotero: About Zotero; plugins: Tools → Plugins; Zoteus: npm view). Report each new version with 2–3 sentences on the release notes and suggest next steps. Install or update nothing without my explicit approval.

What you must back up yourself:

  • Local files in the Linux VM (e.g. Marktext documents, downloaded PDFs)
  • The entire VM configuration (installation, settings, all programs)

How to back up the whole VM:

  1. First back up the Linux VM: ChromeOS → Settings → Linux → "Backup & Restore" → Backup — ChromeOS creates a backup file of the VM (with all programs and settings)
  2. Then upload this backup file to Google Drive
  3. Important for large files: browser upload is more stable than the Files app — so upload in the Chrome browser at drive.google.com

Restore: download the backup file from Google Drive, then ChromeOS → Settings → Linux → "Restore from backup" and select the file

12.4 Learning from other devices' memory

Learning from other devices' memory. Your AI assistant backs up its memory to Zotero automatically (§12.3) — that covers everyday use. But if you have given one device a lot of new memory and want a different device to learn from it, tell that device's assistant:

Check the Zotero memory backups of my other devices (memory_zotero_sync, action "status") and show me which entries are missing here. Import selectively whatever is useful for your work here — import the fitting entries directly with memory_store (tag quelle:cross-import, origin in the source field). Nothing of your own gets overwritten or deleted; what I deliberately deleted does not come back. Report what you imported and why.

This is deliberate: imports happen only on your explicit request — what you deleted on one device does not come back on another. Cleaning up on one device stays final.

12.5 Every 2–4 weeks: website check

Our KI pages on www.logies.de keep evolving. One recurring assignment keeps your installation current with the guide (for example, every 1st and 3rd Friday):

Run the 2–4-week check: check the KI pages on www.logies.de (AI Workstation guide, Cross-Session Memory, the knowledge files): are there new versions, recommendations, or changes that improve your installation (Zoteus, embeddings, memory practice) or your memory? Apply whatever fits and report what you changed.

Learning from other devices is something you do on demand per §12.4 — it does not happen automatically.


13. Optional: mount Google Drive (rclone)

This building block is deliberately optional — the setup is a bit fiddly because the Google interface for the OAuth sharing, unfortunately, is not intuitive. Skipping it costs you nothing. It pays off especially if:

  • you want stable, permanent access to your Google Drive via Double Commander — then you copy files back and forth as if on a local disk, without browser upload
  • KeePassXC is to synchronise its password file reliably via Google Drive — simply put the database file in ~/GoogleDrive and open it from there; then it is at the same state on all your devices

You can also have your AI assistant work through this section: "Work through §13 of this guide and set up rclone with Google Drive for me. Ask me when you need credentials or confirmations from me."

13.1 Install and configure rclone

sudo apt install -y rclone

Setup:

rclone config
  • n for a new configuration
  • Name: GoogleDrive
  • Select Google Drive
  • client_id and client_secret: this is where your own Google API key belongs (step-by-step guide in the next step). You can leave both questions empty with Enter for now, click through the configuration, and repeat rclone config afterwards once the key is ready
  • For the scope, choose 1 (drive)
  • Confirm the rest with Enter
  • q to quit

13.2 Create your own Google API key — step-by-step guide

Background: without your own key, all rclone users share the same quota, which throttles transfers considerably. Let's go:

  1. Open console.cloud.google.com in the browser and sign in with your Google account
  2. At the top of the bar: Create project — name it e.g. "rclone", then Create. Afterwards check that the new project is actually active in the project selection at the top (most common stumbling block)
  3. Menu (☰) top left → APIs & ServicesLibrary → search for "Google Drive API" → Enable
  4. Back to APIs & ServicesOAuth consent screen → User type ExternalCreate → enter an app name (e.g. "rclone") and your e-mail address as support/developer contact → click through the following pages, each with Save and continue
  5. APIs & ServicesCredentials+ Create credentialsOAuth client ID → application type Desktop appCreate
  6. Copy the Client ID and Client secret (copy icons next to the values) — these are exactly the two values rclone asks for at client_id and client_secret
  7. Important — set it to "In production": go back to the OAuth consent screenPUBLISH APP → finish with Confirm. Otherwise the authorisation expires after 7 days and you have to re-authorise constantly

Then enter the two values in rclone config (§13.1) and complete the Google sign-in in the browser.

13.3 Automatic mounting (systemd service)

So that the Drive is mounted automatically after every restart:

mkdir -p ~/GoogleDrive
mkdir -p ~/.config/systemd/user/
nano ~/.config/systemd/user/rclone-mount.service

Insert the following content (with Ctrl+Shift+V):

[Unit]
Description=Rclone Mount für Google Drive
After=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/rclone mount GoogleDrive: %h/GoogleDrive --vfs-cache-mode full
ExecStop=/bin/fusermount3 -u %h/GoogleDrive
Restart=on-failure
RestartSec=10

[Install]
WantedBy=default.target

Save with Ctrl+O, Enter, then Ctrl+X to exit.

Enable the service:

systemctl --user daemon-reload
systemctl --user enable rclone-mount.service
systemctl --user start rclone-mount.service

Test:

systemctl --user status rclone-mount.service
ls -la ~/GoogleDrive

Bonus: Control your VM from your phone. Your workstation stays reachable when you are away: Termius (SSH), the WireGuard VPN of a FRITZ!Box router, and dictation keyboards let you run the VM from your phone — speak research tasks, read results, keep working on the road. The detailed step-by-step guide is on our page Die Linux-VM vom Handy aus steuern (German).

<

Created by Qwen Code (glm-5.3-flash) for www.logies.de — first version written with deepseek-v4-flash — CC0, free to share. Last updated: September 4, 2026 | For questions or updates: check the www.logies.de pages, where the most current information is available.