Configuration

~/.config/dinky/dinky.toml, written on first run and reloaded on save.

Top level

Key Default  
start-at-login true Register as a login item.
workspaces 5 Workspaces across all displays, one native Space each. dinky creates and removes Spaces to match.
default-layout 'tiles' 'tiles' (the existing dwindle layout), 'dwindle', 'accordion', or 'fixed'.
default-tiling true Set false to leave workspaces untiled unless overridden.
follow-app-activation true Cmd-Tab and Dock clicks switch Spaces the fast way. Needs the macOS “switch to a Space with open windows” setting off.

[workspace.<number>]

Override default-tiling or default-layout for a globally numbered workspace. layout = 'fixed' reserves every cell in its template from the start. rows and columns each default to 1; with two columns and three rows, one window occupies one sixth of the workspace, and an empty cell stays empty when another window closes. New windows fill holes first, left to right, top to bottom.

When all cells are occupied, expand chooses what happens next: 'columns' (default) adds a column, 'rows' adds a row, or 'accordion' stacks overflow windows in the last cell. Expansion resizes existing cells but does not rearrange their positions. An overflow row or column disappears once empty; reserved template cells remain. A tree command can still edit the layout; if it changes the template structure, new windows split the focused tile instead of resetting those edits. Changing template settings in the config rebuilds the tree once.

For example, to tile only workspace 2 (and send new Ghostty windows there using a rule):

default-tiling = false

[workspace.2]
tiling = true
layout = 'fixed'
columns = 2
rows = 3
# expand = 'columns' # or 'rows' or 'accordion'

[[rules]]
app-id = 'com.mitchellh.ghostty'
run = 'move-window-to-workspace 2'

rows, columns, and expand apply only to a fixed layout. layout = 'accordion' remains available; conceptually it resembles a 1×1 fixed template with accordion overflow, but keeps the existing accordion orientation behavior. Workspace numbering starts at 1.

[accordion]

Key Default  
padding 30 Points the neighbours peek out by.
orientation 'auto' On switching to accordion, 'auto' runs along the container’s longer side; 'keep' keeps its orientation. An orientation set with layout is always kept.

[gaps]

Key Default  
inner 8 Between windows. Or { horizontal = 8, vertical = 6 }.
outer 8 To the screen edge. Or { top = 44, bottom = 8, left = 8, right = 8 }, or outer.top = 44.

[workspace-to-display]

Which display a workspace lives on, by number. A display pattern is main, secondary (the other one, when there are two), or part of the name from dinky list-displays. A list tries each in turn. Unlisted workspaces, and listed ones whose display isn’t connected, live on the main display.

[workspace-to-display]
5 = 'secondary'         # on the side display while it's connected, else a normal workspace
4 = ['dell', 'lg']

When a display comes or goes, dinky moves the workspace’s windows, layout included, to a Space on its display and removes the Space left behind. Empty leftover Spaces are removed; ones with windows are left alone, unnumbered. A display with no workspaces keeps one unnumbered Space.

[display.<pattern>]

Per-display gaps, with the patterns above. Name patterns beat main/secondary; longer names beat shorter.

[display.main]          # the display with the bar
gaps.outer.top = 44

[borders]

Key Default  
enabled true  
width 4 Points; may be fractional.
active-color '#e1e3e4' '#rrggbb' or '#rrggbbaa'.
inactive-color '#494d64'  
order 'below' 'above' draws a click-through ring over the window.
exclude-apps [] Bundle IDs that get no border.

[focus-follows-mouse]

Key Default  
enabled false Focus the managed window the pointer rests on. Ignored while a button is down or a menu is open, and until the pointer moves to another window after Cmd-Tab or a Space change.
delay-ms 100 How long the pointer must rest.
accordion-edges true Resting on a peeking accordion edge focuses that window.

[hooks]

Commands run on events. See Scripting for the environment exec-and-forget gets.

Key Runs
startup Once, after dinky has read the windows and displays.
workspace-changing When a dinky switch starts, before it lands.
workspace-changed When a display’s workspace changes, or a switch gives up.
focus-changed When focus changes, debounced 50 ms.
mode-changed When the binding mode changes.

[[rules]]

Every rule whose conditions all match a new window runs, in order. Dialogs, sheets, panels and fixed-size windows float without one.

Key  
app-id Bundle ID.
app-name Case-insensitive regex.
title Case-insensitive regex.
kind 'normal', 'dialog', 'sheet' or 'panel'.
run Required. A command or a list.
[[rules]]
app-id = 'com.apple.Music'
run = ['layout floating', 'move-window-to-workspace 5']

[mode.<name>]

Key bindings. dinky starts in main; mode <name> switches. Each key maps to a command or a list of commands. Bound keys are swallowed.

