コンテンツにスキップ

Clone and build from source

このコンテンツはまだ日本語訳がありません。

This page is for people who keep a checkout of the repository: contributors, plugin authors, and anyone who wants to read the code before running it. The instructions below are for Linux; the macOS side is covered in macOS.

Terminal window
git clone https://github.com/sujaisubbanna/utter-assistant.git
cd utter-assistant

The same wizard as the remote installer runs from the repository root:

Terminal window
./install.sh --dry-run # walk the wizard, print the plan, change nothing
./install.sh # install the components you choose
./install.sh --uninstall # undo it

install/install.sh is the minimal alternative: distro packages and the runner service, nothing else. By default it only prints what it would do.

Terminal window
install/install.sh --dry-run # default: print exactly what it would do
install/install.sh --yes # actually install deps + enable the runner unit
install/install.sh --yes --no-deps # skip distro packages, only wire the service

What it does:

  1. Detects the distro from /etc/os-release (ID and ID_LIKE) and picks pacman, apt, dnf or zypper (falling back to command -v).
  2. Installs the system dependencies, name-mapped per distro: wtype, ydotool (and ydotoold), grim, wl-clipboard, pipewire, webkit2gtk-4.1 and libsoup-3.0 for the Tauri settings app, and optionally keyd. AT-SPI accessibility (python-gobject + at-spi2-core) is optional and degrades gracefully.
  3. Checks the input group and /dev/uinput, and prints the usermod -aG input, udev and re-login steps. It never silently changes groups.
  4. Installs and, with --yes, enables the user service utter-runner.service, bound to the graphical session via the scripts/utter-wayland-ready.sh wrapper.
  5. Records what it did in $XDG_STATE_HOME/utter/install.json so it can be reversed.
  6. Runs python -m assistant doctor --json (or recommend --json) to verify.

Uninstall:

Terminal window
install/uninstall.sh --dry-run
install/uninstall.sh --yes # stop/disable units, remove recorded files
install/uninstall.sh --yes --purge # also remove models + config

Package removals are printed, never performed automatically.

The runner is a systemd user unit. User services do not inherit the session environment, so the unit runs through scripts/utter-wayland-ready.sh, which discovers WAYLAND_DISPLAY, DBUS_SESSION_BUS_ADDRESS and NIRI_SOCKET before starting the runner.

UnitPurpose
utter-runnerthe modular runner (plugin supervisor), installed by the installer
utter-bridgelegacy Python assistant (voice→action), for older installs
utter-visionvLLM UI-TARS grounding server (:8000)
utter-plannervLLM planner (:8001)
utter-audio-defaultskeeps the chosen output and denoised input pinned

Only the runner unit (and the legacy utter.service plus ydotoold.service) ship in the repository. The vision, planner and audio-defaults units are conveniences on the reference machine; the scripts they wrap (scripts/serve_vision.sh, scripts/serve_planner.sh, scripts/utter-audio-defaults.sh) are in the repo, and you can turn them into units yourself. See Configuration for the shipped unit files.

Terminal window
systemctl --user status utter-runner.service
journalctl --user -u utter-runner.service -f

Clients such as the settings app and the Noctalia widget connect to the runner at $XDG_RUNTIME_DIR/utter/runner.sock.

Terminal window
python -m assistant doctor [--json] # deps + plugin negotiation + drift
python -m assistant recommend [--json] # hardware-aware profile suggestions
python -m assistant models list|show <n>|pull <src>|rm <n>|prune [--json]
python -m assistant status [--json] # runner.status passthrough
python -m assistant install-state record|show

doctor --json includes a deps section (which CLI tools and libraries are present) alongside, per plugin, the negotiated protocol version, unknown capabilities, missing requirements and the list of permissions with whether each is enforced or advisory. The full command reference is on The assistant CLI.

Models live in an Ollama-style, XDG-compliant store:

$XDG_DATA_HOME/utter/models/ # override with UTTER_MODELS
manifests/<host>/<ns>/<name>/<tag>.json
blobs/sha256-<hex>
  • Sources: hf:org/repo[:file] resolves to the Hugging Face resolve/main URL; bare https:// URLs and local file:// paths also work.
  • Pulls are resumable (partial file plus curl -C -, or urllib Range), with retry and backoff, SHA-256 verification, an atomic rename, a pull lock and a disk-space preflight.
  • rm drops the manifest and any now-unreferenced blobs; prune collects orphans.

Models are your choice. The installer never downloads one. assistant recommend suggests a profile for your GPU and RAM; you pull what you want. See the Models guide.

The assistant core is stdlib-only Python, so you can run it directly:

Terminal window
# route a command without executing it (prints the plan)
python3 -m utter.daemon --text "open youtube" --dry-run
# the full verification: runner unit tests, socket e2e, conformance
scripts/verify.sh

The dry run is the fastest way to check what a phrase would do. The utter_py plugin defaults UTTER_DRY_RUN to on, so only UTTER_DRY_RUN=0 touches the desktop.

The settings app is Tauri v2 + React + Tailwind CSS v4. It needs Rust 1.90+, Node 22+ with pnpm, and the webkit2gtk-4.1 and libsoup-3.0 libraries.

Terminal window
cd gui-tauri
pnpm install
pnpm tauri build # release binary + .deb in src-tauri/target/release[/bundle]
pnpm tauri dev # dev mode with hot reload

For a quick binary without bundling:

Terminal window
pnpm build # frontend -> dist/
cd src-tauri
cargo build --release --features custom-protocol

The custom-protocol feature embeds the built frontend. Without it, Tauri treats the build as dev and expects the Vite server on http://localhost:1420.

Run a built binary directly:

Terminal window
WEBKIT_DISABLE_DMABUF_RENDERER=1 ./src-tauri/target/release/utter

Two environment variables help with screenshots and testing: UTTER_GUI_ROUTE (for example voice) forces the initial page and UTTER_GUI_THEME (light, dark or system) forces the theme.

If you run the Noctalia shell, there is an optional widget package at widgets/noctalia/ (bar widget, persistent attention panel and assistant OSD). It is not installed by default.

Terminal window
widgets/noctalia/install.sh # copy + lint
widgets/noctalia/install.sh --yes # + enable and add the bar widget
./install.sh --with-noctalia # via the main installer

Skip it entirely if you do not use Noctalia. The core assistant does not depend on it. See Noctalia widget and OSD.

Start from plugins/fake_py/ (Python) or plugins/fake_rs/ (Rust) and read Writing a plugin.