@arach/lattices 0.1.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.
- package/README.md +157 -0
- package/app/Lattices.app/Contents/Info.plist +24 -0
- package/app/Package.swift +13 -0
- package/app/Sources/App.swift +49 -0
- package/app/Sources/AppDelegate.swift +104 -0
- package/app/Sources/AppShellView.swift +62 -0
- package/app/Sources/AppTypeClassifier.swift +70 -0
- package/app/Sources/AppWindowShell.swift +63 -0
- package/app/Sources/CheatSheetHUD.swift +331 -0
- package/app/Sources/CommandModeState.swift +1341 -0
- package/app/Sources/CommandModeView.swift +1380 -0
- package/app/Sources/CommandModeWindow.swift +192 -0
- package/app/Sources/CommandPaletteView.swift +307 -0
- package/app/Sources/CommandPaletteWindow.swift +134 -0
- package/app/Sources/DaemonProtocol.swift +101 -0
- package/app/Sources/DaemonServer.swift +406 -0
- package/app/Sources/DesktopModel.swift +121 -0
- package/app/Sources/DesktopModelTypes.swift +71 -0
- package/app/Sources/DiagnosticLog.swift +253 -0
- package/app/Sources/EventBus.swift +29 -0
- package/app/Sources/HotkeyManager.swift +249 -0
- package/app/Sources/HotkeyStore.swift +330 -0
- package/app/Sources/InventoryManager.swift +35 -0
- package/app/Sources/InventoryPath.swift +43 -0
- package/app/Sources/KeyRecorderView.swift +210 -0
- package/app/Sources/LatticesApi.swift +915 -0
- package/app/Sources/MainView.swift +507 -0
- package/app/Sources/MainWindow.swift +70 -0
- package/app/Sources/OrphanRow.swift +129 -0
- package/app/Sources/PaletteCommand.swift +409 -0
- package/app/Sources/PermissionChecker.swift +115 -0
- package/app/Sources/Preferences.swift +48 -0
- package/app/Sources/ProcessModel.swift +199 -0
- package/app/Sources/ProcessQuery.swift +151 -0
- package/app/Sources/Project.swift +28 -0
- package/app/Sources/ProjectRow.swift +368 -0
- package/app/Sources/ProjectScanner.swift +121 -0
- package/app/Sources/ScreenMapState.swift +2397 -0
- package/app/Sources/ScreenMapView.swift +2817 -0
- package/app/Sources/ScreenMapWindowController.swift +89 -0
- package/app/Sources/SessionManager.swift +72 -0
- package/app/Sources/SettingsView.swift +641 -0
- package/app/Sources/SettingsWindow.swift +20 -0
- package/app/Sources/TabGroupRow.swift +178 -0
- package/app/Sources/Terminal.swift +259 -0
- package/app/Sources/TerminalQuery.swift +156 -0
- package/app/Sources/TerminalSynthesizer.swift +200 -0
- package/app/Sources/Theme.swift +124 -0
- package/app/Sources/TilePickerView.swift +209 -0
- package/app/Sources/TmuxModel.swift +53 -0
- package/app/Sources/TmuxQuery.swift +81 -0
- package/app/Sources/WindowTiler.swift +1752 -0
- package/app/Sources/WorkspaceManager.swift +434 -0
- package/bin/daemon-client.js +187 -0
- package/bin/lattices-app.js +205 -0
- package/bin/lattices.js +1295 -0
- package/docs/api.md +707 -0
- package/docs/app.md +250 -0
- package/docs/concepts.md +225 -0
- package/docs/config.md +234 -0
- package/docs/layers.md +317 -0
- package/docs/overview.md +74 -0
- package/docs/quickstart.md +82 -0
- package/package.json +38 -0
package/docs/app.md
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Menu Bar App
|
|
3
|
+
description: Command palette, window tiling, and session management
|
|
4
|
+
order: 3
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Menu Bar App
|
|
8
|
+
|
|
9
|
+
The lattices menu bar app is a native macOS companion that lives in your
|
|
10
|
+
menu bar and gives you quick access to all your lattices sessions.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
lattices app # Build (or download) and launch
|
|
16
|
+
lattices app build # Rebuild from source
|
|
17
|
+
lattices app restart # Quit, rebuild, relaunch
|
|
18
|
+
lattices app quit # Stop the app
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The first run builds from source if Swift is available, otherwise
|
|
22
|
+
downloads a pre-built binary from GitHub releases.
|
|
23
|
+
|
|
24
|
+
## Command palette
|
|
25
|
+
|
|
26
|
+
Press **Cmd+Shift+M** from anywhere to open the command palette.
|
|
27
|
+
It's a searchable list of every action the app can perform, with
|
|
28
|
+
fuzzy matching on titles and subtitles.
|
|
29
|
+
|
|
30
|
+
### Project commands
|
|
31
|
+
|
|
32
|
+
| Command | Description |
|
|
33
|
+
|-------------------------------|------------------------------------------|
|
|
34
|
+
| Launch *project* | Create a new session and open terminal |
|
|
35
|
+
| Attach *project* | Focus or open the running session |
|
|
36
|
+
| Sync *project* | Reconcile session to declared config |
|
|
37
|
+
| Restart *pane* in *project* | Kill and re-run a specific pane's command |
|
|
38
|
+
|
|
39
|
+
### Window commands
|
|
40
|
+
|
|
41
|
+
Available for running sessions:
|
|
42
|
+
|
|
43
|
+
| Command | Description |
|
|
44
|
+
|-------------------------------|------------------------------------------|
|
|
45
|
+
| Go to *project* | Focus the terminal window (switches Spaces if needed) |
|
|
46
|
+
| Tile *project* Left | Snap window to left half |
|
|
47
|
+
| Tile *project* Right | Snap window to right half |
|
|
48
|
+
| Maximize *project* | Expand window to fill screen |
|
|
49
|
+
| Detach *project* | Disconnect clients, keep session alive |
|
|
50
|
+
| Kill *project* | Terminate the tmux session |
|
|
51
|
+
|
|
52
|
+
### Tab group commands
|
|
53
|
+
|
|
54
|
+
Available when `groups` are configured in `~/.lattices/workspace.json`
|
|
55
|
+
(see [Tab Groups](/docs/layers#tab-groups)):
|
|
56
|
+
|
|
57
|
+
| Command | Description |
|
|
58
|
+
|-----------------------------|------------------------------------------|
|
|
59
|
+
| Launch *group* | Start the group session (all tabs) |
|
|
60
|
+
| Attach *group* | Focus the running group session |
|
|
61
|
+
| *Group*: *Tab* | Switch to a specific tab within a group |
|
|
62
|
+
| Kill *group* Group | Terminate the group session |
|
|
63
|
+
|
|
64
|
+
### Layer commands
|
|
65
|
+
|
|
66
|
+
Available when `layers` are configured in `~/.lattices/workspace.json`
|
|
67
|
+
(see [Layers](/docs/layers#layers)):
|
|
68
|
+
|
|
69
|
+
| Command | Description |
|
|
70
|
+
|-----------------------------|------------------------------------------|
|
|
71
|
+
| Switch to Layer: *label* | Focus and tile the layer's project windows |
|
|
72
|
+
|
|
73
|
+
### App commands
|
|
74
|
+
|
|
75
|
+
| Command | Description |
|
|
76
|
+
|-------------------|------------------------------------------|
|
|
77
|
+
| Settings | Open preferences (terminal, scan root) |
|
|
78
|
+
| Diagnostics | View logs and debug info |
|
|
79
|
+
| Refresh Projects | Re-scan for .lattices.json configs |
|
|
80
|
+
| Quit Lattices | Exit the menu bar app |
|
|
81
|
+
|
|
82
|
+
## Project discovery
|
|
83
|
+
|
|
84
|
+
The app scans a configurable root directory (up to 3 levels deep)
|
|
85
|
+
for `.lattices.json` files. It skips `.git/` and `node_modules/`.
|
|
86
|
+
|
|
87
|
+
Auto-detection for the scan root checks these paths in order:
|
|
88
|
+
`~/dev`, `~/Developer`, `~/projects`, `~/src`.
|
|
89
|
+
|
|
90
|
+
For each project found, the app reads:
|
|
91
|
+
- Pane names and commands from `.lattices.json`
|
|
92
|
+
- Dev command and package manager from `package.json`
|
|
93
|
+
- Running status by checking `tmux has-session`
|
|
94
|
+
|
|
95
|
+
## Session management
|
|
96
|
+
|
|
97
|
+
The app calls the lattices CLI for session operations:
|
|
98
|
+
|
|
99
|
+
- **Launch** — runs `lattices` in the project directory, which creates
|
|
100
|
+
or reattaches to the session
|
|
101
|
+
- **Sync** — runs `lattices sync` to reconcile panes to the config
|
|
102
|
+
- **Restart** — runs `lattices restart <pane>` to kill and re-run a
|
|
103
|
+
specific pane's process
|
|
104
|
+
- **Detach** — calls `tmux detach-client` directly
|
|
105
|
+
- **Kill** — calls `tmux kill-session` directly
|
|
106
|
+
|
|
107
|
+
## Window tiling
|
|
108
|
+
|
|
109
|
+
The app can tile terminal windows to preset screen positions via
|
|
110
|
+
the command palette. It finds windows by their `[lattices:session-name]`
|
|
111
|
+
title tag.
|
|
112
|
+
|
|
113
|
+
For Terminal.app and iTerm2, tiling uses AppleScript to set window
|
|
114
|
+
bounds by matching the title tag. For other terminals, it tiles the
|
|
115
|
+
frontmost window.
|
|
116
|
+
|
|
117
|
+
### Tile positions (app)
|
|
118
|
+
|
|
119
|
+
| Position | Area |
|
|
120
|
+
|--------------|---------------------------------|
|
|
121
|
+
| Left | Left half |
|
|
122
|
+
| Right | Right half |
|
|
123
|
+
| Top Left | Top-left quarter |
|
|
124
|
+
| Top Right | Top-right quarter |
|
|
125
|
+
| Bottom Left | Bottom-left quarter |
|
|
126
|
+
| Bottom Right | Bottom-right quarter |
|
|
127
|
+
| Maximize | Full visible screen |
|
|
128
|
+
| Center | 70% width, 80% height, centered |
|
|
129
|
+
|
|
130
|
+
## Space navigation
|
|
131
|
+
|
|
132
|
+
"Go to" commands can switch macOS Spaces to reach a window on a
|
|
133
|
+
different desktop. The app uses a three-path fallback:
|
|
134
|
+
|
|
135
|
+
1. **CGWindowList** (needs Screen Recording) — looks up the window
|
|
136
|
+
by title tag, finds its Space via SkyLight, switches to it, then
|
|
137
|
+
raises the window
|
|
138
|
+
2. **Accessibility API** (needs Accessibility) — finds the window
|
|
139
|
+
via AXUIElement, raises it, and activates the app
|
|
140
|
+
3. **AppleScript** — iterates windows by name for Terminal/iTerm2,
|
|
141
|
+
or bare-activates for other terminals
|
|
142
|
+
|
|
143
|
+
When a window is found and focused, the app flashes a green border
|
|
144
|
+
highlight around it for ~1 second so you can spot it immediately.
|
|
145
|
+
|
|
146
|
+
Grant Screen Recording and Accessibility permissions in System
|
|
147
|
+
Settings > Privacy & Security for the best experience.
|
|
148
|
+
|
|
149
|
+
## Settings
|
|
150
|
+
|
|
151
|
+
Open via the command palette or the gear icon in the main view.
|
|
152
|
+
The settings window has three tabs:
|
|
153
|
+
|
|
154
|
+
### General
|
|
155
|
+
|
|
156
|
+
| Setting | Description |
|
|
157
|
+
|------------|------------------------------------------------------|
|
|
158
|
+
| Terminal | Which terminal to use (auto-detected from installed) |
|
|
159
|
+
| Mode | `learning` or `auto` (see below) |
|
|
160
|
+
| Scan Root | Directory to scan for .lattices.json configs (type a path or click Browse) |
|
|
161
|
+
|
|
162
|
+
**Mode** controls how the app handles session interaction:
|
|
163
|
+
|
|
164
|
+
- **Learning** — shows tmux keybinding hints when you detach
|
|
165
|
+
(helpful while getting used to tmux)
|
|
166
|
+
- **Auto** — detaches sessions automatically (fewer prompts)
|
|
167
|
+
|
|
168
|
+
### Shortcuts
|
|
169
|
+
|
|
170
|
+
Shows keyboard shortcut reference:
|
|
171
|
+
|
|
172
|
+
| Shortcut | Action |
|
|
173
|
+
|-------------------|----------------------|
|
|
174
|
+
| Cmd+Shift+M | Open command palette |
|
|
175
|
+
| Cmd+Option+1/2/3 | Switch workspace layer |
|
|
176
|
+
| Ctrl+B D | Detach from session |
|
|
177
|
+
| Ctrl+B X | Kill current pane |
|
|
178
|
+
| Ctrl+B Left/Right| Move between panes |
|
|
179
|
+
| Ctrl+B Z | Zoom pane (toggle) |
|
|
180
|
+
| Ctrl+B [ | Scroll mode |
|
|
181
|
+
|
|
182
|
+
### Docs
|
|
183
|
+
|
|
184
|
+
Embedded quick reference with glossary, "how it works" steps, and
|
|
185
|
+
links to open the full `config.md` and `concepts.md` docs.
|
|
186
|
+
|
|
187
|
+
## Supported terminals
|
|
188
|
+
|
|
189
|
+
| Terminal | Launch | Focus/Attach | Tile by tag |
|
|
190
|
+
|--------------|--------|--------------|-------------|
|
|
191
|
+
| Terminal.app | yes | yes | yes |
|
|
192
|
+
| iTerm2 | yes | yes | yes |
|
|
193
|
+
| Warp | yes | activate | frontmost |
|
|
194
|
+
| Ghostty | yes | activate | frontmost |
|
|
195
|
+
| Kitty | yes | activate | frontmost |
|
|
196
|
+
| Alacritty | yes | activate | frontmost |
|
|
197
|
+
|
|
198
|
+
"yes" means full AppleScript-based window matching by title tag.
|
|
199
|
+
"activate" means the app is brought to front but a specific window
|
|
200
|
+
can't be targeted. "frontmost" means tiling applies to whatever
|
|
201
|
+
window is in front.
|
|
202
|
+
|
|
203
|
+
## Daemon
|
|
204
|
+
|
|
205
|
+
The menu bar app runs a WebSocket daemon on `ws://127.0.0.1:9399`.
|
|
206
|
+
It starts automatically when the app launches and stops when the app
|
|
207
|
+
quits.
|
|
208
|
+
|
|
209
|
+
### Checking status
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
lattices daemon status
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Or programmatically:
|
|
216
|
+
|
|
217
|
+
```js
|
|
218
|
+
import { isDaemonRunning, daemonCall } from 'lattices/daemon-client'
|
|
219
|
+
|
|
220
|
+
if (await isDaemonRunning()) {
|
|
221
|
+
const status = await daemonCall('daemon.status')
|
|
222
|
+
console.log(status) // { uptime, clientCount, version, windowCount, tmuxSessionCount }
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### What it provides
|
|
227
|
+
|
|
228
|
+
- **20 RPC methods** — read windows, sessions, projects, spaces, layers;
|
|
229
|
+
launch/kill/sync sessions; tile/focus/move windows; switch layers;
|
|
230
|
+
manage tab groups
|
|
231
|
+
- **3 real-time events** — `windows.changed`, `tmux.changed`,
|
|
232
|
+
`layer.switched` — broadcast to all connected clients
|
|
233
|
+
- **Window tracking** — the daemon monitors the desktop window list
|
|
234
|
+
and correlates windows to lattices sessions via title tags
|
|
235
|
+
- **Space awareness** — knows which macOS Space each window is on
|
|
236
|
+
|
|
237
|
+
### Security
|
|
238
|
+
|
|
239
|
+
The daemon binds to **localhost only** (`127.0.0.1:9399`). It is not
|
|
240
|
+
accessible from the network. There is no authentication — any process
|
|
241
|
+
on the same machine can connect. This is intentional: the daemon is
|
|
242
|
+
designed for local automation, not remote access.
|
|
243
|
+
|
|
244
|
+
See the [Daemon API reference](/docs/api) for the full method list.
|
|
245
|
+
|
|
246
|
+
## Diagnostics
|
|
247
|
+
|
|
248
|
+
The diagnostics panel shows a timestamped log of window navigation
|
|
249
|
+
attempts, including which path succeeded or failed. Useful for
|
|
250
|
+
debugging Screen Recording / Accessibility permission issues.
|
package/docs/concepts.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Concepts
|
|
3
|
+
description: Core ideas, glossary, and architecture of lattices
|
|
4
|
+
order: 1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Concepts
|
|
8
|
+
|
|
9
|
+
## What is lattices?
|
|
10
|
+
|
|
11
|
+
lattices is a developer workspace launcher. It creates pre-configured
|
|
12
|
+
terminal layouts for your projects using tmux, so you can go from
|
|
13
|
+
"I want to work on X" to a full development environment in one click.
|
|
14
|
+
|
|
15
|
+
It has two parts:
|
|
16
|
+
|
|
17
|
+
1. **CLI** (`lattices`) — creates and manages tmux sessions from the terminal
|
|
18
|
+
2. **Menu bar app** — a native macOS companion for launching, tiling,
|
|
19
|
+
and navigating sessions with a command palette
|
|
20
|
+
|
|
21
|
+
## Glossary
|
|
22
|
+
|
|
23
|
+
### Daemon
|
|
24
|
+
The lattices daemon is a WebSocket server (`ws://127.0.0.1:9399`) that
|
|
25
|
+
runs inside the menu bar app. It exposes 20 RPC methods and 3 real-time
|
|
26
|
+
events, giving scripts and AI agents full programmatic control over
|
|
27
|
+
sessions, windows, layers, and projects. See the
|
|
28
|
+
[API reference](/docs/api).
|
|
29
|
+
|
|
30
|
+
### Agent
|
|
31
|
+
Any program that calls the daemon API to control the workspace
|
|
32
|
+
autonomously — an AI coding agent, a shell script, a CI pipeline,
|
|
33
|
+
or a custom tool. Agents can discover projects, launch sessions, tile
|
|
34
|
+
windows, switch layers, and react to real-time events without human
|
|
35
|
+
interaction.
|
|
36
|
+
|
|
37
|
+
### Session
|
|
38
|
+
A tmux session is a persistent workspace that lives in the background.
|
|
39
|
+
It survives terminal crashes, disconnects, and even closing your laptop.
|
|
40
|
+
Think of it as a virtual desktop for a single project.
|
|
41
|
+
|
|
42
|
+
### Pane
|
|
43
|
+
A pane is a single terminal view inside a session. A typical lattices
|
|
44
|
+
setup has two panes side by side — one running Claude Code and one
|
|
45
|
+
running your dev server. You can have up to four or more.
|
|
46
|
+
|
|
47
|
+
### Attach / Detach
|
|
48
|
+
Attaching connects your terminal window to an existing session.
|
|
49
|
+
Detaching disconnects your terminal but keeps the session alive.
|
|
50
|
+
Your dev server keeps running, Claude keeps thinking — nothing is lost.
|
|
51
|
+
|
|
52
|
+
### tmux
|
|
53
|
+
tmux (terminal multiplexer) is the engine behind lattices. It manages
|
|
54
|
+
sessions, panes, and layouts. lattices configures tmux for you so you
|
|
55
|
+
don't need to learn tmux commands — but knowing a few shortcuts helps.
|
|
56
|
+
|
|
57
|
+
### Multiplexer
|
|
58
|
+
A program that lets you run multiple terminal sessions inside a single
|
|
59
|
+
window and switch between them. tmux is the most popular one.
|
|
60
|
+
|
|
61
|
+
### Sync / Reconcile
|
|
62
|
+
Sync (`lattices sync`) brings a running session back in line with its
|
|
63
|
+
declared config. It recreates missing panes, re-applies the layout,
|
|
64
|
+
restores labels, and re-runs commands in idle panes. Useful when a pane
|
|
65
|
+
was accidentally killed but you don't want to restart the whole session.
|
|
66
|
+
|
|
67
|
+
### Ensure / Prefill
|
|
68
|
+
Two modes for restoring exited commands when you reattach to a session:
|
|
69
|
+
|
|
70
|
+
- **Ensure** — automatically re-runs the command (hands-free recovery)
|
|
71
|
+
- **Prefill** — types the command into the pane but waits for you to
|
|
72
|
+
press Enter (manual confirmation)
|
|
73
|
+
|
|
74
|
+
Set via `"ensure": true` or `"prefill": true` in `.lattices.json`.
|
|
75
|
+
|
|
76
|
+
### Command Palette
|
|
77
|
+
The menu bar app's primary interface, opened with **Cmd+Shift+M**.
|
|
78
|
+
A searchable list of actions: launch/attach projects, tile windows,
|
|
79
|
+
sync sessions, restart panes, open settings.
|
|
80
|
+
|
|
81
|
+
### Window Tiling
|
|
82
|
+
Both the CLI (`lattices tile`) and the menu bar app can snap terminal
|
|
83
|
+
windows to preset screen positions (halves, quarters, maximize, center).
|
|
84
|
+
Tiling uses AppleScript bounds and respects the menu bar and dock.
|
|
85
|
+
|
|
86
|
+
## How it works
|
|
87
|
+
|
|
88
|
+
1. You create a `.lattices.json` file in your project root (or run `lattices init`)
|
|
89
|
+
2. lattices reads the config and creates a tmux session with your layout
|
|
90
|
+
3. Each pane gets its command (claude, dev server, tests, etc.)
|
|
91
|
+
4. The session persists in the background until you kill it
|
|
92
|
+
5. You can attach/detach from any terminal at any time
|
|
93
|
+
6. If `ensure` is enabled, exited commands auto-restart on reattach
|
|
94
|
+
|
|
95
|
+
## Architecture
|
|
96
|
+
|
|
97
|
+
### Four-layer stack
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
┌─────────────────────────────┐
|
|
101
|
+
│ AI Agents / Scripts │ ← daemon API: 20 RPC methods, real-time events
|
|
102
|
+
├─────────────────────────────┤
|
|
103
|
+
│ Menu bar app (Swift/AppKit)│ ← GUI: command palette, tiling, project list
|
|
104
|
+
├─────────────────────────────┤
|
|
105
|
+
│ CLI (Node.js) │ ← lattices, lattices sync, lattices restart ...
|
|
106
|
+
├─────────────────────────────┤
|
|
107
|
+
│ tmux │ ← session/pane lifecycle, layout, persistence
|
|
108
|
+
└─────────────────────────────┘
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
- The **CLI** talks to tmux directly via `tmux` shell commands.
|
|
112
|
+
- The **menu bar app** calls the CLI binary for session operations
|
|
113
|
+
(launch, sync, restart) and uses tmux directly for status checks
|
|
114
|
+
(has-session, list-panes). It also runs the **daemon** — a WebSocket
|
|
115
|
+
server on `ws://127.0.0.1:9399`.
|
|
116
|
+
- **Agents and scripts** connect to the daemon over WebSocket and can
|
|
117
|
+
do everything the app and CLI can do: discover projects, launch
|
|
118
|
+
sessions, tile windows, switch layers, and subscribe to real-time
|
|
119
|
+
events.
|
|
120
|
+
- All layers share the same session naming convention so they always
|
|
121
|
+
agree on which session belongs to which project.
|
|
122
|
+
|
|
123
|
+
### Session naming
|
|
124
|
+
|
|
125
|
+
A session name is `<basename>-<hash>`, where:
|
|
126
|
+
|
|
127
|
+
- `basename` is the project directory name (non-alphanumeric chars replaced with `-`)
|
|
128
|
+
- `hash` is the first 6 hex chars of the SHA-256 of the full absolute path
|
|
129
|
+
|
|
130
|
+
This guarantees unique session names even if two projects share the
|
|
131
|
+
same directory name (e.g. `~/work/app` and `~/personal/app`).
|
|
132
|
+
|
|
133
|
+
Both the CLI (Node.js `crypto.createHash`) and the app (Swift
|
|
134
|
+
`CryptoKit.SHA256`) produce identical hashes.
|
|
135
|
+
|
|
136
|
+
### Window discovery via title tags
|
|
137
|
+
|
|
138
|
+
When lattices creates a session, it sets the tmux option:
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
set-titles-string "[lattices:<session-name>] #{pane_title}"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
This embeds a `[lattices:name]` tag in the terminal window title. The
|
|
145
|
+
menu bar app uses this tag to find windows via three fallback paths:
|
|
146
|
+
|
|
147
|
+
1. **CGWindowList** (needs Screen Recording permission) — fastest,
|
|
148
|
+
reads window names from the window server
|
|
149
|
+
2. **Accessibility API** (needs Accessibility permission) — queries
|
|
150
|
+
AXUIElement window titles for the terminal app
|
|
151
|
+
3. **AppleScript** — iterates Terminal.app or iTerm2 windows by name
|
|
152
|
+
|
|
153
|
+
### Space switching via SkyLight
|
|
154
|
+
|
|
155
|
+
The menu bar app can switch macOS Spaces to reach a session's window.
|
|
156
|
+
It uses private SkyLight framework APIs loaded at runtime via `dlopen`:
|
|
157
|
+
|
|
158
|
+
- `CGSMainConnectionID` — get the connection to the window server
|
|
159
|
+
- `CGSGetActiveSpace` — current Space ID
|
|
160
|
+
- `CGSCopyManagedDisplaySpaces` — enumerate all Spaces per display
|
|
161
|
+
- `SLSCopySpacesForWindows` — find which Space a window is on
|
|
162
|
+
- `SLSManagedDisplaySetCurrentSpace` — switch a display to a Space
|
|
163
|
+
|
|
164
|
+
This is the same approach used by [Loop](https://github.com/MrKai77/Loop)
|
|
165
|
+
and other macOS window managers.
|
|
166
|
+
|
|
167
|
+
### Ensure/prefill restoration
|
|
168
|
+
|
|
169
|
+
When you run `lattices` (no arguments) and a session already exists:
|
|
170
|
+
|
|
171
|
+
1. lattices checks the `ensure` / `prefill` flag in `.lattices.json`
|
|
172
|
+
2. For each pane, it queries `#{pane_current_command}` via tmux
|
|
173
|
+
3. If the pane is running a shell (bash, zsh, fish, sh, dash) — meaning
|
|
174
|
+
the original command has exited — it either:
|
|
175
|
+
- **ensure**: sends the command + Enter (auto-restart)
|
|
176
|
+
- **prefill**: sends the command without Enter (manual restart)
|
|
177
|
+
4. Then it attaches to the session as normal
|
|
178
|
+
|
|
179
|
+
## Agentic architecture
|
|
180
|
+
|
|
181
|
+
lattices is designed for programmatic control. The daemon API gives
|
|
182
|
+
agents the same capabilities as a human using the menu bar app:
|
|
183
|
+
|
|
184
|
+
- **Discover** — list projects, sessions, windows, and Spaces
|
|
185
|
+
- **Launch** — start sessions for any scanned project
|
|
186
|
+
- **Arrange** — tile windows to screen positions, move between Spaces
|
|
187
|
+
- **Monitor** — subscribe to `windows.changed`, `tmux.changed`, and
|
|
188
|
+
`layer.switched` events for real-time workspace awareness
|
|
189
|
+
- **Recover** — sync sessions back to their declared config, restart
|
|
190
|
+
failed panes
|
|
191
|
+
|
|
192
|
+
An orchestrator agent can set up an entire multi-project workspace in
|
|
193
|
+
a few calls:
|
|
194
|
+
|
|
195
|
+
```js
|
|
196
|
+
import { daemonCall } from 'lattices/daemon-client'
|
|
197
|
+
|
|
198
|
+
await daemonCall('session.launch', { path: '/Users/you/dev/frontend' })
|
|
199
|
+
await daemonCall('session.launch', { path: '/Users/you/dev/api' })
|
|
200
|
+
|
|
201
|
+
const sessions = await daemonCall('tmux.sessions')
|
|
202
|
+
await daemonCall('window.tile', { session: sessions[0].name, position: 'left' })
|
|
203
|
+
await daemonCall('window.tile', { session: sessions[1].name, position: 'right' })
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
See the [Daemon API reference](/docs/api) for the full method list,
|
|
207
|
+
event shapes, and integration patterns.
|
|
208
|
+
|
|
209
|
+
## Key shortcuts (inside tmux)
|
|
210
|
+
|
|
211
|
+
These work when you're inside a tmux session:
|
|
212
|
+
|
|
213
|
+
| Shortcut | Action |
|
|
214
|
+
|----------------|-----------------------|
|
|
215
|
+
| Ctrl+B D | Detach from session |
|
|
216
|
+
| Ctrl+B X | Kill current pane |
|
|
217
|
+
| Ctrl+B Left | Move to left pane |
|
|
218
|
+
| Ctrl+B Right | Move to right pane |
|
|
219
|
+
| Ctrl+B Up | Move to pane above |
|
|
220
|
+
| Ctrl+B Down | Move to pane below |
|
|
221
|
+
| Ctrl+B Z | Zoom pane (toggle) |
|
|
222
|
+
| Ctrl+B [ | Scroll mode (q exits) |
|
|
223
|
+
|
|
224
|
+
The prefix `Ctrl+B` means: hold Control, press B, release both,
|
|
225
|
+
then press the next key.
|