Keys

Modifiers (alt, ctrl, cmd, shift) and one key, joined by -: alt-shift-h, ctrl-left, f5. Names follow a US layout.

The default alt- bindings take over Option-letter characters.

Default config

#:schema https://dinky.rodeo/schemas/dinky.json
# ~/.config/dinky/dinky.toml. Saved changes take effect at once.
# A key you leave out keeps the value shown here.
# Every key and command: https://dinky.rodeo/configuration/

start-at-login = true
workspaces = 5                  # across all displays, one native Space each
default-layout = 'tiles'        # tiles (dwindle) | dwindle | accordion | fixed
default-tiling = true           # false leaves workspaces untiled unless overridden
follow-app-activation = true    # Cmd-Tab and Dock clicks switch Spaces the fast way

# Example: only tile workspace 2 in a fixed 2x3 template.
# Empty cells stay empty; a seventh window adds a column by default.
# default-tiling = false
# [workspace.2]
# tiling = true
# layout = 'fixed'
# columns = 2
# rows = 3
# expand = 'columns'           # columns | rows | accordion (overflow in last cell)

[accordion]
padding = 30                    # points the neighbours peek out by
orientation = 'auto'            # auto: run along the container's longer side | keep

[gaps]
inner = 8                       # or { horizontal = 8, vertical = 8 }
outer = 8                       # or { top = 8, bottom = 8, left = 8, right = 8 }

# Display patterns: main, secondary, or part of a name as `dinky list-displays` prints it.
# A workspace lives on the first display its patterns match, else on the main display.
# [workspace-to-display]
# 5 = 'secondary'

# Overrides for one display.
# [display.main]
# gaps.outer.top = 44

[borders]
enabled = true
width = 4
active-color = '#e1e3e4'        # '#rrggbb' or '#rrggbbaa'
inactive-color = '#494d64'
order = 'below'                 # below | above (a click-through ring over the window)
exclude-apps = []               # bundle IDs whose windows get no border

[focus-follows-mouse]
enabled = false
delay-ms = 100                  # how long the pointer rests on a window before it takes focus
accordion-edges = true          # resting on a peeking accordion edge focuses that window

# dinky commands run on events. exec-and-forget gets $DINKY_WORKSPACE, $DINKY_PREV_WORKSPACE, $DINKY_DISPLAY.
# [hooks]
# startup = ['exec-and-forget brew services restart sketchybar']
# workspace-changed = ['exec-and-forget sketchybar --trigger workspace_change']
# focus-changed = []
# mode-changed = []

# Every rule whose conditions all match a new window runs, in order.
[[rules]]
app-id = 'com.apple.systempreferences'   # also: app-name, title (regexes), kind (normal|dialog|sheet|panel)
run = 'layout floating'

[mode.main]
ctrl-left = 'workspace prev'
ctrl-right = 'workspace next'
alt-1 = 'workspace 1'
alt-2 = 'workspace 2'
alt-3 = 'workspace 3'
alt-4 = 'workspace 4'
alt-5 = 'workspace 5'
alt-6 = 'workspace 6'
alt-7 = 'workspace 7'
alt-8 = 'workspace 8'
alt-9 = 'workspace 9'
alt-shift-1 = 'move-window-to-workspace 1'
alt-shift-2 = 'move-window-to-workspace 2'
alt-shift-3 = 'move-window-to-workspace 3'
alt-shift-4 = 'move-window-to-workspace 4'
alt-shift-5 = 'move-window-to-workspace 5'
alt-shift-6 = 'move-window-to-workspace 6'
alt-shift-7 = 'move-window-to-workspace 7'
alt-shift-8 = 'move-window-to-workspace 8'
alt-shift-9 = 'move-window-to-workspace 9'
alt-tab = 'workspace-back-and-forth'
alt-h = 'focus left'
alt-j = 'focus down'
alt-k = 'focus up'
alt-l = 'focus right'
alt-shift-h = 'move left'
alt-shift-j = 'move down'
alt-shift-k = 'move up'
alt-shift-l = 'move right'
alt-minus = 'resize smart -50'
alt-equal = 'resize smart +50'
alt-f = 'fullscreen'
alt-shift-f = 'layout floating tiling'
alt-comma = 'layout accordion'
alt-slash = 'layout tiles'
alt-shift-n = 'move-window-to-display next'
alt-shift-semicolon = 'mode service'

[mode.service]
esc = ['reload-config', 'mode main']
r = ['flatten-workspace-tree', 'mode main']
alt-shift-h = ['join-with left', 'mode main']
alt-shift-j = ['join-with down', 'mode main']
alt-shift-k = ['join-with up', 'mode main']
alt-shift-l = ['join-with right', 'mode main']