Files
omarchycn/AGENTS.md
T

14 KiB

Style

  • Two spaces for indentation, no tabs
  • Use bash 5 conditionals: use [[ ]] for string/file tests and (( )) for numeric tests
  • In [[ ]], don't quote variables, but do quote string literals when comparing values (e.g., [[ $branch == "dev" ]])
  • Prefer (( )) over numeric operators inside [[ ]] (e.g., (( count < 50 )), not [[ $count -lt 50 ]])
  • For strings/paths with spaces, quote them instead of escaping spaces with \ (e.g., "$APP_DIR/Disk Usage.desktop", not $APP_DIR/Disk\ Usage.desktop)
  • Shebangs must use #!/bin/bash consistently (never #!/usr/bin/env bash)
  • Scripts under install/ and migrations/ may be sourced and intentionally omit shebangs

Command Naming

All commands start with omarchy-. Prefixes indicate purpose.

The authoritative command group list lives in bin/omarchy in GROUP_DESCRIPTIONS. Keep GROUP_DESCRIPTIONS updated when adding a new command prefix.

Common prefixes include:

  • cmd- - check if commands exist, misc utility commands
  • capture- - screenshots, screen recordings, and other capture tools
  • pkg- - package management helpers
  • hw- - hardware detection (return exit codes for use in conditionals)
  • refresh- - copy default config to user's ~/.config/
  • restart- - restart a component
  • launch- - open applications
  • install- - install optional software
  • setup- - interactive setup wizards
  • toggle- - toggle features on/off
  • theme- - theme management
  • update- - update components

Do not maintain a second exhaustive prefix list here. Consult GROUP_DESCRIPTIONS when selecting or checking a command group so this guidance does not drift from the router.

Command Metadata

Commands in bin/ can declare CLI metadata in comments near the top of the file. bin/omarchy scans the first 80 lines, and tests expect command metadata to remain valid.

Supported metadata keys:

  • # omarchy:group=... - override the command group inferred from the filename
  • # omarchy:name=... - override the command name inferred from the filename
  • # omarchy:summary=... - short help text
  • # omarchy:args=... - usage arguments
  • # omarchy:examples=... - examples separated with |
  • # omarchy:alias=... / # omarchy:aliases=... - alternate routes
  • # omarchy:hidden=true - hide from default command listings
  • # omarchy:requires-sudo=true - mark commands that require sudo

Only use omarchy:examples where there are args that need explaining.

Prefer explicit metadata for user-facing commands. Keep routes consistent with the filename unless there is a deliberate alias or compatibility route.

Example:

# omarchy:summary=Take a screenshot
# omarchy:args=[smart|region|windows|fullscreen] [slurp|copy]
# omarchy:examples=omarchy screenshot | omarchy capture screenshot region

Runtime Environment

  • $OMARCHY_PATH is set at the top level by the uwsm session environment and is always available to Omarchy runtime code.
  • Commands in bin/ and Quickshell QML should rely on $OMARCHY_PATH / Quickshell.env("OMARCHY_PATH"); do not derive fallback paths from HOME, Quickshell.shellDir, or re-export/default OMARCHY_PATH manually.

Privileged Commands

  • Whenever you need to trigger a sudo command, use pkexec so it results in a user prompt they can approve.

Git

  • Commits should be atomic: include only one coherent change or fix, and do not mix unrelated work.
  • Commit messages should be succinct and describe the change being made.

Install Scripts

The ISO owns installation orchestration. This repo ships target-side setup commands and reusable setup leaves:

  • bin/omarchy-setup-system runs root-owned system setup during ISO finalization.
  • bin/omarchy-setup-hardware runs idempotent hardware-specific setup and is called by omarchy-setup-system.
  • bin/omarchy-finalize-user runs the per-user runtime finalization (skill symlinks, xdg-user-dirs, mime defaults, install/user/all.sh). Shipped user defaults are seeded by /etc/skel from omarchy-settings, not by this command. bin/omarchy-reinstall-configs is the explicit destructive resync of those defaults into an existing user's $HOME.
  • leaf scripts under install/ are sourced by run_logged $OMARCHY_INSTALL/path/to/script.sh and intentionally do not have shebangs.
  • avoid exit in sourced setup scripts unless intentionally aborting setup.
  • use $OMARCHY_INSTALL and $OMARCHY_PATH instead of hard-coded Omarchy paths.
  • keep root-scoped hardware setup under install/hardware/ and orchestrate it through install/hardware/all.sh.
  • keep every per-user setup leaf under install/user/ (including install/user/hardware/ and install/user/first-run/) so it is clear what must run for each user.
  • prefer helper commands for package and command checks where available.

