# AI Workstation for Students: Research, Learning, and More — a Linux VM on ChromeOS (Crostini)


---


**Audience:** Medical students and others who want to set up 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:** October 8, 2026
**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.
**System:** Debian 13 (Trixie) via ChromeOS Crostini
**License:** CC0 — free to use, no attribution required

---

## 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.

**Hardware requirement — enough storage:** Your Chromebook/Chromebox needs **at least 64 GB of internal storage**. On a 32 GB device the installation is just barely possible (the Linux VM then only fits with about 11 GB), but it is **unusable for actual work** — a test installation on a 32 GB Chromebox ended with a full host disk: the VM could no longer be enlarged, and the local setup of semantic search alone (§6.3 step 4) takes up about 900 MB in one go (measured: 760–890 MB depending on package version). If you are about to buy: 64 GB is the minimum, 128 GB is comfortable.

**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.

```bash
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:

```bash
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

sudo apt install -y keepassxc
sudo apt install -y pcmanfm
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.

Google Chrome is the VM's browser — for you yourself and as the target of browser automation by the AI assistant (§5.4); PCManFM is the VM's file manager.

**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).

**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/`. Depending on the ChromeOS version, the paths may also be `/mnt/chromeos/shared/GoogleDrive/MyDrive` (as verified on Debian 13 on September 27, 2026) — if in doubt, `ls /mnt/chromeos` shows the path that exists on your system. 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

```bash
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.

### 2.5 Enlarge the storage space (recommended)

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. The increase requires free internal storage on the device itself — on a 32 GB Chromebox, the default reserve is already the upper limit (hence the hardware requirement in §1).

### 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](https://www.zotero.org) (name + e-mail is enough).
2. **Create the cloud API key:** logged in at [zotero.org/settings/keys/new](https://www.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**](https://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 ModelStudio** → **Standard 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:

```text
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:

```text
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**](https://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 `/exit` — **all 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](https://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.
```

3. The assistant sets itself up — you only have to provide the key

**Rule — add new providers only in addition to, never instead of, the working provider:** Whenever you have your assistant switch providers, tell it explicitly to **keep** the provider that works — "set up OpenRouter **in addition**", not "switch over". If the switch deletes the old entry and the new provider misbehaves (a mistake in the key, an outage), you are left without a working model: `/model` then shows only the new provider, and the assistant itself becomes hard to steer — precisely when you need it most. If the old entry is kept, getting back is a single choice in the `/model` menu; if it is lost after all, `/auth` brings the setup dialog back — the same dialog as on first start, which rewrites the configuration (§10.3).

**Remember for your own routes:** A route’s `id` must exactly match the model name the provider expects (e.g. `glm-5.3-flash`) — Qwen Code sends the `id` unchanged as the API model name. A freely invented id such as `zai-coding-glm-5.3-flash` only produces `[API Error: 400 Unknown Model]`. The display name (`name`), by contrast, is free to choose.

**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:

```text
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.

**Timeout against truncated model responses (important since Qwen Code 0.23.1):** By default, the server cuts off long model responses after about 150 seconds (upstream timeout) — the response is then lost even though the model was still working; observed with long report generations at only ~14% context usage. Since version 0.23.1, the switch is called `generationConfig.timeout` and belongs **in the respective provider entry** (`modelProviders`) of your configuration; the earlier top-level key `contentGenerator.timeout` no longer exists and only produces a warning at startup. For a 5-minute time limit, give your assistant this order:

```text
In your configuration (~/.qwen/settings.json), set generationConfig.timeout to 300000 milliseconds in all active model routes (each under modelProviders). The top-level key contentGenerator.timeout is deprecated — remove it if it is still present. Show me the changed entries afterwards.
```

### 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") → **PCManFM** → navigate to your home directory in the file pane → select `todo.md` → **Enter** — 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:**
```bash
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 `.gitignore` — **this command creates it in full:**

```bash
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):**
```bash
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):

```bash
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.

```bash
flatpak install --user flathub net.ankiweb.Anki
```

**Start:** launch Anki from the application menu, or:
```bash
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:
```bash
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:** Certain Anki versions have a startup bug (last seen in 26.08.x; the installation under 26.09.3, by contrast, ran stable): on the very first launch, Anki 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. **First check whether your Anki is affected at all:** if it starts normally to the main view, everything is fine and this section does not apply. If it crashes, your assistant fixes this by pre-seeding the database with correct values. Then 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:

```bash
flatpak run --command=python3 net.ankiweb.Anki -c "import anki.utils; print(anki.utils.int_version())"
```

