Files
elizaos--eliza/packages/os/linux/docs/specs/phase-9-customization-actions.md
wehub-resource-sync 426e9eeabd
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Waiting to run
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Waiting to run
Build Agent Image / build-and-push (push) Waiting to run
Chat shell gestures / Chat shell gesture + parity e2e (push) Waiting to run
ci / test (push) Waiting to run
ci / lint-and-format (push) Waiting to run
ci / build (push) Waiting to run
ci / dev-startup (push) Waiting to run
Cloud Gateway Discord / Test (push) Waiting to run
Cloud Gateway Webhook / Test (push) Waiting to run
Cloud Tests / lint-and-types (push) Waiting to run
Cloud Tests / unit-tests (push) Waiting to run
Cloud Tests / integration-tests (push) Waiting to run
Cloud Tests / e2e-tests (push) Blocked by required conditions
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Deploy Apps Worker (Product 2) / Determine environment (push) Waiting to run
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Blocked by required conditions
Deploy Eliza Provisioning Worker / Determine environment (push) Waiting to run
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Blocked by required conditions
Dev Smoke / Classify changed paths (push) Waiting to run
Dev Smoke / bun run dev onboarding chat (push) Blocked by required conditions
Dev Smoke / Vite HMR dependency-level smoke (push) Blocked by required conditions
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Waiting to run
gitleaks / gitleaks (push) Waiting to run
Markdown Links / Relative Markdown Links (push) Waiting to run
Publish @elizaos/example-code / check_npm (push) Waiting to run
Publish @elizaos/example-code / publish_npm (push) Blocked by required conditions
Publish @elizaos/plugin-elizacloud / verify_version (push) Waiting to run
Publish @elizaos/plugin-elizacloud / publish_npm (push) Blocked by required conditions
Quality (Extended) / Homepage Build (PR smoke) (push) Waiting to run
Quality (Extended) / Comment-only diff guard (push) Waiting to run
Quality (Extended) / Format + Type Safety Ratchet (push) Waiting to run
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Waiting to run
Quality (Extended) / Develop Gate (lint) (push) Waiting to run
Sandbox Live Smoke / Sandbox live smoke (push) Waiting to run
Snap Build & Test / Build Snap (amd64) (push) Waiting to run
Snap Build & Test / Build Snap (arm64) (push) Waiting to run
supply-chain / sbom (push) Waiting to run
supply-chain / vulnerability-scan (push) Waiting to run
Build, Push & Deploy to Phala Cloud / build-and-push (push) Waiting to run
Test Packaging / Validate Packaging Configs (push) Waiting to run
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Waiting to run
Test Packaging / Pack & Test JS Tarballs (push) Waiting to run
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Waiting to run
UI Fixture E2E / ui-fixture-e2e (push) Waiting to run
UI Fixture E2E / fixture-e2e (push) Waiting to run
UI Story Gate / story-gate (push) Waiting to run
vault-ci / test (macos-latest) (push) Waiting to run
vault-ci / test (ubuntu-latest) (push) Waiting to run
vault-ci / test (windows-latest) (push) Waiting to run
vault-ci / app-core wiring tests (push) Waiting to run
verify-patches / verify patches/CHECKSUMS.sha256 (push) Waiting to run
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Waiting to run
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Waiting to run
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Waiting to run
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Waiting to run
Voice Benchmark Smoke / voice bench smoke summary (push) Blocked by required conditions
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Waiting to run
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Waiting to run
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Waiting to run
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Waiting to run
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Waiting to run
Test Packaging / Build & Test PyPI Package (push) Waiting to run
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

6.5 KiB

Phase 9 — Customization chat actions

"Install i3", "switch to tiling", "swipe-down for notifications", "dark theme" — all through chat, the bundled elizaOS app orchestrating Linux underneath. Each action should live in the app/runtime packages that are actually bundled into the ISO. Persistence-aware: customizations only stick in persistent mode.

Established pattern

An Action is { name, similes[], description, validate, handler, examples }. validate returns a bool from a text matcher; handler calls callback({ text, actions:[NAME] }) and returns { success, text, data }. System boundaries (spawn, apt) are injected via options so tests don't shell out. Multi-turn work uses a flow + dispatcher route. Actions register in the bundled runtime plugin/action registry.

What already exists — do NOT duplicate

  • SET_WALLPAPER (actions/wallpaper.ts) — THEME must not touch wallpaper.
  • INSTALL_PACKAGE + install-package-flow.ts + install-package-runner.ts — chat-driven apt-get install with a confirmation flow, package-name validation, curated PACKAGE_GROUPS (i3 desktop[i3, i3status, i3lock, dmenu, xterm], etc.), DANGEROUS_PACKAGES blocklist. This is the SHELL substrate — it already does the apt install.
  • OPEN_TERMINAL — the "drop me into a shell" escape hatch.
  • SETUP_PERSISTENCE + persistence-flow.ts — Phase 9 actions read persistence state, they don't manage it.

