Niri Compositor Control
Use this skill when working with Niri compositor operations, window management, or workspace automation.
Activation Triggers
Activate this skill ONLY when the user explicitly mentions:
- •Niri compositor operations
- •Generic Window positioning or management
- •Workspace control and organization
- •Output/monitor configuration changes
- •Niri IPC automation
- •Compositor state queries
- •You are running on Linux,
- •Niri is installed and active
Do NOT activate automatically - this is an on-demand skill that requires explicit user request.
Capabilities
This skill provides:
- •Window management (focus, move, resize, float/tile)
- •Workspace operations (create, name, navigate, organize)
- •Output configuration (resolution, scale, position, VRR)
- •Column-based layout control (Niri's scrollable tiling)
- •Real-time compositor state queries
- •IPC automation and scripting
- •Event stream monitoring
Available Tools
- •niri msg: Primary IPC interface for compositor control
- •distrobox-host-exec: Required wrapper to reach host compositor from containers
- •JSON output: All commands support
--jsonflag for scripting
Context Awareness
Environment Detection
- •Running in distrobox container - use
distrobox-host-exec niri msg - •Niri version 25.11+ with full IPC support
- •KDL configuration format
- •DMS (DankMaterialShell) integration present
Core Concepts
Niri's Layout Model
Scrollable Tiling: Unlike i3/sway, Niri uses horizontal scrolling columns:
- •Windows are organized in columns
- •Columns can contain multiple windows (stacked/tabbed)
- •Scroll horizontally through columns
- •Each workspace has independent columns
- •Column index starts at 1 (not 0)
Key Differences from Traditional Tilers:
- •Not binary split (no automatic right/left split)
- •Navigate by scrolling, not by directional splits
- •Columns can be repositioned by index
- •Multiple windows per column form a vertical stack
Window States
- •Tiled: Default state, in scrollable column layout
- •Floating: Positioned absolutely, outside column flow
- •Fullscreen: Takes entire output
- •Maximized: Column fills available width
Workspace Model
- •Multiple workspaces per output/monitor
- •Workspaces can be named (optional)
- •Reference by number (1, 2, 3...) or name
- •Each workspace has independent column layout
- •Empty workspaces will auto remove in a few seconds
Common Operations
Query Compositor State
# List all windows with details distrobox-host-exec niri msg windows distrobox-host-exec niri msg --json windows # List outputs (monitors) distrobox-host-exec niri msg outputs # List workspaces distrobox-host-exec niri msg workspaces # Get focused window distrobox-host-exec niri msg focused-window # Get focused output distrobox-host-exec niri msg focused-output # Check overview state distrobox-host-exec niri msg overview-state
Window Management
# Focus window by ID distrobox-host-exec niri msg action focus-window --id <WINDOW_ID> # Move window to different workspace distrobox-host-exec niri msg action move-window-to-workspace --window-id <ID> --focus false <WORKSPACE_NUM> # Toggle floating distrobox-host-exec niri msg action toggle-window-floating --id <ID> distrobox-host-exec niri msg action move-window-to-floating --id <ID> distrobox-host-exec niri msg action move-window-to-tiling --id <ID> # Resize window distrobox-host-exec niri msg action set-window-width --id <ID> "50%" distrobox-host-exec niri msg action set-window-height --id <ID> "30%" # Close window distrobox-host-exec niri msg action close-window --id <ID> # Fullscreen distrobox-host-exec niri msg action fullscreen-window --id <ID>
Column Control (Niri-Specific)
# Move column to specific horizontal position distrobox-host-exec niri msg action focus-window --id <WINDOW_ID> distrobox-host-exec niri msg action move-column-to-index <COLUMN_INDEX> # Column index starts at 1 (leftmost) # Higher numbers = further right # Move column left/right distrobox-host-exec niri msg action move-column-left distrobox-host-exec niri msg action move-column-right # Center column on screen distrobox-host-exec niri msg action center-column # Maximize column width distrobox-host-exec niri msg action maximize-column
Workspace Operations
# Focus workspace by number distrobox-host-exec niri msg action focus-workspace 1 # Focus workspace by name distrobox-host-exec niri msg action focus-workspace "development" # Name current workspace distrobox-host-exec niri msg action set-workspace-name "myproject" # Name specific workspace distrobox-host-exec niri msg action set-workspace-name --workspace 2 "email" # Unset workspace name (back to number only) distrobox-host-exec niri msg action unset-workspace-name distrobox-host-exec niri msg action unset-workspace-name 2
Floating Window Positioning
# Float a window first distrobox-host-exec niri msg action move-window-to-floating --id <ID> # Move to specific position distrobox-host-exec niri msg action move-floating-window --id <ID> --x 0 --y 1000 # Position is absolute in logical pixels # For bottom-left: x=0, y=(screen_height - window_height - margin)
Output Configuration (Temporary)
# Change resolution/refresh rate distrobox-host-exec niri msg output "DP-1" mode 3440 1440 159.962 # Change scale distrobox-host-exec niri msg output "DP-1" scale 1.5 # Reposition output distrobox-host-exec niri msg output "DP-2" position 3440 200 # Enable VRR distrobox-host-exec niri msg output "DP-1" vrr on # Turn output off/on distrobox-host-exec niri msg output "DP-2" off distrobox-host-exec niri msg output "DP-2" on
Interactive Tools
# Pick window with mouse distrobox-host-exec niri msg pick-window # Pick color from screen distrobox-host-exec niri msg pick-color
Workflow Patterns
Organize Windows by App Type
# Get all windows windows=$(distrobox-host-exec niri msg --json windows) # Sort by app_id and move to organized columns # 1. Get Firefox windows # 2. Get terminal windows # 3. Get communication apps (Discord, Slack) # 4. Move each group to sequential column positions # Example: # Column 1: Terminals # Column 2: Communication # Columns 3+: Browsers
Move All Windows to New Workspace
# Get all window IDs from workspace N
window_ids=$(distrobox-host-exec niri msg --json windows | \
grep -o '"id":[0-9]*.*"workspace_id":N' | \
grep -o '^"id":[0-9]*' | cut -d: -f2)
# Move each to target workspace without following
for id in $window_ids; do
distrobox-host-exec niri msg action move-window-to-workspace \
--window-id $id --focus false <TARGET_WORKSPACE>
done
Create Monitoring Workspace
# Move to new workspace distrobox-host-exec niri msg action focus-workspace 5 # Name it distrobox-host-exec niri msg action set-workspace-name "monitoring" # Spawn monitoring windows distrobox-host-exec niri msg action spawn -- alacritty -e btop distrobox-host-exec niri msg action spawn -- alacritty -e htop distrobox-host-exec niri msg action spawn -- alacritty -e top
Float and Corner Position
# Get window ID WINDOW_ID=<id> # Float it distrobox-host-exec niri msg action move-window-to-floating --id $WINDOW_ID # Resize to corner-appropriate size distrobox-host-exec niri msg action set-window-width --id $WINDOW_ID "25%" distrobox-host-exec niri msg action set-window-height --id $WINDOW_ID "30%" # Position in bottom-left corner (for 1440p display) distrobox-host-exec niri msg action move-floating-window --id $WINDOW_ID --x 0 --y 1000
Best Practices
Always Use distrobox-host-exec
Since you're running in a container, always wrap niri msg:
distrobox-host-exec niri msg <command>
Get Window IDs First
Before operating on windows, get their IDs:
# Human-readable distrobox-host-exec niri msg windows | grep "Window ID" # For scripting distrobox-host-exec niri msg --json windows | grep -o '"id":[0-9]*'
Use --focus Flag Appropriately
When moving windows:
- •
--focus true(default): Follow window to new workspace - •
--focus false: Keep focus on current workspace
# Move but stay on current workspace distrobox-host-exec niri msg action move-window-to-workspace \ --window-id 308 --focus false 2
Reference Workspaces Consistently
- •Use numbers for unnamed workspaces:
1,2,3 - •Use names for named workspaces:
"development","monitoring" - •Don't mix - if workspace has name, use the name
Understand Column Indexing
- •Column index starts at 1 (not 0)
- •Higher index = further right in layout
- •Moving to index beyond current columns appends to end
- •Columns re-index automatically when one is removed
Validate Configuration
Before making config changes:
distrobox-host-exec niri validate
Monitor Events
For automation, use event stream:
distrobox-host-exec niri msg event-stream # Outputs real-time events (window open/close, focus changes, etc.)
Integration with Other Skills
With Containers Skill
Spawn containerized apps in specific workspaces:
# Switch to workspace distrobox-host-exec niri msg action focus-workspace "containers" # Spawn container with GUI distrobox-host-exec niri msg action spawn -- \ distrobox enter dev -- firefox
With DMS Integration
Many operations go through DMS IPC:
# DMS shortcuts dms ipc call spotlight toggle dms ipc call clipboard toggle # Direct niri equivalent distrobox-host-exec niri msg action spawn -- <command>
Limitations and Notes
Workspace Deletion
- •Cannot delete workspaces - No IPC command exists, a workspace must be empty and unnamed to be cleaned up
- •Can only unset names or ignore them
Configuration Changes
- •Output changes via IPC are temporary
- •Reset on config reload or compositor restart
- •For permanent changes, edit
~/.config/niri/config.kdlwith chezmoi
Window Identification
- •Window IDs change across sessions
- •Don't hardcode IDs - always query first
- •Use app_id and title for matching if needed
Column Behavior
- •Columns auto-collapse when last window removed
- •Column indices shift when column removed
- •Can't pre-create empty columns
JSON Parsing
- •If you are missing
jq, run it viamise exec
Troubleshooting
Commands Not Working
Check compositor version:
distrobox-host-exec niri msg version # Should be 25.11+
Window Not Moving
Verify window exists and get correct ID:
distrobox-host-exec niri msg windows | grep -A 5 "Window ID: <id>"
Workspace Issues
List all workspaces to see current state:
distrobox-host-exec niri msg workspaces
Output Configuration Not Applying
Remember changes are temporary:
# Won't persist across restarts distrobox-host-exec niri msg output "DP-1" mode 3440 1440 159.962
Related Documentation
- •Niri Wiki: https://github.com/YaLTeR/niri/wiki
- •DMS integration:
dms --help - •Config validation:
distrobox-host-exec niri validate
Quick Reference
Most Common Commands
# Query distrobox-host-exec niri msg windows distrobox-host-exec niri msg workspaces distrobox-host-exec niri msg outputs # Focus distrobox-host-exec niri msg action focus-window --id <ID> distrobox-host-exec niri msg action focus-workspace <NUM> # Move distrobox-host-exec niri msg action move-window-to-workspace --window-id <ID> <WORKSPACE> distrobox-host-exec niri msg action move-column-to-index <INDEX> # Float distrobox-host-exec niri msg action toggle-window-floating --id <ID> # Resize distrobox-host-exec niri msg action set-window-width --id <ID> "50%" # Spawn distrobox-host-exec niri msg action spawn -- <command>
Example: Complete Window Organization
# 1. Query current state
distrobox-host-exec niri msg windows > /tmp/windows.txt
# 2. Identify windows by app
TERMINAL_IDS=$(grep -B2 "Alacritty" /tmp/windows.txt | grep "Window ID" | awk '{print $3}' | tr -d ':')
FIREFOX_IDS=$(grep -B2 "firefox" /tmp/windows.txt | grep "Window ID" | awk '{print $3}' | tr -d ':')
# 3. Move to workspace 1
for id in $TERMINAL_IDS $FIREFOX_IDS; do
distrobox-host-exec niri msg action move-window-to-workspace --window-id $id --focus false 1
done
# 4. Organize columns (focus each, move to position)
col=1
for id in $TERMINAL_IDS; do
distrobox-host-exec niri msg action focus-window --id $id
distrobox-host-exec niri msg action move-column-to-index $col
((col++))
done
# 5. Name workspace
distrobox-host-exec niri msg action focus-workspace 1
distrobox-host-exec niri msg action set-workspace-name "organized"
Skill Activation Reminder
This skill should ONLY be activated when explicitly requested by the user.
Do not automatically use this skill for general window management discussions. Wait for specific mentions of:
- •"use niri msg"
- •"control niri"
- •"organize my windows"
- •"move windows via IPC"
- •Other explicit niri compositor operations
This prevents unnecessary invocation and keeps the skill focused on actual compositor automation tasks.