**Download (per add-on):**

```bash
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.

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

### 5.4 Google Chrome in the VM (for browser automation)

Google Chrome is already installed as the VM's browser (§2.3) — separate from the Chrome preinstalled with ChromeOS, which runs outside the VM and is unreachable for the AI. So that your AI assistant can also **operate web pages autonomously** (open pages, fill in forms, take screenshots, run checks), it gets a small browser extension on request.

**Optional — letting your AI assistant drive Chrome:** With the extension, your assistant can operate the VM Chrome in the background — open pages, read them, click. This pays off when a website blocks automated access (for example Reddit, which shows script-driven access only a login prompt), or when you have signed in inside the VM Chrome and want the assistant to work with your login. The installation is handled by your assistant itself via browser policy — the same mechanism that in §6.2 puts the Zotero connectors into the browser. Copy this instruction:

```
Install the Qwen Code extension (ID hdhmmjclhibojdddmancfgbkleahfaph) into the Google Chrome of this Linux VM via browser policy. Procedure:

1. If /etc/opt/chrome/policies/managed/qwen-extensions.json already exists, show me its content first. Then create the file (create the directory if needed; sudo is passwordless in the VM) with exactly this content:

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

2. Validate the file with python3 -m json.tool /etc/opt/chrome/policies/managed/qwen-extensions.json >/dev/null && echo OK. If Chrome windows are running, close them properly — the extension installs automatically at the next Chrome start; existing extensions are not touched. Confirm the file content to me.
```

It is the extension with the ID `hdhmmjclhibojdddmancfgbkleahfaph` — only this one belongs to Qwen Code (the store hits "Qwen" and "Qwen AI" are different products). Chrome will then show a notice that the browser is "managed by your organization" — that comes from the policy file and is harmless, the same notice as with the Zotero connectors.

**Manually or via policy — both are valid routes:** The Chrome Web Store does not reliably deliver the extension through the policy channel in all regions (it then answers with an empty HTTP 204 — observed on September 27, 2026); the policy file itself is still set correctly. So if the automatic route fails, that is not a mistake on your part: install the extension by hand in the VM Chrome — or by hand right away, to skip the detour. Preferably directly via this link, because the store search shows several lookalikes: 👉 [**Qwen Code — Chrome Web Store**](https://chromewebstore.google.com/detail/qwen-code/hdhmmjclhibojdddmancfgbkleahfaph)

**First use:** For the connection, Qwen Code automatically sets up a small helper on its first browser task. If the connection does not work right away, close Chrome once and reopen it. Afterwards you can instruct the assistant, for example: "Open <website> in Chrome and summarize the content" — you can watch every move live in the VM Chrome window.

**Transparency:** What the assistant can do in this Chrome is deliberately far-reaching: it can read pages you have open and signed into there. Treat the VM Chrome like any real browser — it is meant for studying and research, not for passwords and banking.

---

## 6. Reference management (Zotero)

### 6.1 Install Zotero

```bash
flatpak install --user flathub org.zotero.Zotero
```

**Start:**
```bash
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. Give the start some time afterwards: after the integrity window, Zotero with six plug-ins takes roughly 50 seconds to come up — a single check finishes within seconds. Always quit Zotero via *File → Quit*; aborting a running start counts as another unclean shutdown, and the check will be due again at the next start. However, if the check returns on every start and stays stuck for good, neither waiting nor a restart helps (observed twice, 29 Aug and 30 Sep 2026) — the only thing that helped each time was a full reset of the Zotero databases with backup, followed by the library restore per §8. 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"** → Chrome opens. **Sign in promptly** — the login session expires after about 10 minutes. The browser 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](https://github.com/retorquere/zotero-better-bibtex/releases) | `zotero-better-bibtex-<version>.xpi` |
| Better Notes | 3.3.3 | [windingwind/zotero-better-notes](https://github.com/windingwind/zotero-better-notes/releases) | `better-notes-for-zotero.xpi` |
| Beaver | 0.24.0 | [jlegewie/beaver-zotero](https://github.com/jlegewie/beaver-zotero/releases) | `beaver.xpi` |
| Zoplicate | 5.1.1 | [ChenglongMa/zoplicate](https://github.com/ChenglongMa/zoplicate/releases) | `zoplicate.xpi` |
| Translate | 2.4.7 | [windingwind/zotero-pdf-translate](https://github.com/windingwind/zotero-pdf-translate/releases) | `translate-for-zotero.xpi` |
| Zutilo | 4.2.2 | [wshanks/Zutilo](https://github.com/wshanks/Zutilo/releases) | `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 `applications.zotero.id` or `browser_specific_settings.zotero.id` — it varies by plug-in, check both if in doubt (with the six plug-ins used here it was under `applications.zotero.id` in every case), 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**](https://www.logies.de/zotero-mcp-server-beaver-comparison.html)

**Zotero Connector in the VM Chrome (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 the **Google Chrome of the VM** via browser policy — together with the ad blocker **uBlock Origin Lite**. Copy this instruction:

```
Set up the Zotero connectors in the Google Chrome of this Linux VM via browser policy — Zotero Connector (ekhagklcjbdpajgpjgmbionohlpdbjgc) and uBlock Origin Lite (ddkjiahejlhfcafbddmgiahcphecmpfh). Procedure:

1. If /etc/opt/chrome/policies/managed/zotero-extensions.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):

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

2. Validate the file with python3 -m json.tool /etc/opt/chrome/policies/managed/zotero-extensions.json >/dev/null && echo OK. If Chrome windows are running, close them properly (Zotero may keep running) and restart Chrome once — allow about one minute so the Chrome Web Store can install the extensions; then close Chrome again.

3. Verify and report back to me: the folders ekhagklcjbdpajgpjgmbionohlpdbjgc and ddkjiahejlhfcafbddmgiahcphecmpfh must exist under ~/.config/google-chrome/Default/Extensions/. Do not install anything beyond that.
```

In brief: Chrome gets 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 the JSON file with `python3 -m json.tool <file> >/dev/null && echo OK`; policies take effect on the next browser start.

**Manually or by policy — both are valid ways:** Just like with the Qwen Code extension (§5.4), the Chrome Web Store does not reliably deliver the extensions through the policy channel in all regions (empty HTTP 204 — observed on 27 Sep 2026 on the test-installation Chromebox and on 30 Sep 2026 on a Chromebook); the policy file itself is still correct. If the automatic way fails, that is not a mistake on your part: install Zotero Connector and uBlock Origin Lite by hand in the VM’s Chrome — or straight away by hand to skip the detour: 👉 [Zotero Connector](https://chromewebstore.google.com/detail/zotero-connector/ekhagklcjbdpajgpjgmbionohlpdbjgc) · 👉 [uBlock Origin Lite](https://chromewebstore.google.com/detail/ublock-origin-lite/ddkjiahejlhfcafbddmgiahcphecmpfh)

**The only manual step left: Chrome from ChromeOS (outside the VM)** — the VM cannot reach that browser: install the [Zotero Connector](https://chromewebstore.google.com/detail/zotero-connector/ekhagklcjbdpajgpjgmbionohlpdbjgc) 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).

### 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.

**For the assistant — really quit Zotero:** Zotero runs in the Flatpak as `/app/lib/zotero/zotero`. A pgrep/pkill pattern aimed at the launcher `/app/bin/zotero` only matches the starter, not the running program — the old instance then stays alive (single instance), new prefs.js lines or plugin files never appear, and verification steps deliver misleading results (up to `403 "Local API is not enabled"`). The clean way: check with `pgrep -af "/app/lib/[z]otero/zotero"` first, kill hits with `pkill -f "/app/lib/[z]otero/zotero"` — the bracket trick keeps the pattern from matching its own shell.

**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**](https://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 in the current LTS version.** Zoteus runs on Node.js — on a fresh Crostini system, install it first. Debian's own package is outdated (version 20 without built-in `node:sqlite`, see the warning further down) — take the current LTS straight from NodeSource (as of this revision: Node 24; a quick look at nodejs.org shows whichever LTS is current):

```bash
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo bash -
sudo apt install -y nodejs
```

The NodeSource package already includes `npm` — the old Debian `npm` package from the previous route is no longer needed.

**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:

```json
"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) Only if you use the old Debian Node 20 instead: it lacks the built-in `node:sqlite`, and Zoteus then falls back to a JSON index backend — index files beyond roughly 512 MB cannot be saved with it. With the NodeSource LTS from the prerequisite above, Zoteus uses the robust SQLite backend and this point never arises.

**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.

**If the index build is killed for lack of memory:** On devices with little RAM (about 6–8 GB) and larger libraries, the build can abort without apparent reason, taking the assistant session with it — behind this is the kernel's OOM killer ("out of memory"): when memory runs out, it force-kills the hungriest process to save the system. The kernel log reveals it (`dmesg | grep -i -e oom -e "killed process"`). The remedy is a 4 GB swap file, entered so it survives reboots — your assistant sets this up:

```
The Zoteus process was killed by the OOM killer during the semantic index build. Please set up a 4 GB swap file, in exactly this order: 1) touch /swapfile (empty file), 2) sudo chattr +C /swapfile (NOCOW flag — works only on the still-empty file), 3) sudo fallocate -l 4G /swapfile, 4) sudo chmod 600 /swapfile, 5) sudo mkswap /swapfile && sudo swapon /swapfile, 6) make it survive a reboot: append the line "/swapfile none swap sw 0 0" to /etc/fstab (create the file if it is missing). Verify with swapon --show and free -h and then start the index build again.
```

Verified on a real device (October 1–2, 2026, 6.3 GB RAM, about 11,800 entries): without swap the build aborted twice; with swap the same build completed — swap usage peaked at 2.1 GB.

Note: The embedding model (129 MB) is stored in addition to the copy that your AI memory from §3.2 uses — the memory server and Zoteus are separate runtime environments (Python vs. Node), and each manages its own copy in its own directory (`~/.qwen/models/` or `~/.cache/huggingface/`); sharing the files between them is not intended and not necessary.

**If the local setup fails with a missing package dependency:** Since Zoteus v1.21.0, the embedding package `@huggingface/transformers` is no longer bundled (neither as a dependency nor as an option) — depending on the version, the index build aborts with `ERR_MODULE_NOT_FOUND` — or Zoteus starts silently and only reports the gap in `zotero_whoami` ("@huggingface/transformers is not installed", `embeddings.active=false`). This is not a setup error: following the Zoteus README, the assistant installs the package into its own folder (`~/.zoteus-deps`, about 900 MB (measured: 760–890 MB depending on package version) — free up space first on small disks) and sets `ZOTEUS_TRANSFORMERS_PATH` to its `node_modules` directory in the MCP entry. Alternatively, it can fall back to the OpenAI route below, which works without this extra path.

**Verification — do not skip:** The smoke test above stays green even when the embedding runtime is missing: Zoteus still starts, and only reports the shortfall on request (`embeddings.active=false`, “Semantic ranking is off”). After installing the package, have your assistant show you `zotero_whoami` — it must report `embeddings.active=true`. If it says `false`, the package is missing: repeat the installation per the Zoteus README and only then start the index build.

If the library is still empty at study start (for instance because the sync restore is still running), the build may be deferred — catch up as soon as literature is present: first the embedding verification from just above, then the build.

**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 — important: with the fulltext:true parameter, because without it the update does not read in the PDF contents of newly attached files — and 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.

**Why this parameter matters:** During an index update without `fulltext:true`, Zoteus captures only the metadata. The contents of PDFs attached later to existing entries are then missing from semantic search — even though the entries themselves are visible (behavior verified on a real index on September 13, 2026; details are in the Zotero knowledge export from §3.2, your assistant knows them). With the parameter, the update reads in the missing contents selectively, without re-indexing the whole library.

**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:

```bash
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.

### 6.5 Optional: Translation server (automatic webpage import)

Without an extra tool, your assistant can import literature by DOI or arXiv ID — full webpages (and ISBN/PMID numbers) only become possible once a **Zotero translation server** is running. It is a small Node.js program that evaluates webpages just like the Zotero browser connector and hands the metadata to your assistant. The setup is one-time and takes only a few minutes:

```text
Install the Zotero translation server (github.com/zotero/translation-server) for me: clone the repository with --recurse-submodules to ~/translation-server and run npm install there. Start the server with npm start and configure it to listen on 127.0.0.1 only (file config/local.json5 in the project directory containing {"host": "127.0.0.1"} — security reason: otherwise the server would be visible on the local network), then restart it. Afterwards, verify with a test import of https://example.com (without saving to the library) that webpage metadata arrives cleanly, and report the result to me.
```

**Notes:**

- The prerequisites (Node.js and git) are already installed at this point (§4.2 and §6.3).
- **The first start takes about a minute** (bootstrapping). A message such as "port not open" right after starting is normal, not an error.
- The server runs in the foreground of the terminal; stop it with **Ctrl+C**. For continuous operation, simply use a second terminal tab.
- Your assistant finds the server automatically as long as it runs on the same machine. Only for a server on a different device would the environment variable `ZOTEUS_TRANSLATION_SERVER_URL` need to be set — not the case here.
- **Platform-independent:** The translation server is an ordinary Node.js program and runs anywhere Node.js runs (Linux, macOS, Windows). This guide describes the route inside the ChromeOS Linux VM (Crostini); on macOS or Windows the procedure is similar.

---

### 6.6 Catching up on missing PDFs: OpenAlex PDF Finder (plugin)

Zotero's built-in "Find Available PDF" gives up when an item has no DOI. The free plugin "OpenAlex PDF Finder" ([github.com/Littview/zotero-openalex-pdf](https://github.com/Littview/zotero-openalex-pdf)) also matches via PMID, arXiv ID, and exact title (year ±1). Select items → right-click → "Find PDF via OpenAlex". Uncertain matches are only reported, never attached; only legal, freely accessible copies are fetched.

Installation: download the `.xpi` from the project's releases page, then open **Tools → Plugins** in Zotero and drag the file into that window. Limitation: the plugin only sees what OpenAlex lists — if it finds nothing, a free full text may still exist (for example, obtain it via Europe PMC).

---

## 7. Installed software (overview)

### Installed via apt

```bash
# Step 2.2
sudo apt install -y git

# Step 2.3
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install -y ./google-chrome-stable_current_amd64.deb
sudo apt install -y keepassxc pcmanfm pavucontrol sqlite3 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 6.3 — Node.js LTS as a prerequisite for Zoteus (NodeSource, see §6.3)
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo bash -
sudo apt install -y nodejs

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

### Installed via Flatpak

```bash
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 (Chrome, KeePassXC, PCManFM, 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 (mandatory step of the initial setup, not optional)
11. **§4.1** — university VPN (Cisco Secure Client from the Play Store)
12. **§5.1, §5.3 + §5.4** — Anki, Marktext, browser extension in the VM Chrome
13. **§6** — Zotero + plugins (including §6.1: **sync preparation**, before you sign in for the first time; §6.2: Connector in the VM Chrome; §6.4: PDF tools)
14. **§6.3 step 4** — set up semantic search (locally without a key; OpenAI key only for very large libraries)
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:

```bash
sudo mkdir -p /usr/share/icons/Adwaita/scalable/apps/
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
```
The `mkdir -p` is necessary because the Adwaita target folder does not always exist on Debian 13. 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.com` → **Singapore**, 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 ModelStudio** → **Standard API Key** → **region** → 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.

**Back to the proven model:** The same route helps when a model change (§3.3) went wrong — `/auth` → **Alibaba ModelStudio** → **Standard API Key** → region → paste the key rewrites the working default configuration; afterwards `/model` shows the ModelStudio models again.

---

## 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](https://openrouter.ai), then ask the AI assistant to switch itself over (§3.3) |
| **Semantic index (only if deferred)** | Semantic search in Zotero | If the index build in §6.3 step 4 was deferred because the library was empty: catch up as soon as literature is present — first the embedding verification (`zotero_whoami` must report `embeddings.active=true`), then the full build |

### 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 — <device-id>". 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 the file manager (PCManFM)** — 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

```bash
sudo apt install -y rclone
```

**Setup:**
```bash
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](https://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 & Services** → **Library** → search for "Google Drive API" → **Enable**
4. Back to **APIs & Services** → **OAuth consent screen** → User type **External** → **Create** → 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 & Services** → **Credentials** → **+ Create credentials** → **OAuth client ID** → application type **Desktop app** → **Create**
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 screen** → **PUBLISH 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.

If a sign-in fails with `invalid_grant` (token expired or revoked — this can happen even in a finished setup), run `rclone config reconnect GoogleDrive:` in the terminal and re-authorise in the browser; the systemd service from §13.3 will mount the Drive again afterwards.

### 13.3 Automatic mounting (systemd service)

So that the Drive is mounted automatically after every restart:

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

Insert the following content (with **Ctrl+Shift+V**):
```ini
[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:
```bash
systemctl --user daemon-reload
systemctl --user enable rclone-mount.service
systemctl --user start rclone-mount.service
```

**Test:**
```bash
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](linux-vm-vom-handy-steuern.html) *(German)*.

## 14. Security notes for AI research

**Check AI output before you adopt it.** When your AI agent puts research findings into a fixed format (tables, ratings, extracted data), define that format first, then spot-check that the output follows it and that the cited evidence really exists. Reliable results come from two ends: a clear specification and your own control.

**PDFs and web pages are external material.** Anything your agent reads from PDFs, web pages, or emails may be phrased to lure it into unwanted actions ("prompt injection"). Therefore: keep credentials out of any folder the agent reads, and never act on suspicious instructions found inside documents — report them instead.

*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: October 8, 2026 | For questions or updates: check the www.logies.de pages, where the most current information is available.*
