changelog — full history from the start
/theme, /voice, /think) and the new aios-time command.aios-time command — timezone and NTP, the step that used to live inside the installer. Works interactively or as aios-time zone Europe/Madrid._read_line span forever on EOF, an empty password was accepted and silently skipped by chpasswd (leaving the factory password on the installed disk), the disk selector cancelled after three bad answers, and a typo in the wipe confirmation aborted the installation. Now they re-ask, and cancelling is explicit.CONFIRM 3/4 vs 2/4, TOOL 17/17 vs 16/17 in the OFF mode).Qwen3.6-35B-A3B-UD-Q4_K_M.gguf (21.1 GB) + mmproj-qwen3.6-F16.gguf (858 MB).describe_screen() points at the chat endpoint, so there is one model to run and one route to maintain instead of two.RACK 7 TEMP 63C) — the model read it back exactly.bios@aios:~), the user, the hostname and what the terminal was doing. The previous 4B model could not do this./vision/* route and the llama-vision container (Gemma-3-4B + mmproj) were removed; the vision.endpoint default now points at the chat endpoint./v1 is kept as a legacy alias and now serves the same model as /ollama, so existing configurations and any client pointed at /v1 keep working unchanged.describe_screen() returned an EMPTY description. It was the only LLM call in the agent that did not send enable_thinking; the model reasoned by default, spent all 400 max_tokens on reasoning_content and returned an empty content. Fixed by sending enable_thinking: false, like every other call in the agent. This bug existed before this release — the previous model happened to work anyway.setup.py would configure a broken installation. The model list for the VPS provider still offered nemotron-3.5-lightning (removed) and qwen3.5:9b (no longer served), and the vision option wrote the now-removed /vision endpoint. Both corrected to the live model and endpoint.llama-hardened stack is now two containers (proxy + qwen) instead of four. Removed: the llama (Nemotron) and vision (Gemma) services, their entrypoints, their Dockerfile COPY lines, the /vision Caddy block, the depends_on that referenced the removed service, the two Nemotron GGUFs (48 GB), the two Gemma GGUFs (3.3 GB), a stray second Gemma server that had been running unattended on port 8095 for 3 days, and the dead k2-test tree.~/llama-hardened/.bak-qwen36/.finish=stop) whenever enable_thinking=false: the agent went mute on any request that needed a tool call ("hello" answered, "check the running containers" did not).enable_thinking, so it emitted a closed, empty reasoning block ( thinking) in front of the tool call. The model learned that transition and was out of distribution when a real reasoning block opened at inference.mask_generation_prompt: true + mask_reasoning_content: true (the template's own tokens are no longer supervised), tool-call arguments kept as a mapping (the Nemotron template iterates them with |items), and model.output_hidden_states: true.run_command {"command":"sven install vim"} — with enable_thinking: true and false.aios-model repo: behaviour dataset (249 pairs, 154 with real tool_calls), NeMo AutoModel recipes, the manual tensor-merge script and the training/deploy scripts.enable_thinking cloud patch in agent.py is no longer required: the model handles both modes, so /think on and /think off both work.torrent.py + 5 agent tools). The user asks in plain language ("I want to watch Metropolis by Fritz Lang") and the agent searches, downloads and plays — no GUI needed.torrent_search(query) — searches apibay.org (The Pirate Bay API) and torrents-csv.com, merges and ranks by seeders, caches the numbered list so torrent_download("<number>") just works. Verified: "Metropolis 1927 Fritz Lang" → restored 1080p release, 115 seeders.torrent_download / torrent_status / torrent_control (start|stop|verify|remove|remove-data) — driven through the transmission-daemon RPC on 127.0.0.1:9091.torrent_play([id]) — plays with mpv fullscreen (ffmpeg does the decoding); with no id it plays the newest media file downloaded.torrent.fetch().transmission-cli 4.1.3-2, aria2 1.37.0-3, mpv 0.41.0-6 (+ ffmpeg/libbluray refreshed to the same upstream so libbluray.so.4 and so.3 coexist)./etc/aios-torrent.conf (system defaults, shipped in aios-lfs) with a per-user override in ~/.aios/torrent.conf; downloads default to ~/Downloads.aios-update deploys torrent.py and the new system configs (previously the manifest would have silently skipped them).User=transmission (uid 169) and /var/lib/transmission, so downloads would not be readable/deletable by the user who watches them. New drop-in transmission-daemon.service.d/user.conf (aios-lfs) sets User=aios, HOME/XDG under /home/aios and --download-dir /home/aios/Downloads. No Group= line: AIOS' user aios has primary group wheel, and a wrong Group= fails the unit with 216/GROUP.torrent.py starts it on demand (systemctl, NOPASSWD in the AIOS live/installed model, with a direct-launch fallback), so an unused system keeps no extra service or open peer port.xt=urn%3Abtih%3A<hash> with "unrecognized info" — the xt value is now emitted verbatim (raw colons), only dn/tr are encoded.describe_screen() tool — captures the screen and describes it with Gemma-3-4B (multimodal VLM) on the VPS. Recognizes apps, logos and UI text (verified: identified the Grafana editor, "Prometheus default", "Kick start your query"...).llama-vision (Gemma-3-4B Q4_K_M + mmproj) on /vision/* with the same X-API-Key. Analysis takes ~43s (12.6s prompt + 30.8s gen).vision.enabled + endpoint + key.MAX_TOKENS 2048 + reasoning_effort: low + 240s watchdog + no retry — a turn no longer burns 40 min thinking.fetch() from browser_eval for authenticated web apps (Grafana, Prometheus, Jenkins, GitLab...).get_installed_info tool + markdown fact sheets.break and skipped the counter — K2 looped ~18x on the same failing command). continue (not break) + whitespace-stripped args.mcp_call, run_playbook, process_send, module playbook.py); deleted the discarded vision-ladder GGUFs on the VPS (SmolVLM 256M/500M/2.2B) — only K2 + Gemma-3-4B remain; vision policy added to the prompt (describe_screen → browser_eval → ocr → screenshot).k2-horizon:7b → webuillama.ccmai.org/v1/chat/completions (K2-Horizon-7B Q4_K_M, llama-server fork MBZUAI-IFM)qwen3.5:9b → webuillama.ccmai.org/ollama/v1/chat/completions (Qwen3.5-9B, same stack, separate route)X-API-Key for both; the menu propagates the URL per model (3rd tuple element).ollama-core (Ollama 0.32.15) cannot serve K2 (MoVA architecture not yet supported in its llama.cpp), so the stack moves to llama-server from the MBZUAI-IFM fork behind Caddy X-API-Key. /v1 serves K2 and /ollama/* serves Qwen3.5. Ollama stays stopped as reserve (models intact in its volume).shortcuts.txt (F1).btn-create-dashboard, inp-search) with visible text and CSS selector — the agent SEES the page before clicking (like Hermes drive_preview action="elements").innerText/aria-label/value/placeholder, case-insensitive) — click by what you SEE ("Create your first dashboard") without guessing selectors.browser_elements() BEFORE clicking/typing (workflow navigate → elements → click/type).browser_navigate, browser_eval, browser_click, browser_type — real browser control via DevTools Protocol (real DOM, clicks by selector, forms by field). No more blind OCR. Chromium 152 installed from sven.browser_* to browse (never process_send — browsers ignore stdin); documented workflow (navigate → eval → click → type).aios-install reads the version from the CHANGELOG (shows AIOS LFS INSTALLER v0.18.5 instead of the hardcoded 1.1.3).Device or resource busy silenced. Fix: close/reopen the tic aplay INSIDE the _speak_sync thread (voice.py) — speak() spawns a thread and returns, so closing in chat.py reopened before TTS opened the device._ensure_browser() used _urlopen without importing it (silent NameError) in the check and in the wait loop → 10s timeout. Fix: urllib.request as _url in both + 30s wait (Chromium takes a while to start on the laptop)./usr/local/bin/aios-diag wrapper had no x)./dev/dri/card0 → open /dev/dri/card0: Permission denied → no screens found → getty loop → start-limit-hit → blinking cursor with no session. aios-session now waits up to 30s for /dev/dri/card0 to be readable/writable before startx.audio-detect.py ran 9s into boot, when only the HDMI card was visible → wrote plughw:0,0 (HDMI) instead of the analog one. Now if the only detected card is HDMI, it waits and retries (up to 15s) until the analog card appears.aios-deploy-and-build.sh now copies scripts/aios-session and scripts/audio-detect.py to the tree (they never reached the ISO before).Read timed out.user (not system): the no-thinking model frob/qwen3.5-instruct:9b requires system at the start of the history; a summary inserted as system in the middle caused 500 Jinja Exception: System message must be at the beginning.(continue) Aún no he terminado... ¿Quieres que continúe? instead of (no response).(continue) status messages._read_line() (setup.py): copy/paste works in the API key prompt.AIOS/v0.18.3 is read from the CHANGELOG (auto-updates with each release) instead of the hardcoded AIOS/1.4.--period-size=128 (tick per character, no bursts); the user-typing tick is removed (only the agent's typewriter sounds).20-systemd-sysusers etc.) — added to the tree; sven install docker now creates the docker group automatically./var/run → /run, /var/lock → /run/lock, /etc/mtab → /proc/self/mounts were missing (lost by an old mksquashfs over overlay) — recreated in tree and installed disks.aios-deploy-and-build.sh verifies/recreates the 3 LFS symlinks before every mksquashfs.getpass read passwords corruptly on a dirty raw terminal — replaced with a self-contained _read_password() that masks input and controls the tty directly.cleanup_chroot() ran before set_passwords()/harden_* — reordered so it runs last, just before the final umount./etc/pam.d/system-auth was truncated to a single line with no password stack — chpasswd never wrote to /etc/shadow. Restored the full BLFS system-auth.run_command that already failed./sudo round-trip; run_command prompts for the sudo password (masked) directly.Qwen3.5-9B (Q4_K_M), replacing Qwen3-8B — better reasoning and tool calling. llama-server upgraded to b10655 (CPU-dispatched: runs on any x86-64, from SSE4.2 to AVX-512).qwen3.5:9b with a 32K context window (OLLAMA_CONTEXT_LENGTH=32768) instead of the 4K default — fixes empty responses where reasoning + tool-calling exhausted the context.finish_reason, reasoning characters emitted) instead of the generic "(empty model response)".aplay now uses a minimal period/buffer (--period-size=512 --buffer-size=1024) so the typewriter tic sounds per-character instead of accumulating into a continuous beep.amixer set Master (the same ALSA mixer aplay/plughw uses) instead of pactl (PipeWire), so the keys actually change the volume./sound, /voice, /theme) work after setup (once the agent/LLM starts).:443 (valid cert via Cloudflare) and TLS verification enabled by default (VERIFY_TLS no longer tied to x-api-key); model switched from Moonlight (no function calling) to qwen3.5:9b.max_tokens now scales with the context (_cloud_context // 4) instead of a fixed 4096, and the Ollama Hardened context_limit raised 8K → 32K — fixes empty responses from reasoning models exhausting the token budget.CTX block now resolves the Ollama Hardened context limit (32K) instead of the 128K default.aios-audio.service was never enabled (missing multi-user.target.wants symlink) — audio-detect.py didn't run at boot and asound.conf kept the hardcoded plughw:1,0. Now enabled, analog card auto-detected.run_command passed both stdin and input to subprocess.run — sven update/upgrade/install failed with "stdin and input arguments may not both be used". Fixed.sudo -n true). Live runs sudo directly; installed asks for /sudo <password> (in-memory only, never persisted)./sudo <password> (cached in session) + run_command uses sudo -S; the agent accepts the password in local and cloud modes (no NOPASSWD needed).asound.conf dynamically — audio works on any hardware.<think> tag corruption.setup.py was missing Blade Runner) + shuffle-cycle picker to avoid repeats.vt.global_cursor_default=0 from the disk GRUB entry.scripts/aios-diag exec bit.voice: section from chatvoice: section in config.yaml (tts/stt/tts_lang), separate from cloud: (chat). Setup (live and aios-install) lets you choose TTS (off/espeak/gemini/openai), STT (off/vosk/gemini/openai) and language; voice keys go to ~/.aios/.env apart from the chat key.voice.py): local espeak-ng (no key), Gemini gemini-2.5-flash-tts and OpenAI gpt-4o-mini-tts. Skips code blocks/tables and speaks in a thread. espeak-ng installed via sven.voice.py): local vosk, Gemini and OpenAI (records with arecord)./voice (toggles, persists) and /mic (records + transcribes + sends).VOX/MIC block in the i3 bar.aplay --buffer-size=512 --period-size=512 (buffer == period) failed silently on some codecs; removed. aios-diag now collects audio state.select + buffered readline left listening stuck; fix: reader thread + queue (no select).Print): inline scrot with % + && + nested quotes broke the i3 parser; fix: dedicated scripts/screenshot.sh.import sys in agent.py: fixed NameError swallowed by the stream except (the agent seemed "mute").⚙ tool(...) is shown before execute_tool.run_command with correct stdin: /dev/null by default + auto-y for sven prompts.list_desktop_apps: parses /usr/share/applications/*.desktop._start_local_model: real phases from the llama-server log.scrot to ~/screenshots/; documented in shortcuts.txt.aios-diag: collects diagnostics, redacts keys, uploads tar.zst via rsync to a write-only diag account._live_flow returns True and main() breaks._read_line: escape sequences handled.sven install/upgrade/sync._out() writes explicit CRLF.auth_type (bearer/x-api-key); verify=False only for x-api-key.webuillama.ccmai.org:8443, Moonlight-16B-A3B._AIOS_GROUNDING injects AIOS invariants into the system prompt.local.think (default OFF).delta.reasoning_content, not delta.content._detect_cpu() + _auto_context()./think command: toggle without leaving the agent.chat.py swallowed agent.run() return; stream cut left empty content./tmp/aios-stream.log, single retry on empty stream./lib/firmware (~534MB) + iwlwifi symlinks.aios-wifi.service path → replaced by networkd.[ -b ] loop).sdc, sdd, hd*, nvme*, mmcblk*).AIOS: boot media not found + busybox shell.exit code=0x7f00).sed pattern → double backslash fix.exec /bin/sh → exec /bin/busybox sh.switch_root.getpass, chpasswd).nokaslr; print_box centered.validate_api_key in a daemon thread with join(timeout=12).os._exit(0) at the end to force exit.~/.aios/.env.print_box centered.grub-mkconfig (graphical, hung in VirtualBox) replaced by a fixed text-mode grub.cfg.set default=0, set timeout=5, menuentry "AIOS LFS"./v1/tokenize.run_command, read_file, write_file.