Configuration
CLI commands, .lattices.json format, and tile positions
.lattices.json
Place a .lattices.json file in your project root to define your
workspace layout. lattices reads this file when creating a session.
Minimal example
{
"panes": [
{ "name": "shell" },
{ "name": "server", "cmd": "pnpm dev" }
]
}Full example
{
"ensure": true,
"panes": [
{ "name": "shell", "size": 60 },
{ "name": "server", "cmd": "pnpm dev" },
{ "name": "tests", "cmd": "pnpm test --watch" }
]
}Config fields
| Field | Type | Required | Description |
|---|---|---|---|
| panes | array | no | List of pane definitions (see below) |
| ensure | boolean | no | Auto-restart exited commands on reattach |
| prefill | boolean | no | Type exited commands into idle panes on reattach (you hit Enter) |
ensure and prefill are mutually exclusive. If both are set,
ensure takes priority.
- ensure — when you reattach to an existing session, lattices checks each pane. If a pane's process has exited and the shell is idle, lattices automatically re-runs its declared command.
- prefill — same check, but the command is typed into the pane without pressing Enter. You review and hit Enter yourself.
Pane fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | no | Label for the pane (shown in app) |
| cmd | string | no | Command to run when pane opens |
| size | number | no | Width % for the first pane (1-99) |
sizeonly applies to the first pane. It sets the width of the main pane as a percentage. Default is 60.cmdcan be any shell command. If omitted, the pane opens a shell.nameis used in the lats app to show a summary of your layout, and as a target forlats restart <name>.
Layouts
lattices picks a layout based on how many panes you define:
2 panes — side by side
┌──────────┬─────────┐
│ shell │ server │
│ (60%) │ (40%) │
└──────────┴─────────┘Horizontal split. First pane on the left, second on the right.
3+ panes — main-vertical
┌──────────┬─────────┐
│ shell │ server │
│ (60%) ├─────────┤
│ │ tests │
└──────────┴─────────┘First pane takes the left side. Remaining panes stack vertically on the right.
4 panes
┌──────────┬─────────┐
│ shell │ server │
│ (60%) ├─────────┤
│ │ tests │
│ ├─────────┤
│ │ logs │
└──────────┴─────────┘Auto-detection (no config)
If there's no .lattices.json, lattices still works. It will:
- Create a 2-pane layout (60/40 split)
- Open a shell in the left pane
- Auto-detect your dev command from package.json scripts and run it on the right:
- Looks for:
dev,start,serve,watch(in that order) - Detects package manager: bun > pnpm > yarn > npm
- Looks for:
Creating a config
Run lats init in your project directory to generate a starter
.lattices.json based on your project. The generated config includes
"ensure": true by default.
CLI commands
| Command | Description |
|---|---|
lats |
Show workspace status and common commands |
lats start |
Create or attach to session for current project |
lattices tmux |
Alias for lats start |
lats init |
Generate .lattices.json config for this project |
lats ls |
List active sessions (requires tmux) |
lats kill [name] |
Kill a session (defaults to current project) |
lats sync |
Reconcile session to match declared config |
lats restart [pane] |
Restart a pane's process (by name or index) |
lats tile <position> |
Tile the frontmost window to a screen position |
lats tile family [app] [region] |
Smart-grid the frontmost app family, or a named app |
lats window move <wid> --display <n> [--placement <slot>] |
Move a window to another display |
lats window place <wid> <slot> [--display <n>] |
Snap a window into a placement slot |
lats distribute [app] [region] |
Smart-grid visible windows or just one app |
lats group [id] |
List tab groups or launch/attach a group |
lats groups |
List all tab groups with status |
lats tab <group> [tab] |
Switch tab within a group (by label or index) |
lats app |
Launch the menu bar companion app |
lats app install |
Register launch-at-login and start now |
lats app login status |
Show launch-at-login registration |
lats app login disable |
Disable launch-at-login |
lats update |
Update lattices (CLI + app), keep startup, relaunch |
lats app update |
Swap in the latest app release only (not the CLI) |
lats app build |
Rebuild the menu bar app from source |
lats app restart |
Rebuild and relaunch the menu bar app |
lats app quit |
Stop the menu bar app |
lats layer [name|slot] |
Switch to a workspace layer by name or pad slot (1-4, 6-9) |
lats windows [--json] |
List all visible windows |
lats map [--json] |
Read-only current-Space terminal/JSON map |
lats layer add wid:N --to <layer> |
Add a window to a layer |
lats layer remove wid:N --from <layer> |
Take a window out of a layer |
lats actor toggle |
Hide/show persistent overlay actors |
lats hud register [manifest] |
Register a .lattices/hud/manifest.json |
lats hud publish [id|manifest] |
Publish a static HUD actor to the desktop |
lats hud sync |
Publish all registered HUD actors |
lats search <query> |
Search windows by title, app, session, OCR |
lats search <q> --deep |
Deep search: index + live terminal inspection |
lats search <q> --all |
Same as --deep (all search sources) |
lats search <q> --wid |
Print matching window IDs only (pipeable) |
lats place <query> [pos] |
Deep search + focus + tile (default: bottom-right) |
lats focus <session> |
Focus a session's window and switch Spaces |
lats scan search <query> |
Search indexed screen text |
lats action |
Action product status (install, agent, checkout) |
lats action install |
Download the latest Action.app release to /Applications |
lats action launch |
Open Action.app (--launch also works on install) |
lats action quit |
Quit Action.app |
lats action call <m> |
Raw Action agent call over its private socket |
lats action <cmd> |
Forward to the Action CLI (monorepo checkout) |
lattices diag [limit] |
Show recent diagnostic entries |
lats help |
Show help |
Aliases: ls/list, kill/rm, sync/reconcile,
restart/respawn, tile/t.
Keyboard remaps
The menu bar app can create a lightweight keyboard layer from
~/.lattices/keyboard-remaps.json. The default config is:
{
"rules": [
{
"enabled": true,
"from": "caps_lock",
"id": "caps_lock_hyper_escape",
"toIfAlone": "escape",
"toIfHeld": "hyper"
}
]
}It is enabled by default and can be turned off from Settings -> General ->
Keyboard remaps. Hold Caps Lock to send Hyper (Control + Option +
Shift + Command), or tap Caps Lock alone to send Escape.
Machine-readable output
--json flag
lats windows --json returns the raw window array.
lats map --json returns a versioned, per-display
current-Space snapshot with coordinate metadata:
lats windows --json
lats map --jsonBoth are useful for piping into jq or consuming from scripts.
Daemon responses
All agent API calls return JSON natively. If you need structured data from lattices, the daemon is easier than parsing stdout. See the API reference.
Exit codes
| Code | Meaning |
|---|---|
0 |
Success |
1 |
General error (missing args, bad config) |
2 |
Session not found |
Recovery
sync
lats syncReconciles a running session to match the declared config:
- Counts actual panes vs declared panes
- Recreates any missing panes
- Re-applies the layout (main-vertical with correct width)
- Restores pane labels
- Re-runs declared commands in any idle panes
Use when a pane was killed and you want to get back to the declared state without killing the whole session.
restart
lats restart [target]Kills the process in a specific pane and re-runs its declared command. The target can be:
- A pane name (case-insensitive):
lats restart server - A 0-based index:
lats restart 1 - Omitted (defaults to pane 0):
lats restart
The restart sequence: send Ctrl-C, wait 0.5s, check if the process stopped. If it's still running, escalate to SIGKILL on child processes. Then send the declared command.
Tile positions
The lats tile command moves the frontmost window to a preset
screen position. Available positions:
| Position | Area |
|---|---|
left |
Left half |
right |
Right half |
top |
Top half |
bottom |
Bottom half |
top-left |
Top-left quarter |
top-right |
Top-right quarter |
bottom-left |
Bottom-left quarter |
bottom-right |
Bottom-right quarter |
maximize |
Full screen (visible area) |
left-third |
Left third |
center-third |
Center third |
right-third |
Right third |
center |
80% width, 80% height, centered (20% margin all sides) |
Aliases: left-half/left, right-half/right, top-half/top,
bottom-half/bottom, max/maximize.
Tiling respects the menu bar and dock. It uses the visible desktop area, not the full screen.
For arbitrary cells, use compact CxR:c,r with 1-indexed coordinates
from the top-left, or canonical grid:CxR:c,r with 0-indexed coordinates.
Example: lats tile 4x4:1,2.
When the menu bar app is running, lats tile routes through the daemon's
canonical windows.place and reports a verified receipt. Without the daemon it
falls back to AppleScript (frontmost app, primary display) and says so.
Moving a specific window
lats tile always targets the frontmost window. To move a specific
window — by the CGWindowID shown in lats map or lats windows —
use lats window move / lats window place (daemon required):
lats window move 4182 --display 1 # keep relative size/position
lats window move 4182 --display 1 --placement right
lats window place 4182 top-left # slot on its current display
lats window move 4182 --display 0 --dry-run --json # plan without movingA malformed wid is an error; these commands never fall back to the frontmost
window. Slots are the named positions above plus grid placements; fractional
typed placements remain available via lats call windows.place.
Smart app tiling
Use lats tile family when you want lattices to arrange a whole
window family instead of just moving the frontmost window.
Examples:
lats tile family
lats tile family right
lats tile family iTerm2
lats tile family "Google Chrome" left- With no app name,
familymeans the frontmost app. If iTerm is frontmost, lattices grids your visible iTerm windows. - If you pass a region (
left,right,top,bottom, etc.), the smart grid is constrained to that part of the screen. lats distributeuses the same smart grid engine, but defaults to all visible windows instead of the current app family.