@lattices/cli 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +155 -0
  2. package/app/Lattices.app/Contents/Info.plist +24 -0
  3. package/app/Package.swift +13 -0
  4. package/app/Sources/AccessibilityTextExtractor.swift +111 -0
  5. package/app/Sources/ActionRow.swift +61 -0
  6. package/app/Sources/App.swift +10 -0
  7. package/app/Sources/AppDelegate.swift +242 -0
  8. package/app/Sources/AppShellView.swift +62 -0
  9. package/app/Sources/AppTypeClassifier.swift +70 -0
  10. package/app/Sources/AppWindowShell.swift +63 -0
  11. package/app/Sources/CheatSheetHUD.swift +332 -0
  12. package/app/Sources/CommandModeState.swift +1362 -0
  13. package/app/Sources/CommandModeView.swift +1405 -0
  14. package/app/Sources/CommandModeWindow.swift +192 -0
  15. package/app/Sources/CommandPaletteView.swift +307 -0
  16. package/app/Sources/CommandPaletteWindow.swift +134 -0
  17. package/app/Sources/DaemonProtocol.swift +101 -0
  18. package/app/Sources/DaemonServer.swift +414 -0
  19. package/app/Sources/DesktopModel.swift +149 -0
  20. package/app/Sources/DesktopModelTypes.swift +71 -0
  21. package/app/Sources/DiagnosticLog.swift +271 -0
  22. package/app/Sources/EventBus.swift +30 -0
  23. package/app/Sources/HotkeyManager.swift +254 -0
  24. package/app/Sources/HotkeyStore.swift +338 -0
  25. package/app/Sources/InventoryManager.swift +35 -0
  26. package/app/Sources/InventoryPath.swift +43 -0
  27. package/app/Sources/KeyRecorderView.swift +210 -0
  28. package/app/Sources/LatticesApi.swift +1234 -0
  29. package/app/Sources/LayerBezel.swift +203 -0
  30. package/app/Sources/MainView.swift +479 -0
  31. package/app/Sources/MainWindow.swift +83 -0
  32. package/app/Sources/OcrModel.swift +430 -0
  33. package/app/Sources/OcrStore.swift +329 -0
  34. package/app/Sources/OmniSearchState.swift +283 -0
  35. package/app/Sources/OmniSearchView.swift +288 -0
  36. package/app/Sources/OmniSearchWindow.swift +105 -0
  37. package/app/Sources/OrphanRow.swift +129 -0
  38. package/app/Sources/PaletteCommand.swift +419 -0
  39. package/app/Sources/PermissionChecker.swift +125 -0
  40. package/app/Sources/Preferences.swift +99 -0
  41. package/app/Sources/ProcessModel.swift +199 -0
  42. package/app/Sources/ProcessQuery.swift +151 -0
  43. package/app/Sources/Project.swift +28 -0
  44. package/app/Sources/ProjectRow.swift +368 -0
  45. package/app/Sources/ProjectScanner.swift +128 -0
  46. package/app/Sources/ScreenMapState.swift +2387 -0
  47. package/app/Sources/ScreenMapView.swift +2820 -0
  48. package/app/Sources/ScreenMapWindowController.swift +89 -0
  49. package/app/Sources/SessionManager.swift +72 -0
  50. package/app/Sources/SettingsView.swift +1064 -0
  51. package/app/Sources/SettingsWindow.swift +20 -0
  52. package/app/Sources/TabGroupRow.swift +178 -0
  53. package/app/Sources/Terminal.swift +259 -0
  54. package/app/Sources/TerminalQuery.swift +156 -0
  55. package/app/Sources/TerminalSynthesizer.swift +200 -0
  56. package/app/Sources/Theme.swift +163 -0
  57. package/app/Sources/TilePickerView.swift +209 -0
  58. package/app/Sources/TmuxModel.swift +53 -0
  59. package/app/Sources/TmuxQuery.swift +81 -0
  60. package/app/Sources/WindowTiler.swift +1778 -0
  61. package/app/Sources/WorkspaceManager.swift +575 -0
  62. package/bin/client.js +4 -0
  63. package/bin/daemon-client.js +187 -0
  64. package/bin/lattices-app.js +221 -0
  65. package/bin/lattices.js +1551 -0
  66. package/docs/api.md +924 -0
  67. package/docs/app.md +297 -0
  68. package/docs/concepts.md +135 -0
  69. package/docs/config.md +245 -0
  70. package/docs/layers.md +410 -0
  71. package/docs/ocr.md +185 -0
  72. package/docs/overview.md +94 -0
  73. package/docs/quickstart.md +75 -0
  74. package/package.json +42 -0
