🤖 Warning: this is a vibe coded project built by Codex. Treat the code and behavior as experimental, and verify changes before relying on it.
hyprsummon is a small Go CLI for Hyprland that implements a practical run-or-raise workflow.
- if a matching window already exists, focus it
- otherwise, launch the application
The CLI has three commands:
run: focus a matching window, or launch when no match existsfocus: focus a matching window onlysetup: discover a running application and generate a validated Hyprland Lua bind
wizard remains available as an alias for setup.
There is no config file. Behavior is controlled entirely through flags.
Quick install:
go install github.com/rigerc/hyprsummon@latestThen verify it is available:
hyprsummon --helpInstall from source:
git clone https://github.com/rigerc/hyprsummon.git
cd hyprsummon
GOCACHE=/tmp/go-build-cache go install .Build a local binary:
git clone https://github.com/rigerc/hyprsummon.git
cd hyprsummon
GOCACHE=/tmp/go-build-cache go build -o hyprsummon .Make sure your Go bin directory is on PATH. On most systems that is either:
$HOME/go/bin
or:
$(go env GOPATH)/bin
hyprsummon connects to the current Hyprland instance, lists clients, filters them by exact match rules, selects one candidate, and then either focuses it or launches a new process.
Matching is exact string matching, not regex matching.
--classis required--titleis optional--initial-classis optional
A client matches only if:
- it is mapped
- its
classexactly equals--class - if
--titleis set, itstitleexactly equals--title - if
--initial-classis set, itsinitialClassexactly equals--initial-class
When multiple windows match:
- by default,
hyprsummonprefers a match on the active workspace - if no match is on the active workspace, it falls back to the first remaining match
--cyclewalks the ordered match list instead of always choosing the first one
Useful selection flags:
--current-workspace-only--all-workspaces--prefer-floating--prefer-tiled--prefer-special--exclude-special
Existing-window actions:
- default: focus the selected match
--pull: move the selected match to the active workspace, then focus it--move-to-special --special-workspace NAME: move the selected match tospecial:NAME--toggle-special --special-workspace NAME: reveal a hidden target special workspace before focus, or hide it when the selected window is already focused there--fullscreenor--maximize: apply a focus mode after selection
Launch actions:
- default: launch and briefly poll for a matching new window, then focus it
--background: launch and return immediately--special-workspace NAME: launch ontospecial:NAME--show-special-after-launch: reveal the target special workspace after launch, then focus the new matching window
If an app should live on a named special workspace, use --scratch with --special-workspace NAME.
--scratch is the high-level alias for the common scratchpad workflow.
For run, it expands to:
--prefer-special --move-to-special --toggle-special --show-special-after-launch
For focus, it expands to:
--prefer-special --move-to-special --toggle-special
This is the intended mode for app-specific special-workspace toggles such as music players, scratch terminals, or utility apps.
Basic run-or-raise:
hyprsummon run --class kitty -- kittyFocus only:
hyprsummon focus --class kittyBring an existing app to the current workspace:
hyprsummon run --class firefox --pull -- firefoxRestrict matching to the current workspace:
hyprsummon run --class org.gnome.Nautilus --current-workspace-only -- nautilusNamed special-workspace scratch toggle:
hyprsummon run --class spotify --special-workspace music --scratch -- spotify-launcherLaunch directly onto a named special workspace without scratch semantics:
hyprsummon run --class kitty --special-workspace scratch -- kitty --class scratchpadShow diagnostics on stderr:
hyprsummon run --class kitty --verbose -- kittyUse built-in help for current flag details:
hyprsummon --help
hyprsummon setup
hyprsummon run --help
hyprsummon focus --help
hyprsummon help flag --class
hyprsummon help flag --toggle-specialUse setup when you want hyprsummon to discover an application and generate the command for you.
hyprsummon setupThe guided flow is built with huh and:
- discovers and groups mapped Hyprland windows by exact class
- lets you refresh discovery or enter a class manually
- intent selection
- class/title matching
- launch command setup
- special-workspace or scratch behavior
- optional advanced flags
- optional Hyprland 0.55+ Lua bind generation
- non-mutating syntax validation through Hyprland's Lua runtime
For example, generated bind output looks like:
hl.bind("SUPER + M", hl.dsp.exec_cmd("/absolute/path/to/hyprsummon run --class spotify -- spotify"), { repeating = false, description = "Summon Spotify" })Setup prints its result by default and never edits or reloads your active Hyprland configuration. To create a standalone Lua snippet safely:
hyprsummon setup --format bind --output ~/.config/hypr/hyprsummon.luaThen load it from hyprland.lua:
require("hyprsummon")Existing files are preserved unless --force is explicit. Use --accessible or --no-color for line-oriented prompts. wizard can still be used as a backward-compatible alias.
Build:
go build -o hyprsummon .Run without installing:
go run . run --class kitty -- kittyTest:
go test ./...- Linux
- Go 1.26+
- Hyprland 0.55 or newer running in the current session
- access to the Hyprland IPC socket
XDG_RUNTIME_DIRsethyprctlfor setup-time Lua validation
Optional:
notify-sendfor--notifyand--debug
hyprsummon connects to:
$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket.sock
If HYPRLAND_INSTANCE_SIGNATURE is missing, it falls back to discovering a Hyprland socket under $XDG_RUNTIME_DIR/hypr.
- no persistent hyprsummon runtime config file
- no regex matching
- no persistent cycle state across invocations
- no fallback notification backend beyond
notify-send - special-workspace behavior is tied to explicit flags; there is no automatic policy layer beyond
--scratch