@axelgar/opentree 0.2.0 โ†’ 1.0.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 (2) hide show
  1. package/README.md +373 -73
  2. package/package.json +5 -5
package/README.md CHANGED
@@ -11,7 +11,8 @@ opentree is a cross-platform CLI tool that manages multiple AI coding agent sess
11
11
  ## Features
12
12
 
13
13
  - **๐ŸŒณ Isolated Workspaces**: Each workspace = git worktree + branch + tmux window
14
- - **๐Ÿค– Agent Integration**: Launch OpenCode (or other agents) automatically in each workspace
14
+ - **๐Ÿค– Agent Integration**: Launch your agent automatically in each workspace
15
+ - **๐Ÿ’ฌ Built-in Chat**: Every agent speaks the [Agent Client Protocol](https://agentclientprotocol.com) and runs inside opentree's own chat view โ€” answer permissions, watch diffs, send images, and drive the agent from the dashboard without attaching
15
16
  - **๐Ÿ“Š TUI Dashboard**: Interactive terminal UI for managing workspaces (press `?` for help)
16
17
  - **๐Ÿ”€ Parallel Development**: Work on multiple branches simultaneously without checkout overhead
17
18
  - **๐Ÿ“ Diff Viewer**: Review changes before committing
@@ -26,8 +27,9 @@ opentree is a cross-platform CLI tool that manages multiple AI coding agent sess
26
27
 
27
28
  - **Git** (2.5+) - for worktree support
28
29
  - **tmux** (3.0+) - for session orchestration
29
- - **OpenCode** (optional) - default coding agent ([install](https://github.com/anomalyco/opencode))
30
+ - **A coding agent** (optional) - OpenCode (the default), Claude Code, GitHub Copilot CLI or Gemini CLI
30
31
  - **GitHub CLI** (`gh`) (optional) - for PR creation and issue fetching ([install](https://cli.github.com/))
32
+ - **Node** (optional) - only to run Claude Code through its ACP adapter
31
33
 
32
34
  ## Installation
33
35
 
@@ -75,6 +77,8 @@ opentree attach feat/add-auth # Attach to tmux window
75
77
  opentree diff feat/add-auth # Review changes
76
78
  opentree pr feat/add-auth # Create GitHub PR
77
79
  opentree delete feat/add-auth # Clean up workspace
80
+ opentree skills list # See every agent skill on this machine
81
+ opentree skills sync # Give every agent and workspace the repo's skills
78
82
  ```
79
83
 
80
84
  ## Usage
@@ -101,14 +105,180 @@ opentree
101
105
  - `p` - Create PR for selected workspace (auto-generates title and body from commits)
102
106
  - `o` - Open PR in browser
103
107
  - `x` - Delete selected workspace (shows diff confirmation if uncommitted changes)
108
+ - `R` - Send the workspace's open PR review comments to its agent
109
+ - `w` - Start or stop the workspace's dev server
110
+ - `b` - Jump to the workspace that has been waiting longest on a permission (press again to cycle)
104
111
  - `space` - Toggle multi-select on current workspace
105
112
  - `/` - Filter workspaces by name
106
113
  - `s` - Cycle sort order (name โ†’ age โ†’ activity โ†’ PR)
107
114
  - `E` - Toggle error log
115
+ - `tab` - Switch between Workspaces, Skills and Servers
108
116
  - `?` - Toggle full help
109
117
  - `q` - Quit
110
118
 
111
- The TUI also shows a live **agent output preview** for the selected workspace and **CI check status** badges for open PRs.
119
+ Each row also carries what its agent is doing โ€” working, waiting on a
120
+ permission, stopped โ€” plus cost and context use, read live from the chat's
121
+ control socket. Open PRs show **CI check status** badges.
122
+
123
+ ### Skills
124
+
125
+ Skills are a filesystem convention rather than anything an agent exposes over
126
+ its API โ€” a directory holding a `SKILL.md` โ€” so opentree reads them directly.
127
+ Press `tab` for the inventory: every skill on the machine, which agents can
128
+ actually use each one, and what each agent will do with it.
129
+
130
+ - `enter` - Open the SKILL.md in `$EDITOR`
131
+ - `a` - Add a skill from a git URL
132
+ - `c` - Copy a skill into another agent's directory
133
+ - `x` - Delete a skill
134
+ - `t` - Switch a skill off for the agents that can be told
135
+ - `l` - Link the repository's skills to every agent and workspace that is missing them
136
+ - `v` - Ask the agent itself what it loaded, and flag anything the list got wrong. Gemini keeps its skills out of the protocol, so it cannot be asked
137
+
138
+ A `git worktree` carries only what git tracks, and most repositories leave
139
+ their skills untracked โ€” so opentree links the repository's skills into each
140
+ workspace it creates. `opentree skills sync` repairs workspaces that predate
141
+ this, and `opentree skills list` prints the same inventory for a script.
142
+
143
+ ### Talking to the agent
144
+
145
+ opentree talks to agents over the [Agent Client Protocol](https://agentclientprotocol.com)
146
+ (ACP) and draws the conversation itself, rather than handing the tmux window to
147
+ the agent's own TUI. You get the same worktree-per-branch
148
+ flow, but the agent's turns, tool calls, diffs, what each tool printed, and
149
+ permission prompts are rendered by opentree, which means the dashboard knows
150
+ what every agent is doing without scraping its output.
151
+
152
+ Press `Enter` on a workspace to attach to its chat:
153
+
154
+ ```
155
+ fix-auth โ—† OpenCode claude-sonnet-4.6 ยท plan ยท 12% ctx ยท $0.0431
156
+
157
+ โ”ƒ add a rate limiter to the login handler
158
+
159
+ โ—† Adding one keyed by client IP, and a test for the burst case.
160
+ โœ“ grep -rn rate.Limiter pkg/
161
+ pkg/api/throttle.go:14: var limiter = rate.NewLimiter(rate.Every(time.Minute), 60)
162
+ โœ“ pkg/auth/login.go +18 -2
163
+ + limiter := rate.NewLimiter(rate.Every(time.Second), 5)
164
+ โ น go test ./pkg/auth/
165
+
166
+ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
167
+ โ”‚ go test ./pkg/auth/ โ”‚
168
+ โ”‚ [a] Allow once โ”‚
169
+ โ”‚ [A] Always allow โ”‚
170
+ โ”‚ [d] Reject โ”‚
171
+ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
172
+ permission needed ยท esc to cancel
173
+ ```
174
+
175
+ Each agent has its own mark and colour โ€” `โ—†` for OpenCode, `โœป` for Claude Code,
176
+ `โ—‰` for GitHub Copilot, `โœฆ` for Gemini CLI โ€”
177
+ so the chat header and every workspace row in the dashboard say which agent you
178
+ are dealing with without being read word by word. An empty chat opens on the
179
+ agent's own logo, in its own colours:
180
+
181
+ ```
182
+ โ–โ–›โ–ˆโ–ˆโ–ˆโ–œโ–Œ Claude Code
183
+ โ–โ–œโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–›โ–˜ fix-auth
184
+ โ–˜โ–˜ โ–โ– ~/src/myrepo/.opentree/fix-auth
185
+ ```
186
+
187
+ | Key | |
188
+ | --- | --- |
189
+ | `enter` | send |
190
+ | `ctrl+j` | newline |
191
+ | `/` | slash commands โ€” the agent's own, plus `/resume`, `/login`, `/model` and the rest |
192
+ | `@` | attach a file from this worktree |
193
+ | `ctrl+v` | paste โ€” an image on the clipboard is attached, anything else is text |
194
+ | `esc` | interrupt the current turn |
195
+ | `shift+tab` | cycle the agent's mode (plan / build / โ€ฆ) |
196
+ | `ctrl+g` | settings โ€” model, reasoning effort, anything else the agent declares |
197
+ | `ctrl+o` | show or hide the agent's reasoning |
198
+ | `?` | every key |
199
+
200
+ **Images.** Press `ctrl+v` to attach a screenshot from the clipboard, or drag one
201
+ onto the terminal. Either way the path collapses into `[image ยท shot.png ยท 412 KB]`
202
+ in the message you are writing โ€” backspace over it and the attachment goes with
203
+ it โ€” and it travels to the agent as a real image block. On macOS
204
+ that is `ctrl+v` and not `cmd+v`: `cmd+v` is the terminal's own paste, and a
205
+ terminal asked to paste a picture sends nothing at all. An agent that does not
206
+ take images gets the path as a link instead, and the chat says so rather than
207
+ letting the difference go unnoticed.
208
+
209
+ **Earlier conversations.** `/resume` lists what this worktree has already
210
+ talked about โ€” newest first, by what each conversation was about โ€” and picking
211
+ one reopens it in place, history and all. The list is the agent's own where it
212
+ keeps one, merged with what opentree recorded itself, so the command works the
213
+ same whichever agent is running.
214
+
215
+ The agent's live model, mode and effort sit on the right of the input, next to
216
+ the running context and cost. `ctrl+c` takes you back to the workspace list and
217
+ leaves the chat running: the agent keeps working, its row keeps reporting, and
218
+ attaching again drops you straight back into the conversation.
219
+
220
+ **From the dashboard.** You don't have to attach to drive a chat. With a
221
+ workspace selected, `m` sends it a prompt, `a` answers a pending permission
222
+ request, and `c` interrupts the current turn โ€” the row shows what the agent is
223
+ doing, what it's waiting on, and what it has cost. A prompt sent to a busy agent
224
+ is queued rather than refused.
225
+
226
+ **Which agents.** OpenCode, GitHub Copilot CLI and Gemini CLI serve ACP
227
+ themselves, so having the binary is the whole setup. Claude Code is reached
228
+ through the `claude-agent-acp` adapter, which opentree installs on request into
229
+ `~/.opentree/tools` rather than your global npm root โ€” press `A` in the
230
+ dashboard, pick Claude Code, and it offers the download (303MB, needs `node`).
231
+
232
+ Those four are the whole list. opentree drives agents over ACP and nothing else,
233
+ so an agent without an ACP server has no way in โ€” if one ships support, it
234
+ becomes a single registry entry and everything above applies to it unchanged.
235
+
236
+ ### Notifications
237
+
238
+ The cost of running four agents at once is that idleness becomes invisible: the
239
+ one workspace blocked on a permission prompt looks exactly like the three that
240
+ are working, unless you are staring at the list. So each chat says something
241
+ when it starts needing you:
242
+
243
+ | Event | |
244
+ | --- | --- |
245
+ | `blocked` | the agent stopped to ask for a permission |
246
+ | `done` | a turn finished |
247
+ | `stopped` | the agent died, failed to start, or its setup commands failed |
248
+
249
+ Two surfaces. In tmux the window's own bell rings, which tmux renders as an
250
+ inverted window name in the status bar until you select that window โ€” no
251
+ configuration, and it clears itself. Outside the terminal, a desktop banner
252
+ (`osascript` on macOS, `notify-send` on Linux) reaches you with the terminal
253
+ behind a browser or closed.
254
+
255
+ Nothing is sent while you are looking at the window it happened in, and nothing
256
+ at all when the chat is not running inside tmux. The banners are signposts
257
+ rather than buttons: pressing `b` in the dashboard is what takes you to the
258
+ workspace that has been waiting longest, and pressing it again walks the rest.
259
+ Each waiting row says how long it has been at it โ€” `blocked 12m`.
260
+
261
+ ```bash
262
+ opentree notify test # one of each, through the surfaces you have
263
+ ```
264
+
265
+ Worth running once: macOS silently drops notifications sent by `osascript`
266
+ until they have been allowed, which is otherwise a feature with no symptom.
267
+
268
+ ```toml
269
+ [notify]
270
+ on = ["blocked", "stopped"] # add "done"; [] switches everything off
271
+ desktop = true # false: tmux bell only
272
+ ```
273
+
274
+ `blocked` and `stopped` are on by default and `done` is off, because four agents
275
+ finishing turns is a banner every ninety seconds โ€” and a notifier you mute is a
276
+ notifier you deleted.
277
+
278
+ This section is read from `~/.config/opentree/opentree.toml` only. A repository's
279
+ own `opentree.toml` may configure how the project is built; how you like to be
280
+ interrupted is yours, and a cloned repository does not get to start sending you
281
+ desktop banners.
112
282
 
113
283
  ### CLI Mode (Direct Commands)
114
284
 
@@ -177,6 +347,17 @@ opentree pr feat/user-auth --title "Add user auth" --body "..." # Non-interactiv
177
347
 
178
348
  Requires GitHub CLI (`gh`) to be authenticated.
179
349
 
350
+ #### Send PR Reviews to the Agent
351
+
352
+ ```bash
353
+ opentree review <branch-name>
354
+ ```
355
+
356
+ Fetches the open PR's review comments and sends them to the workspace's agent as
357
+ a prompt, over the chat's control socket. The chat has to be running, but it
358
+ doesn't have to be the window you're looking at โ€” and if the agent is mid-turn
359
+ the command says so rather than reporting a send that went nowhere.
360
+
180
361
  #### Delete Workspace
181
362
 
182
363
  ```bash
@@ -206,101 +387,194 @@ base_dir = ".opentree" # Where to store worktrees (relative to repo root)
206
387
  default_base = "main" # Default base branch
207
388
 
208
389
  [agent]
209
- command = "opencode" # Command to launch agent
210
- args = [] # Additional arguments
390
+ command = "opencode" # Agent to run: "opencode", "claude", "copilot" or "gemini"
391
+
392
+ [workspace]
393
+ seed = [".env", ".npmrc"] # Untracked files to link into each new worktree
394
+ setup = ["pnpm install --frozen-lockfile"] # Commands run before the agent starts
395
+ run = "pnpm dev" # Dev server, started on demand, PORT exported
211
396
 
212
397
  [tmux]
213
398
  session_prefix = "opentree" # Prefix for the tmux session name
214
399
 
215
400
  [github]
216
401
  auto_push = true # Push branch before creating a PR (set false to push manually)
402
+
403
+ [notify] # Global config only โ€” see Notifications
404
+ on = ["blocked", "stopped"]
405
+ desktop = true
217
406
  ```
218
407
 
219
- ### Using Different Agents
408
+ ### Seeding a Worktree
220
409
 
221
- To use a different coding agent instead of OpenCode:
410
+ A git worktree carries only what git tracks, so a fresh one has no `.env` and no
411
+ `.npmrc` โ€” and the agent's first turn goes on discovering that. List the
412
+ untracked files a worktree needs and opentree links them in as it creates one:
222
413
 
223
414
  ```toml
224
- [agent]
225
- command = "claude" # Or "aider", "cursor", etc.
226
- args = ["--some-flag"]
415
+ [workspace]
416
+ seed = [".env", ".npmrc", "config/local.json"]
417
+ ```
418
+
419
+ Each entry is a path relative to the repository root, and it lands at the same
420
+ path inside the worktree. They are symlinks rather than copies: one credential
421
+ set, shared, so rotating a token in the repository rotates it in every worktree
422
+ instead of in one out of five.
423
+
424
+ Files only. A directory is refused โ€” `node_modules` is the output of an install,
425
+ not a file to link, and a worktree that deletes a linked one has just emptied
426
+ your main checkout's. A path that leaves the repository, by `..` or through a
427
+ symlink, is refused when the workspace is created rather than seeded quietly.
428
+
429
+ A file the repository does not have is skipped, and one the branch tracks itself
430
+ is left alone: git checking it out is the signal that the branch has its own.
431
+
432
+ When one branch has to change a shared file, detach it โ€” the link becomes that
433
+ worktree's own copy, keeping what was in it:
434
+
435
+ ```bash
436
+ opentree seed detach feat/add-dark-mode .env
437
+ ```
438
+
439
+ That can also happen by accident: tools that save by renaming over a file
440
+ replace the link with an ordinary one. `opentree setup <branch> --check` reports
441
+ which seeded files are still linked and which have quietly detached.
442
+
443
+ ### Setting Up a Worktree
444
+
445
+ Seeding puts config where git could not. Setup is the other half โ€” what has to
446
+ be built rather than copied:
447
+
448
+ ```toml
449
+ [workspace]
450
+ setup = ["pnpm install --frozen-lockfile"]
227
451
  ```
228
452
 
229
- ### Agent status signals
453
+ The commands run as the first phase of the chat, in the worktree, with their
454
+ output streaming into the window. The agent starts when they finish. That is the
455
+ point of running them there: an agent that starts against a worktree with no
456
+ `node_modules` spends its first turn discovering it, and may "fix" your lockfile
457
+ on the way.
230
458
 
231
- Agents can tell opentree how they're doing by writing a `.opentree-status.json`
232
- file to the **worktree root**. The workspace list reads it on every refresh and
233
- shows a badge, so a glance across the dashboard tells you which worktrees are
234
- working and which have gone quiet and want your attention.
459
+ While they run the dashboard shows the workspace as `setting upโ€ฆ`. Nothing is
460
+ timed out โ€” a warm install is two seconds and a cold `cargo build` is twenty
461
+ minutes โ€” so `esc` is how a hung one ends, and it stops the whole process tree
462
+ rather than just the shell. If a command fails, the panel offers `[r]` to try
463
+ again and `[s]` to start the agent anyway, and the failure is recorded in the
464
+ dashboard's error log (`E`). It is never pasted into the conversation: whether
465
+ the agent should see it is your call.
235
466
 
236
- ```jsonc
237
- {
238
- "status": "needs_input", // required: "in_progress" or "needs_input"
239
- "message": "Approve running tests?" // optional โ€” shown on the row
240
- }
467
+ Setup runs once per worktree. It runs again when you edit the commands, and not
468
+ otherwise โ€” losing a chat window relaunches one, and reinstalling on every attach
469
+ would make attaching cost a minute.
470
+
471
+ Not sure what to put in the block? opentree will read the project and propose
472
+ one, from `package.json` or a `Procfile`:
473
+
474
+ ```bash
475
+ opentree setup --suggest
241
476
  ```
242
477
 
243
- Agents only ever report two things โ€” `in_progress` (a turn started) and
244
- `needs_input` (a turn ended, or it hit a prompt). opentree pairs that with **how
245
- long ago** the file last changed to derive the badge, so a finished turn from an
246
- hour ago doesn't look the same as one that just landed:
478
+ It prints; it never writes. What lands in `opentree.toml` is committed, runs on
479
+ every machine that clones the repository, and is approved by a prompt that means
480
+ nothing if opentree wrote the thing being approved.
247
481
 
248
- | Agent wrote | Last change | Badge | Meaning |
249
- | ------------- | ---------------- | -------------------- | ------------------------------------ |
250
- | `in_progress` | recent | `workingโ€ฆ` | actively generating |
251
- | `in_progress` | stale | `stalled ยท 40m ago` | turn never ended โ€” likely dead session |
252
- | `needs_input` | recent | `waiting ยท your turn`| just stopped โ€” your move |
253
- | `needs_input` | stale | `idle ยท 2h ago` | parked; nobody's touched it |
482
+ To repair a worktree, or run a setup you skipped, without restarting a chat and
483
+ tearing down a live conversation:
254
484
 
255
- The status bar tallies the ones that want you: `N waiting` and, if any, `N stalled`.
485
+ ```bash
486
+ opentree setup feat/add-dark-mode # re-seed, then run the commands here
487
+ opentree setup feat/add-dark-mode --check # report what is seeded and what has run
488
+ ```
489
+
490
+ Both paths write the same marker, so a worktree prepared from the terminal is one
491
+ the chat will not prepare again.
256
492
 
257
- Pane activity also rescues a stuck badge in both directions: a long-running
258
- `in_progress` with a quiet status file but a still-active pane stays
259
- `workingโ€ฆ` instead of reading `stalled`, and a `needs_input` with pane output
260
- *after* the status write (e.g. you approved a permission prompt, which isn't
261
- a new top-level message) reads `workingโ€ฆ` again instead of staying wedged on
262
- `waiting`.
493
+ #### Approving what it runs
263
494
 
264
- **One-step setup.** Let opentree install the hooks for you:
495
+ `opentree.toml` is tracked in git, so `setup` and `run` are executable code that
496
+ arrives with a clone, from whoever last had commit rights. opentree asks before
497
+ running them the first time, in the chat, showing exactly what it is about to
498
+ run. The answer is recorded per machine, per repository, and per exact text โ€” an
499
+ edited command is asked about again.
500
+
501
+ From the command line, for CI or to answer ahead of time:
265
502
 
266
503
  ```bash
267
- opentree agents setup claude # or: codex, gemini, opencode
268
- ```
269
-
270
- This merges the guarded status hooks into the agent's user-level config
271
- (`~/.claude/settings.json`, `~/.codex/hooks.json`, `~/.gemini/settings.json`, or
272
- an OpenCode plugin), backing up any existing file first. It's idempotent โ€” safe
273
- to re-run. opentree exports `OPENTREE_STATUS_FILE` into every agent shell it
274
- launches, so the hooks write to the right worktree and stay inert (a no-op) in
275
- any session opentree didn't start. That means you install once, globally, and it
276
- just works across all your worktrees.
277
-
278
- `opentree agents setup <agent>` maps a new prompt and a completed tool call โ†’
279
- `in_progress`, and a permission prompt / notification / turn-end โ†’
280
- `needs_input`. The tool-completion hook is what flips the badge back to
281
- `workingโ€ฆ` after you approve a permission prompt mid-turn, since that isn't a
282
- new prompt itself. The bundled hooks report `status` only; the optional
283
- `message` is for hand-written or custom hooks.
284
-
285
- **GitHub Copilot** and **Pi** can't be fully automated (Copilot has no
286
- "waiting for input" event; Pi's notify config holds a single script) โ€” running
287
- `opentree agents setup gh` / `pi` prints tailored manual instructions.
288
-
289
- **Manual wiring / other agents.** Any agent can drive the badge by writing the
290
- status file itself. Point it at `$OPENTREE_STATUS_FILE` (exported by opentree),
291
- e.g. a Claude Code hook in `~/.claude/settings.json`:
292
-
293
- ```jsonc
294
- {
295
- "hooks": {
296
- "UserPromptSubmit": [{ "hooks": [{ "type": "command",
297
- "command": "[ -n \"$OPENTREE_STATUS_FILE\" ] && printf '{\"status\":\"in_progress\"}' > \"$OPENTREE_STATUS_FILE\"" }] }],
298
- "Notification": [{ "hooks": [{ "type": "command",
299
- "command": "[ -n \"$OPENTREE_STATUS_FILE\" ] && printf '{\"status\":\"needs_input\"}' > \"$OPENTREE_STATUS_FILE\"" }] }]
300
- }
301
- }
504
+ opentree trust # approve what opentree.toml now says
505
+ opentree trust show # print those commands, and whether they are approved
506
+ opentree trust revoke # drop this repository's approvals
507
+ ```
508
+
509
+ Approvals live in `~/.opentree/trust.json`, never in the repository โ€” a
510
+ repository cannot vouch for itself.
511
+
512
+ ### Dev Servers
513
+
514
+ Five worktrees of one project all want port 3000. Give opentree the command and
515
+ each gets a port of its own instead:
516
+
517
+ ```toml
518
+ [workspace]
519
+ run = "pnpm dev"
302
520
  ```
303
521
 
522
+ `opentree prune`, which already reaps workspaces whose worktree was deleted
523
+ outside opentree, also stops server windows with no workspace left behind them.
524
+
525
+ Servers start on demand, never on creation โ€” five worktrees each running
526
+ `next dev` is several gigabytes nobody asked for. Press `w` on a workspace row
527
+ to start or stop one, or open the **Servers** tab (`tab`) for the full list:
528
+ every workspace, what its server is doing, and its address.
529
+
530
+ Each workspace is assigned a port between 20000 and 32000 once, and keeps it โ€”
531
+ so an OAuth redirect URI registered against `localhost:20431` keeps working. The
532
+ port arrives as `PORT`; opentree never rewrites your command, so a stack that
533
+ ignores `PORT` can be told `--port $PORT` in the command itself.
534
+
535
+ The server runs in its own tmux window (`<branch>:run`), so `enter` in the
536
+ Servers tab attaches to it and all of its output is there. Deleting a workspace
537
+ stops its server.
538
+
539
+ #### Names instead of ports, with portless
540
+
541
+ If [portless](https://github.com/vercel-labs/portless) is installed and its
542
+ proxy is running, opentree starts servers behind it and the Servers tab shows
543
+ `https://<branch>.<repo>.localhost` โ€” which reads as "this branch of this
544
+ project" โ€” with the port still listed beside it.
545
+
546
+ The name is passed explicitly rather than left to portless's own inference,
547
+ which reads `package.json` or the git root and so infers the same name for every
548
+ worktree of one repository.
549
+
550
+ opentree never installs or starts portless itself. Getting its proxy running
551
+ means a certificate authority, an `/etc/hosts` entry and a root-owned service,
552
+ and it asks for those with a sudo prompt โ€” which in a detached tmux window
553
+ nobody would see. If portless is installed but its proxy is down, the tab says
554
+ so and serves on ports meanwhile.
555
+
556
+ ### Using Different Agents
557
+
558
+ To use one of the others instead of OpenCode:
559
+
560
+ ```toml
561
+ [agent]
562
+ command = "claude" # or "copilot", or "gemini"
563
+ ```
564
+
565
+ Or press `A` in the dashboard to pick from the agents you have installed โ€” it
566
+ writes the same config, and offers to fetch the ACP adapter if the agent needs
567
+ one. From the CLI:
568
+
569
+ ```bash
570
+ opentree agents list # what's installed, and which is active
571
+ opentree agents use claude # switch this repo (--global for everywhere)
572
+ opentree agents setup claude # fetch its ACP adapter, if it needs one
573
+ ```
574
+
575
+ An agent opentree has no ACP spec for is refused up front, when you create a
576
+ workspace, rather than later inside a chat that cannot start.
577
+
304
578
  ## How It Works
305
579
 
306
580
  1. **Worktrees**: Git worktrees allow multiple checkouts of the same repo in different directories. Each workspace lives in `.opentree/<branch-name>/`.
@@ -311,6 +585,8 @@ e.g. a Claude Code hook in `~/.claude/settings.json`:
311
585
 
312
586
  4. **Agent Integration**: When creating a workspace, opentree launches your configured agent inside the tmux window, ready to code. With no agent configured, it uses the first supported agent found on your PATH.
313
587
 
588
+ 5. **The Chat**: The tmux window runs `opentree chat`, never the agent's own TUI. It holds one JSON-RPC connection to the agent over stdio and renders the conversation, so opentree sees every turn, tool call and permission request as structured data instead of scraped terminal output. The dashboard reaches a running chat over a Unix socket, which is how `m`, `a` and `c` work without attaching. Session IDs are kept in `state.json` so conversations survive closing the window.
589
+
314
590
  ## Workflow Example
315
591
 
316
592
  ```bash
@@ -362,6 +638,30 @@ opentree sets the agent's environment via `tmux new-window -e`, which needs tmux
362
638
 
363
639
  Install OpenCode from [github.com/anomalyco/opencode](https://github.com/anomalyco/opencode), or configure a different agent in `opentree.toml`.
364
640
 
641
+ ### The chat says the agent needs an adapter
642
+
643
+ Claude Code speaks ACP through `claude-agent-acp`. Press `A` in the dashboard,
644
+ select Claude Code, and accept the download โ€” it installs to `~/.opentree/tools`
645
+ and needs `node` on your PATH. If you already have the package installed
646
+ globally, opentree uses that instead of fetching a second copy.
647
+
648
+ ### The chat says the agent needs credentials
649
+
650
+ The chat's stopped panel offers `[l]`. What that does depends on how the agent
651
+ logs in, and opentree takes the agent's word for it in this order: a command the
652
+ agent names itself (Copilot sends its own path and `login`), the command opentree
653
+ has recorded for it (`opencode auth login`, `claude auth login`), or the login
654
+ performed over the protocol. Gemini CLI takes the last route and offers four
655
+ ways in โ€” Google account, Gemini API key, Vertex AI, gateway โ€” so `[l]` opens a
656
+ picker. A terminal login hands the window to the agent and restarts it when it
657
+ finishes; a protocol login happens inside the running agent and needs no restart.
658
+
659
+ Credentials also go wrong while an agent is perfectly happy to answer: a token
660
+ expires, a key is revoked, a login lands on the wrong account. `/login` reaches
661
+ the same picker mid-conversation, and the conversation survives it.
662
+
663
+ Anything else that stops an agent offers `[r]` to restart it.
664
+
365
665
  ### "Error: gh not found"
366
666
 
367
667
  Install GitHub CLI from [cli.github.com](https://cli.github.com/), then authenticate:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axelgar/opentree",
3
- "version": "0.2.0",
3
+ "version": "1.0.0",
4
4
  "description": "Git worktree manager CLI for orchestrating parallel AI coding sessions",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,10 +15,10 @@
15
15
  "bin/opentree"
16
16
  ],
17
17
  "optionalDependencies": {
18
- "@axelgar/opentree-linux-x64": "0.2.0",
19
- "@axelgar/opentree-linux-arm64": "0.2.0",
20
- "@axelgar/opentree-darwin-x64": "0.2.0",
21
- "@axelgar/opentree-darwin-arm64": "0.2.0"
18
+ "@axelgar/opentree-linux-x64": "1.0.0",
19
+ "@axelgar/opentree-linux-arm64": "1.0.0",
20
+ "@axelgar/opentree-darwin-x64": "1.0.0",
21
+ "@axelgar/opentree-darwin-arm64": "1.0.0"
22
22
  },
23
23
  "engines": {
24
24
  "node": ">=18"