Niri Plus / Agent instructions
Agent setup guide
Agent-guided setup is the recommended way to install Niri Plus. Give this operational guide to your agent; it will inspect the target, adapt the setup to your choices and verify each stage. A plain Markdown version is available to share directly. The setup overview explains the desktop and its choices.
Agents: follow the numbered stages in order and open each linked recipe before applying its part.
Arch reference install target: components 0.4.3 and SwayNC 0.12.6-18 from fork release 1. It includes direct Network, Audio and Bluetooth controls, a pure-black workspace, the selected Neutral Slate appearance and the unified full-height information panel. Its authored profile uses width 448, zero margins, ungrouped notifications, a bold clock and inline Do Not Disturb control. The fresh-Arch installation and routine-task qualification is described under verified scope and in the dated receipt. The previous 0.4.1 guide at source revision 4672016 and its dated replay receipt remain historical.
Execution contract
The target is one user-authorized Arch Linux x86-64 machine with an installed OS, an ordinary sudo-capable account and working package/network access. The reference includes the browser, terminal, appearance and everyday desktop services below. OS installation, partitioning, Ubuntu/Debian, authenticated agent tools and personal fleet deployment are outside this route.
Before changing anything, establish the account/home, OS and package versions, local or SSH access, active graphical session, current display manager, network manager, portal/secret providers and configuration authority. Inspect existing files, units and startup owners. If the target is already managed by chezmoi or another tool, change that source within the user's requested scope; do not apply fresh-account copies over its deployed files.
When the user wants selected pieces or an existing setup adapted, apply only that scope and record the other stages as out of scope. Do not reset a working desktop to recreate the fresh-install tests. The commands below are individual reviewed steps, not one batch script; use your file-reading tools for inspection steps such as the PKGBUILD review.
Keep a small execution record outside the source checkout:
- Target and reviewed source revision; existing owners and package baseline.
- Files to merge or create, backups/preimages and recovery access.
- User choices: actual output profiles/scales, keyboard/input languages, browser preferences, and idle/locking/suspend policy. A reference example is a choice to review, not permission to replace an existing preference.
- Per-stage result: passed, failed, unavailable hardware, or awaiting human action, with the actual observation and any restoration still required.
Use the user's existing authorization for the agreed setup. Ask only for missing choices, credentials through their native prompt, or a disruptive transition that is not already authorized. Keep the current console/SSH recovery path working. Coordinate display-manager handover, network handover, logout and reboot with active work; do not restart an occupied SDDM session. Do not read passwords from private files or put them in chat, clipboard history, logs or captures. Browser terms/account choices and password prompts require the user's native interaction unless a disposable test account and an explicit input mechanism were supplied for that test.
Do not continue past a failed gate or substitute another compositor, portal family, secret backend or package pin to hide a failure. Diagnose and record it, restore the affected scope when needed, and return the unresolved decision. Source checks, installed files, a running service and a completed native task are different observations. Missing hardware and human-only checks remain explicit; they are not passes.
Inputs and working directory
Use a reviewed checkout of Niri Plus
containing this guide, its input inventory and scripts/stage-arch-reference.py.
Record its revision before starting. The input stager and authored SwayNC
reference profile are checkout files, separate from the published components
0.4.3 archive and the pinned public examples. If a specific revision or source
export was supplied, use that exact source; do not substitute an older component
archive or a private machine's configuration.
This walkthrough starts from an installed Arch Linux x86-64 system, an ordinary sudo-capable user, working networking, and package access. It does not install Arch, partition disks, copy a private home directory, or use a display-free capture login. Keep a working console login and, when available, SSH recovery while changing the desktop. File-copy commands assume new target names. Inspect existing config and unit paths first; back them up and merge when they already contain your choices. Run the following commands from the reviewed Niri Plus checkout root and keep that path in a task-specific variable; package builds below change directories:
export NIRI_PLUS_CHECKOUT="$PWD"
test -f "$NIRI_PLUS_CHECKOUT/tools/reference/inputs.json"
The selected reference is Neutral Slate with Clear Blue focus, a pure-black workspace and Balanced+ Kitty palette, and Noto Sans/Meslo typography. Its overview retains a charcoal surround so empty black workspaces have visible boundaries. The session uses SDDM and Niri, GTK portals for file/access/settings/notification interfaces, WLR for whole-monitor capture, and the pinned SwayNC fork for the on-demand dashboard. The focused recipes retain the details for each part.
Niri Plus first-party code is covered by the repository LICENSE, and bundled design assets are indexed in assets/LICENSES.txt. The pinned SwayNC fork keeps its GPL-3.0 terms in the notification source recipe; fetched Zsh dependencies include their own third-party notices. Chrome, fonts, GTK themes, and icon themes remain governed by their upstream terms and package notices; Chrome presents its own terms on first run.
Verified scope: the numbered 0.4.3/SwayNC 0.12.6-18 route and 21 mapped routine native task groups completed through the independent fresh replay starting on 2026-11-08 from an untouched installed Arch base, with later checkpoint-copy supplements recorded separately. Cold wallet lookup and warm/cold monitor sharing passed; sharing used the documented conditional VirtIO portal candidate after a bounded stock failure. The dated qualification records exact inputs, evidence limits and the separate physical-host checklist. The VM suspend/resume check is waived at Bryan's request, with its failed observations retained. Optional extensions remain independent. Historical media and the earlier 0.4.1/package 17 receipts retain their dates. Recheck every task on a new target.
1. Prepare the account and record the starting state
Confirm that you are an ordinary user with sudo access and can recover from a
console. Record the current network owner before installing or enabling another
manager. The development copy used systemd-networkd and systemd-resolved;
do not enable NetworkManager until its handover has a tested recovery route.
id
sudo -v
ip route
systemctl is-active systemd-networkd.service systemd-resolved.service NetworkManager.service || true
systemctl --user status || true
Apply Arch's normal full upgrade, then reboot if the transaction asks for it:
sudo pacman -Syu
Record the package baseline with pacman -Q before continuing. Arch package
versions move independently of the pinned Niri Plus source inputs.
Stage 1 gate: Record the target, existing owners, recovery path, package baseline and upgrade result. Resolve an unexpected starting state before starting another network manager or display manager.
2. Stage the reviewed inputs
The first-party helper and its input inventory are checkout source files in the
Niri Plus checkout containing this guide; the helper is not part of the
published 0.4.3 component archive. It runs as your user and writes only into a
new output tree. It verifies the immutable component archive, its manifest and
all 44 payloads; the independently pinned identity; and the listed public
examples from source commit
07cf4a393314c195ace7e66d162f21d3a2f73136.
It then renders appearance previews and writes provenance.json with the input
and output hashes. It does not install packages, write normal configuration,
start services, or import capture-pilot state.
Install the staging prerequisites and set a new output path once. If the
example path already exists, keep it and choose another name for STAGE:
sudo pacman -S --needed curl git less python unzip
mkdir -p "$HOME/.local/share/niri-plus"
export STAGE="$HOME/.local/share/niri-plus/arch-reference-0.4.3"
python3 "$NIRI_PLUS_CHECKOUT/scripts/stage-arch-reference.py" \
--inputs "$NIRI_PLUS_CHECKOUT/tools/reference/inputs.json" \
--output "$STAGE"
Set these paths for the commands below:
export SOURCE="$STAGE/source"
export BUNDLE="$STAGE/bundle"
export APPEARANCE="$STAGE/appearance"
Inspect $STAGE/provenance.json. The source checkout is used only to provide
the selected public examples; the staged components and previews remain
self-contained. The authored SwayNC reference.json described later is a
separate reviewed checkout input and is deliberately not fetched from the
pinned public snapshot.
Stage 2 gate: The new staging tree has a verified provenance record, component payloads and rendered appearance. Record its exact paths and hashes. An existing or failed staging output is not a successful new stage.
This numbered route selects only the components 0.4.3 reference pin. Manual display-away is an optional post-reference branch with its own 0.5.0 input pin; it is not part of this stage or the required reference acceptance.
3. Install the first-session packages
Install Niri, SDDM, the selected portal providers, and the basic window, terminal, and launcher tools. The SDDM package supplies its Xorg server and authentication dependencies; this reference does not require KWin.
sudo pacman -S --needed \
niri xwayland-satellite sddm qt6-declarative qt6-svg \
kitty rofi dolphin \
xdg-desktop-portal xdg-desktop-portal-gtk xdg-desktop-portal-wlr \
noto-fonts noto-fonts-emoji ttf-meslo-nerd
The pinned public Niri starter is proportional and contains no personal paths, automatic suspend policy, or session startup hooks. Inspect it and preserve any existing configuration before installing. On the fresh account, install the starter only when neither target exists:
if [ -e "$HOME/.config/niri/config.kdl" ] || [ -L "$HOME/.config/niri/config.kdl" ] ||
[ -e "$HOME/.config/xdg-desktop-portal/niri-portals.conf" ] ||
[ -L "$HOME/.config/xdg-desktop-portal/niri-portals.conf" ]; then
printf '%s\n' 'Existing Niri or portal config found; inspect and merge the staged examples.'
else
install -Dm644 "$SOURCE/examples/niri/config.kdl" "$HOME/.config/niri/config.kdl" &&
install -Dm644 "$SOURCE/examples/portals/niri-portals.conf" \
"$HOME/.config/xdg-desktop-portal/niri-portals.conf" &&
niri validate --config "$HOME/.config/niri/config.kdl"
fi
The Niri starter has no PATH override. Before the first login, make later
user-local launchers discoverable. Print the account's absolute home path and
merge the line into a top-level Niri environment block; create that block if
absent. Do not put ~ or $HOME in the KDL value. If you already customize
PATH, retain its other required directories:
printf 'PATH "%s/.local/bin:/usr/local/bin:/usr/bin"\n' "$HOME"
This sets the environment of Niri-spawned apps, including Rofi, clipboard and device controls, feedback helpers and Kanshi. It does not replace the systemd user-manager environment. Validate the merged config before login:
niri validate --config "$HOME/.config/niri/config.kdl"
The portal profile selects GTK for file/access/settings/notification interfaces and WLR for whole-monitor capture. Individual-window capture remains outside this reference. If a VirtIO/VirGL guest reproduces the documented whole-monitor failure with the Arch portal package, the optional local compatibility candidate explains its reviewed build and recovery path. It is not required on a physical desktop or where the stock portal works.
Stage 3 gate: The complete Niri config validates; the intended portal configuration is installed or deliberately merged. Keep the existing login owner and recovery path until the next planned transition.
4. Verify stock SDDM password login before theming
Check that no other display manager owns the login path. Keep the distribution's SDDM/PAM configuration unchanged for this first login. From a local console, enable and start SDDM:
sudo systemctl enable --now sddm.service
Select Niri in the greeter and log in with the account password. Verify the session and user manager:
loginctl show-session "$XDG_SESSION_ID" -p Type -p State
systemctl --user is-active niri.service graphical-session.target
Log out to SDDM and log in again. If the greeter or session fails, return to the
console, inspect journalctl -b -u sddm.service, and restore the previous
display-manager owner. Do not add a PAM module, autologin drop-in, or theme to
repair the stock login gate.
Stage 4 gate: Actual stock password login, logout to the greeter and relogin work. Record the Niri/graphical-session owners. A greeter preview or successful SSH login does not satisfy this gate.
5. Add the reference appearance and browser/files
Install the application, appearance, input, audio, and session prerequisites in one reviewed package transaction. NetworkManager and BlueZ remain installed only; do not enable them until their actual device/service handovers are ready.
sudo pacman -S --needed \
adw-gtk-theme ark base-devel bluez bluez-utils brightnessctl \
breeze breeze-cursors breeze-icons cliphist dconf fcitx5 \
fcitx5-chinese-addons fcitx5-configtool fcitx5-gtk fcitx5-qt \
fontconfig fzf python-gobject nm-connection-editor gsettings-desktop-schemas gtk3 gtk4 gtk4-layer-shell \
gwenview kanshi kwallet kwallet-pam libadwaita libgee libnotify libsecret \
libpulse json-glib granite7 mpv neovim networkmanager pavucontrol \
pipewire pipewire-audio pipewire-pulse polkit polkit-kde-agent qt5-wayland qt5ct \
qt6-wayland qt6ct shared-mime-info swayidle gtklock upower udisks2 \
wl-clipboard wireplumber xdg-utils zoxide zsh adobe-source-han-sans-cn-fonts
base-devel and the GTK4 libraries above are for the pinned SwayNC package
recipe. Do not install upstream swaync separately. Add nvidia-utils only
when the host has supported NVIDIA hardware.
Use the rendered files under $APPEARANCE as appearance-only layers. The
appearance recipe gives ordinary GTK3, Qt5/Qt6, KDE,
Rofi, Kitty, and Gtklock targets, the fonts.json and kdeglobals-managed.json
merge, a reversible GSettings profile for GTK appearance, and the Qt-only
systemd user-service environment profile. The pavucontrol GTK4 dark-surface
check passed through the selected GSettings preference with GTK_THEME unset.
The notification recipe owns the selected SwayNC stylesheet target. Merge the
Niri fragment's layout settings into the starter's existing layout block
and add its separate top-level overview block, keep its proportional
columns and bindings, and validate the complete file after each change. Use the
login recipe to preview the pinned greeter theme and install
it only after the stock password login passed. Use the matching renderer
outputs in $APPEARANCE; do not download or copy a second palette snapshot.
The transaction above includes the file tools. Follow the files recipe
to install the Neovim desktop entry only when absent and apply the staged MIME
defaults with xdg-mime, which leaves unrelated associations intact.
The reference browser is Chrome. Its Arch recipe is pinned at commit
f0071e0692f4545bcb3e0881ea60c031a9f99343 for version 156.0.8078.47:
CHROME_BUILD=$(mktemp -d "$HOME/.local/share/niri-plus/chrome-build.XXXXXX")
git clone https://aur.archlinux.org/google-chrome.git "$CHROME_BUILD"
git -C "$CHROME_BUILD" checkout --detach f0071e0692f4545bcb3e0881ea60c031a9f99343
test "$(git -C "$CHROME_BUILD" rev-parse HEAD)" = f0071e0692f4545bcb3e0881ea60c031a9f99343
less "$CHROME_BUILD/PKGBUILD"
cd "$CHROME_BUILD"
makepkg --verifysource
makepkg --syncdeps --rmdeps
Inspect the exact generated google-chrome package with pacman -Qip and
install that file with sudo pacman -U. Record the recipe revision and
installed package version. Launch Chrome normally from Mod+D for its first
run. Review its terms and browser-default/telemetry choices yourself, and leave
the browser signed out. Do not pass first-run suppression flags or reuse an
isolated lab profile. Use disposable PDF, image, audio/video, and archive
samples to check defaults, browser download/open/upload, and safe archive
extraction. After stage 7 supplies authorization, check UDisks mounting with
a new explicitly authorized disposable disk for read/write/unmount.
Stage 5 gate: The selected GTK, Qt/KDE, Rofi, Kitty and greeter layers come from the same staged identity. Inspect real application surfaces and validate Niri after merging. Record Chrome's source/package, the user's first-run choices and actual file-default tasks; keep account state local.
6. Install the selected notification and clipboard paths
The full dashboard requires the pinned swaync-bryan fork. Follow the
notification recipe to review and build its exact
recipe/source tuple as an ordinary user, inspect the package, and install the
replacement transaction. The candidate dashboard config is a small authored
file in this source checkout; verify its recorded hash before copying it. Use
$APPEARANCE/swaync.css for the selected stylesheet.
For text and image clipboard history, use the generated minimal-Niri service
and its paired 200-item Cliphist config. The clipboard recipe
has the exact targets and niri.service wants. Do not combine it with the
separate portable collector unit.
Network, Audio and Bluetooth use direct Rofi controls from the verified bundle. Session keeps its existing helper. Install the complete controls library, wrappers and derived appearance before installing their launcher entries. NetworkManager, the audio server and BlueZ retain device ownership; opening a menu does not start a missing provider or change a connection.
The Niri starter binds Mod+D to the normal Rofi application list. Preserve it
or merge this line into an existing Niri binds block when it is absent:
Mod+D { spawn "rofi" "-show" "drun"; }
Use Network after NetworkManager owns the link. The
network owner handover
is a narrow conditional example for the exact cloud-init/networkd starting
state; a system already owned by NetworkManager skips it. Package installation
does not start BlueZ. Start the packaged bluetooth.service only when an
adapter is present and ready; do not run a second daemon. The Bluetooth menu
reports absent hardware or an unavailable provider without silently enabling it.
Retain nm-connection-editor, pavucontrol, nmtui and bluetoothctl as native
advanced settings and recovery tools.
PipeWire and WirePlumber keep their packaged socket/session ownership. If their packages were installed after this user manager was already running, start the standard units for the current session before checking audio:
systemctl --user start pipewire.socket pipewire-pulse.socket wireplumber.service
systemctl --user is-active pipewire.socket pipewire-pulse.socket wireplumber.service
wpctl status
Install the shared launcher helper and entries:
install -Dm755 "$SOURCE/examples/desktop/desktop-session-ready" \
"$HOME/.local/bin/desktop-session-ready"
install -Dm755 "$SOURCE/examples/desktop/desktop-session-menu" \
"$HOME/.local/bin/desktop-session-menu"
install -d -m755 "$HOME/.local/bin" "$HOME/.local/lib/niri_plus_controls"
for helper in desktop-controls desktop-network-menu desktop-audio-menu desktop-bluetooth-menu; do
install -m755 "$BUNDLE/components/desktop/bin/$helper" "$HOME/.local/bin/$helper"
done
for module in "$BUNDLE"/components/desktop/lib/niri_plus_controls/*.py; do
install -m644 "$module" "$HOME/.local/lib/niri_plus_controls/"
done
install -Dm644 "$APPEARANCE/niri-plus-controls.rasi" \
"$HOME/.config/rofi/niri-plus-controls.rasi"
install -Dm644 "$APPEARANCE/controls-appearance.json" \
"$HOME/.config/niri-plus/controls-appearance.json"
python3 -c 'import gi; gi.require_version("NM", "1.0"); gi.require_version("Secret", "1"); from gi.repository import NM, Secret, Gio'
install -Dm644 "$BUNDLE/components/desktop/share/applications/niri-plus-network.desktop" \
"$HOME/.local/share/applications/niri-plus-network.desktop"
install -Dm644 "$BUNDLE/components/desktop/share/applications/niri-plus-bluetooth.desktop" \
"$HOME/.local/share/applications/niri-plus-bluetooth.desktop"
install -Dm644 "$BUNDLE/components/desktop/share/applications/niri-plus-audio.desktop" \
"$HOME/.local/share/applications/niri-plus-audio.desktop"
install -Dm644 "$SOURCE/examples/desktop/niri-plus-session.desktop" \
"$HOME/.local/share/applications/niri-plus-session.desktop"
Check the graphical session's PATH resolves all four installed wrappers and
that each menu opens through the application list. In each landing list,
Tab/Shift+Tab cycle Open and Details; Enter runs the visible action. Back restores
the filter and selection, and Escape/Ctrl+G closes the menu. The
controls recipe records credentials, pairing,
advanced-tool and recovery behavior. A VM without wireless hardware verifies
its unavailable state, not physical Wi-Fi or Bluetooth operation.
The desktop-utility recipe records Session and
the older recovery entry points. Use the hardware-feedback recipe to
install both helpers from SOURCE and merge all six hardware-key binds from the
verified fragment into the existing Niri binds block.
Stage 6 gate: One notification owner, two paired clipboard collectors, and the intended launcher entries are installed. Exercise the panel, exact text/image restore and Delete/Cancel/Clear. Open each actual controls entry; check device state, named actions, Details, Back and cancellation. Exercise available audio output/input separately and record absent Wi-Fi/Bluetooth. Check feedback only on available devices. Native providers retain ownership.
7. Wire wallet, policy, and authorization services
Keep one owner for each function. Choose and record the power policy. Reuse the readiness helper installed in section 6, and install the reviewed units into ordinary user paths:
install -Dm755 "$SOURCE/examples/session/desktop-power" \
"$HOME/.local/bin/desktop-power"
install -Dm644 "$SOURCE/examples/session/profiles/minimal-niri/desktop-lock.service" \
"$HOME/.config/systemd/user/desktop-lock.service"
install -Dm644 "$SOURCE/examples/session/desktop-idle.service" \
"$HOME/.config/systemd/user/desktop-idle.service"
install -Dm644 "$SOURCE/examples/session/desktop-battery.service" \
"$HOME/.config/systemd/user/desktop-battery.service"
install -Dm644 "$SOURCE/examples/session/polkit-session.conf" \
"$HOME/.config/systemd/user/plasma-polkit-agent.service.d/session.conf"
On the development copy, /etc/pam.d/sddm already contained the package's
optional pam_kwallet5 auth/session entries. The KWallet PAM package and Niri
unit wiring were added after the initial stock login, so only a later fresh
password login tested their handshake. Keep the installed PAM file unchanged;
inspect it and the kwallet-pam package on a new system rather than copying
another machine's file. Wire the packaged PAM initialization unit to the Niri
graphical session with this user drop-in and one Niri wants link:
mkdir -p "$HOME/.config/systemd/user/plasma-kwallet-pam.service.d"
cat > "$HOME/.config/systemd/user/plasma-kwallet-pam.service.d/session.conf" <<'EOF'
[Unit]
After=graphical-session.target
Requisite=graphical-session.target
EOF
systemctl --user add-wants niri.service plasma-kwallet-pam.service
Merge this preference into the existing Niri portal configuration so the KWallet backend owns the Secret portal for this reference setup:
[preferred]
org.freedesktop.impl.portal.Secret=kwallet;
Finish the appearance and input steps in section 8 before testing the wallet.
The KWallet PAM package and packaged Fcitx5 autostart both need a fresh login
after installation. Do not run secret-tool from the earlier stock-login
session.
Before installing the idle service, review
$SOURCE/examples/session/power.toml.example, choose values, and save the full
policy to ~/.config/desktop-session/power.toml. Do not start the policy helper
with a missing or unreviewed policy. Verify the units and add only the idle,
battery, polkit, and KWallet PAM services to Niri; the manual lock unit stays
on-demand:
systemctl --user daemon-reload
systemd-analyze --user verify \
"$HOME/.config/systemd/user/desktop-lock.service" \
"$HOME/.config/systemd/user/desktop-idle.service" \
"$HOME/.config/systemd/user/desktop-battery.service" \
plasma-polkit-agent.service plasma-kwallet-pam.service
if ! systemctl is-active --quiet polkit-agent-helper.socket; then
sudo systemctl start polkit-agent-helper.socket
fi
systemctl --user add-wants niri.service \
desktop-idle.service desktop-battery.service plasma-polkit-agent.service \
plasma-kwallet-pam.service
systemctl --user daemon-reload
systemctl --user start \
desktop-idle.service desktop-battery.service plasma-polkit-agent.service
These are candidate Niri session wires; verify one instance at login and clean teardown at logout using the session recipe. The packaged PipeWire/WirePlumber user services retain their native activation; do not add Niri spawns or duplicate units for them. Fcitx5's packaged XDG autostart and the BlueZ daemon keep their own owners. Do not start a second SwayNC, clipboard, audio, or input-method process from Niri.
When polkit was installed after sockets.target had started, the static helper
socket may still be inactive for this boot. Starting the packaged
polkit-agent-helper.socket activates its native route; it is normally socket
activated after boot, so do not enable the static unit or change its packaged
permissions. Run a graphical pkexec /usr/bin/true check and authenticate to
confirm the prompt and allow path. Cancelling denies the action; the
fresh-replay test returned 127 on cancel and 0 after authentication, with
the packaged polkit files unchanged.
The KWallet/Secret Service path, manual Gtklock password check, SDDM-session lock request, idle restart with an existing locker, polkit prompt/allow path, native Chrome/Kitty input composition, and guest playback through its virtual HDA device passed the fresh-guide replay. Physical/SPICE audibility and microphone signal are not established. Restart cancellation preserved the same boot ID; confirmed Restart rebooted the guest, and confirmed Shut down powered it off. A later full power-on, logout and relogin restored the expected owners.
Stage 7 gate: Units verify, the full power policy is explicitly chosen, and startup ownership has no duplicates. Test real polkit cancel/allow and manual lock rejection/unlock. Keep the locker alive during an idle reload. Complete stage 8 and its fresh password-login gate before testing the wallet.
8. Add display, input, audio, and shell workflows
Kanshi has no packaged user unit in the current Arch snapshot. Adapt
$SOURCE/examples/displays/kanshi.conf to the actual outputs, then use the
single startup owner described in the display recipe.
The installed Fcitx5 package has its own XDG autostart desktop entry. Niri's
packaged session starts xdg-desktop-autostart.target; verify
app-org.fcitx.Fcitx5@autostart.service and one fcitx5 process after the
fresh login described below.
Do not add a Niri fcitx5 -d spawn or a second user service. The
input recipe supplies a guarded
fresh-account profile for keyboard-us, Pinyin, US layout, and Super+Space.
Use fcitx5-configtool when modifying an existing profile.
For direct Niri-launched applications, merge these values into the existing
Niri environment block and validate the complete config:
environment {
QT_IM_MODULE "fcitx"
XMODIFIERS "@im=fcitx"
SDL_IM_MODULE "fcitx"
}
QT_IM_MODULE is for Qt clients using Fcitx under Niri; XMODIFIERS is for
XIM clients under X11/XWayland; retain SDL_IM_MODULE for SDL2 clients.
Leave GTK_IM_MODULE unset globally. Niri's environment block does not change
the systemd user-manager environment; the appearance recipe's environment.d
file covers user services only. See the Fcitx Wayland guide
for toolkit-specific behavior.
Keep the user-local PATH configured in stage 3 when merging these environment
values; do not replace the existing block.
Fresh-guide checks passed for native composition in Chrome 156
launched with --ozone-platform=wayland only and Kitty 0.49.2 using native
Wayland text input. Preedit, cancellation, candidate selection, commit, and
Super+Space Latin switching worked; the candidate popup followed fields at
scale 1.5. See the receipt for exact committed text and versions. Do not
add GTK_IM_MODULE, --enable-wayland-ime, or a forced text-input version to
these tested routes.
Retain the packaged audio units started in stage 6; verify them again after the fresh login before the playback and microphone checks.
On the fresh-guide replay, an attached virtual ICH9 HDA device
produced the real PipeWire sink
alsa_output.pci-0000_00_1b.0.analog-stereo; a three-second test tone reached
the ALSA PCM (RUNNING) and its monitor. This checks the guest playback path
only. It does not establish physical or SPICE audibility or microphone signal.
Do not substitute a dummy sink for playback acceptance. The
hardware-feedback recipe verifies volume and
notification controls. Check brightness and radio features only when the
corresponding hardware exists.
Fresh password-login gate for wallet and autostart
After completing the appearance, session, and input changes, log out to SDDM
and password-login again. This is the first login after installing kwallet-pam
and Fcitx5, so it exercises the real PAM handoff and starts the packaged input
method autostart. Check one Fcitx5 process and the KWallet PAM initialization
result. The initialization process exits after its handoff, so its unit can be
inactive afterward. Confirm a start during this fresh login, Result=success
and ExecMainStatus=0; then verify the provider and store/read a disposable
secret without another password prompt. Keep it in the wallet until after the
cold-login check:
systemctl --user show plasma-kwallet-pam.service \
-p Type -p RemainAfterExit -p ActiveState -p ExecMainStartTimestamp \
-p Result -p ExecMainStatus
test -n "$(systemctl --user show plasma-kwallet-pam.service -p ExecMainStartTimestamp --value)"
test "$(systemctl --user show plasma-kwallet-pam.service -p Result --value)" = success
test "$(systemctl --user show plasma-kwallet-pam.service -p ExecMainStatus --value)" = 0
systemctl --user status app-org.fcitx.Fcitx5@autostart.service
pgrep -ax fcitx5
busctl --user status org.freedesktop.secrets
busctl --user status org.freedesktop.impl.portal.desktop.kwallet
secret-tool store --label='Niri Plus disposable check' service niri-plus-reference account disposable
secret-tool lookup service niri-plus-reference account disposable
Reboot and password-login once more. Check the secret again before clearing it:
secret-tool lookup service niri-plus-reference account disposable
secret-tool clear service niri-plus-reference account disposable
The fresh-guide replay opened the wallet without a second password prompt and read the disposable secret after password login following reboot. A later cold power-on and final relogin also retained the native provider and passed a new disposable store/read/clear check. Keep PAM unchanged while testing its normal package handoff.
Stage the four pinned shell dependency trees manually from the verified examples. Choose a new leaf, then follow the terminal recipe to add the source shim and Kitty shell choice:
ZSH_BUNDLE="$HOME/.local/share/niri-plus/zsh-neutral-slate"
python3 "$SOURCE/examples/terminal/fetch.py" "$ZSH_BUNDLE"
This fetcher requires network access and runs only when invoked; it is not a
shell-startup installer. Do not copy prompt caches from another home. On the
fresh-guide check, the first Kitty Git prompt fetched the pinned Powerlevel10k
gitstatusd binary, Tab completed a partial directory path, and Up/Enter repeated
the prior command. This first prompt needs network access; it is not an offline
startup guarantee.
Stage 8 gate: One Kanshi and one packaged Fcitx owner; supported output change restored; actual composition in Chrome and Kitty; real audio sink and signal where available; fresh-login wallet lookup; first terminal prompt, history and completion. Do not use pasted Unicode as IME evidence or a dummy sink as hardware playback evidence.
9. Replay the task checklist and recover cleanly
Before claiming the reference complete, run the tasks in the login, files, notifications, clipboard, session, display, input, and hardware-feedback recipes. Reboot to SDDM, password-login, test core tasks, log out, and log in again. Record package versions and whether each required service has exactly one owner. Resolve a failed gate in its owning source and record the change before continuing. Repeat affected commands and native tasks from saved preimages or a fresh working copy; restage changed component/identity pins before testing. Report every guide amendment and which gates were repeated.
Keep backups of any native files changed and exact preimages for privileged
SDDM files. To back out a user service, stop only the unit introduced, remove
only its exact niri.service.wants link, and restore its saved file. Keep the
console path working until SDDM login, lock/unlock, and session teardown pass.
Completion report
Use this checklist with the linked recipes. Report the observed result for each row; do not silently drop tasks that could not be exercised.
| Area | Required observation |
|---|---|
| Login and secrets | Stock login before theming, themed login, actual polkit cancel/allow, disposable wallet lookup after another password login; clear the disposable secret. |
| Session and power | Lock rejects/accepts input, repeated lock retains one locker, idle reload preserves it, the graphical session's loginctl lock request works; restore any short test timer. |
| Displays and input | Actual supported output/scale change and restoration; preedit, cancel, candidate selection and committed text in Chrome and Kitty. |
| Everyday desktop | Available panel metrics; Rofi entries; exact text/image clipboard restore, Delete and Cancel-first Clear; volume/mute restoration with no history pollution. |
| Files and devices | PDF/image/audio/video/archive defaults, archive byte comparison, browser download/open/upload via GTK picker; available radio/storage/backlight tasks recorded separately. Format only a new explicitly authorized disposable disk. |
| Audio and sharing | Real sink/monitor signal where available; whole-monitor share advances frames, Stop releases tracks/nodes; repeat sharing after a full cold start. Use the conditional VirtIO branch only for its demonstrated guest failure. |
| Lifecycle | Planned reboot, logout teardown and password relogin restore exactly the intended owners. Keep recovery available until this passes. |
At handoff, report the target and source revision, installed versions and provenance, changed files/service owners, user choices, per-task observations, remaining human/hardware work, compatibility branches, backups/recovery and final running/stopped state. State whether the requested scope is complete or which required task is unresolved. Do not push, publish or extend to other hosts unless that was part of the user's request.
The current qualification records the numbered 0.4.3/SwayNC18 installation, 21 mapped routine tasks and the user-waived VM suspend/resume check, alongside its conditional VirtIO branch. The earlier sync retains scoped package 17 checks and their native captures. The dated 0.4.1 installation receipt retains the earlier fresh-base run, its guide amendments and repeated gates. Physical-host and human acceptance remain separate.
Optional post-reference branch: manual display-away
After completing the numbered 0.4.3 reference, you may separately select the
manual away companion. Read the away-mode recipe for its
0.5.0 pin, staged-file review, install paths, optional key binding, status and
rollback. It retains desktop-power/swayidle as the automatic idle and
suspend owner; do not connect automatic resume to the manual away latch.
Record this extension separately from the required reference checklist:
| Optional extension | Completion record |
|---|---|
| Manual display-away, if selected | State not selected, or record the reviewed 0.5.0 provenance, installed helper/unit, exact Niri include or merge, selected input backend, away/resume/stop restoration result and rollback preimages. Keep physical input and panel acceptance separate. |
The integration record summarizes the current release split and dated host evidence. It does not extend or replace the preserved 0.4.1 VM and media receipts or the separate current 0.4.3 replay.
Optional post-reference branch: unified session screen
Published components 0.9.2 offer the
native session screen
through desktop-session-menu --screen. Treat it as an independently reviewed
extension after the reference. Use the components-v0.9.2 checkout's generated helpers
and examples/session/profiles/minimal-niri/session-screen.kdl, preserving
existing target and binding preimages. Do not take these files from the frozen
0.4.3 $SOURCE, silently select the full new bundle, or add the screen to
the numbered reference's completion claim.
Record the exact release revision and helper/profile selection; GTK and GtkLayerShell prerequisites; the existing locker, Away and suspend-policy owners; the installed Ctrl+Alt+Delete override; cancellation/refusal results; and rollback paths. Lock must establish the lock then request display-off; Display off must add no lock, on every machine. All six choices retain the countdown as their confirmation: selection starts the timer and expiry sends the request without another activation. Keep automatic policy and ordinary inhibitors unchanged. Do not permit the screen above the real locker.
Source tests and private native GUI checks are distinct from actual lock readiness, installed-consumer and physical panel/wake acceptance. A consumer's managed source owns final machine admission and deployment; do not run a broad apply to adopt the screen.
Optional post-reference branch: Close All
Published components 0.10.0 contain the independent
Close All utility and
examples/desktop/profiles/minimal-niri/close-all.kdl. It requests ordinary
closes across all workspaces and outputs from one captured window-ID list.
Apps retain their save/cancel dialogs; this is not logout or a process kill.
Verify the immutable published tuple before managed adoption. Select only
niri-close-all and the optional profile from that verified archive, preserving
the existing component and policy pins. Merge Mod+Shift+Q with repeat=false
and keep Mod+Q unchanged. Preserve the helper/binding preimages and record
source, archive/manifest hashes, installed hashes/modes and scoped convergence.
This extension does not join the numbered reference's completion claim.
Use fixture command traces or controlled windows for acceptance. A dry run can inspect the one ID snapshot without closing windows; ordinary live work must never serve as a destructive test fixture. Follow the recipe's JSON/exit-status contract and do not infer actual application exit from a successful request.
Focused recipes
- SDDM login and greeter
- Neutral Slate appearance
- Files and removable media
- Notifications and dashboard
- Clipboard history
- Locking and session services
- Optional unified session screen
- Optional manual display-away
- Display profiles
- Fcitx5 input
- Volume and brightness feedback
- Network, Bluetooth, Audio, and Session entries
- Kitty and Zsh