Skip to content

typester/yashiki

Repository files navigation

Yashiki (屋敷)

macOS tiling window manager written in Rust.

Features

  • Tag-based workspaces - Bitmask tags (like awesome/river) allow windows to belong to multiple tags and view any combination
  • External layout engines - Stdin/stdout JSON protocol lets you write custom layouts in any language
  • Multi-monitor support - Each display has independent tags
  • Window rules - Automatically configure windows by app name, bundle identifier, or title
  • Cursor warp - Mouse follows focus (configurable: disabled, on-output-change, on-focus-change)
  • Auto-raise - Focus follows mouse with optional delay (focus window when cursor enters)
  • State streaming - Real-time events for status bars and external tools
  • No SIP disable required - Uses only public Accessibility API
  • Shell script configuration - Config is just a shell script (~/.config/yashiki/init)

Status

Early development stage. API and configuration format may change.

Requirements

  • macOS 12.0+
  • Accessibility permission (System Settings → Privacy & Security → Accessibility)

Installation

Homebrew (Recommended)

brew tap typester/yashiki
brew install --cask yashiki

The cask installs:

  • Yashiki.app to /Applications
  • CLI tools: yashiki, yashiki-layout-tatami, yashiki-layout-byobu

Note: Yashiki.app is not signed. On first launch, allow it in System Settings → Privacy & Security. Or install with --no-quarantine:

brew install --cask --no-quarantine yashiki

Using Cargo

# Core daemon and CLI
cargo install yashiki

# Install layout engines you want to use
cargo install yashiki-layout-tatami   # Master-stack layout
cargo install yashiki-layout-byobu    # Accordion layout

Grant Accessibility Permission

  1. Open System Settings → Privacy & Security → Accessibility
  2. Add Yashiki.app (if installed via Homebrew or as app bundle)
  3. Or add your terminal app if running yashiki start directly (Not recommended)

Quick Start

For a detailed walkthrough, see the Quick Start Guide.

  1. Launch Yashiki.app:

    • If installed via Homebrew: Open /Applications/Yashiki.app
    • The app will request Accessibility permission on first launch

    Note: Running yashiki start from terminal is not recommended as it requires granting Accessibility permission to your terminal app.

  2. Create config file ~/.config/yashiki/init:

    #!/bin/sh
    
    # Add Homebrew to exec path (if needed for custom layout engines)
    # yashiki add-exec-path /opt/homebrew/bin
    
    # Layout configuration
    yashiki layout-set-default tatami
    yashiki set-outer-gap 10  # Gap between windows and screen edges (global)
    yashiki layout-cmd --layout tatami set-inner-gap 10  # Gap between windows (layout-specific)
    
    # Cursor warp (mouse follows focus)
    yashiki set-cursor-warp on-focus-change
    
    # Tag bindings (tag N = bitmask $((1<<(N-1))))
    for i in 1 2 3 4 5 6 7 8 9; do
      yashiki bind "alt-$i" tag-view "$((1<<(i-1)))"
      yashiki bind "alt-shift-$i" window-move-to-tag "$((1<<(i-1)))"
    done
    
    # Window focus
    yashiki bind alt-j window-focus next
    yashiki bind alt-k window-focus prev
    yashiki bind alt-h layout-cmd dec-main-ratio
    yashiki bind alt-l layout-cmd inc-main-ratio
    
    # Multi-monitor
    yashiki bind alt-o output-focus next
    yashiki bind alt-shift-o output-send next
  3. Make it executable:

    chmod +x ~/.config/yashiki/init
  4. Restart yashiki to apply config:

    • Quit with yashiki quit
    • Relaunch Yashiki.app

Configuration

Yashiki uses a shell script for configuration. The init script is executed when the daemon starts.

Hotkey Syntax

Format: <modifiers>-<key>

Modifiers:

  • alt (Option key)
  • ctrl (Control key)
  • shift
  • cmd (Command key)

Examples: alt-1, alt-shift-j, ctrl-alt-return

Tag System

Tags use bitmask format:

  • Tag 1 = 1 (binary: 001)
  • Tag 2 = 2 (binary: 010)
  • Tag 3 = 4 (binary: 100)
  • Tags 1+2 = 3 (binary: 011)

In shell scripts: $((1<<0)) = 1, $((1<<1)) = 2, $((1<<2)) = 4

CLI Commands

Daemon Control

yashiki start              # Start daemon
yashiki quit               # Stop daemon
yashiki version            # Show version

Hotkey Management