package/docs/app.md ADDED
@@ -0,0 +1,297 @@
1
+ ---
2
+ title: Menu Bar App
3
+ description: Command palette, window tiling, and session management
4
+ order: 3
5
+ ---
6
+
7
+ The lattices menu bar app sits in your menu bar and controls your
8
+ workspace from there.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ lattices app # Build (or download) and launch
14
+ lattices app build # Rebuild from source
15
+ lattices app restart # Quit, rebuild, relaunch
16
+ lattices app quit # Stop the app
17
+ ```
18
+
19
+ The first run builds from source if Swift is available, otherwise
20
+ downloads a pre-built binary from GitHub releases.
21
+
22
+ ## Command palette
23
+
24
+ Press **Cmd+Shift+M** from anywhere to open the command palette.
25
+ It's a searchable list of every action the app can perform, with
26
+ fuzzy matching on titles and subtitles.
27
+
28
+ ### Project commands
29
+
30
+ | Command | Description |
31
+ |-------------------------------|------------------------------------------|
32
+ | Launch *project* | Create a new session and open terminal |
33
+ | Attach *project* | Focus or open the running session |
34
+ | Sync *project* | Reconcile session to declared config |
35
+ | Restart *pane* in *project* | Kill and re-run a specific pane's command |
36
+
37
+ ### Window commands
38
+
39
+ Available for running sessions:
40
+
41
+ | Command | Description |
42
+ |-------------------------------|------------------------------------------|
43
+ | Go to *project* | Focus the terminal window (switches Spaces if needed) |
44
+ | Tile *project* Left | Snap window to left half |
45
+ | Tile *project* Right | Snap window to right half |
46
+ | Maximize *project* | Expand window to fill screen |
47
+ | Detach *project* | Disconnect clients, keep session alive |
48
+ | Kill *project* | Terminate the tmux session |
49
+
50
+ ### Tab group commands
51
+
52
+ Available when `groups` are configured in `~/.lattices/workspace.json`
53
+ (see [Tab Groups](/docs/layers#tab-groups)):
54
+
55
+ | Command | Description |
56
+ |-----------------------------|------------------------------------------|
57
+ | Launch *group* | Start the group session (all tabs) |
58
+ | Attach *group* | Focus the running group session |
59
+ | *Group*: *Tab* | Switch to a specific tab within a group |
60
+ | Kill *group* Group | Terminate the group session |
61
+
62
+ ### Layer commands
63
+
64
+ Available when `layers` are configured in `~/.lattices/workspace.json`
65
+ (see [Layers](/docs/layers#layers)):
66
+
67
+ | Command | Description |
68
+ |-----------------------------|------------------------------------------|
69
+ | Switch to Layer: *label* | Focus and tile the layer's project windows |
70
+
71
+ ### App commands
72
+
73
+ | Command | Description |
74
+ |-------------------|------------------------------------------|
75
+ | Settings | Open preferences (terminal, scan root) |
76
+ | Diagnostics | View logs and debug info |
77
+ | Refresh Projects | Re-scan for .lattices.json configs |
78
+ | Quit Lattices | Exit the menu bar app |
79
+
80
+ ## Project discovery
81
+
82
+ The app scans a configurable root directory (up to 3 levels deep)
83
+ for `.lattices.json` files. It skips `.git/` and `node_modules/`.
84
+
85
+ Auto-detection for the scan root checks these paths in order:
86
+ `~/dev`, `~/Developer`, `~/projects`, `~/src`.
87
+
88
+ For each project found, the app reads:
89
+ - Pane names and commands from `.lattices.json`
90
+ - Dev command and package manager from `package.json`
91
+ - Running status by checking `tmux has-session`
92
+
93
+ ## Session management
94
+
95
+ The app calls the lattices CLI for session operations. Launch runs
96
+ `lattices` in the project directory, Sync runs `lattices sync` to
97
+ reconcile panes, and Restart runs `lattices restart <pane>` to kill
98
+ and re-run a pane's process. Detach and Kill call `tmux detach-client`
99
+ and `tmux kill-session` directly.
100
+
101
+ ## Window tiling
102
+
103
+ The app can tile terminal windows to preset screen positions via
104
+ the command palette. It finds windows by their `[lattices:session-name]`
105
+ title tag.
106
+
107
+ For Terminal.app and iTerm2, tiling uses AppleScript to set window
108
+ bounds by matching the title tag. For other terminals, it tiles the
109
+ frontmost window.
110
+
111
+ ### Tile positions (app)
112
+
113
+ | Position | Area |
114
+ |--------------|---------------------------------|
115
+ | Left | Left half |
116
+ | Right | Right half |
117
+ | Top Left | Top-left quarter |
118
+ | Top Right | Top-right quarter |
119
+ | Bottom Left | Bottom-left quarter |
120
+ | Bottom Right | Bottom-right quarter |
121
+ | Maximize | Full visible screen |
122
+ | Left Third | Left third |
123
+ | Center Third | Center third |
124
+ | Right Third | Right third |
125
+ | Center | 70% width, 80% height, centered |
126
+
127
+ ## Space navigation
128
+
129
+ "Go to" commands can switch macOS Spaces to reach a window on a
130
+ different desktop. The app uses a three-path fallback:
131
+
132
+ 1. **CGWindowList** (needs Screen Recording) — looks up the window
133
+ by title tag, finds its Space via SkyLight, switches to it, then
134
+ raises the window
135
+ 2. **Accessibility API** (needs Accessibility) — finds the window
136
+ via AXUIElement, raises it, and activates the app
137
+ 3. **AppleScript** — iterates windows by name for Terminal/iTerm2,
138
+ or bare-activates for other terminals
139
+
140
+ When a window is found and focused, the app flashes a green border
141
+ highlight around it for ~1 second so you can spot it immediately.
142
+
143
+ Grant Screen Recording and Accessibility permissions in System
144
+ Settings > Privacy & Security for all three paths to work.
145
+
146
+ ## Settings
147
+
148
+ Open via the command palette or the gear icon in the main view.
149
+ The settings window has three tabs:
150
+
151
+ ### General
152
+
153
+ | Setting | Description |
154
+ |------------|------------------------------------------------------|
155
+ | Terminal | Which terminal to use (auto-detected from installed) |
156
+ | Mode | `learning` or `auto` (see below) |
157
+ | Scan Root | Directory to scan for .lattices.json configs (type a path or click Browse) |
158
+
159
+ **Mode** controls how the app handles session interaction:
160
+
161
+ - **Learning** — shows tmux keybinding hints when you detach
162
+ (helpful while getting used to tmux)
163
+ - **Auto** — detaches sessions automatically (fewer prompts)
164
+
165
+ ### Shortcuts
166
+
167
+ Shows keyboard shortcut reference:
168
+
169
+ | Shortcut | Action |
170
+ |-------------------|----------------------|
171
+ | Cmd+Shift+M | Open command palette |
172
+ | Cmd+Option+1/2/3 | Switch workspace layer |
173
+ | Ctrl+B D | Detach from session |
174
+ | Ctrl+B X | Kill current pane |
175
+ | Ctrl+B Left/Right| Move between panes |
176
+ | Ctrl+B Z | Zoom pane (toggle) |
177
+ | Ctrl+B [ | Scroll mode |
178
+
179
+ ### Docs
180
+
181
+ Embedded quick reference with glossary, "how it works" steps, and
182
+ links to open the full `config.md` and `concepts.md` docs.
183
+
184
+ ## Supported terminals
185
+
186
+ | Terminal | Launch | Focus/Attach | Tile by tag |
187
+ |--------------|--------|--------------|-------------|
188
+ | Terminal.app | yes | yes | yes |
189
+ | iTerm2 | yes | yes | yes |
190
+ | Warp | yes | activate | frontmost |
191
+ | Ghostty | yes | activate | frontmost |
192
+ | Kitty | yes | activate | frontmost |
193
+ | Alacritty | yes | activate | frontmost |
194
+
195
+ "yes" means full AppleScript-based window matching by title tag.
196
+ "activate" means the app is brought to front but a specific window
197
+ can't be targeted. "frontmost" means tiling applies to whatever
198
+ window is in front.
199
+
200
+ ## Screen OCR
201
+
202
+ > See [Screen OCR](/docs/ocr) for full details on configuration, scanning,
203
+ > search, and agent usage.
204
+
205
+ The app reads text from visible windows using Apple's Vision framework
206
+ and stores results in a local SQLite database with FTS5 full-text search.
207
+ Agents can use this to "see" what's on screen.
208
+
209
+ ### How it works
210
+
211
+ 1. Every 60 seconds, the app captures the top visible windows as images
212
+ 2. A SHA256 hash detects whether the window content has changed
213
+ 3. Changed windows are processed through `VNRecognizeTextRequest` (fast mode)
214
+ 4. Results are stored in `~/.lattices/ocr.db` with full-text indexing
215
+ 5. Entries older than 3 days are automatically purged
216
+
217
+ ### Desktop Inventory integration
218
+
219
+ The Desktop Inventory view (Hyper+4) uses OCR to make windows searchable
220
+ by their content — not just by title or app name. When you type a search
221
+ query, windows matching by OCR content show contextual snippets.
222
+
223
+ ### API access
224
+
225
+ Agents can query OCR data through four API methods:
226
+
227
+ | Method | Description |
228
+ |----------------|------------------------------------------------|
229
+ | `ocr.snapshot` | Current OCR results for all visible windows |
230
+ | `ocr.search` | Full-text search across history (FTS5 syntax) |
231
+ | `ocr.history` | Timeline of OCR results for a specific window |
232
+ | `ocr.scan` | Trigger an immediate scan (bypasses timer) |
233
+
234
+ ```js
235
+ import { daemonCall } from '@lattices/cli'
236
+
237
+ // Find windows showing error messages
238
+ const errors = await daemonCall('ocr.search', { query: 'error OR failed' })
239
+
240
+ // Read what's currently on screen
241
+ const snapshot = await daemonCall('ocr.snapshot')
242
+ ```
243
+
244
+ More in the [Agent API reference](/docs/api#ocrsnapshot).
245
+
246
+ ### Requirements
247
+
248
+ - **Screen Recording** permission — required to capture window images
249
+ - Granted via System Settings > Privacy & Security > Screen Recording
250
+
251
+ ## Agent API server
252
+
253
+ The menu bar app runs a WebSocket server on `ws://127.0.0.1:9399`.
254
+ It starts automatically when the app launches and stops when the app
255
+ quits.
256
+
257
+ ### Checking status
258
+
259
+ ```bash
260
+ lattices daemon status
261
+ ```
262
+
263
+ Or programmatically:
264
+
265
+ ```js
266
+ import { isDaemonRunning, daemonCall } from '@lattices/cli'
267
+
268
+ if (await isDaemonRunning()) {
269
+ const status = await daemonCall('daemon.status')
270
+ console.log(status) // { uptime, clientCount, version, windowCount, tmuxSessionCount }
271
+ }
272
+ ```
273
+
274
+ ### What it provides
275
+
276
+ - 35+ RPC methods for reading windows, sessions, projects, spaces, layers,
277
+ processes, terminals, and OCR. Also launching/killing sessions, tiling
278
+ windows, switching layers, and managing tab groups.
279
+ - 5 real-time events (`windows.changed`, `tmux.changed`, `processes.changed`,
280
+ `layer.switched`, `ocr.scanComplete`) broadcast to all connected clients.
281
+ - Window tracking that monitors the desktop window list and correlates
282
+ windows to lattices sessions via title tags.
283
+ - Space awareness, so it knows which macOS Space each window is on.
284
+
285
+ ### Security
286
+
287
+ The server binds to localhost only (`127.0.0.1:9399`). Not accessible
288
+ from the network. No authentication, so any local process can connect.
289
+ This is intentional — it's for local automation, not remote access.
290
+
291
+ Full method list in the [Agent API reference](/docs/api).
292
+
293
+ ## Diagnostics
294
+
295
+ The diagnostics panel shows a timestamped log of window navigation
296
+ attempts, including which path succeeded or failed. Useful for
297
+ debugging Screen Recording / Accessibility permission issues.
@@ -0,0 +1,135 @@
1
+ ---
2
+ title: Concepts
3
+ description: Core ideas, glossary, and architecture of lattices
4
+ order: 6
5
+ ---
6
+
7
+ ## Glossary
8
+
9
+ | Term | Definition |
10
+ |------|------------|
11
+ | **Command Palette** | The menu bar app's primary interface (**Cmd+Shift+M**). Searchable list of actions: launch, tile, sync, restart, settings. |
12
+ | **Window Tiling** | Snap terminal windows to preset screen positions (halves, quarters, thirds, maximize, center). Works from the CLI (`lattices tile`) or the command palette. |
13
+ | **Agent API** | WebSocket server (`ws://127.0.0.1:9399`) inside the menu bar app. Exposes 35+ RPC methods and 5 real-time events for programmatic control. See the [API reference](/docs/api). |
14
+ | **Agent** | Any program that calls the agent API autonomously — an AI coding agent, a shell script, a CI pipeline, or a custom tool. |
15
+ | **Session** | A persistent tmux workspace that lives in the background. Survives terminal crashes, disconnects, and closing your laptop. One session per project. Requires tmux. |
16
+ | **Pane** | A single terminal view inside a session. A typical setup has two panes side by side — Claude Code on the left, dev server on the right. Requires tmux. |
17
+ | **Attach / Detach** | Attaching connects your terminal to an existing session. Detaching disconnects but keeps the session alive — your dev server keeps running, Claude keeps thinking. Requires tmux. |
18
+ | **Sync / Reconcile** | `lattices sync` brings a running session back in line with its declared config — recreates missing panes, re-applies layout, restores labels, re-runs commands in idle panes. Requires tmux. |
19
+ | **Ensure / Prefill** | Two modes for restoring exited commands on reattach. **Ensure** auto-reruns the command. **Prefill** types it but waits for you to press Enter. Set via `.lattices.json`. Requires tmux. |
20
+ | **tmux** | Terminal multiplexer (optional). Provides persistent sessions, pane layouts, and command restoration. Install with `brew install tmux` if you want session management. |
21
+
22
+ ## How it works
23
+
24
+ 1. You create a `.lattices.json` file in your project root (or run `lattices init`)
25
+ 2. The menu bar app discovers the project and adds it to the command palette
26
+ 3. You can tile windows, switch layers, search via OCR, and use the agent API
27
+ 4. With tmux installed, `lattices` also creates persistent terminal sessions:
28
+ - Each pane gets its command (claude, dev server, tests, etc.)
29
+ - The session persists in the background until you kill it
30
+ - You can attach/detach from any terminal at any time
31
+ - If `ensure` is enabled, exited commands auto-restart on reattach
32
+
33
+ ## Architecture
34
+
35
+ <img src="/architecture.svg" alt="lattices architecture diagram" style="margin: 2rem 0; max-width: 100%;" />
36
+
37
+ - The menu bar app is the core. It provides the command palette,
38
+ window tiling, OCR, project discovery, and the agent API (a WebSocket
39
+ server on `ws://127.0.0.1:9399`). It works with or without tmux.
40
+ - The CLI handles tiling, OCR queries, and (when tmux is installed)
41
+ session management via `tmux` shell commands.
42
+ - Agents and scripts connect to the agent API over WebSocket. They can
43
+ do everything the app and CLI can do: discover projects, tile windows,
44
+ switch layers, read on-screen text, and subscribe to real-time events.
45
+ See the [Agent API reference](/docs/api).
46
+ - When tmux is installed, the app and CLI can also launch, sync, and
47
+ manage persistent terminal sessions. All layers share the same session
48
+ naming convention so they always agree on which session belongs to
49
+ which project.
50
+
51
+ ### Session naming
52
+
53
+ A session name is `<basename>-<hash>`, where:
54
+
55
+ - `basename` is the project directory name (non-alphanumeric chars replaced with `-`)
56
+ - `hash` is the first 6 hex chars of the SHA-256 of the full absolute path
57
+
58
+ This guarantees unique session names even if two projects share the
59
+ same directory name (e.g. `~/work/app` and `~/personal/app`).
60
+
61
+ Both the CLI (Node.js `crypto.createHash`) and the app (Swift
62
+ `CryptoKit.SHA256`) produce identical hashes.
63
+
64
+ ### Window discovery via title tags
65
+
66
+ When lattices creates a tmux session, it sets the tmux option:
67
+
68
+ ```
69
+ set-titles-string "[lattices:<session-name>] #{pane_title}"
70
+ ```
71
+
72
+ This embeds a `[lattices:name]` tag in the terminal window title. The
73
+ menu bar app uses this tag to find windows via three fallback paths:
74
+
75
+ 1. **CGWindowList** (needs Screen Recording permission) — fastest,
76
+ reads window names from the window server
77
+ 2. **Accessibility API** (needs Accessibility permission) — queries
78
+ AXUIElement window titles for the terminal app
79
+ 3. **AppleScript** — iterates Terminal.app or iTerm2 windows by name
80
+
81
+ ### Space switching via SkyLight
82
+
83
+ The menu bar app can switch macOS Spaces to reach a session's window.
84
+ It uses private SkyLight framework APIs loaded at runtime via `dlopen`:
85
+
86
+ - `CGSMainConnectionID` — get the connection to the window server
87
+ - `CGSGetActiveSpace` — current Space ID
88
+ - `CGSCopyManagedDisplaySpaces` — enumerate all Spaces per display
89
+ - `SLSCopySpacesForWindows` — find which Space a window is on
90
+ - `SLSManagedDisplaySetCurrentSpace` — switch a display to a Space
91
+
92
+ This is the same approach used by [Loop](https://github.com/MrKai77/Loop)
93
+ and other macOS window managers.
94
+
95
+ ### Ensure/prefill restoration (requires tmux)
96
+
97
+ When you run `lattices` (no arguments) and a session already exists:
98
+
99
+ 1. lattices checks the `ensure` / `prefill` flag in `.lattices.json`
100
+ 2. For each pane, it queries `#{pane_current_command}` via tmux
101
+ 3. If the pane is running a shell (bash, zsh, fish, sh, dash) — meaning
102
+ the original command has exited — it either:
103
+ - **ensure**: sends the command + Enter (auto-restart)
104
+ - **prefill**: sends the command without Enter (manual restart)
105
+ 4. Then it attaches to the session as normal
106
+
107
+ ## Agent control
108
+
109
+ The agent API gives agents the same control as a human using the
110
+ menu bar app. An agent can list projects and windows, launch sessions,
111
+ tile windows to screen positions, subscribe to real-time events
112
+ (`windows.changed`, `tmux.changed`, `layer.switched`), and sync
113
+ sessions back to their declared config.
114
+
115
+ A typical orchestrator sets up a multi-project workspace in a few
116
+ `daemonCall()` invocations. See the [Agent API reference](/docs/api)
117
+ for the full method list and code examples.
118
+
119
+ ## Key shortcuts (inside tmux)
120
+
121
+ These work when you're inside a tmux session:
122
+
123
+ | Shortcut | Action |
124
+ |----------------|-----------------------|
125
+ | Ctrl+B D | Detach from session |
126
+ | Ctrl+B X | Kill current pane |
127
+ | Ctrl+B Left | Move to left pane |
128
+ | Ctrl+B Right | Move to right pane |
129
+ | Ctrl+B Up | Move to pane above |
130
+ | Ctrl+B Down | Move to pane below |
131
+ | Ctrl+B Z | Zoom pane (toggle) |
132
+ | Ctrl+B [ | Scroll mode (q exits) |
133
+
134
+ The prefix `Ctrl+B` means: hold Control, press B, release both,
135
+ then press the next key.
package/docs/config.md ADDED
@@ -0,0 +1,245 @@
1
+ ---
2
+ title: Configuration
3
+ description: CLI commands, .lattices.json format, and tile positions
4
+ order: 2
5
+ ---
6
+
7
+ ## .lattices.json
8
+
9
+ Place a `.lattices.json` file in your project root to define your
10
+ workspace layout. lattices reads this file when creating a session.
11
+
12
+ ### Minimal example
13
+
14
+ ```json
15
+ {
16
+ "panes": [
17
+ { "name": "claude", "cmd": "claude" },
18
+ { "name": "server", "cmd": "pnpm dev" }
19
+ ]
20
+ }
21
+ ```
22
+
23
+ ### Full example
24
+
25
+ ```json
26
+ {
27
+ "ensure": true,
28
+ "panes": [
29
+ { "name": "claude", "cmd": "claude", "size": 60 },
30
+ { "name": "server", "cmd": "pnpm dev" },
31
+ { "name": "tests", "cmd": "pnpm test --watch" }
32
+ ]
33
+ }
34
+ ```
35
+
36
+ ## Config fields
37
+
38
+ | Field | Type | Required | Description |
39
+ |----------|---------|----------|------------------------------------------------------|
40
+ | panes | array | no | List of pane definitions (see below) |
41
+ | ensure | boolean | no | Auto-restart exited commands on reattach |
42
+ | prefill | boolean | no | Type exited commands into idle panes on reattach (you hit Enter) |
43
+
44
+ `ensure` and `prefill` are mutually exclusive. If both are set,
45
+ `ensure` takes priority.
46
+
47
+ - **ensure** — when you reattach to an existing session, lattices checks
48
+ each pane. If a pane's process has exited and the shell is idle, lattices
49
+ automatically re-runs its declared command.
50
+ - **prefill** — same check, but the command is typed into the pane
51
+ without pressing Enter. You review and hit Enter yourself.
52
+
53
+ ## Pane fields
54
+
55
+ | Field | Type | Required | Description |
56
+ |--------|--------|----------|-------------------------------------|
57
+ | name | string | no | Label for the pane (shown in app) |
58
+ | cmd | string | no | Command to run when pane opens |
59
+ | size | number | no | Width % for the first pane (1-99) |
60
+
61
+ - `size` only applies to the **first pane**. It sets the width of the
62
+ main pane as a percentage. Default is 60.
63
+ - `cmd` can be any shell command. If omitted, the pane opens a shell.
64
+ - `name` is used in the lattices app to show a summary of your layout,
65
+ and as a target for `lattices restart <name>`.
66
+
67
+ ## Layouts
68
+
69
+ lattices picks a layout based on how many panes you define:
70
+
71
+ ### 2 panes — side by side
72
+
73
+ ```
74
+ ┌──────────┬─────────┐
75
+ │ claude │ server │
76
+ │ (60%) │ (40%) │
77
+ └──────────┴─────────┘
78
+ ```
79
+
80
+ Horizontal split. First pane on the left, second on the right.
81
+
82
+ ### 3+ panes — main-vertical
83
+
84
+ ```
85
+ ┌──────────┬─────────┐
86
+ │ claude │ server │
87
+ │ (60%) ├─────────┤
88
+ │ │ tests │
89
+ └──────────┴─────────┘
90
+ ```
91
+
92
+ First pane takes the left side. Remaining panes stack vertically
93
+ on the right.
94
+
95
+ ### 4 panes
96
+
97
+ ```
98
+ ┌──────────┬─────────┐
99
+ │ claude │ server │
100
+ │ (60%) ├─────────┤
101
+ │ │ tests │
102
+ │ ├─────────┤
103
+ │ │ logs │
104
+ └──────────┴─────────┘
105
+ ```
106
+
107
+ ## Auto-detection (no config)
108
+
109
+ If there's no `.lattices.json`, lattices still works. It will:
110
+
111
+ 1. Create a 2-pane layout (60/40 split)
112
+ 2. Run `claude` in the left pane
113
+ 3. Auto-detect your dev command from package.json scripts:
114
+ - Looks for: `dev`, `start`, `serve`, `watch` (in that order)
115
+ - Detects package manager: pnpm > bun > yarn > npm
116
+
117
+ ## Creating a config
118
+
119
+ Run `lattices init` in your project directory to generate a starter
120
+ `.lattices.json` based on your project. The generated config includes
121
+ `"ensure": true` by default.
122
+
123
+ ## CLI commands
124
+
125
+ | Command | Description |
126
+ |----------------------------|--------------------------------------------------|
127
+ | `lattices` | Create or attach to session for current project |
128
+ | `lattices init` | Generate .lattices.json config for this project |
129
+ | `lattices ls` | List active sessions (requires tmux) |
130
+ | `lattices kill [name]` | Kill a session (defaults to current project) |
131
+ | `lattices sync` | Reconcile session to match declared config |
132
+ | `lattices restart [pane]` | Restart a pane's process (by name or index) |
133
+ | `lattices tile <position>` | Tile the frontmost window to a screen position |
134
+ | `lattices group [id]` | List tab groups or launch/attach a group |
135
+ | `lattices groups` | List all tab groups with status |
136
+ | `lattices tab <group> [tab]` | Switch tab within a group (by label or index) |
137
+ | `lattices app` | Launch the menu bar companion app |
138
+ | `lattices app build` | Rebuild the menu bar app from source |
139
+ | `lattices app restart` | Rebuild and relaunch the menu bar app |
140
+ | `lattices layer [name\|index]` | Switch to a workspace layer by name or index |
141
+ | `lattices windows [--json]` | List all visible windows |
142
+ | `lattices window assign <wid> <layer>` | Tag a window to a layer |
143
+ | `lattices window map [--json]` | Show all window→layer assignments |
144
+ | `lattices scan search <query>` | Search indexed screen text |
145
+ | `lattices diag [limit]` | Show recent diagnostic entries |
146
+ | `lattices focus <session>` | Focus a session's window and switch Spaces |
147
+ | `lattices app` | Launch the menu bar companion app |
148
+ | `lattices app build` | Rebuild the menu bar app from source |
149
+ | `lattices app restart` | Rebuild and relaunch the menu bar app |
150
+ | `lattices app quit` | Stop the menu bar app |
151
+ | `lattices help` | Show help |
152
+
153
+ Aliases: `ls`/`list`, `kill`/`rm`, `sync`/`reconcile`,
154
+ `restart`/`respawn`, `tile`/`t`.
155
+
156
+ ## Machine-readable output
157
+
158
+ ### `--json` flag
159
+
160
+ The `lattices windows` command supports a `--json` flag for structured
161
+ output:
162
+
163
+ ```bash
164
+ lattices windows --json
165
+ ```
166
+
167
+ Returns a JSON array of window objects to stdout, useful for piping
168
+ into `jq` or consuming from scripts.
169
+
170
+ ### Daemon responses
171
+
172
+ All agent API calls return JSON natively. If you need structured data
173
+ from lattices, the daemon is easier than parsing stdout. See the
174
+ [API reference](/docs/api).
175
+
176
+ ### Exit codes
177
+
178
+ | Code | Meaning |
179
+ |------|---------------------------------------------|
180
+ | `0` | Success |
181
+ | `1` | General error (missing args, bad config) |
182
+ | `2` | Session not found |
183
+
184
+ ## Recovery
185
+
186
+ ### sync
187
+
188
+ ```
189
+ lattices sync
190
+ ```
191
+
192
+ Reconciles a running session to match the declared config:
193
+
194
+ 1. Counts actual panes vs declared panes
195
+ 2. Recreates any missing panes
196
+ 3. Re-applies the layout (main-vertical with correct width)
197
+ 4. Restores pane labels
198
+ 5. Re-runs declared commands in any idle panes
199
+
200
+ Use when a pane was killed and you want to get back to the declared
201
+ state without killing the whole session.
202
+
203
+ ### restart
204
+
205
+ ```
206
+ lattices restart [target]
207
+ ```
208
+
209
+ Kills the process in a specific pane and re-runs its declared command.
210
+ The target can be:
211
+
212
+ - A **pane name** (case-insensitive): `lattices restart server`
213
+ - A **0-based index**: `lattices restart 1`
214
+ - **Omitted** (defaults to pane 0): `lattices restart`
215
+
216
+ The restart sequence: send Ctrl-C, wait 0.5s, check if the process
217
+ stopped. If it's still running, escalate to SIGKILL on child
218
+ processes. Then send the declared command.
219
+
220
+ ## Tile positions
221
+
222
+ The `lattices tile` command moves the frontmost window to a preset
223
+ screen position. Available positions:
224
+
225
+ | Position | Area |
226
+ |----------------|-----------------------------|
227
+ | `left` | Left half |
228
+ | `right` | Right half |
229
+ | `top` | Top half |
230
+ | `bottom` | Bottom half |
231
+ | `top-left` | Top-left quarter |
232
+ | `top-right` | Top-right quarter |
233
+ | `bottom-left` | Bottom-left quarter |
234
+ | `bottom-right` | Bottom-right quarter |
235
+ | `maximize` | Full screen (visible area) |
236
+ | `left-third` | Left third |
237
+ | `center-third` | Center third |
238
+ | `right-third` | Right third |
239
+ | `center` | 70% width, 80% height, centered |
240
+
241
+ Aliases: `left-half`/`left`, `right-half`/`right`, `top-half`/`top`,
242
+ `bottom-half`/`bottom`, `max`/`maximize`.
243
+
244
+ Tiling respects the menu bar and dock. It uses the visible desktop
245
+ area, not the full screen.