Decisions
0032: Optional modules
AI, developer, creative and console stacks as removable modules and Kits.
Status: proposed (main, 2026-11-01, at the lead's request). Builds on 0016 (snapshot), 0021 (wopkg), 0023 (install plan), 0024 (first-use check), 0029 (repository split), 0013 (first run) and 0031 (shell plugins).
Context
WolOS ships one desktop for everyone and installs drivers online at first boot. People who code or create want Claude Code and other agents, local models, toolchains, editors, Blender-class apps and a serious console, the way macOS ships Xcode or Final Cut as installs, not as the base. Omarchy sets the UX bar (one menu, lazy mise installs, an agents panel, everything themed) but runs agents auto-approving and plugins unsandboxed. WolOS already has what Omarchy lacks: every agent action can pass wol mcp -> helper policy -> on-screen approval -> audit (crates/controller/src/mcp.rs, approve.rs, crates/core/src/automation/). The base must stay small and offline-installable; modules must never be mandatory and must stay pinned to the release.
Decision
- A module is one meta package
wolos-module-<id>in wolos-pkgbuilds (depends=on snapshot-pinned Arch and[wolos]packages, plus/usr/share/wolos/modules/<id>.jsonand config drop-ins), listed inpackages. Anything outside Arch or[wolos](Claude Code, PowerShell, Craft launcher, DaVinci) is never a pacman dependency: the module'senablestep installs it as the user through wopkg (recipe or AppImage, ADR 0021) or mise, so the sealed system stays sealed and no root is needed. - Registry
/usr/share/wolos/modules/<id>.json:{id, name, summary, icon, category, size_mb, packages, flatpaks, recipes, mise, post, offline, needs}read bywol_core::modules. Verbs:wol modules list|status(Read),wol modules install|remove(Admin, new capabilitymodules),wol modules enable(Change,apps). pacman is the truth for packages;$XDG_STATE_HOME/wolos/modules.jsonholds per-user enablement. - Three doors, one registry: (a) installer
Step::Modulesbetween Account and Summary (checkboxes, none pre-ticked, a "Downloads N MB" badge,Plan.modules);install-runinstalls ticked modules in its existing online step and queues the rest in/var/lib/wolos/modules-pending, whichfirstbootdrains like the NVIDIA driver; (b) Settings > Modules (toggle rows, same verbs); (c) App Store > Kits shelf, where a kit tile installs a set of apps or a module in one approval (the "Adobe kit" idea: the Kits concept is new). - Agents act through WolOS policy.
wolos-module-ai-claudeships/etc/claude-code/managed-settings.jsonallowing thewol mcpserver (not exclusive, so people keep their own servers), and itsenablestep runsclaude mcp add --scope user wolos -- wol mcpper user. Agents change WolOS only throughapprove::decide; every action appears in Settings > Assistants & Automation. The gate itself does not change. - Productive by default, jailed by default (lead, 2026-11-01: "AI needs to be productive; the system needs to disappear; not too limiting, also for lazy people"). The WolOS agent runs in a workspace jail that needs no configuration: a per-project directory tree (default
~/Work/<project>), its own$XDG_*dirs, network allowed, no access to the rest of$HOME, implemented with Landlock + seccomp + a mount namespace bywol jail run(the technical model is github.com/akitaonrails/ai-jail, whose UX we do not copy). Inside the jail the agent does not ask: file edits, builds, tests, reports and MCP calls to other servers are approved by the jail itself. One approval sheet appears only when the agent reaches outside: another directory (the sheet offers "add this folder to the project"), a system change throughwol(the existing gate), or a credential. Settings shows one switch, "Ask before every action", off by default.kleedolinux/claude-infinite(the lead's Claude memory tool) ships as part of ai-claude and is pre-wired so memory survives sessions. - Proprietary formats one click away, never default: a
codecsentry in the module registry (ffmpeg full, gst-plugins-ugly/bad, libdvdcss, Microsoft fonts) offered by the Store and by the "can't play this file" sheet of the media apps; not on the ISO, not pre-ticked in the installer. - Agent-generated extensions stay in the existing sandboxes: Lua widgets and ADR 0031 plugins. The ai-claude module ships a skill (
/usr/share/wolos/agents/skills/wolos/SKILL.md, linked into~/.claude/skillsand~/.agents/skills) documenting thewolverb tree, the plugin manifest andwol plugin check, so an agent can author and self-check a plugin without root. Installing a plugin stays a Change capability with an approval sheet. - Pinning. pacman dependencies are pinned by the snapshot. mise ships
/etc/mise/config.toml(global-only:lockfile=true,disable_backends=["asdf"],paranoid=["plugins","provenance"], no trusted project paths, python shims excluded) and a per-releasemise.lock; its registry is pinned by themisepackage version (registry_floating=false). Two vendor self-updaters are the deliberate exceptions, both user-side and vendor-signed, both labelled "updates on its own" in Software Update: Claude Code (stable channel, release manifest signature checked by the recipe) and the Craft launcher. - Security coexistence (ADR 0024, xguard): mise, Claude and wopkg write under
/home, which xguard scans on first exec. The dev module adds a mise postinstall hook that runswol-xguard scanon the install directory and tags files like a browser download. Interpreters stay the known gap and the copy says so. Models are data and are not scanned. - GPU for local AI reuses the hardware catalog:
wol hw compute --jsonreturns{backend: cuda|rocm|vulkan|cpu, vram_mb, gpu};wolos-module-ai-localdepends onollama(CPU) and installs the matching backend package (ollama-cudafor NVIDIA Turing+,ollama-rocmfor AMD gfx9+,ollama-vulkanotherwise). Settings shows the backend badge and a model picker sized by VRAM. - Sessions mean re-openable work:
{workspace, cwd, kind: terminal|agent, command, title}saved by wol-shell at logout to$XDG_STATE_HOME/wolos/sessions.json; at login the shell offers "Reopen windows from last time?" and relaunches each terminal (foot -D <cwd>, zellij attach) and agent (claude --continue) in its workspace. Multiplexing inside a boot is zellij, themed bywol theme. No process survives a reboot; layout, place and the conversation pointer do. - Console: zsh stays the default login shell. One prompt engine, starship, themed from the tokens (
toolkits/starship/palette.tomlwritten bywol theme), with the pure-zsh prompt kept as fallback. fzf history (Ctrl+R), zoxide, eza, bat, fd, ripgrep wired behindcommand -v. fish, nushell, bash and PowerShell (wopkg recipe from Microsoft's tarball; no Arch package) get the same keys, colours and history size from the same tokens. Settings > Modules > Console chooses the default shell and terminal (foot default; ghostty, kitty optional). - Developer: mise for every runtime (never pacman), git, gh, docker or podman as a choice (docker group opt-in), Code-OSS or Zed themed by
wol theme, lazygit and btop as floating TUI apps,~/Work. - Creative: the Arch creative set (Blender, GIMP, Krita, Inkscape, OBS, darktable, Kdenlive, Ardour, Audacity), fonts, colord with per-display ICC, a switchable low-latency PipeWire profile (
wol audio profile low-latency, Control Center toggle), DaVinci Resolve as a user-side wopkg recipe on NVIDIA/AMD only. - gpu-unlock is kernel work, not a module (lead's call):
Zagitta/gpu-unlock(GPL-2.0, out-of-tree, lifts NVIDIA GeForce tensor-core FP16/BF16/TF32 half-rate caps before the stock driver binds; Ampere stable, Ada/Turing experimental) is carried in-tree onwonderlandos/linuxwolos-7.3asdrivers/gpu/wolos_gpu_unlock/,CONFIG_WOLOS_GPU_UNLOCK=m, off by default. The NVIDIA firmware it depends on is never redistributed:wol hw boot --onlinefetches it into/usr/lib/firmware/wolos/gpu-unlock/and the module loads it withrequest_firmware(). Built in-tree it is signed like every module (ADR 0025). Settings > Hardware gets an experimental toggle writing/etc/modprobe.d/wolos-gpu-unlock.conf. It is a driver, recorded in SERIES.md as such, exempt from the "under 100 lines" patch rule. - Craft Suite (storytold) is a Store kit, not a module: the
craft-launcherAppImage (Apache-2.0/MIT, alpha, self-updating) installed user-side through wopkg with a pinned key, xguard-scanned; the launcher installs the Craft apps under the user. Not on the ISO.
Consequences
the base ISO does not grow. Every module is removable with pacman -R wolos-module-<id> plus wol modules remove for user-side parts. Each module gets a contract test in wolos-pkgbuilds/checks (dependencies exist at the snapshot) and a VM check in wolos-iso/tests. Rejected: everything on the ISO (3 to 6 GB more, not optional); Flatpak for everything (no CLI tools, no GPU compute, no mise); exclusive managed-mcp.json (blocks people's own servers); asdf plugins in mise (arbitrary shell); gpu-unlock as unsigned DKMS from AUR. Open for the lead: starship for all shells vs hand-written prompts; whether the two self-updaters are acceptable; the maintenance cost of carrying gpu-unlock in-tree against a small upstream.
Reference synced from wonderlandos/wolos docs/adr/0032-optional-modules.md.