yashiki bind alt-1 tag-view 1    # Bind hotkey
yashiki unbind alt-1             # Unbind hotkey
yashiki list-bindings            # List all bindings

Tag Operations

yashiki tag-view 1               # Switch to tag 1
yashiki tag-view 3               # View tags 1+2 (bitmask 3)
yashiki tag-toggle 2             # Toggle tag 2 visibility
yashiki tag-view-last            # Switch to previous tags
yashiki window-move-to-tag 1     # Move focused window to tag 1
yashiki window-toggle-tag 2      # Toggle tag 2 on focused window

Window Operations

yashiki window-focus next        # Focus next window
yashiki window-focus prev        # Focus previous window
yashiki window-focus left        # Focus window to the left
yashiki window-focus right       # Focus window to the right
yashiki window-focus up          # Focus window above
yashiki window-focus down        # Focus window below
yashiki window-swap next         # Swap with next window
yashiki window-swap prev         # Swap with previous window
yashiki window-swap left         # Swap with window to the left
yashiki window-swap right        # Swap with window to the right
yashiki window-swap up           # Swap with window above
yashiki window-swap down         # Swap with window below
yashiki window-toggle-fullscreen # Toggle fullscreen (AeroSpace-style)
yashiki window-toggle-float      # Toggle floating state
yashiki window-close             # Close focused window

Multi-Monitor

yashiki output-focus next        # Focus next display
yashiki output-focus prev        # Focus previous display
yashiki output-send next         # Move window to next display
yashiki output-send prev         # Move window to previous display
yashiki tag-view --output 2 1    # Switch tag on display 2
yashiki tag-view --output "DELL" 1  # Target display by name

Layout

yashiki retile                   # Apply layout
yashiki layout-set-default tatami     # Set default layout
yashiki layout-set byobu              # Set layout for current tag
yashiki layout-set --tags 4 byobu     # Set layout for tag 3
yashiki layout-get                    # Get current layout
yashiki layout-cmd set-main-ratio 0.6 # Send command to layout
yashiki layout-cmd --layout tatami set-inner-gap 10  # Configure specific layout

Utilities

yashiki list-windows             # List managed windows
yashiki list-windows --all       # Include ignored windows (popups, tooltips)
yashiki list-windows --debug     # Show debug info (ax_id, subrole, window_level, buttons)
yashiki list-outputs             # List all displays
yashiki get-state                # Get current state
yashiki exec "open -a Safari"    # Execute command
yashiki exec --track "borders"   # Execute and terminate on yashiki quit
yashiki exec-or-focus --app-name Safari "open -a Safari"  # Focus or launch

The --track option is useful for launching companion tools like JankyBorders that should run alongside yashiki:

# In ~/.config/yashiki/init
yashiki exec --track "borders active_color=0xffe1e3e4"

Cursor Warp

Control whether mouse cursor follows window focus.

yashiki set-cursor-warp disabled          # Don't move cursor (default)
yashiki set-cursor-warp on-output-change  # Move cursor when switching displays
yashiki set-cursor-warp on-focus-change   # Always move cursor to focused window
yashiki get-cursor-warp                   # Get current mode

Auto-Raise

Focus follows mouse - automatically focus windows when the cursor enters them.

yashiki set-auto-raise disabled           # Don't auto-focus (default)
yashiki set-auto-raise enabled            # Focus window immediately when cursor enters
yashiki set-auto-raise enabled --delay 100  # Wait 100ms before focusing (useful when moving across windows)
yashiki get-auto-raise                    # Get current mode and delay

Outer Gap

Control the gap between windows and screen edges. Applied globally to all layouts and fullscreen windows.

yashiki set-outer-gap 10              # Set all sides to 10px
yashiki set-outer-gap 10 20           # Set vertical=10px, horizontal=20px
yashiki set-outer-gap 10 20 15 25     # Set top=10, right=20, bottom=15, left=25 (CSS-style)
yashiki get-outer-gap                 # Get current outer gap

State Streaming

Subscribe to real-time state change events (useful for status bars like engawa):

yashiki subscribe                     # Subscribe to all events
yashiki subscribe --snapshot          # Get initial snapshot on connect
yashiki subscribe --filter focus,tags # Filter specific events

Event types: window, focus, display, tags, layout

Events are streamed as JSON lines to stdout.

Exec Path

The exec path is used for exec commands and custom layout engine discovery.

yashiki exec-path                # Get current exec path
yashiki set-exec-path "/path1:/path2"  # Set exec path
yashiki add-exec-path /opt/homebrew/bin       # Add to start (high priority)
yashiki add-exec-path --append /usr/local/bin # Add to end (low priority)

