- Overview
- Matching Options
- Available Actions
- Rule Specificity
- Managing Rules
- Finding AX Attributes
- Common Use Cases
- Troubleshooting
Window rules let you automatically configure window properties based on various attributes. Rules are applied when windows are created, allowing you to:
- Ignore specific windows completely (never manage)
- Float specific windows (exclude from tiling)
- Assign windows to specific tags
- Move windows to specific displays
- Set initial position and dimensions
Note: By default, new windows inherit the display's current visible tags. Use the tags action to assign windows to specific tags instead.
| Option | Description | Example |
|---|---|---|
--app-name |
Application name | Safari, *Chrome* |
--app-id |
Bundle identifier | com.apple.Safari, com.google.* |
--title |
Window title | *Preferences*, *Dialog* |
--ax-id |
AXIdentifier attribute | com.mitchellh.ghostty.quickTerminal, none |
--subrole |
AXSubrole attribute | Dialog, FloatingWindow, none |
--window-level |
Window level | normal, floating, other, 8 |
--close-button |
Close button state | exists, none, enabled, disabled |
--fullscreen-button |
Fullscreen button state | exists, none, enabled, disabled |
--minimize-button |
Minimize button state | exists, none, enabled, disabled |
--zoom-button |
Zoom button state | exists, none, enabled, disabled |
Glob patterns (* for any characters) are supported for --app-name, --app-id, --title, --ax-id, and --subrole.
For --ax-id and --subrole, the special pattern none matches windows where the attribute is absent (not set). This is useful for matching windows that lack these accessibility attributes:
# Match windows with no AXIdentifier and no AXSubrole (e.g., Outlook invisible windows)
yashiki rule-add --app-id com.microsoft.Outlook --ax-id none --subrole none ignoreThe --window-level option matches windows based on their CGWindowLevel:
| Value | Level | Description |
|---|---|---|
normal |
0 | Standard application windows |
floating |
3 | Utility panels, palettes |
modal |
8 | Modal dialogs |
utility |
19 | Utility windows |
popup |
101 | Popup menus |
other |
!= 0 | Any non-normal window |
<number> |
N | Specific numeric level |
# Ignore all non-normal windows (palettes, panels, etc.)
yashiki rule-add --window-level other ignore
# Float utility panels (level 3)
yashiki rule-add --window-level floating float
# Match by specific numeric level
yashiki rule-add --window-level 8 floatButton matchers check the state of window control buttons:
| Value | Description |
|---|---|
exists |
Button exists (enabled or disabled) |
none |
Button doesn't exist |
enabled |
Button exists and is enabled |
disabled |
Button exists but is disabled |
# Float windows without fullscreen button (dialogs, sheets)
yashiki rule-add --fullscreen-button none float
# Ignore windows without close button (popups, tooltips)
yashiki rule-add --close-button none ignore
# Ghostty Quick Terminal: fullscreen disabled, close enabled
yashiki rule-add --app-id com.mitchellh.ghostty --fullscreen-button disabled ignore
# Firefox PiP: use window-level floating
yashiki rule-add --app-id org.mozilla.firefox --window-level floating floatYou can combine multiple matchers for more specific rules:
# Safari preferences window
yashiki rule-add --app-name Safari --title "*Preferences*" float
# Ghostty floating windows
yashiki rule-add --app-id com.mitchellh.ghostty --subrole FloatingWindow float
# Ghostty Quick Terminal (specific combination)
yashiki rule-add --app-id com.mitchellh.ghostty --fullscreen-button disabled --close-button enabled ignore| Action | Syntax | Description |
|---|---|---|
ignore |
ignore |
Never manage (skip completely) |
float |
float |
Window floats (excluded from tiling) |
no-float |
no-float |
Override more general float rules |
tags |
tags <bitmask> |
Set window tags |
output |
output <id|name> |
Move to specific display |
position |
position <x> <y> |
Set initial position |
dimensions |
dimensions <w> <h> |
Set initial size |
Both ignore and float exclude windows from tiling, but they behave differently.
ignore |
float |
|
|---|---|---|
| Managed | No (completely skipped) | Yes (floating state) |
| list-windows | Not shown | Shown |
| window-focus | Cannot focus | Can focus |
| Tag operations | No effect | Hidden/shown on tag switch |
| Manual toggle | Not possible | window-toggle-float works |
| Use case | Temporary windows (popups, tooltips, dropdowns) | Windows you interact with (dialogs, preferences, Finder) |
When to use each:
-
ignore: Windows you don't want yashiki to touch at all
- Examples: Firefox dropdowns, tooltips, autocomplete popups
- Characteristics: Appear/disappear frequently, not directly interacted with
-
float: Windows excluded from tiling but still managed by yashiki
- Examples: Finder, System Settings, dialogs, Quick Terminal
- Characteristics: User interacts with them, may want to move between tags, should be focusable
# Example: Completely ignore Firefox popups
yashiki rule-add --app-id org.mozilla.firefox --subrole AXUnknown ignore
# Example: Finder floats but is still managed
yashiki rule-add --app-name Finder floatRules are sorted by specificity - more specific rules take priority. Specificity is calculated as:
- Exact match - highest priority (e.g.,
Safari) - Prefix/suffix match - medium priority (e.g.,
Safari*,*Safari) - Contains match - lower priority (e.g.,
*Safari*) - Wildcard only - lowest priority (e.g.,
*)
When multiple rules match a window, each action type uses the first matching rule:
# More specific rule takes priority
yashiki rule-add --app-name Safari --title "*Preferences*" float
yashiki rule-add --app-name Safari tags 2
# Result: Safari Preferences window floats AND goes to tag 2
# Result: Other Safari windows go to tag 2 (not floating)# List all rules
yashiki list-rules
# Remove a rule (must match exactly)
yashiki rule-del --app-name Finder float
# Rules are evaluated in specificity order, not insertion orderThe --ax-id and --subrole options use macOS Accessibility API attributes. Here's how to find them.
Accessibility Inspector is included with Xcode:
- Open Xcode
- Menu: Xcode → Open Developer Tool → Accessibility Inspector
- Click the target button (crosshair icon) in the toolbar
- Hover over the target window
- Look for these attributes in the inspector:
- AXIdentifier - Use with
--ax-id - AXSubrole - Use with
--subrole
- AXIdentifier - Use with
Two Swift scripts are provided in the scripts/ directory for inspecting window attributes.
scripts/ax-inspect.swift prints attributes of the currently focused window:
./scripts/ax-inspect.swiftOutput:
Application: Ghostty
Bundle ID: com.mitchellh.ghostty
Window Level: 0 (normal)
AXIdentifier: TerminalWindowRestoration
AXSubrole: AXStandardWindow
AXTitle: tmux a -d
scripts/ax-inspect-all.swift lists all on-screen windows grouped by application:
./scripts/ax-inspect-all.swiftThis is useful for:
- Finding Firefox popup windows (AXUnknown subrole)
- Discovering all windows an app creates
- Debugging window rules that don't match
When bound to a yashiki hotkey via yashiki exec, there's no terminal to display output. Redirect to a file instead:
-
Copy the script to your config directory:
cp scripts/ax-inspect.swift ~/.config/yashiki/ chmod +x ~/.config/yashiki/ax-inspect.swift
-
Bind a hotkey that appends output to a file:
yashiki bind alt-i exec "~/.config/yashiki/ax-inspect.swift >> /tmp/ax-inspect.txt"
-
Focus on a window and press the hotkey
-
Check the output:
cat /tmp/ax-inspect.txt
Using >> (append) allows inspecting multiple windows in sequence. Clear the file with > /tmp/ax-inspect.txt when needed.
The easiest way to inspect window attributes is using list-windows --debug:
# Show managed windows with debug info (ax_id, subrole, window_level, buttons)
yashiki list-windows --debug
# Show ALL windows including ignored ones (popups, tooltips)
yashiki list-windows --all
# Combine both to see everything
yashiki list-windows --all --debugThis shows output like:
12345: Firefox (org.mozilla.firefox) - Menu [tags=1, 200x50 @ (100,200)] [ignored]
ax_id=None, subrole=AXUnknown, level=normal, close=enabled, fullscreen=enabled, minimize=enabled, zoom=enabled
The --all flag is useful for finding ignored windows (like Firefox dropdowns) that you might want to create rules for.
The --subrole option accepts values with or without the "AX" prefix:
# These are equivalent
yashiki rule-add --subrole Dialog float
yashiki rule-add --subrole AXDialog floatCommon subroles:
AXStandardWindow- Normal windowsAXDialog- Dialog windowsAXFloatingWindow- Floating panelsAXSystemDialog- System dialogsAXUnknown- Unspecified (often popups, dropdowns, tooltips)
Problem: System dialogs and preference windows get tiled with other windows.
Solution: Use --subrole Dialog to float all dialog windows:
yashiki rule-add --subrole Dialog float
yashiki rule-add --subrole FloatingWindow floatFor specific apps:
yashiki rule-add --app-name "System Preferences" float
yashiki rule-add --app-name "System Settings" float
yashiki rule-add --title "*Preferences*" floatProblem: Some apps have special popup windows (Quick Terminal, Quick Note, Spotlight-like search) that should float, or temporary popup windows (dropdowns, tooltips) that should be ignored entirely.
Solution: Use --ax-id with the window's AXIdentifier, or --subrole for popup windows:
# Ghostty Quick Terminal - float (still managed, but excluded from tiling)
yashiki rule-add --ax-id "com.mitchellh.ghostty.quickTerminal" float
# Ignore all AXUnknown windows (Firefox dropdowns, tooltips, etc.)
yashiki rule-add --subrole AXUnknown ignore
# Ignore only Firefox popup windows
yashiki rule-add --app-id org.mozilla.firefox --subrole AXUnknown ignore
# Ignore windows with no AX attributes (e.g., Outlook invisible windows)
yashiki rule-add --app-id com.microsoft.Outlook --ax-id none --subrole none ignore
# Find the AXIdentifier using Accessibility Inspector or the script aboveNote: The ignore action completely skips window management - the window won't appear in list-windows or be affected by any yashiki operations. Use float if you want the window to be managed but excluded from tiling.
Problem: You want certain apps to always open on a specific tag.
Solution:
# Safari on tag 2 (bitmask 2 = 1<<1)
yashiki rule-add --app-name Safari tags 2
# Slack on tag 3 (bitmask 4 = 1<<2)
yashiki rule-add --app-name Slack tags 4Problem: You want certain apps on a specific monitor.
Solution:
# Chrome on display 2
yashiki rule-add --app-name "Google Chrome" output 2
# All Google apps on display 2
yashiki rule-add --app-id "com.google.*" output 2-
Check with
list-rules- Verify the rule exists:yashiki list-rules
-
Verify the matcher values - Use Accessibility Inspector or the Swift script to confirm:
- App name matches
--app-name - Bundle ID matches
--app-id - Window title matches
--title - AXIdentifier matches
--ax-id - AXSubrole matches
--subrole
- App name matches
-
Check glob patterns - Remember that
*matches any characters:Safari- exact match only*Safari*- contains "Safari"Safari*- starts with "Safari"
-
Check if a
no-floatrule exists - A more specificno-floatrule may override yourfloatrule. -
Verify the window is being created, not moved - Rules only apply to newly created windows. Use
window-toggle-floatfor existing windows.
Not all windows have an AXIdentifier. If Accessibility Inspector shows "(null)" or empty:
- Use
--ax-id noneto match windows without an AXIdentifier - Try using
--subroleinstead (or--subrole noneif subrole is also absent) - Use
--app-idcombined with--titlefor more specific matching - Some windows may not be distinguishable by AX attributes
Example for windows with no AX attributes:
yashiki rule-add --app-id com.microsoft.Outlook --ax-id none --subrole none ignore