So: SHELL is a thin gating layer over the existing INSTALL_PACKAGE substrate; SET_DESKTOP / THEME / NOTIFICATIONS are genuinely new actions.

Shared prerequisite: runtime customization helper

Exports persistenceState(): "persistent" | "amnesia" (reads a marker the live system knows). Every Phase 9 handler calls it and appends a persistence-aware sentence: persistent → "this'll stick after reboot"; amnesia → "heads up — resets to defaults next boot; say 'set up persistence' to make it stick." Implements the PLAN "persistence-aware" requirement once.

Action 1 — SHELL (superseded security note)

The earlier passwordless sudo/polkit direction below is not accepted for the current product security model. Production must route privileged package, service, network, and device operations through the elizaOS capability broker with named commands, exact argument schemas, user approval or enterprise policy, and audit events. Do not add passwordless apt-get sudoers for the desktop user.

Action 1 — SHELL (legacy sketch, not accepted as-is)

File: app/runtime action module for SHELL. validate defers to INSTALL_PACKAGE when install intent is present (returns false) so package installs keep going through the confirmation flow; SHELL handles the non-install privileged commands ("update the package list", "remove i3", "enable bluetooth service"). validate matches a curated verb→command-template allowlist (not free-form shell — charset-validated args, array-spawn, no shell metacharacters). handler shells via an injectable spawnFn.

This sketch is useful only as app-side intent parsing. The privileged execution half is superseded by the capability-broker policy above.

Rejected legacy polkit/sudoers direction (do not implement without a new approved broker policy):

  • TAILS/config/chroot_local-includes/etc/polkit-1/rules.d/org.elizaos.shell.rules — grants the desktop user Result.YES for the relevant systemd / packagekit actions (pattern from Tails' org.boum.tails.additional-software.rules).
  • TAILS/config/chroot_local-includes/etc/generate-sudoers.d/elizaos-shell.toml — a [[commands]] block (pattern from tps.toml) granting the desktop user NOPASSWD on /usr/bin/apt-get + a wrapper with a fixed arg allowlist. This makes the agent's existing sudo apt-get passwordless.

Action 2 — SET_DESKTOP

File: app/runtime action module for SET_DESKTOP. similes switch to i3, use sway, tiling desktop, etc. validate matches verb + a known-WM token. Composes INSTALL_PACKAGE: if the WM's packages aren't installed, hands off to beginInstallPackageFlow(), then on the follow-up turn writes session config. System surface: writes ~/.dmrc / an AccountsService user-session key naming the .desktop session file in /usr/share/xsessions/ or /usr/share/wayland-sessions/ — additive, never modifies Tails' GDM hooks.

Action 3 — THEME

File: app/runtime action module for THEME. similes dark theme, make it dark, etc. Distinct from SET_WALLPAPER — THEME is GTK theme + dotfiles, no image generation. handler writes gsettings set org.gnome.desktop.interface gtk-theme/color-scheme and/or ~/.config/gtk-{3,4}.0/settings.ini. Curated theme set should preserve the current blue/white elizaOS theme and may add optional dark variants later. Writes to ~/.config/elizaos/ (already in Phase 7's persistence dir list).

Action 4 — NOTIFICATIONS

File: app/runtime action module for NOTIFICATIONS. similes swipe down for notifications, android-style notifications, install swaync, etc. Like SET_DESKTOP, composes install-package-flow if swaync/the GNOME shell extension isn't installed, then writes config (~/.config/swaync/config.json, or gnome-extensions enable).

Plugin registration

  • Add all 4 to the bundled runtime action registry.
  • SET_DESKTOP + NOTIFICATIONS reuse the existing install-package-flow for the multi-turn install handoff — no new flow files.
  • Update HELP_ACTION reply text in actions/system.ts.

Documentation

New file ./docs/customization-vocabulary.md — the full chat command set (every simile for the 4 actions, the WM/theme/ notification options) + the "amnesia vs persistent" note.

Ordered implementation checklist

  1. Runtime customization helper — persistenceState() + the reply helper.
  2. Define broker-backed privileged commands with exact schemas, approval prompts, audit events, and tests; do not add passwordless apt sudoers.
  3. actions/shell.ts — defers to INSTALL_PACKAGE on install intent and calls only approved broker commands for privileged work.
  4. actions/set-desktop.ts — composes install-package-flow, writes ~/.dmrc additively.
  5. actions/theme.ts — GTK theme + ~/.config/gtk-* / ~/.config/elizaos/.
  6. actions/notifications.ts — composes install-package-flow, writes notification config.
  7. Register all 4 in plugin.ts; update HELP_ACTION.
  8. Unit tests in the owning runtime package (inject fake spawnFn, assert no shell-out, assert persistence-aware reply branches).
  9. Write docs/customization-vocabulary.md.