IPC commands
Control Shoji from the command line through Hammerspoon’s IPC mechanism. Use it for shell scripts, keyboard shortcuts from other tools, and automation.
Prerequisites
Load the hs.ipc module in Hammerspoon config:
-- ~/.hammerspoon/init.luarequire("hs.ipc")This enables the hs CLI tool. If hs is not in PATH, run
hs.ipc.cliInstall() in the Hammerspoon console.
Basic usage
Send commands via the hs CLI:
# Get current statushs -c 'spoon.Shoji:cmd("status")'
# Cycle to next layouths -c 'spoon.Shoji:cmd("cycle-layout")'
# Set specific layout (varargs style)hs -c 'spoon.Shoji:cmd("set-layout", "wide")'
# Set specific layout (array style - also supported)hs -c 'spoon.Shoji:cmd("set-layout", {"wide"})'Available commands
list-commands
Returns all available command names.
hs -c 'spoon.Shoji:cmd("list-commands")'The response includes all commands: cycle-layout, dec-nmaster, focus,
focus-down, focus-left, focus-next, focus-prev, focus-right,
focus-up, get-layout, inc-nmaster, list-commands, list-layouts,
nmaster, ratio, resize-main-dec, resize-main-inc, retile,
retile-only, set-layout, status, swap, swap-main, swap-next,
swap-prev, toggle-float.
status
Returns the current state of the focused space.
hs -c 'spoon.Shoji:cmd("status")'Response:
{ success = true, data = { spaceID = 1, layout = "tall", mainRatio = 0.5, nmaster = 1, windowCount = 3 }}cycle-layout
Cycles to the next layout in the enabled layouts list.
hs -c 'spoon.Shoji:cmd("cycle-layout")'Response:
{ success = true, data = { cycled = true }}set-layout
Sets a specific layout by name.
hs -c 'spoon.Shoji:cmd("set-layout", {"bsp"})'Arguments:
layoutName(required): Name of the layout to set
Response:
{ success = true, data = { layout = "bsp" }}Error (unknown layout):
{ success = false, error = "Unknown layout: nonexistent"}retile
Retiles the current space and resets layout parameters (mainRatio, nmaster,
layoutState) to defaults.
hs -c 'spoon.Shoji:cmd("retile")'Response:
{ success = true, data = { spaceID = 1 }}retile-only
Retiles without resetting layout parameters. Preserves mainRatio, nmaster,
and layout state. Useful for re-applying the layout after manual window moves.
hs -c 'spoon.Shoji:cmd("retile-only")'Response:
{ success = true, data = { spaceID = 1 }}list-layouts
Returns all available layout names.
hs -c 'spoon.Shoji:cmd("list-layouts")'get-layout
Returns the current layout for the focused space.
hs -c 'spoon.Shoji:cmd("get-layout")'toggle-float
Toggles floating state for the focused window.
hs -c 'spoon.Shoji:cmd("toggle-float")'focus
Focus window in a direction.
# Focus directions: left, right, up, down, next, prevhs -c 'spoon.Shoji:cmd("focus", "left")'hs -c 'spoon.Shoji:cmd("focus", "next")'swap
Swap focused window with another.
# Swap directions: next, prev, mainhs -c 'spoon.Shoji:cmd("swap", "next")'hs -c 'spoon.Shoji:cmd("swap", "main")'ratio
Adjust the main area ratio.
# Increase ratio by 0.05hs -c 'spoon.Shoji:cmd("ratio", "0.05")'
# Decrease ratio by 0.1hs -c 'spoon.Shoji:cmd("ratio", "-0.1")'The ratio is clamped between 0.1 and 0.9.
nmaster
Adjust the number of master windows.
# Increase nmaster by 1hs -c 'spoon.Shoji:cmd("nmaster", "1")'
# Decrease nmaster by 1hs -c 'spoon.Shoji:cmd("nmaster", "-1")'The nmaster count is clamped to a minimum of 1.
Shorthand commands
These commands provide shortcuts for common operations:
# Focus shortcutshs -c 'spoon.Shoji:cmd("focus-left")'hs -c 'spoon.Shoji:cmd("focus-right")'hs -c 'spoon.Shoji:cmd("focus-up")'hs -c 'spoon.Shoji:cmd("focus-down")'hs -c 'spoon.Shoji:cmd("focus-next")'hs -c 'spoon.Shoji:cmd("focus-prev")'
# Swap shortcutshs -c 'spoon.Shoji:cmd("swap-next")'hs -c 'spoon.Shoji:cmd("swap-prev")'hs -c 'spoon.Shoji:cmd("swap-main")'
# Ratio shortcuts (uses default step)hs -c 'spoon.Shoji:cmd("resize-main-inc")'hs -c 'spoon.Shoji:cmd("resize-main-dec")'
# Nmaster shortcutshs -c 'spoon.Shoji:cmd("inc-nmaster")'hs -c 'spoon.Shoji:cmd("dec-nmaster")'Response format
All commands return a table with:
---@class IPCSuccessResult---@field success true -- Whether the command succeeded---@field data table -- Result data (on success)
---@class IPCErrorResult---@field success false -- Whether the command succeeded---@field error string -- Error message (on failure)
---@alias IPCResult IPCSuccessResult|IPCErrorResultError handling
Commands fail gracefully with descriptive error messages:
# Unknown commandhs -c 'spoon.Shoji:cmd("unknown")'# { success = false, error = "Unknown command: unknown" }
# Shoji not startedhs -c 'spoon.Shoji:cmd("status")'# { success = false, error = "Shoji is not started" }
# Missing argumenths -c 'spoon.Shoji:cmd("set-layout")'# { success = false, error = "Missing layout name argument" }Scripting examples
Toggle between layouts
#!/bin/bashCURRENT=$(hs -c 'return spoon.Shoji:cmd("status").data.layout')
if [ "$CURRENT" = "tall" ]; then hs -c 'spoon.Shoji:cmd("set-layout", {"wide"})'else hs -c 'spoon.Shoji:cmd("set-layout", {"tall"})'fiGet window count
hs -c 'return spoon.Shoji:cmd("status").data.windowCount'Conditional retile
# Only retile if using BSP layoutLAYOUT=$(hs -c 'return spoon.Shoji:cmd("status").data.layout')if [ "$LAYOUT" = "bsp" ]; then hs -c 'spoon.Shoji:cmd("retile-only")'fitmux integration
Bind Shoji commands to tmux keys:
bind-key C-l run-shell "hs -c 'spoon.Shoji:cmd(\"cycle-layout\")'"bind-key C-t run-shell "hs -c 'spoon.Shoji:cmd(\"set-layout\", {\"tall\"})'"Lua API
Use the same commands from Lua:
-- In your Hammerspoon configlocal result = spoon.Shoji:cmd("status")if result.success then print("Current layout: " .. result.data.layout)end