Default exec path: <yashiki_executable_dir>:<system_PATH>

Window Rules

Automatically configure window properties based on app name, bundle identifier, title, AXIdentifier, AXSubrole, window level, or button states.

By default, new windows inherit the display's current visible tags. Use the tags action to override this.

# Match by app name
yashiki rule-add --app-name Finder float
yashiki rule-add --app-name Safari tags 2

# Match by bundle identifier (app-id)
yashiki rule-add --app-id com.apple.finder float
yashiki rule-add --app-id "com.google.*" output 2    # Glob pattern

# Match by window title
yashiki rule-add --title "*Preferences*" float

# Match by AXIdentifier (useful for special windows like Ghostty Quick Terminal)
yashiki rule-add --ax-id "com.mitchellh.ghostty.quickTerminal" float

# Match by AXSubrole (AX prefix optional: "Dialog" matches "AXDialog")
yashiki rule-add --subrole Dialog float
yashiki rule-add --subrole FloatingWindow float

# Match by window level (normal, floating, modal, utility, popup, other, or numeric)
yashiki rule-add --window-level other ignore      # Ignore non-normal windows (palettes, etc.)
yashiki rule-add --window-level floating float    # Float utility panels

# Match by button states (exists, none, enabled, disabled)
yashiki rule-add --fullscreen-button none float   # Float windows without fullscreen button
yashiki rule-add --close-button none ignore       # Ignore windows without close button (popups)
yashiki rule-add --app-id com.mitchellh.ghostty --fullscreen-button disabled ignore  # Ghostty Quick Terminal

# Ignore windows completely (never manage - useful for popups/dropdowns)
yashiki rule-add --subrole AXUnknown ignore  # Ignore all popup windows
yashiki rule-add --app-id org.mozilla.firefox --subrole AXUnknown ignore  # Firefox popups only
yashiki rule-add --app-id com.microsoft.Outlook --ax-id none --subrole none ignore  # Outlook invisible windows

# Combined matching (more specific)
yashiki rule-add --app-name Safari --title "*Preferences*" float
yashiki rule-add --app-id com.mitchellh.ghostty --subrole FloatingWindow float

# Other actions
yashiki rule-add --app-name Preview dimensions 800 600
yashiki rule-add --app-name Preview position 100 100

# Remove rule
yashiki rule-del --app-name Finder float

# List all rules
yashiki list-rules

Available actions:

Action Example Description
ignore ignore Never manage (skip completely)
float float Window floats (excluded from tiling)
no-float no-float Override float rule
tags tags 2 Set window tags
output output 2 Move to display
position position 100 200 Set position
dimensions dimensions 800 600 Set size

Rules are sorted by specificity - more specific rules take priority.

For detailed window rules configuration including how to find AX attributes (--ax-id, --subrole), see docs/window-rules.md.

For app-specific workarounds (Firefox flickering, etc.), see docs/workarounds.md.

Built-in Layout Engines

tatami (master-stack)

Classic tiling layout with main area and stack.

Commands:

Command Description
set-main-ratio <0.1-0.9> Set main area ratio
inc-main-ratio Increase main ratio
dec-main-ratio Decrease main ratio
inc-main-count Add window to main area
dec-main-count Remove window from main area
zoom [window_id] Move window to main area
set-inner-gap <px> Gap between windows

byobu (accordion)

AeroSpace-style stacked windows with focused window at front.

Commands:

Command Description
set-padding <px> Stagger offset between windows
set-orientation <h|v> Horizontal or vertical stacking
toggle-orientation Toggle orientation

Custom Layout Engines

Yashiki supports external layout engines via stdin/stdout JSON protocol.

See docs/layout-engine.md for the specification.

Development

# Run daemon with debug logging
RUST_LOG=info cargo run -p yashiki -- start

# Run CLI commands
cargo run -p yashiki -- list-windows

# Run tests
cargo test --all

# Format code
cargo fmt --all

Project Structure

yashiki/                  # WM core daemon + CLI
yashiki-ipc/              # Shared protocol definitions
yashiki-layout-tatami/    # Master-stack layout engine
yashiki-layout-byobu/     # Accordion layout engine

Credits

App Icon

Designed by Yuta Okajima

Inspiration

  • river - External layout protocol, multi-monitor model
  • AeroSpace - Virtual workspaces approach, accordion layout
  • dwm / awesomewm - Tag-based workspaces

License

MIT License - see LICENSE for details.