claude-garage 0.2.1 → 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.
- package/README.md +134 -62
- package/bin/garage.js +358 -3
- package/daemon/src/claude-home.js +16 -0
- package/daemon/src/diff.js +1 -1
- package/daemon/src/events.js +6 -2
- package/daemon/src/health.js +28 -0
- package/daemon/src/hooks.js +18 -110
- package/daemon/src/index.js +6 -1
- package/daemon/src/poller.js +90 -23
- package/daemon/src/registry.js +3 -1
- package/daemon/src/session-resolve.js +58 -0
- package/daemon/src/sessions.js +93 -10
- package/daemon/src/settings-install.js +62 -0
- package/daemon/src/status.js +36 -26
- package/daemon/src/statusline.js +200 -0
- package/daemon/src/tmux.js +76 -16
- package/daemon/src/token-auth.js +13 -0
- package/daemon/src/transcript.js +142 -0
- package/daemon/src/worktrees.js +5 -1
- package/package.json +6 -3
- package/ui/dist/assets/index-bVL5DcKG.js +81 -0
- package/ui/dist/assets/{index-B9ScE6Rx.css → index-u3ZEnG0l.css} +2 -2
- package/ui/dist/index.html +2 -2
- package/wall/dist/garage-wall-darwin-arm64 +0 -0
- package/ui/dist/assets/index-D2yHw1H6.js +0 -81
package/README.md
CHANGED
|
@@ -3,19 +3,20 @@
|
|
|
3
3
|
<img src="docs/banner.png" alt="claude-garage: a pit wall for your Claude Code agents" width="100%" />
|
|
4
4
|
|
|
5
5
|
**Multiple Claude agents driving you crazy? Park them all in one
|
|
6
|
-
garage.**
|
|
7
|
-
|
|
6
|
+
garage.** A needs-input queue that follows you across every project (`a`
|
|
7
|
+
jumps to whoever's waiting), file-by-file diff review, and tmux-owned
|
|
8
|
+
sessions that outlive the tool — reboot the Mac, `tmux attach` still works.
|
|
8
9
|
|
|
9
10
|
[](https://www.npmjs.com/package/claude-garage)
|
|
10
11
|
[](LICENSE)
|
|
11
12
|
[](package.json)
|
|
12
13
|
[](#local-only-by-design)
|
|
13
14
|
|
|
14
|
-
<img src="docs/hero.png" alt="The
|
|
15
|
+
<img src="docs/hero.png" alt="The web wall: two workspaces, a session asking for permission (amber), a finished worktree session, and the diff pane" width="100%" />
|
|
15
16
|
|
|
16
17
|
</div>
|
|
17
18
|
|
|
18
|
-
**▶ 60-second reveal** — the wall, needs-input triage, diff review, and the pit pet, beat by beat:
|
|
19
|
+
**▶ 60-second reveal** — the web wall, needs-input triage, diff review, and the pit pet, beat by beat:
|
|
19
20
|
|
|
20
21
|
https://github.com/user-attachments/assets/b19defa0-a60d-4082-9ca5-9b8ce9480b18
|
|
21
22
|
|
|
@@ -24,49 +25,90 @@ https://github.com/user-attachments/assets/b19defa0-a60d-4082-9ca5-9b8ce9480b18
|
|
|
24
25
|
Running multiple Claude Code sessions across multiple projects means juggling
|
|
25
26
|
terminal windows and editor windows. There is no single place to see:
|
|
26
27
|
|
|
27
|
-
- **which
|
|
28
|
-
|
|
29
|
-
count, it's attention routing
|
|
28
|
+
- **which one is blocked waiting for your input** — right now, anywhere.
|
|
29
|
+
The real pain isn't window count, it's attention routing.
|
|
30
30
|
- **what each session changed**, reviewable without hunting
|
|
31
|
+
- **which sessions exist**, per project, without them dying the moment you
|
|
32
|
+
close a terminal or reboot
|
|
31
33
|
|
|
32
34
|
claude-garage is that single place: the garage your agents are parked in,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
1.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
2.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
built around four things that rarely coexist.
|
|
36
|
+
|
|
37
|
+
1. 🚨 **Needs-input triage as a first-class queue.** Blocked sessions sort
|
|
38
|
+
first everywhere, light up amber, and count into the header badge, the
|
|
39
|
+
tab title, and the TUI's status strip; `a` jumps to whichever agent is
|
|
40
|
+
waiting, across every project, on either surface.
|
|
41
|
+
2. 🔌 **Real terminals that survive the tool.** tmux owns every session, not
|
|
42
|
+
the app. Close the terminal, kill the daemon, reboot the Mac:
|
|
43
|
+
`tmux attach -t garage/<workspace>/<label>` still works, dead sessions
|
|
44
|
+
restore with their full conversation (`claude --resume`) in one keypress,
|
|
45
|
+
and `t` pops a live session into its own OS terminal window alongside
|
|
46
|
+
the wall.
|
|
47
|
+
3. 📋 **File-by-file diff review with an editor jump — in the web wall.**
|
|
48
|
+
Per-workspace or per-worktree changes (committed and uncommitted), a
|
|
49
|
+
full-screen review mode with viewed-tracking, and `o` to open your editor
|
|
50
|
+
at the exact line. (The TUI doesn't have review mode yet — it's on the
|
|
51
|
+
[Roadmap](#roadmap).)
|
|
52
|
+
4. 🖥️ **Every session of a project visible at once.** Not a switcher: the
|
|
53
|
+
web wall renders every session in a workspace as a live terminal
|
|
54
|
+
simultaneously (split/resize/maximize/detach); the TUI groups sessions
|
|
55
|
+
into named views (`d`/`D`/`Tab`) with a 6-tile grid and an overflow rail
|
|
56
|
+
for the rest.
|
|
49
57
|
|
|
50
58
|
## Quick start
|
|
51
59
|
|
|
60
|
+
```bash
|
|
61
|
+
npx claude-garage tui
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
A full-screen terminal wall, right in your terminal. Starts the daemon if
|
|
65
|
+
one isn't already running; `1`–`9` switch workspaces, `Enter` engages the
|
|
66
|
+
focused terminal (keys go to the agent byte-exact — Alt+arrows, paste,
|
|
67
|
+
everything), `Ctrl+G` hands keys back to the garage, `a` jumps to whoever's
|
|
68
|
+
waited longest, `?` for the full keymap. Quitting the TUI leaves the daemon
|
|
69
|
+
and every tmux session running. It's also light: ~5ms input latency, ~2%
|
|
70
|
+
CPU, and a 2.4MB binary (measured on the ratatui port — see
|
|
71
|
+
[`openspec/changes/archive/2026-08-31-p9-ratatui-port/verification.md`](openspec/changes/archive/2026-08-31-p9-ratatui-port/verification.md)).
|
|
72
|
+
|
|
73
|
+
Since p10–p12, the TUI also groups sessions into views (`d` detaches the
|
|
74
|
+
focused one into its own view or rejoins it to the default, `D` moves it to
|
|
75
|
+
a chosen group, `Tab` cycles views), shows a dim auto-subtitle under each
|
|
76
|
+
session's label straight from Claude Code's own terminal-title updates (zero
|
|
77
|
+
config), and tracks context pressure: a per-tile meter plus a `5h`/`7-day`
|
|
78
|
+
usage chip in the strip, fed by a one-keypress `I` install of a chaining
|
|
79
|
+
statusline wrapper (any statusline you already have keeps running). Closing
|
|
80
|
+
a plain session tears it down; closing a worktree session keeps its branch
|
|
81
|
+
and points you at the web wall to merge or discard it.
|
|
82
|
+
|
|
83
|
+
**Prefer a browser?**
|
|
84
|
+
|
|
52
85
|
```bash
|
|
53
86
|
npx claude-garage
|
|
54
87
|
```
|
|
55
88
|
|
|
56
|
-
Opens the
|
|
57
|
-
|
|
89
|
+
Opens the web wall at `http://127.0.0.1:4747` — the companion surface, with
|
|
90
|
+
diff review and the worktree finish flow (see [Web wall](#web-wall)). Both
|
|
91
|
+
commands start the same daemon and see the same tmux sessions, so you can
|
|
92
|
+
run either one, or both, at once.
|
|
58
93
|
|
|
59
94
|
**Requirements**
|
|
60
95
|
|
|
61
|
-
- macOS
|
|
96
|
+
- macOS (Linux support is on the [Roadmap](#roadmap))
|
|
97
|
+
- Node.js ≥ 20
|
|
62
98
|
- [tmux](https://github.com/tmux/tmux) ≥ 3.2 (garage offers to `brew install` it if missing)
|
|
63
99
|
- [Claude Code](https://docs.claude.com/en/docs/claude-code) CLI on `PATH`
|
|
64
|
-
-
|
|
100
|
+
- Rust — **not required on Apple Silicon.** The TUI ships as a prebuilt
|
|
101
|
+
`arm64` binary in the npm package. On an Intel Mac, `claude-garage tui`
|
|
102
|
+
builds it once from source the first time you run it if `cargo` is on
|
|
103
|
+
`PATH` ([rustup.rs](https://rustup.rs)); without `cargo` you get an
|
|
104
|
+
actionable error naming exactly what's missing, not a crash. The web wall
|
|
105
|
+
never needs Rust.
|
|
65
106
|
|
|
66
107
|
**Hooks (recommended):** status updates poll every 2s by default. Click
|
|
67
|
-
**install hooks for me** in the banner
|
|
68
|
-
|
|
69
|
-
|
|
108
|
+
**install hooks for me** in the web wall's banner (or press `I` in the TUI
|
|
109
|
+
for the statusline half of the story) for instant detection. The daemon
|
|
110
|
+
merges Claude Code's hooks/statusline into `~/.claude/settings.json` (backup
|
|
111
|
+
kept, idempotent).
|
|
70
112
|
|
|
71
113
|
## Local-only by design
|
|
72
114
|
|
|
@@ -77,8 +119,8 @@ Everything runs on your machine and stays there.
|
|
|
77
119
|
phones home to no one.
|
|
78
120
|
- All state is a single local file (`~/.garage/state.json`) plus your own
|
|
79
121
|
tmux server and git repos.
|
|
80
|
-
- Your sessions talk to Claude exactly as they would without garage.
|
|
81
|
-
wall
|
|
122
|
+
- Your sessions talk to Claude exactly as they would without garage. Both
|
|
123
|
+
the TUI and the web wall are viewers, not a middleman.
|
|
82
124
|
|
|
83
125
|
## Session states
|
|
84
126
|
|
|
@@ -88,12 +130,19 @@ Everything runs on your machine and stays there.
|
|
|
88
130
|
| `◐` | working | Claude is running. |
|
|
89
131
|
| `✓` | done | Finished a turn since you last looked (fades after 2 min). |
|
|
90
132
|
| `○` | idle | Waiting for you to *ask*, not to *answer*. |
|
|
91
|
-
| `⟳` | restorable | tmux died (reboot?). One click resurrects the conversation. |
|
|
133
|
+
| `⟳` | restorable | tmux died (reboot?). One keypress/click resurrects the conversation. |
|
|
92
134
|
|
|
93
|
-
##
|
|
135
|
+
## Web wall
|
|
94
136
|
|
|
95
|
-
|
|
96
|
-
|
|
137
|
+
The browser companion (`npx claude-garage`, `http://127.0.0.1:4747`) carries
|
|
138
|
+
the features the TUI doesn't have yet:
|
|
139
|
+
|
|
140
|
+
- 🎨 **Diff review**: the changes pane and full-screen review mode described
|
|
141
|
+
in [Why](#why) — `Tab`/`j`/`k`/`r`/`v`/`o`, see [Keybindings](#keybindings).
|
|
142
|
+
- 🌳 **Worktree finish flow**: spawn a worktree session from either surface
|
|
143
|
+
(`N` in the TUI, the worktree toggle here), but **merge / discard / keep**
|
|
144
|
+
on close is web-only for now — the TUI always keeps the branch and tells
|
|
145
|
+
you to finish it here.
|
|
97
146
|
- 🎨 **Themes**: garage, claude dark, claude light, or follow the OS.
|
|
98
147
|
Terminals re-skin in place, full ANSI palettes included.
|
|
99
148
|
- 🔔 **Notifications**: badge + tab title in-app, opt-in browser
|
|
@@ -101,7 +150,7 @@ Everything runs on your machine and stays there.
|
|
|
101
150
|
notification when no page is open (clickable with
|
|
102
151
|
[`terminal-notifier`](https://github.com/julienXX/terminal-notifier)).
|
|
103
152
|
|
|
104
|
-
|
|
153
|
+
### The pit pet 🐈 (web wall)
|
|
105
154
|
|
|
106
155
|
An optional ASCII companion on the key strip whose mood *is* the wall:
|
|
107
156
|
asleep when all is quiet, watching while agents run, **sprinting toward the
|
|
@@ -130,55 +179,78 @@ state in character:
|
|
|
130
179
|
|
|
131
180
|
## Keybindings
|
|
132
181
|
|
|
182
|
+
The TUI's full keymap (`claude-garage tui`, also shown in-app with `?`).
|
|
183
|
+
Bindings apply at the garage layer; `Enter` hands your keystrokes to the
|
|
184
|
+
focused session byte-exact until `Ctrl+G` takes them back.
|
|
185
|
+
|
|
133
186
|
| Key | Action |
|
|
134
187
|
|---|---|
|
|
135
|
-
| `1`–`9` |
|
|
136
|
-
| `[` / `]` | cycle
|
|
137
|
-
| `
|
|
138
|
-
|
|
|
139
|
-
| `m` | maximize
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
147
|
-
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
188
|
+
| `1`–`9` | focus workspace |
|
|
189
|
+
| `[` / `]` | cycle focused tile |
|
|
190
|
+
| `Enter` | engage focused tile (restore it when restorable) |
|
|
191
|
+
| `Ctrl+G` | disengage (while engaged) |
|
|
192
|
+
| `m` | maximize / restore focused tile |
|
|
193
|
+
| `t` | open focused session in a new terminal window (macOS) |
|
|
194
|
+
| `a` | jump to longest-waiting blocked session |
|
|
195
|
+
| `A` | triage queue |
|
|
196
|
+
| `n` / `N` | spawn session / worktree session |
|
|
197
|
+
| `R` | restore all restorable sessions in workspace |
|
|
198
|
+
| `I` | install statusline feed for context meters |
|
|
199
|
+
| `x x` | close focused session (press twice) |
|
|
200
|
+
| `X X` | remove focused workspace (sessions keep running) |
|
|
201
|
+
| `X K` | remove focused workspace AND kill its sessions |
|
|
202
|
+
| `w` | add workspace |
|
|
203
|
+
| `d` | detach focused session to its own view, or rejoin main |
|
|
204
|
+
| `D` | move focused session to another view / new group |
|
|
205
|
+
| `Tab` | cycle the focused workspace's views |
|
|
206
|
+
| `?` | toggle this help |
|
|
207
|
+
| `q` | quit (tmux sessions keep running) |
|
|
208
|
+
|
|
209
|
+
The web wall has its own compact keymap for its own features (grid
|
|
210
|
+
navigation plus diff review) — press `?` there for the full list:
|
|
211
|
+
`1`–`9` workspace, `[`/`]` cycle terminal, `a` jump, `\` split cell, `m`
|
|
212
|
+
maximize, `Tab`/`j`/`k`/`r`/`v`/`o` for the changes pane and review mode,
|
|
213
|
+
`` Ctrl+` `` releases keys back to the browser wall.
|
|
151
214
|
|
|
152
215
|
## How it works
|
|
153
216
|
|
|
154
217
|
```
|
|
155
218
|
tmux (persistence, source of truth)
|
|
156
|
-
└─ small Node daemon (spawn / list / bridge / diff / hooks)
|
|
157
|
-
|
|
219
|
+
└─ small Node daemon (spawn / list / bridge / diff / hooks / statusline)
|
|
220
|
+
├─ Rust terminal wall (ratatui + crossterm — `claude-garage tui`)
|
|
221
|
+
└─ browser web wall (React + xterm.js — `npx claude-garage`)
|
|
158
222
|
```
|
|
159
223
|
|
|
160
224
|
The daemon is a thin Fastify process that shells out to `tmux`/`git`/`claude`
|
|
161
|
-
rather than re-implementing them; diffs are computed read-only; hook
|
|
162
|
-
are token-authed.
|
|
163
|
-
|
|
225
|
+
rather than re-implementing them; diffs are computed read-only; hook and
|
|
226
|
+
statusline events are token-authed. Both UIs are viewers over the same
|
|
227
|
+
daemon: the web wall over SSE + WebSockets, the TUI over HTTP/SSE for state
|
|
228
|
+
and direct `tmux attach` PTYs for the terminals themselves — no WebSocket
|
|
229
|
+
terminal bridge in the TUI path. tmux is the registry: garage can be deleted
|
|
230
|
+
and your sessions won't notice.
|
|
164
231
|
|
|
165
232
|
## Development
|
|
166
233
|
|
|
167
234
|
```bash
|
|
168
235
|
npm install
|
|
169
|
-
npm run dev
|
|
170
|
-
npm test
|
|
236
|
+
npm run dev # daemon :4747 + Vite :5173 (web wall)
|
|
237
|
+
npm test # node:test suite (status, poller, hooks, layout, views)
|
|
238
|
+
npm run build:tui # cargo build --release; copies the binary into wall/dist
|
|
171
239
|
```
|
|
172
240
|
|
|
241
|
+
`wall/` is a separate Rust workspace with its own unit and e2e suites
|
|
242
|
+
(`cd wall && cargo test`; e2e harnesses under `wall/test/e2e`).
|
|
243
|
+
|
|
173
244
|
Built through spec-driven phases ([`openspec/`](openspec/)), each verified
|
|
174
245
|
end-to-end on a real system.
|
|
175
246
|
|
|
176
247
|
## Roadmap
|
|
177
248
|
|
|
178
249
|
- `claude-garage attach`: adopt an existing tmux session onto the wall
|
|
179
|
-
-
|
|
180
|
-
- View renaming and drag-between-views
|
|
250
|
+
- Review mode in the TUI (the web wall's file-by-file diff review, ported)
|
|
181
251
|
- Linux support
|
|
252
|
+
- Phone push (ntfy/webhook) for when you're away from the machine
|
|
253
|
+
- View renaming
|
|
182
254
|
|
|
183
255
|
## License
|
|
184
256
|
|