Raw command -v, pacman, and pacman-key are acceptable in package-helper contexts where direct package-manager behavior is the point of the script.

Helper Commands

Use these instead of raw shell commands:

  • omarchy-cmd-missing / omarchy-cmd-present - check for commands
  • omarchy-pkg-missing / omarchy-pkg-present - check for packages (don't use these if you can just use omarchy-pkg-add/omarchy-pkg-drop)
  • omarchy-pkg-add - install packages (handles both pacman and AUR)
  • omarchy-pkg-drop - remove packages; use this instead of raw pacman -R*
  • omarchy-notification-send - send desktop notifications; do not call notify-send directly
  • omarchy-hw-asus-rog - detect ASUS ROG hardware (and similar hw-* commands)

Commands installed by Omarchy's default package set are runtime invariants. Invoke them directly; do not add defensive omarchy-cmd-present / omarchy-cmd-missing checks around them. Use command-presence helpers only for genuinely optional dependencies or code that can run before the default package set is installed.

Exceptions are allowed for migration and package-helper scripts where the helper may not be available yet, where the helper itself is being implemented, or where direct package-manager behavior is required.

Config Structure

  • config/ - default configs copied to ~/.config/
  • default/themed/*.tpl - templates with {{ variable }} placeholders for theme colors
  • themes/*/colors.toml - theme color definitions (accent, background, foreground, red/green/yellow/blue/magenta/cyan and bright_* variants)

Tests

Run focused automated tests for the area you changed. Current test entry points:

  • ./test/all - aggregate runner for CLI and shell tests; it intentionally does not run graphical acceptance tests
  • ./test/cli - CLI routing, command metadata, theme helpers, and safe dispatch coverage
  • ./test/shell - all Omarchy shell tests under test/shell.d/

New Omarchy shell tests should live in test/shell.d/*-test.sh so ./test/shell picks them up automatically. Source test/shell.d/base-test.sh for shared root-path discovery, assertions, and Node test helpers.

Acceptance Tests

The graphical acceptance suite lives in test/acceptance with test files under test/acceptance.d/*-test.sh. It exercises a real installed Omarchy desktop, including session health, shell surfaces, panels, keyboard navigation, representative applications, and system setup. Source test/acceptance.d/base-test.sh for the shared helpers.

Run acceptance tests in a disposable VM through the sibling omarchy-iso repository, not in the active development session. The suite opens and closes applications and temporarily changes desktop configuration.

For acceptance-test-only changes, reuse an installed base and sync the suite:

cd ../omarchy-iso
./bin/omarchy-iso-test release/<iso>.iso --reuse-base --sync-omarchy ../omarchy --no-preview

Use --sync-all ../omarchy instead of --sync-omarchy ../omarchy when the acceptance run must exercise local bin/, config/, or shell/ source too. Changes to package manifests, installation, finalization, or shipped defaults require a fresh ISO built from the local checkouts and a run without --reuse-base:

cd ../omarchy-iso
./bin/omarchy-iso-make --no-boot-offer --local-source ../omarchy ../omarchy-pkgs
./bin/omarchy-iso-test release/<generated-iso>.iso --no-preview

Keep unrelated acceptance workflows in separate test files. The runner records a failed file and continues with the remaining files, which preserves as much diagnostic coverage as possible. Restore modified user state with traps, close anything the test opens, and capture every visually distinct state (including entered input where relevant) as success-<step>.png; failure helpers capture failure-<step>.png. The ISO harness collects the screenshots and logs under its timestamped test-runs/ directory and opens the screenshots after the run unless --no-preview is passed.

The ISO harness exercises compositor-level shortcuts with QMP virtual keyboard input. In-guest wtype is suitable for typing into focused controls, but it does not reliably prove that a global Hyprland keybinding works.

Visual Verification

Visual changes must be verified in the running UI in addition to automated tests. This includes Omarchy shell styling and layout, panels, menus, notifications, desktop appearance, animations, transitions, screenshots, and screen recording flows. Creating an artifact is not sufficient: inspect it for clipping, overlap, incorrect spacing, stale state, focus problems, and visual regressions before finishing.

Take a full-screen screenshot without opening the editor:

omarchy capture screenshot fullscreen save

The command prints the saved path and writes to the configured Pictures directory. Use omarchy screenshot for the interactive smart-region flow. Capture reference and candidate states as separate images when changing a layer-shell surface or layout, then compare both.

Record a short full-screen video for animation, transition, timing, capture, or screen-recording changes:

omarchy screenrecord --fullscreen
# Exercise the changed behavior.
omarchy screenrecord --stop-recording

The stop command prints the saved video path in the configured Videos directory. Review the recording before finishing, and keep it short and focused on the changed behavior.

For interactive UI work, use wtype to simulate keyboard input when available. Example: start the UI in the background, wait briefly for focus, then run wtype -k Right -k Return to exercise keyboard selection and confirm the resulting command output or state change. Prefer this over manual-only verification when a UI returns a selected value or changes a symlink/config.

If a launched UI would otherwise remain open, keep track of its PID and stop it after the screenshot or recording; avoid broad process kills unless checking with ps first.

Omarchy shell

The Quickshell desktop runs as a single long-running process out of shell/. Hyprland autostart launches it directly with quickshell -n -p; do not start additional standalone Quickshell instances for individual components.

Run omarchy-restart-shell after making changes to QML files.

Plugin contract:

  • First-party plugins live directly under shell/plugins/ or one category level deeper, such as shell/plugins/panels/weather/. First-party bar-only widgets may use adjacent *.manifest.json files. Third-party plugins live at ~/.config/omarchy/plugins/<id>/ with a manifest.json at the root.
  • Every plugin manifest declares schemaVersion, id, name, version, kinds, and entryPoints. See docs/omarchy-shell.md and shell/services/PluginRegistry.qml for the current contract; fields such as activation are optional.
  • Entry-point QML files are Items (not ShellRoot), and accept the shell-injected properties omarchyPath, shell, manifest, and pluginRegistry / barWidgetRegistry as appropriate.
  • Panel / overlay / menu plugins must expose open(payloadJson) and close() lifecycle methods for shell summon and shell hide.

IPC:

  • bin/omarchy-shell is the canonical IPC entry point. It forwards to the running shell and does not start it. Prefer it over re-implementing direct Quickshell socket calls in every CLI.
  • The shell IPC target exposes lifecycle and configuration methods including ping, summon, hide, toggle, call, rescanPlugins, reloadConfig, setPluginEnabled, and listPlugins. Individual plugins can register additional IPC targets (the bar registers bar, the background switcher registers image-selector).

Widget files in shell/plugins/bar/widgets/ contain Nerd Font glyphs as raw unicode characters. The Write and Edit tools strip multi-byte codepoints in some positions — do not rewrite widget files wholesale through those tools. For glyph fixes, use the targeted Edit tool with the surrounding context, or a Python script that inserts codepoints via chr(0xXXXXX).

Refresh Pattern

To copy a default config to user config with automatic backup:

omarchy-refresh-config hypr/hyprlock.conf

This copies $OMARCHY_PATH/config/hypr/hyprlock.conf to ~/.config/hypr/hyprlock.conf.

Migrations

Read docs/migrations.md before creating or changing migrations.

Migrations are per-user and run through omarchy-migrate during omarchy update or from the migration notification. Put migrations directly under migrations/<timestamp>.sh. Pending state is per-user under ~/.local/state/omarchy/migrations/, so every user gets a chance to run every migration. Migrations run as the user; privileged work should invoke the appropriate helper or privilege prompt, and no-op when another user already applied it.

To create a new migration, run omarchy-dev-add-migration --no-edit.

New migration format:

  • File permissions must be 0644 (-rw-r--r--); migration runners execute them with bash -euo pipefail, not through executable bits
  • No shebang line
  • Start with an echo describing what the migration does
  • Use $OMARCHY_PATH to reference the omarchy directory
  • Prefer helper commands such as omarchy-cmd-present, omarchy-cmd-missing, omarchy-pkg-present, and omarchy-pkg-missing

Omarchy 4.0 is upgraded through bin/omarchy-upgrade-to-quattro, not through the normal migration runner. Do not add compatibility migrations for old installer layouts; put pre-4 package-layout transition work in the upgrade command instead.

Migrations may use raw pacman, command -v, or direct config edits when needed for one-off repair work.