@axelgar/opentree 1.0.2 → 1.2.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/LICENSE +21 -0
- package/NOTICE +54 -0
- package/README.md +458 -35
- package/package.json +8 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Àxel García Roigé
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
opentree — third-party notices
|
|
2
|
+
==============================
|
|
3
|
+
|
|
4
|
+
opentree itself is distributed under the MIT Licence; see LICENSE. This file
|
|
5
|
+
records the third-party names, marks and code that opentree touches, and the
|
|
6
|
+
rights it does not claim in them.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
Trade marks
|
|
10
|
+
-----------
|
|
11
|
+
|
|
12
|
+
opentree drives coding agents it did not write. It draws each one under that
|
|
13
|
+
agent's own name, wordmark and brand colour so that the agent you are talking
|
|
14
|
+
to is identifiable at a glance, and those wordmarks are reproduced as terminal
|
|
15
|
+
text in pkg/config/agents.go, transcribed from each tool's own splash screen.
|
|
16
|
+
|
|
17
|
+
opencode "opencode", its wordmark and the colour #CFCECD are marks of
|
|
18
|
+
the opencode project.
|
|
19
|
+
|
|
20
|
+
Claude Code "Anthropic", "Claude", "Claude Code", the Claude mark and
|
|
21
|
+
the colour #D97757 are marks of Anthropic PBC.
|
|
22
|
+
|
|
23
|
+
GitHub Copilot "GitHub", "Copilot", "GitHub Copilot", the Copilot mark and
|
|
24
|
+
the colour #A371F7 are marks of GitHub, Inc.
|
|
25
|
+
|
|
26
|
+
Gemini CLI "Google", "Gemini", "Gemini CLI", the Gemini sparkle and the
|
|
27
|
+
colour #4285F4 are marks of Google LLC.
|
|
28
|
+
|
|
29
|
+
All trade marks, service marks, trade names and logos are the property of their
|
|
30
|
+
respective owners. They appear here only to identify the tools opentree can
|
|
31
|
+
drive, descriptively and accurately, and no claim of any right in them is made
|
|
32
|
+
or implied.
|
|
33
|
+
|
|
34
|
+
opentree is an independent project. It is not affiliated with, sponsored by,
|
|
35
|
+
endorsed by or otherwise connected to any of the owners named above; none of
|
|
36
|
+
them has reviewed or approved it, and its MIT licence grants no rights in
|
|
37
|
+
anyone's marks.
|
|
38
|
+
|
|
39
|
+
If you own one of these marks and would prefer opentree did not reproduce it,
|
|
40
|
+
open an issue at https://github.com/axelgar/opentree/issues and it will be
|
|
41
|
+
changed.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
Third-party code
|
|
45
|
+
----------------
|
|
46
|
+
|
|
47
|
+
opentree redistributes no code belonging to the projects above. The one adapter
|
|
48
|
+
it needs — @agentclientprotocol/claude-agent-acp, which bridges Claude Code onto
|
|
49
|
+
the Agent Client Protocol — is fetched from npm when the user asks for it and
|
|
50
|
+
installed under ~/.opentree/tools, under its own licence. `opentree uninstall`
|
|
51
|
+
removes that directory again.
|
|
52
|
+
|
|
53
|
+
The Go modules opentree links against are listed in go.mod and carry their own
|
|
54
|
+
licences.
|
package/README.md
CHANGED
|
@@ -17,10 +17,15 @@ opentree is a cross-platform CLI tool that manages multiple AI coding agent sess
|
|
|
17
17
|
- **🔀 Parallel Development**: Work on multiple branches simultaneously without checkout overhead
|
|
18
18
|
- **📝 Diff Viewer**: Review changes before committing
|
|
19
19
|
- **🚀 PR Creation**: Create GitHub PRs directly from the TUI with auto-generated title and body
|
|
20
|
+
- **✈️ Autopilot**: After each agent turn, run your check command, feed failures back, and publish the PR when it passes — per workspace, opt-in
|
|
21
|
+
- **📦 Dispatch**: `opentree dispatch 42 --headless` turns an issue into a PR with nobody watching, exiting with a code a script can branch on
|
|
22
|
+
- **⑂ Fan-out**: `opentree new feat/x --agents claude,opencode,gemini` races the same task across agents — grouped in the dashboard, compared side by side, the winner promoted and the rest deleted
|
|
20
23
|
- **🐛 Issue Workflow**: Create a workspace directly from a GitHub issue number
|
|
21
24
|
- **✅ CI Status**: Live CI check status displayed per workspace
|
|
22
25
|
- **🔍 Filter & Sort**: Filter workspaces by name, sort by name/age/activity/PR status
|
|
23
|
-
-
|
|
26
|
+
- **🔌 Agent Plugins**: Install a plugin from the open [Agent Plugins](https://agent-plugins.org) standard once, and every agent in every worktree can use the skills it bundles
|
|
27
|
+
- **🗂 ACP Registry**: `opentree agents add <id>`, or `a` on the dashboard's Agents tab, installs any agent the [ACP Registry](https://agentclientprotocol.com/get-started/registry) lists, and it becomes first-class everywhere the built-in four are — chats, fan-outs, per-workspace overrides
|
|
28
|
+
- **🧹 Clean Lifecycle**: A merged PR marks its row `merged · ready to delete`, and `opentree delete --merged` clears them all at once
|
|
24
29
|
- **⌨️ Shell Completion**: Tab completion for workspace names in bash, zsh, and fish
|
|
25
30
|
|
|
26
31
|
## Requirements
|
|
@@ -60,6 +65,16 @@ sudo mv opentree /usr/local/bin/
|
|
|
60
65
|
go install github.com/axelgar/opentree/cmd/opentree@latest
|
|
61
66
|
```
|
|
62
67
|
|
|
68
|
+
### Uninstalling
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
opentree uninstall
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Removes what opentree wrote into your home directory: the agent adapters under `~/.opentree/tools` (a few hundred megabytes each), the agents installed from the ACP Registry under `~/.opentree/registry` along with its cached index, the plugins installed under `~/.opentree/plugins`, the record of approved setup and run commands, the shell completion script and the global config file. It lists all of it with sizes and asks before removing anything — `--dry-run` lists and stops, `--yes` answers the question from a script.
|
|
75
|
+
|
|
76
|
+
It never touches a repository, and it never touches a worktree. The worktrees under `~/.opentree/worktrees` (or wherever `base_dir` points) are your own work in progress, and `opentree delete <branch>` is what removes those. The binary belongs to whichever of brew, npm or `go install` put it there, so the command that removes it is printed at the end.
|
|
77
|
+
|
|
63
78
|
## Quick Start
|
|
64
79
|
|
|
65
80
|
```bash
|
|
@@ -72,13 +87,16 @@ opentree
|
|
|
72
87
|
# Or use CLI commands directly
|
|
73
88
|
opentree new feat/add-auth # Create workspace
|
|
74
89
|
opentree issue 42 # Create workspace from GitHub issue #42
|
|
75
|
-
opentree
|
|
90
|
+
opentree dispatch 42 --headless # Issue #42 → agent → checks → PR, unattended
|
|
91
|
+
opentree list # List all workspaces, with their paths
|
|
76
92
|
opentree attach feat/add-auth # Attach to tmux window
|
|
93
|
+
opentree shell feat/add-auth # A shell in the worktree, beside the chat
|
|
77
94
|
opentree diff feat/add-auth # Review changes
|
|
78
95
|
opentree pr feat/add-auth # Create GitHub PR
|
|
79
96
|
opentree delete feat/add-auth # Clean up workspace
|
|
80
97
|
opentree skills list # See every agent skill on this machine
|
|
81
98
|
opentree skills sync # Give every agent and workspace the repo's skills
|
|
99
|
+
opentree plugins add <git-url> # Install an Agent Plugin once, for every agent
|
|
82
100
|
```
|
|
83
101
|
|
|
84
102
|
## Usage
|
|
@@ -101,31 +119,59 @@ opentree
|
|
|
101
119
|
- `n` - Create new workspace (prompts for branch name, then base branch)
|
|
102
120
|
- `i` - Create workspace from a GitHub issue number
|
|
103
121
|
- `Enter` - Attach to selected workspace
|
|
104
|
-
- `d` - Show diff for selected workspace
|
|
122
|
+
- `d` - Show diff for selected workspace (`pgup`/`pgdn` page it, `g`/`G` jump to the ends)
|
|
123
|
+
- `D` - Compare a fan-out group: every sibling's diff in one scroll
|
|
124
|
+
- `W` - Promote a fan-out's winner: keep this sibling, delete the rest
|
|
105
125
|
- `p` - Create PR for selected workspace (auto-generates title and body from commits)
|
|
106
126
|
- `o` - Open PR in browser
|
|
107
127
|
- `x` - Delete selected workspace (shows diff confirmation if uncommitted changes)
|
|
108
128
|
- `R` - Send the workspace's open PR review comments to its agent
|
|
129
|
+
- `P` - Switch the workspace's autopilot on or off
|
|
109
130
|
- `w` - Start or stop the workspace's dev server
|
|
131
|
+
- `u` - Merge the base branch in (fetched from origin first); conflicts are offered to the agent
|
|
132
|
+
- `t` - Open a shell in the workspace's worktree, in a tmux window beside its chat
|
|
133
|
+
- `y` - Copy the worktree's path to the clipboard
|
|
134
|
+
- `e` - Open the worktree in `$VISUAL`/`$EDITOR`
|
|
110
135
|
- `b` - Jump to the workspace that has been waiting longest on a permission (press again to cycle)
|
|
111
136
|
- `space` - Toggle multi-select on current workspace
|
|
112
137
|
- `/` - Filter workspaces by name
|
|
113
138
|
- `s` - Cycle sort order (name → age → activity → PR)
|
|
114
139
|
- `E` - Toggle error log
|
|
115
|
-
- `tab` - Switch between Workspaces, Skills and Servers
|
|
140
|
+
- `tab` - Switch between Workspaces, Agents, Skills, Plugins and Servers
|
|
116
141
|
- `?` - Toggle full help
|
|
117
142
|
- `q` - Quit
|
|
118
143
|
|
|
144
|
+
The mouse works too: the wheel scrolls, a click selects a row, and a
|
|
145
|
+
double-click attaches to it.
|
|
146
|
+
|
|
119
147
|
Each row also carries what its agent is doing — working, waiting on a
|
|
120
148
|
permission, stopped — plus cost and context use, read live from the chat's
|
|
121
149
|
control socket. Open PRs show **CI check status** badges.
|
|
122
150
|
|
|
151
|
+
### Agents
|
|
152
|
+
|
|
153
|
+
Press `tab` once for every agent this machine knows — the built-in four and
|
|
154
|
+
whatever was installed from the ACP Registry — with its readiness, where it
|
|
155
|
+
came from, and which one this repository uses. It is `opentree agents` as a
|
|
156
|
+
place rather than a set of commands:
|
|
157
|
+
|
|
158
|
+
- `enter` - Use this agent for the repository (`g` for everywhere)
|
|
159
|
+
- `a` - Browse the ACP Registry and install an agent (`/` filters the list)
|
|
160
|
+
- `u` - Update the selected registry agent (`U` checks every one)
|
|
161
|
+
- `i` - Fetch a built-in agent's ACP adapter
|
|
162
|
+
- `x` - Remove a registry agent, or clear a broken install
|
|
163
|
+
- `r` - Rescan the store, without touching the network
|
|
164
|
+
|
|
165
|
+
Every install shows the same consent card the command line prints — what will
|
|
166
|
+
run or what will be downloaded, and where — before anything is fetched. See
|
|
167
|
+
[Agents from the ACP Registry](#agents-from-the-acp-registry).
|
|
168
|
+
|
|
123
169
|
### Skills
|
|
124
170
|
|
|
125
171
|
Skills are a filesystem convention rather than anything an agent exposes over
|
|
126
172
|
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
|
|
128
|
-
actually use each one, and what each agent will do with it.
|
|
173
|
+
Press `tab` twice for the inventory: every skill on the machine, which agents
|
|
174
|
+
can actually use each one, and what each agent will do with it.
|
|
129
175
|
|
|
130
176
|
- `enter` - Open the SKILL.md in `$EDITOR`
|
|
131
177
|
- `a` - Add a skill from a git URL
|
|
@@ -140,6 +186,30 @@ their skills untracked — so opentree links the repository's skills into each
|
|
|
140
186
|
workspace it creates. `opentree skills sync` repairs workspaces that predate
|
|
141
187
|
this, and `opentree skills list` prints the same inventory for a script.
|
|
142
188
|
|
|
189
|
+
### Plugins
|
|
190
|
+
|
|
191
|
+
opentree is a client of the open [Agent Plugins](https://agent-plugins.org)
|
|
192
|
+
standard: a plugin is a directory with a `plugin.json` manifest, skills under
|
|
193
|
+
`skills/`, and optionally an `mcp.json` naming MCP servers.
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
opentree plugins add https://github.com/someone/their-plugin
|
|
197
|
+
opentree plugins list # what each plugin declares, secrets masked
|
|
198
|
+
opentree plugins remove <name> # the store entry and every link into it
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Install one and every agent in every worktree can use the skills it bundles:
|
|
202
|
+
the clone lands once per machine in `~/.opentree/plugins`, is validated
|
|
203
|
+
against the spec — a broken manifest refuses the whole plugin, a broken skill
|
|
204
|
+
or server entry costs only itself and is reported — and its skills are linked
|
|
205
|
+
into each agent's own user-scope tree. On the Skills tab they wear their
|
|
206
|
+
provenance (`plugin:<name>` and `ro`); the Plugins tab shows each plugin as a
|
|
207
|
+
unit, with `a` to install, `x` to remove, and every declared MCP server named.
|
|
208
|
+
|
|
209
|
+
Declared is as far as it goes: opentree lists a plugin's MCP servers with
|
|
210
|
+
their env and header values masked, and neither launches them nor writes them
|
|
211
|
+
into any agent's own configuration. Nothing a plugin ships is executed.
|
|
212
|
+
|
|
143
213
|
### Talking to the agent
|
|
144
214
|
|
|
145
215
|
opentree talks to agents over the [Agent Client Protocol](https://agentclientprotocol.com)
|
|
@@ -181,7 +251,7 @@ agent's own logo, in its own colours:
|
|
|
181
251
|
```
|
|
182
252
|
▐▛███▜▌ Claude Code
|
|
183
253
|
▝▜█████▛▘ fix-auth
|
|
184
|
-
▘▘ ▝▝
|
|
254
|
+
▘▘ ▝▝ ~/.opentree/worktrees/myrepo/fix-auth
|
|
185
255
|
```
|
|
186
256
|
|
|
187
257
|
| Key | |
|
|
@@ -189,15 +259,34 @@ agent's own logo, in its own colours:
|
|
|
189
259
|
| `enter` | send |
|
|
190
260
|
| `shift+enter` | newline — `ctrl+j` where the terminal cannot report modifiers |
|
|
191
261
|
| `↑` / `↓` | walk back through the messages already sent, and forward again |
|
|
192
|
-
| `/` | slash commands — the agent's own, plus `/resume`, `/login`, `/model` and the rest |
|
|
262
|
+
| `/` | slash commands — the agent's own, plus `/resume`, `/login`, `/model`, `/shell`, `/export` and the rest |
|
|
193
263
|
| `@` | attach a file from this worktree |
|
|
194
264
|
| `ctrl+v` | paste — an image on the clipboard is attached, anything else is text |
|
|
195
|
-
| `esc` | interrupt the current turn |
|
|
196
|
-
| `shift+tab` | cycle the agent's mode (plan / build / …) |
|
|
265
|
+
| `esc` | interrupt the current turn — or clear an unsent message (`↑` brings it back) |
|
|
266
|
+
| `shift+tab` | cycle the agent's mode (plan / build / …) — Claude Code's plan mode and accept-edits included |
|
|
197
267
|
| `ctrl+g` | settings — model, reasoning effort, anything else the agent declares |
|
|
198
268
|
| `ctrl+o` | show or hide the agent's reasoning |
|
|
269
|
+
| `ctrl+x` | expand what the last tool call held back, and fold it again |
|
|
270
|
+
| `ctrl+r` | retry a failed turn — the same message, pasted images included |
|
|
271
|
+
| `ctrl+y` | copy — the last reply, any code block in it, the last tool's output, or the whole conversation as markdown |
|
|
272
|
+
| `ctrl+f` | find in the conversation — `ctrl+n` / `ctrl+p` step through the matches, `esc` leaves the log where it stands |
|
|
273
|
+
| `drag` | select text — it goes to the clipboard when the button comes up; double-click takes a word, triple-click a row. `shift+drag` (`option+drag` in iTerm2) is the terminal's own selection, which still works |
|
|
274
|
+
| `click` | a permission option answers it; a `… 42 more lines` row opens the way `ctrl+x` does |
|
|
199
275
|
| `?` | every key |
|
|
200
276
|
|
|
277
|
+
**Prose.** The agent's replies render as markdown while they stream: emphasis,
|
|
278
|
+
headings, lists, quotes, and fenced code on its own background, syntax-coloured
|
|
279
|
+
when the fence names a language — code is never rewrapped, so its indentation
|
|
280
|
+
keeps meaning. A half-arrived fence already reads
|
|
281
|
+
as code and never snaps back to prose; a lone `**` stays two asterisks until
|
|
282
|
+
its closer arrives. Tables render as the text they are.
|
|
283
|
+
|
|
284
|
+
**Tool output.** A tool row shows a few lines of what it did — the diff, or
|
|
285
|
+
what it printed — and holds the rest back behind `… 42 more lines · ctrl+x`.
|
|
286
|
+
`ctrl+x` opens the most recent held-back row where you are reading, up to 500
|
|
287
|
+
lines; the same key folds it again. There is no cursor to place: the row you
|
|
288
|
+
want open is the one that just said how much it was hiding.
|
|
289
|
+
|
|
201
290
|
**Newlines.** `shift+enter` breaks the line instead of sending it, with nothing
|
|
202
291
|
to configure. A terminal left to itself sends a bare carriage return for
|
|
203
292
|
`shift+enter` — the same byte `enter` sends, and nothing downstream can tell the
|
|
@@ -226,6 +315,17 @@ forward again, and coming back past the newest returns whatever was half typed
|
|
|
226
315
|
when you started looking — so a prompt worth repeating, or repeating with one
|
|
227
316
|
word changed, is a keypress away rather than a retype. Inside a message the
|
|
228
317
|
arrows still move the cursor: they only recall from its first and last row.
|
|
318
|
+
They are kept per workspace, under `~/.opentree/history`, so a window closed
|
|
319
|
+
and reopened — or a chat restarted after its agent died — still has the last
|
|
320
|
+
two hundred.
|
|
321
|
+
|
|
322
|
+
**Messages you have not sent yet.** Enter while the agent is still working
|
|
323
|
+
queues the message instead of dropping it: it waits as a `⏳` line above the
|
|
324
|
+
box, one fires after each finished turn — so each answer still gets read
|
|
325
|
+
before the next question goes — and backspace on an empty box takes the
|
|
326
|
+
newest one back to be edited, pasted images and all. A failed turn drops the
|
|
327
|
+
queue by name rather than firing into a broken session; `↑` still has every
|
|
328
|
+
message.
|
|
229
329
|
|
|
230
330
|
**Earlier conversations.** `/resume` lists what this worktree has already
|
|
231
331
|
talked about — newest first, by what each conversation was about — and picking
|
|
@@ -233,6 +333,10 @@ one reopens it in place, history and all. The list is the agent's own where it
|
|
|
233
333
|
keeps one, merged with what opentree recorded itself, so the command works the
|
|
234
334
|
same whichever agent is running.
|
|
235
335
|
|
|
336
|
+
**Getting the conversation out.** `/export` writes it as markdown — what was
|
|
337
|
+
said, what was run and what it printed — to `~/.opentree/exports`, never into
|
|
338
|
+
the worktree, and says where. `ctrl+y` puts the same document on the clipboard.
|
|
339
|
+
|
|
236
340
|
The agent's live model, mode and effort sit on the right of the input, next to
|
|
237
341
|
the running context and cost. `ctrl+c` takes you back to the workspace list and
|
|
238
342
|
leaves the chat running: the agent keeps working, its row keeps reporting, and
|
|
@@ -247,12 +351,132 @@ is queued rather than refused.
|
|
|
247
351
|
**Which agents.** OpenCode, GitHub Copilot CLI and Gemini CLI serve ACP
|
|
248
352
|
themselves, so having the binary is the whole setup. Claude Code is reached
|
|
249
353
|
through the `claude-agent-acp` adapter, which opentree installs on request into
|
|
250
|
-
`~/.opentree/tools` rather than your global npm root —
|
|
251
|
-
|
|
354
|
+
`~/.opentree/tools` rather than your global npm root — open the dashboard's
|
|
355
|
+
Agents tab, pick Claude Code, and it offers the download (340MB, needs `node`).
|
|
356
|
+
|
|
357
|
+
Those four ship with opentree; the rest of the ecosystem comes from the
|
|
358
|
+
[ACP Registry](https://agentclientprotocol.com/get-started/registry).
|
|
359
|
+
`opentree agents add <id>` installs any agent it lists, and the install is
|
|
360
|
+
first-class everywhere the four are — the picker, chats, fan-outs,
|
|
361
|
+
per-workspace overrides. opentree drives agents over ACP and nothing else, so
|
|
362
|
+
an agent without an ACP server has no way in — but shipping support and one
|
|
363
|
+
registry entry is now the whole path in. See
|
|
364
|
+
[Agents from the ACP Registry](#agents-from-the-acp-registry).
|
|
365
|
+
|
|
366
|
+
### Autopilot
|
|
367
|
+
|
|
368
|
+
The dashboard shows everything, but without autopilot you are still the event
|
|
369
|
+
loop: watch the badge, forward the failure, press `p`. Autopilot closes the
|
|
370
|
+
loop per workspace — when a turn ends, the project's check command decides
|
|
371
|
+
whether the work is done:
|
|
372
|
+
|
|
373
|
+
```toml
|
|
374
|
+
[workspace]
|
|
375
|
+
check = "make test" # the same thing a contributor runs before pushing
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
- The check runs in the worktree, streaming into the chat log. A failure goes
|
|
379
|
+
back to the agent as the next prompt — the tail of the output, where the
|
|
380
|
+
test runner's summary is — and the loop repeats.
|
|
381
|
+
- A pass publishes: push what origin is missing, then create the PR with a
|
|
382
|
+
generated title and body, or bring the existing one up to date. Never a
|
|
383
|
+
duplicate — if the agent already pushed or opened the PR itself, publishing
|
|
384
|
+
notices and stands down.
|
|
385
|
+
- You get a `pr_ready` notification when the PR exists, through the same
|
|
386
|
+
surfaces as `blocked`.
|
|
387
|
+
|
|
388
|
+
Switch it per workspace: `P` in the dashboard, `/autopilot` in the chat, or
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
opentree auto feat/add-dark-mode on # off; bare reports where the loop stands
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
The row shows `auto` while the loop owns a workspace, and `checking…` /
|
|
395
|
+
`publishing…` while it works.
|
|
396
|
+
|
|
397
|
+
Autopilot knows when to stand down. A cancelled or refused turn never triggers
|
|
398
|
+
the check. Your queued message always runs first, and any message from you
|
|
399
|
+
resets the loop. Five autopilot-fed turns without a green check and it halts —
|
|
400
|
+
the row says `auto · halted`, the error log says why, and your next message
|
|
401
|
+
starts it again. `check` is executable code from a tracked file, so it sits
|
|
402
|
+
behind the same trust gate as `setup` and `run`: the first run asks, once,
|
|
403
|
+
showing the exact text.
|
|
404
|
+
|
|
405
|
+
Without a `check` command autopilot still pushes and keeps the PR current
|
|
406
|
+
after each turn — for projects whose CI is the check.
|
|
407
|
+
|
|
408
|
+
**Once the PR exists, autopilot watches it.** Every two minutes the chat asks
|
|
409
|
+
GitHub what is new: a failing check gets forwarded with the tail of its
|
|
410
|
+
Actions log, new review comments get forwarded the way `R` sends them — each
|
|
411
|
+
as its own turn, CI before reviews, the moment the agent is free. Nothing is
|
|
412
|
+
sent twice: the watermarks live in `state.json`, keyed on the commit a failure
|
|
413
|
+
was reported for and the fingerprint of the review set, so a new push re-arms
|
|
414
|
+
CI forwarding by itself and a reopened window does not repeat its
|
|
415
|
+
predecessor. `opentree ci <branch>` sends the same CI report by hand,
|
|
416
|
+
autopilot or not.
|
|
417
|
+
|
|
418
|
+
### Dispatch
|
|
419
|
+
|
|
420
|
+
The whole pipeline in one command:
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
opentree dispatch 42 # issue #42 → workspace → agent → checks → PR
|
|
424
|
+
opentree dispatch "fix the login race" # the prompt is the task
|
|
425
|
+
opentree dispatch 42 --headless # no attach: wait, print the PR URL, exit
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Dispatch creates the workspace (branch `auto-<slug>` in prompt mode), starts
|
|
429
|
+
the agent in its tmux window, switches autopilot on and sends the task. By
|
|
430
|
+
default it attaches so you can watch; `--headless` waits on the chat's socket
|
|
431
|
+
instead and exits with a code a script can branch on:
|
|
432
|
+
|
|
433
|
+
| Code | Meaning |
|
|
434
|
+
| --- | --- |
|
|
435
|
+
| 0 | the PR was published; its URL is on stdout |
|
|
436
|
+
| 1 | autopilot halted (the check kept failing) or reported an error |
|
|
437
|
+
| 2 | the agent stopped, or the chat became unreachable |
|
|
438
|
+
| 3 | blocked on a permission only a human can answer |
|
|
439
|
+
| 4 | `--timeout` (default 30m) elapsed; the workspace is still working |
|
|
440
|
+
|
|
441
|
+
Every failure leaves the workspace alive — `opentree attach` picks up exactly
|
|
442
|
+
where it stopped. Headless can ask nothing, so the repository's `setup` and
|
|
443
|
+
`check` commands must be approved ahead of time with `opentree trust`, and a
|
|
444
|
+
tmux server must be running (`tmux new-session -d` in CI).
|
|
445
|
+
|
|
446
|
+
### Fan-out
|
|
447
|
+
|
|
448
|
+
Four agents through one protocol makes a comparison no single-agent tool can
|
|
449
|
+
run: the same task, raced.
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
opentree new feat/x --agents claude,opencode,gemini --prompt "add dark mode"
|
|
453
|
+
git log --oneline | opentree new fix/y --agents claude,gemini # or pipe the task in
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
One sibling workspace per agent — `feat/x-claude`, `feat/x-opencode`,
|
|
457
|
+
`feat/x-gemini` — all from the same base, each running its own agent, every
|
|
458
|
+
one handed the same prompt (queued until its agent is ready). A name a
|
|
459
|
+
sibling would have taken is stepped past with a numeric suffix rather than
|
|
460
|
+
refused. Without `--prompt` or a pipe the siblings start idle, and `m` in the
|
|
461
|
+
dashboard messages whichever you like.
|
|
462
|
+
|
|
463
|
+
The dashboard shows the group as one thing: siblings sort together under
|
|
464
|
+
every sort mode, each row wears a `⑂ feat/x` badge, and the cost, context
|
|
465
|
+
and diff numbers already on every row become the scoreboard. `D` opens the
|
|
466
|
+
comparison — every sibling's diff in one scroll, sectioned by agent.
|
|
467
|
+
|
|
468
|
+
Then pick:
|
|
469
|
+
|
|
470
|
+
```bash
|
|
471
|
+
opentree promote feat/x-claude # or W on the row in the dashboard
|
|
472
|
+
```
|
|
252
473
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
474
|
+
The winner stays, every other sibling is deleted — worktree, branch, window —
|
|
475
|
+
and the group dissolves. Dirty losers show their diffs and ask first, the way
|
|
476
|
+
delete does. **The winner keeps its suffixed branch name**: `feat/x-claude`
|
|
477
|
+
does not become `feat/x`, because its worktree, chat and any open PR are all
|
|
478
|
+
keyed on the name it has. Rename it on the PR page if the suffix bothers you,
|
|
479
|
+
or not at all.
|
|
256
480
|
|
|
257
481
|
### Notifications
|
|
258
482
|
|
|
@@ -266,6 +490,7 @@ when it starts needing you:
|
|
|
266
490
|
| `blocked` | the agent stopped to ask for a permission |
|
|
267
491
|
| `done` | a turn finished |
|
|
268
492
|
| `stopped` | the agent died, failed to start, or its setup commands failed |
|
|
493
|
+
| `pr_ready` | autopilot opened or updated a pull request |
|
|
269
494
|
|
|
270
495
|
Two surfaces. In tmux the window's own bell rings, which tmux renders as an
|
|
271
496
|
inverted window name in the status bar until you select that window — no
|
|
@@ -288,13 +513,14 @@ until they have been allowed, which is otherwise a feature with no symptom.
|
|
|
288
513
|
|
|
289
514
|
```toml
|
|
290
515
|
[notify]
|
|
291
|
-
on = ["blocked", "stopped"] # add "done"; [] switches everything off
|
|
292
|
-
desktop = true
|
|
516
|
+
on = ["blocked", "stopped", "pr_ready"] # add "done"; [] switches everything off
|
|
517
|
+
desktop = true # false: tmux bell only
|
|
293
518
|
```
|
|
294
519
|
|
|
295
|
-
`blocked` and `
|
|
296
|
-
finishing turns is a banner every ninety seconds — and a
|
|
297
|
-
notifier you deleted.
|
|
520
|
+
`blocked`, `stopped` and `pr_ready` are on by default and `done` is off,
|
|
521
|
+
because four agents finishing turns is a banner every ninety seconds — and a
|
|
522
|
+
notifier you mute is a notifier you deleted. `pr_ready` cannot spam: it fires
|
|
523
|
+
only from autopilot, which is opt-in, and only when a publish moved something.
|
|
298
524
|
|
|
299
525
|
This section is read from `~/.config/opentree/opentree.toml` only. A repository's
|
|
300
526
|
own `opentree.toml` may configure how the project is built; how you like to be
|
|
@@ -311,11 +537,20 @@ opentree new <branch-name> [flags]
|
|
|
311
537
|
# Examples
|
|
312
538
|
opentree new feat/user-auth # Create workspace with branch
|
|
313
539
|
opentree new fix/login-bug --base dev # Branch off 'dev' instead of 'main'
|
|
540
|
+
opentree new feat/x --agent claude # Run claude here, whatever the config says
|
|
541
|
+
opentree new feat/x --agents claude,gemini --prompt "task" # Fan out — see Fan-out
|
|
542
|
+
opentree new feat/x --no-fetch # Branch from the local base as it is
|
|
314
543
|
```
|
|
315
544
|
|
|
545
|
+
The base is fetched from origin first, and the branch made from `origin/<base>`:
|
|
546
|
+
a `main` last pulled yesterday would otherwise start the workspace a day behind,
|
|
547
|
+
and its PR would carry or conflict with commits already merged. Offline, the
|
|
548
|
+
command says so and branches from the local base; `--no-fetch` skips the fetch
|
|
549
|
+
on purpose. `issue` and `dispatch` do the same.
|
|
550
|
+
|
|
316
551
|
Creates:
|
|
317
552
|
|
|
318
|
-
1. Git worktree at
|
|
553
|
+
1. Git worktree at `~/.opentree/worktrees/<repo>/<branch-name>/` (see [Where worktrees live](#where-worktrees-live))
|
|
319
554
|
2. New branch (or checks out existing)
|
|
320
555
|
3. tmux window in `opentree-<repo>` session
|
|
321
556
|
4. Launches the configured coding agent in the workspace
|
|
@@ -348,6 +583,22 @@ opentree attach <branch-name>
|
|
|
348
583
|
|
|
349
584
|
Attaches to the workspace's tmux window. Detach with `Ctrl+b d`.
|
|
350
585
|
|
|
586
|
+
#### Get Into the Worktree
|
|
587
|
+
|
|
588
|
+
```bash
|
|
589
|
+
opentree path <branch-name> # print the worktree's directory
|
|
590
|
+
cd "$(opentree path feat/x)" # …which is what it is for
|
|
591
|
+
opentree shell <branch-name> # a shell there, in a tmux window beside the chat
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
The chat's window is opentree's, holding the conversation. When the agent asks
|
|
595
|
+
for something only a person at a prompt can do — run the tests, check a URL,
|
|
596
|
+
paste back what a command printed — `shell` opens a window of your own in the
|
|
597
|
+
worktree (`<branch>:sh`, reused while it lives) and takes you to it; `/shell`
|
|
598
|
+
in the chat and `t` in the dashboard do the same. `path` prints the directory
|
|
599
|
+
and nothing else, because a branch's directory is not its name: `feat/x` lives
|
|
600
|
+
at `feat-x`, under `~/.opentree/worktrees/<repo>` by default.
|
|
601
|
+
|
|
351
602
|
#### Show Diff
|
|
352
603
|
|
|
353
604
|
```bash
|
|
@@ -377,7 +628,33 @@ opentree review <branch-name>
|
|
|
377
628
|
Fetches the open PR's review comments and sends them to the workspace's agent as
|
|
378
629
|
a prompt, over the chat's control socket. The chat has to be running, but it
|
|
379
630
|
doesn't have to be the window you're looking at — and if the agent is mid-turn
|
|
380
|
-
the
|
|
631
|
+
the prompt is queued and runs when the turn ends, which the row's badge shows.
|
|
632
|
+
|
|
633
|
+
#### Send CI Failures to the Agent
|
|
634
|
+
|
|
635
|
+
```bash
|
|
636
|
+
opentree ci <branch-name>
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
The dashboard's badge says CI is red; this is how the agent learns why: the
|
|
640
|
+
failing checks by name, and the tail of each GitHub Actions log — where the
|
|
641
|
+
test runner's summary is. Same delivery as `review`, over the control socket.
|
|
642
|
+
With autopilot on, this happens by itself.
|
|
643
|
+
|
|
644
|
+
#### Merge the Base In
|
|
645
|
+
|
|
646
|
+
```bash
|
|
647
|
+
opentree sync <branch-name> # fetch origin's main and merge it into the branch
|
|
648
|
+
opentree sync <branch-name> --ask # …and on conflicts, hand the files to the agent
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
The dashboard's row says `PR open · conflicts`; this is what to do about it.
|
|
652
|
+
The base is fetched from origin first — offline, the local one is merged and
|
|
653
|
+
the command says so — and merged rather than rebased, because the branch may
|
|
654
|
+
already be pushed and under review. Conflicts are not a failure: they are
|
|
655
|
+
listed, the merge is left in progress in the worktree with its markers, and
|
|
656
|
+
`--ask` (or `y` in the dashboard's dialog) sends the agent a prompt naming the
|
|
657
|
+
files and asking it to finish the merge.
|
|
381
658
|
|
|
382
659
|
#### Delete Workspace
|
|
383
660
|
|
|
@@ -386,9 +663,23 @@ opentree delete <branch-name>
|
|
|
386
663
|
|
|
387
664
|
# Examples
|
|
388
665
|
opentree delete feat/user-auth
|
|
666
|
+
opentree delete --merged # every workspace whose PR has merged
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
Removes the worktree, kills its tmux windows, and deletes the branch. If uncommitted changes are detected, a diff is shown and confirmation is required before proceeding. `--merged` does the same for every workspace the dashboard has seen merge — one question each for any that still hold something — which is how a week's worth of `merged · ready to delete` rows is cleared at once.
|
|
670
|
+
|
|
671
|
+
#### Promote a Fan-out Winner
|
|
672
|
+
|
|
673
|
+
```bash
|
|
674
|
+
opentree promote <branch-name>
|
|
675
|
+
|
|
676
|
+
# Example
|
|
677
|
+
opentree promote feat/x-claude # keep this sibling; delete feat/x-gemini, feat/x-opencode
|
|
389
678
|
```
|
|
390
679
|
|
|
391
|
-
|
|
680
|
+
Keeps the named sibling, deletes every other member of its fan-out group, and
|
|
681
|
+
dissolves the group. Losers with uncommitted or unpushed work show their diffs
|
|
682
|
+
and ask for confirmation first. The winner keeps its suffixed branch name.
|
|
392
683
|
|
|
393
684
|
#### Install Shell Completion
|
|
394
685
|
|
|
@@ -404,7 +695,7 @@ Create `opentree.toml` in your repo root or `~/.config/opentree/opentree.toml`.
|
|
|
404
695
|
|
|
405
696
|
```toml
|
|
406
697
|
[worktree]
|
|
407
|
-
base_dir = ".opentree" # Where
|
|
698
|
+
base_dir = ".opentree" # Where worktrees go — unset: ~/.opentree/worktrees/<repo>; relative: inside the repo
|
|
408
699
|
default_base = "main" # Default base branch
|
|
409
700
|
|
|
410
701
|
[agent]
|
|
@@ -414,6 +705,7 @@ command = "opencode" # Agent to run: "opencode", "claude", "copilot" or
|
|
|
414
705
|
seed = [".env", ".npmrc"] # Untracked files to link into each new worktree
|
|
415
706
|
setup = ["pnpm install --frozen-lockfile"] # Commands run before the agent starts
|
|
416
707
|
run = "pnpm dev" # Dev server, started on demand, PORT exported
|
|
708
|
+
check = "pnpm test" # What autopilot runs after each agent turn
|
|
417
709
|
|
|
418
710
|
[tmux]
|
|
419
711
|
session_prefix = "opentree" # Prefix for the tmux session name
|
|
@@ -426,6 +718,44 @@ on = ["blocked", "stopped"]
|
|
|
426
718
|
desktop = true
|
|
427
719
|
```
|
|
428
720
|
|
|
721
|
+
### Where worktrees live
|
|
722
|
+
|
|
723
|
+
Outside the repository, by default: `~/.opentree/worktrees/<repo>/<branch>`,
|
|
724
|
+
where `<repo>` is the name of the repository's directory. Worktrees used to go
|
|
725
|
+
under `<repo>/.opentree`, and every tool that walks a project found the extra
|
|
726
|
+
checkouts — test runners collected their tests twice, `tsc` compiled them,
|
|
727
|
+
linters and formatters walked them, watchers rebuilt on every save an agent
|
|
728
|
+
made, and a worktree without its own `node_modules` quietly resolved the
|
|
729
|
+
parent's. Git was the only tool told to look away. Out of the working tree,
|
|
730
|
+
none of them can see a worktree at all.
|
|
731
|
+
|
|
732
|
+
Two clones with the same directory name get separate directories: the first
|
|
733
|
+
claims `<repo>` with a small `.repo` marker naming it, and the second gets
|
|
734
|
+
`<repo>-<hash>`.
|
|
735
|
+
|
|
736
|
+
To keep worktrees inside the repository — where a plain `find` will meet them —
|
|
737
|
+
set `base_dir` to a relative path, in the repository's own `opentree.toml` or
|
|
738
|
+
globally:
|
|
739
|
+
|
|
740
|
+
```toml
|
|
741
|
+
[worktree]
|
|
742
|
+
base_dir = ".opentree" # inside the repository, as before
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
An absolute path, or one under `~`, is accepted from the global config only: a
|
|
746
|
+
cloned repository does not get to point opentree at the rest of your
|
|
747
|
+
filesystem. Workspaces made before a change of `base_dir` stay where they were
|
|
748
|
+
made — opentree finds them through git — and `opentree doctor` says where the
|
|
749
|
+
worktrees of the current setting go, and whether that is inside the working
|
|
750
|
+
tree.
|
|
751
|
+
|
|
752
|
+
The state lives outside the repository too, at
|
|
753
|
+
`~/.opentree/state/opentree-<hash>/state.json`. Nothing of opentree's is written
|
|
754
|
+
into the working tree, and nothing in `.git` is touched, so pre-commit hooks
|
|
755
|
+
that stage everything and automations that refuse a dirty checkout never meet
|
|
756
|
+
opentree. A `state.json` an older release left under `<repo>/.opentree` is
|
|
757
|
+
moved out the first time any command runs.
|
|
758
|
+
|
|
429
759
|
### Seeding a Worktree
|
|
430
760
|
|
|
431
761
|
A git worktree carries only what git tracks, so a fresh one has no `.env` and no
|
|
@@ -458,7 +788,7 @@ opentree seed detach feat/add-dark-mode .env
|
|
|
458
788
|
```
|
|
459
789
|
|
|
460
790
|
That can also happen by accident: tools that save by renaming over a file
|
|
461
|
-
replace the link with an ordinary one. `opentree setup <branch> --
|
|
791
|
+
replace the link with an ordinary one. `opentree setup <branch> --dry-run` reports
|
|
462
792
|
which seeded files are still linked and which have quietly detached.
|
|
463
793
|
|
|
464
794
|
### Setting Up a Worktree
|
|
@@ -505,7 +835,7 @@ tearing down a live conversation:
|
|
|
505
835
|
|
|
506
836
|
```bash
|
|
507
837
|
opentree setup feat/add-dark-mode # re-seed, then run the commands here
|
|
508
|
-
opentree setup feat/add-dark-mode --
|
|
838
|
+
opentree setup feat/add-dark-mode --dry-run # report what is seeded and what has run
|
|
509
839
|
```
|
|
510
840
|
|
|
511
841
|
Both paths write the same marker, so a worktree prepared from the terminal is one
|
|
@@ -583,9 +913,9 @@ To use one of the others instead of OpenCode:
|
|
|
583
913
|
command = "claude" # or "copilot", or "gemini"
|
|
584
914
|
```
|
|
585
915
|
|
|
586
|
-
Or press `
|
|
587
|
-
|
|
588
|
-
|
|
916
|
+
Or press `tab` in the dashboard for the Agents tab and pick one — it writes
|
|
917
|
+
the same config, and offers to fetch the ACP adapter if the agent needs one.
|
|
918
|
+
From the CLI:
|
|
589
919
|
|
|
590
920
|
```bash
|
|
591
921
|
opentree agents list # what's installed, and which is active
|
|
@@ -596,13 +926,56 @@ opentree agents setup claude # fetch its ACP adapter, if it needs one
|
|
|
596
926
|
An agent opentree has no ACP spec for is refused up front, when you create a
|
|
597
927
|
workspace, rather than later inside a chat that cannot start.
|
|
598
928
|
|
|
929
|
+
### Agents from the ACP Registry
|
|
930
|
+
|
|
931
|
+
The four built-in agents are a curated list, not a boundary. The
|
|
932
|
+
[ACP Registry](https://agentclientprotocol.com/get-started/registry) — the
|
|
933
|
+
same index Zed and JetBrains install from — lists every agent that ships an
|
|
934
|
+
ACP server, and opentree installs from it:
|
|
935
|
+
|
|
936
|
+
```bash
|
|
937
|
+
opentree agents search # what the registry has (add a term to filter)
|
|
938
|
+
opentree agents add devin # install one, into ~/.opentree/registry
|
|
939
|
+
opentree agents use devin # it is a normal agent from here on
|
|
940
|
+
opentree agents update # re-resolve every install against a fresh index
|
|
941
|
+
opentree agents remove devin # delete the install
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
Installing executes code, so nothing is fetched before you have seen exactly
|
|
945
|
+
what will happen: an npm-distributed agent shows the full install command —
|
|
946
|
+
pinned version, opentree's own prefix, npm's install scripts disabled, the
|
|
947
|
+
same posture as the Claude Code adapter — and a binary-distributed one shows
|
|
948
|
+
the archive URL and the sha256 it will be held to. Each install lands in its
|
|
949
|
+
own directory under `~/.opentree/registry`, wears a `registry` tag in
|
|
950
|
+
`agents list` and the version the index pinned; `agents update` builds the
|
|
951
|
+
new version beside the old and swaps it in only when complete, so a failed
|
|
952
|
+
update leaves the old agent working.
|
|
953
|
+
|
|
954
|
+
The dashboard's Agents tab is the same feature without leaving the
|
|
955
|
+
terminal you are already in: `a` fetches the index and lists it, `enter` on
|
|
956
|
+
an entry shows the same consent card `agents add` prints and installs on
|
|
957
|
+
`y`, `u` and `U` are `agents update`, `x` is `agents remove`. An agent
|
|
958
|
+
installed there is a row the moment the install finishes — no restart.
|
|
959
|
+
|
|
960
|
+
Everything else is indistinguishable from the built-in four:
|
|
961
|
+
`--agents claude,devin,goose` races them, a workspace remembers which one it
|
|
962
|
+
runs, and `opentree doctor` reports them.
|
|
963
|
+
Two honest gaps: a registry entry does not say where its agent keeps skills,
|
|
964
|
+
so the Skills tab leaves registry agents out rather than guessing; and the
|
|
965
|
+
few agents distributed only via PyPI's `uvx` are listed by `agents search`
|
|
966
|
+
but not installable yet.
|
|
967
|
+
|
|
968
|
+
Ordinary commands never touch the network — the loader reads installed
|
|
969
|
+
agents from disk, and only `agents search`, `add` and `update` fetch the
|
|
970
|
+
index. Offline, the last index this machine saw answers, with its age noted.
|
|
971
|
+
|
|
599
972
|
## How It Works
|
|
600
973
|
|
|
601
|
-
1. **Worktrees**: Git worktrees allow multiple checkouts of the same repo in different directories. Each workspace lives in
|
|
974
|
+
1. **Worktrees**: Git worktrees allow multiple checkouts of the same repo in different directories. Each workspace lives in `~/.opentree/worktrees/<repo>/<branch-name>/` — outside the working tree, so the project's own tools never see it — unless `base_dir` says otherwise.
|
|
602
975
|
|
|
603
976
|
2. **tmux Orchestration**: A single tmux session (`opentree-<repo>`) manages all workspaces. Each workspace = one tmux window. Attach to work, detach to switch.
|
|
604
977
|
|
|
605
|
-
3. **State Persistence**: Workspace metadata (branch, created time, agent, issue number) stored in
|
|
978
|
+
3. **State Persistence**: Workspace metadata (branch, created time, agent, issue number) stored in `~/.opentree/state/<repo-key>/state.json`, outside the repository.
|
|
606
979
|
|
|
607
980
|
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.
|
|
608
981
|
|
|
@@ -627,6 +1000,11 @@ opentree new fix/header-overflow
|
|
|
627
1000
|
# (work on bugfix...)
|
|
628
1001
|
# (detach)
|
|
629
1002
|
|
|
1003
|
+
# Not sure which agent will do a refactor best? Race them
|
|
1004
|
+
opentree new refactor/auth --agents claude,opencode,gemini --prompt "extract the auth middleware"
|
|
1005
|
+
# (press D in the dashboard to compare, then promote the winner)
|
|
1006
|
+
opentree promote refactor/auth-claude
|
|
1007
|
+
|
|
630
1008
|
# Review changes for first feature
|
|
631
1009
|
opentree diff feat/add-dark-mode
|
|
632
1010
|
|
|
@@ -639,6 +1017,30 @@ opentree delete feat/add-dark-mode
|
|
|
639
1017
|
|
|
640
1018
|
## Troubleshooting
|
|
641
1019
|
|
|
1020
|
+
### Start here: `opentree doctor`
|
|
1021
|
+
|
|
1022
|
+
```bash
|
|
1023
|
+
opentree doctor
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
Prints what opentree can see — its own version, the versions of git, tmux, gh
|
|
1027
|
+
and node, which config file it resolved and what it says, whether this
|
|
1028
|
+
repository's setup commands are approved, where state and sockets live, and
|
|
1029
|
+
what each workspace's chat is doing. Everything it does is a read, so it is
|
|
1030
|
+
safe to run and safe to paste into an issue.
|
|
1031
|
+
|
|
1032
|
+
If a problem needs reproducing rather than describing, point opentree at a log
|
|
1033
|
+
first:
|
|
1034
|
+
|
|
1035
|
+
```bash
|
|
1036
|
+
OPENTREE_LOG=/tmp/opentree.log opentree
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
An environment variable rather than a flag, because the interesting failures
|
|
1040
|
+
happen inside `opentree chat`, which a tmux window starts rather than you — and
|
|
1041
|
+
the variable is inherited by every process opentree launches. Off by default.
|
|
1042
|
+
The file holds branch names, paths and session ids, and is written `0600`.
|
|
1043
|
+
|
|
642
1044
|
### "Error: not a git repository"
|
|
643
1045
|
|
|
644
1046
|
opentree must be run from inside a git repository. Navigate to your project root first.
|
|
@@ -661,8 +1063,8 @@ Install OpenCode from [github.com/anomalyco/opencode](https://github.com/anomaly
|
|
|
661
1063
|
|
|
662
1064
|
### The chat says the agent needs an adapter
|
|
663
1065
|
|
|
664
|
-
Claude Code speaks ACP through `claude-agent-acp`.
|
|
665
|
-
select Claude Code, and accept the download — it installs to `~/.opentree/tools`
|
|
1066
|
+
Claude Code speaks ACP through `claude-agent-acp`. Open the dashboard's Agents
|
|
1067
|
+
tab, select Claude Code, and accept the download — it installs to `~/.opentree/tools`
|
|
666
1068
|
and needs `node` on your PATH. If you already have the package installed
|
|
667
1069
|
globally, opentree uses that instead of fetching a second copy.
|
|
668
1070
|
|
|
@@ -693,7 +1095,7 @@ gh auth login
|
|
|
693
1095
|
|
|
694
1096
|
### Workspaces not appearing in TUI
|
|
695
1097
|
|
|
696
|
-
State file might be corrupted.
|
|
1098
|
+
State file might be corrupted. `opentree doctor` prints where it is (under `~/.opentree/state`); delete it and recreate workspaces.
|
|
697
1099
|
|
|
698
1100
|
## Contributing
|
|
699
1101
|
|
|
@@ -711,12 +1113,33 @@ go build -o opentree ./cmd/opentree
|
|
|
711
1113
|
|
|
712
1114
|
### Architecture
|
|
713
1115
|
|
|
714
|
-
|
|
1116
|
+
`cmd/opentree` is the CLI surface; `pkg/` is where the work happens.
|
|
1117
|
+
|
|
1118
|
+
| package | what it owns |
|
|
1119
|
+
| --- | --- |
|
|
1120
|
+
| `tui` | the dashboard: the workspace list, the Agents, Skills, Plugins and Servers tabs |
|
|
1121
|
+
| `chat` | the conversation view, and the control socket the dashboard reaches it through |
|
|
1122
|
+
| `acp` | the Agent Client Protocol client — the agent subprocess and its stdio |
|
|
1123
|
+
| `workspace` | a workspace's lifecycle, over the four below it |
|
|
1124
|
+
| `worktree` | git worktrees and branches |
|
|
1125
|
+
| `tmux` | sessions and windows |
|
|
1126
|
+
| `state` | `state.json`, shared between the dashboard and every chat |
|
|
1127
|
+
| `github` | `gh`, for PRs, issues and CI status |
|
|
1128
|
+
| `bootstrap` | seeding a worktree, running its setup, and the trust gate over those commands |
|
|
1129
|
+
| `skills` | propagating agent skills into worktrees |
|
|
1130
|
+
| `plugins` | the Agent Plugins store: install, validate, list, remove |
|
|
1131
|
+
| `registry` | the ACP Registry client: the index, its cache, and installed agents |
|
|
1132
|
+
| `config` | `opentree.toml` and the agent registry |
|
|
1133
|
+
| `notify`, `diag`, `ui`, `fsutil`, `gitutil` | the small shared pieces |
|
|
715
1134
|
|
|
716
1135
|
## License
|
|
717
1136
|
|
|
718
1137
|
MIT License - see [LICENSE](LICENSE) for details.
|
|
719
1138
|
|
|
1139
|
+
## Trademarks
|
|
1140
|
+
|
|
1141
|
+
opentree draws each agent it drives — opencode, Claude Code, GitHub Copilot and Gemini CLI — under that agent's own wordmark and brand colour, so you can see at a glance which one you are talking to. Those marks belong to their respective owners. opentree is an independent project and is not affiliated with, sponsored by or endorsed by any of them. See [NOTICE](NOTICE).
|
|
1142
|
+
|
|
720
1143
|
## Acknowledgments
|
|
721
1144
|
|
|
722
1145
|
- Inspired by [Conductor.build](https://conductor.build) by Sahil Lavingia
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axelgar/opentree",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Git worktree manager CLI for orchestrating parallel AI coding sessions",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -12,13 +12,15 @@
|
|
|
12
12
|
"opentree": "bin/opentree"
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
|
-
"bin/opentree"
|
|
15
|
+
"bin/opentree",
|
|
16
|
+
"LICENSE",
|
|
17
|
+
"NOTICE"
|
|
16
18
|
],
|
|
17
19
|
"optionalDependencies": {
|
|
18
|
-
"@axelgar/opentree-linux-x64": "1.0
|
|
19
|
-
"@axelgar/opentree-linux-arm64": "1.0
|
|
20
|
-
"@axelgar/opentree-darwin-x64": "1.0
|
|
21
|
-
"@axelgar/opentree-darwin-arm64": "1.0
|
|
20
|
+
"@axelgar/opentree-linux-x64": "1.2.0",
|
|
21
|
+
"@axelgar/opentree-linux-arm64": "1.2.0",
|
|
22
|
+
"@axelgar/opentree-darwin-x64": "1.2.0",
|
|
23
|
+
"@axelgar/opentree-darwin-arm64": "1.2.0"
|
|
22
24
|
},
|
|
23
25
|
"engines": {
|
|
24
26
|
"node": ">=18"
|