treebox 0.4.0__tar.gz → 0.5.0__tar.gz
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.
- {treebox-0.4.0 → treebox-0.5.0}/CLAUDE.md +16 -13
- {treebox-0.4.0 → treebox-0.5.0}/CONTRIBUTING.md +3 -2
- {treebox-0.4.0 → treebox-0.5.0}/PKG-INFO +68 -60
- {treebox-0.4.0 → treebox-0.5.0}/README.md +67 -59
- treebox-0.5.0/assets/treebox-demo.gif +0 -0
- treebox-0.5.0/assets/treebox-logo.png +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/docs/agents.md +4 -3
- treebox-0.5.0/docs/configuration.md +160 -0
- {treebox-0.4.0 → treebox-0.5.0}/docs/how-it-works.md +14 -5
- {treebox-0.4.0 → treebox-0.5.0}/docs/index.md +8 -8
- {treebox-0.4.0 → treebox-0.5.0}/docs/install.md +5 -5
- {treebox-0.4.0 → treebox-0.5.0}/docs/usage.md +92 -13
- {treebox-0.4.0 → treebox-0.5.0}/install.sh +4 -12
- {treebox-0.4.0 → treebox-0.5.0}/pyproject.toml +1 -1
- {treebox-0.4.0 → treebox-0.5.0}/skills/treebox/SKILL.md +31 -29
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/assets.py +4 -3
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/cli.py +182 -91
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/config.py +74 -23
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/forge.py +8 -2
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/git.py +58 -25
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/locking.py +2 -1
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/models.py +26 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/output.py +32 -18
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/provision.py +18 -7
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/runners/base.py +4 -2
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/runners/docker.py +55 -23
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/state.py +8 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/system.py +2 -1
- treebox-0.5.0/tests/test_contract.py +366 -0
- {treebox-0.4.0 → treebox-0.5.0}/tests/test_integration.py +374 -8
- {treebox-0.4.0 → treebox-0.5.0}/tests/test_units.py +803 -15
- treebox-0.4.0/docs/assets/treebox-logo.png +0 -0
- treebox-0.4.0/docs/configuration.md +0 -130
- {treebox-0.4.0 → treebox-0.5.0}/.agents/skills/no-mistakes/SKILL.md +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/.github/workflows/autofix.yml +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/.github/workflows/ci.yml +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/.github/workflows/claude.yml +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/.github/workflows/docs.yml +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/.github/workflows/release.yml +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/.gitignore +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/.pre-commit-config.yaml +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/AGENTS.md +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/LICENSE +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/ROADMAP.md +0 -0
- {treebox-0.4.0 → treebox-0.5.0/docs}/assets/treebox-logo.png +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/docs/javascripts/treebox.js +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/docs/stylesheets/extra.css +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/hooks/copy_page.py +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/mkdocs.yml +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/scripts/validate.sh +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/__init__.py +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/assets/container/Dockerfile +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/assets/container/allowed-domains.sh +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/assets/container/container.json +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/assets/container/firewall.json +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/assets/container/init-firewall.sh +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/assets/container/post-create.sh +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/assets/pre-push +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/ecosystems.py +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/names.py +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/py.typed +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/resolve.py +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/runners/__init__.py +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/runners/host.py +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/src/treebox/status.py +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/tests/conftest.py +0 -0
- {treebox-0.4.0 → treebox-0.5.0}/uv.lock +0 -0
|
@@ -21,8 +21,8 @@ uv run --extra dev python -m pytest # full unit + integration suite
|
|
|
21
21
|
uv run --extra dev python -m pytest tests/test_units.py::test_name # single test (or -k <pattern>)
|
|
22
22
|
uv run --extra dev ruff check src tests # lint
|
|
23
23
|
uv run --extra dev ruff format --check src tests # format check (drop --check to apply)
|
|
24
|
-
uv run --extra dev mypy # type check (config in pyproject.toml)
|
|
25
|
-
uv run --extra dev pre-commit install # install lint/format/type hooks (see CONTRIBUTING.md)
|
|
24
|
+
uv run --extra dev mypy # strict type check (config in pyproject.toml)
|
|
25
|
+
uv run --extra dev pre-commit install # install lint/format/strict type-check hooks (see CONTRIBUTING.md)
|
|
26
26
|
./scripts/validate.sh # lint + format + tests + live host-runner smoke (real uv, throwaway local remote)
|
|
27
27
|
uv pip install -e ".[dev]" # editable dev environment
|
|
28
28
|
uv run --extra docs mkdocs serve # docs site (docs/ + mkdocs.yml), live-reloading
|
|
@@ -52,13 +52,13 @@ run (pluggable)**.
|
|
|
52
52
|
git just works). `HARNESS_COMMANDS` maps `claude`/`codex` to their
|
|
53
53
|
fully-autonomous launch argv.
|
|
54
54
|
- **`cli.py`** (Typer) is the entry point: `create [NAME] / enter <ref> /
|
|
55
|
-
list / teardown <ref>... / doctor` (`ls`/`rm` are hidden aliases
|
|
56
|
-
list/teardown). `enter`/`teardown` resolve a ref as
|
|
55
|
+
list / teardown <ref>... / doctor / version` (`ls`/`rm` are hidden aliases
|
|
56
|
+
of list/teardown). `enter`/`teardown` resolve a ref as
|
|
57
57
|
name → live branch → unique substring (`resolve.py`); ambiguity exits 2.
|
|
58
|
-
It enforces **stable exit codes** (`0` ok · `
|
|
59
|
-
auth/fetch · `5` conflict) and **`--json`**
|
|
60
|
-
`schemaVersion` that only gains fields within a version —
|
|
61
|
-
bumps it (git-porcelain discipline). Agents
|
|
58
|
+
It enforces **stable exit codes** (`0` ok · `1` runtime/doctor hard-check ·
|
|
59
|
+
`2` usage · `3` not-found · `4` auth/fetch · `5` conflict) and **`--json`**
|
|
60
|
+
output carrying a `schemaVersion` that only gains fields within a version —
|
|
61
|
+
a breaking reshape bumps it (git-porcelain discipline). Agents
|
|
62
62
|
branch on these, so don't change their meanings casually.
|
|
63
63
|
- **`ecosystems.py`** detects package managers (uv, npm, pnpm, go, cargo),
|
|
64
64
|
drives their cache-backed setup, and defines which manifest files feed the
|
|
@@ -73,11 +73,14 @@ run (pluggable)**.
|
|
|
73
73
|
with `git branch -m`). `create --checkout feature/auth` derives the name by
|
|
74
74
|
flattening slashes to `--` (`feature--auth`); generated names come from
|
|
75
75
|
`names.py`.
|
|
76
|
-
- **`config.py`** is **user-level TOML only
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
- **`config.py`** is **user-level TOML only** (`$TREEBOX_CONFIG`, else
|
|
77
|
+
`$TREEBOX_HOME/config.toml`, default `~/.treebox/config.toml`), never read
|
|
78
|
+
from the target repo — a repo-level config could run arbitrary host commands.
|
|
79
|
+
Same principle in **`assets.py`**: templates resolve from
|
|
80
|
+
`$TREEBOX_TEMPLATE_DIR`, then `$TREEBOX_HOME/templates/<name>` (default
|
|
81
|
+
`~/.treebox/templates/<name>`), and the sandbox template is operator-owned
|
|
82
|
+
and rendered into a host-side dir *beside* the worktree, never inside the
|
|
83
|
+
mount, so a boxed agent cannot edit the config that defines its own sandbox.
|
|
81
84
|
|
|
82
85
|
## Invariants to preserve
|
|
83
86
|
|
|
@@ -13,7 +13,7 @@ For larger feature ideas, open an issue first so we can decide whether they fit
|
|
|
13
13
|
## Local checks
|
|
14
14
|
|
|
15
15
|
Install the pre-commit hooks once so every commit is auto-formatted, lint-fixed,
|
|
16
|
-
and type-checked (`ruff format`, `ruff check --fix`, and `mypy`):
|
|
16
|
+
and type-checked in strict mode (`ruff format`, `ruff check --fix`, and `mypy`):
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
19
|
uv run --extra dev pre-commit install
|
|
@@ -32,7 +32,8 @@ will have no reported checks and the PR will stall; the remedy is to push from
|
|
|
32
32
|
the workflow using a PAT or GitHub App token stored as a repo secret (e.g.
|
|
33
33
|
`AUTOFIX_TOKEN`) instead of `GITHUB_TOKEN`.
|
|
34
34
|
|
|
35
|
-
For code changes, run the relevant checks before opening a PR
|
|
35
|
+
For code changes, run the relevant checks before opening a PR. Mypy runs in
|
|
36
|
+
strict mode (configured in `pyproject.toml`):
|
|
36
37
|
|
|
37
38
|
```bash
|
|
38
39
|
uv run --extra dev python -m pytest
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: treebox
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Isolated, ready-to-run git worktrees for AI coding agents — host-native or docker-sandboxed.
|
|
5
5
|
Project-URL: Homepage, https://github.com/Seth-Peters/treebox
|
|
6
6
|
Project-URL: Documentation, https://seth-peters.github.io/treebox/
|
|
@@ -36,13 +36,13 @@ Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
|
|
|
36
36
|
Description-Content-Type: text/markdown
|
|
37
37
|
|
|
38
38
|
<p align="center">
|
|
39
|
-
<img src="assets/treebox-logo.png" alt="treebox" width="
|
|
39
|
+
<img src="https://raw.githubusercontent.com/Seth-Peters/treebox/main/assets/treebox-logo.png" alt="treebox logo: a small tree growing inside a glass box" width="300">
|
|
40
40
|
</p>
|
|
41
41
|
|
|
42
|
-
<h1 align="center">treebox</h1>
|
|
42
|
+
<h1 align="center">Spin up worktrees, put them in a box,<br>tear them down - treebox</h1>
|
|
43
43
|
|
|
44
44
|
<p align="center">
|
|
45
|
-
<strong>Isolated, ready-to-run git worktrees for
|
|
45
|
+
<strong>Isolated, ready-to-run git worktrees for coding agents.</strong>
|
|
46
46
|
</p>
|
|
47
47
|
|
|
48
48
|
<p align="center">
|
|
@@ -61,17 +61,19 @@ Description-Content-Type: text/markdown
|
|
|
61
61
|
<a href="https://www.linkedin.com/in/seth-peters/">Seth Peters</a>
|
|
62
62
|
</p>
|
|
63
63
|
|
|
64
|
+
<p align="center">
|
|
65
|
+
<img src="https://raw.githubusercontent.com/Seth-Peters/treebox/main/assets/treebox-demo.gif" alt="treebox lifecycle demo: create, enter, ls, and an interactive teardown" width="900">
|
|
66
|
+
</p>
|
|
67
|
+
|
|
64
68
|
---
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
`
|
|
70
|
+
`treebox` hands coding agents isolated, ready-to-run git worktrees — one
|
|
71
|
+
directory per worktree name. `treebox create` fetches, cuts a worktree from a
|
|
72
|
+
fresh `origin/<base>`, copies your `.env`, installs dependencies from a shared
|
|
68
73
|
cache, and launches `claude` or `codex` inside. No branch name needed up
|
|
69
|
-
front: the worktree gets a stable name
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
on a laptop or over plain SSH.
|
|
73
|
-
|
|
74
|
-
Built by [Seth Peters](https://www.linkedin.com/in/seth-peters/) as a small, operator-focused layer for AI agent infrastructure: git worktrees, sandbox boundaries, subscription auth, and repeatable developer environments. If that is the kind of problem you are solving, the [docs](https://seth-peters.github.io/treebox/) go deeper on the design tradeoffs — and I'm [on LinkedIn](https://www.linkedin.com/in/seth-peters/) if you want to compare notes.
|
|
74
|
+
front: the worktree gets a stable name and an un-pushable `treebox/<name>`
|
|
75
|
+
placeholder branch the agent renames when the work takes shape. Agents work the same repo
|
|
76
|
+
in parallel without collisions — on a laptop or over plain SSH.
|
|
75
77
|
|
|
76
78
|
Provisioning is identical everywhere; a pluggable **isolation mode** decides
|
|
77
79
|
where the agent runs:
|
|
@@ -81,26 +83,6 @@ where the agent runs:
|
|
|
81
83
|
| `host` (default) | none | the worktree shell |
|
|
82
84
|
| `docker` | sandboxed | a docker container, with your `.env` + caches mounted |
|
|
83
85
|
|
|
84
|
-
## Every agent ships its own cage
|
|
85
|
-
|
|
86
|
-
Every coding agent invents its own answer to "run me in parallel" and "don't
|
|
87
|
-
let me touch the wrong thing" — a different config file, a different schema, a
|
|
88
|
-
different word for the same idea:
|
|
89
|
-
|
|
90
|
-
| Agent | Sandbox / permission config | Built-in worktrees | Config lives in |
|
|
91
|
-
| ----- | --------------------------- | ------------------ | --------------- |
|
|
92
|
-
| **Claude Code** | `permissions` allow/ask/deny **+** native OS sandbox (Seatbelt/bubblewrap) **+** dev container | Yes (`--worktree`) | `.claude/settings.json`, `.devcontainer/` |
|
|
93
|
-
| **OpenAI Codex** | `sandbox_mode` × `approval_policy` (Seatbelt / Landlock+seccomp) | No in CLI (app only) | `~/.codex/config.toml`, `[profiles.*]` |
|
|
94
|
-
| **opencode** | `permission` per-tool allow/ask/deny (no OS sandbox) | No (community plugins) | `opencode.json` |
|
|
95
|
-
| **pi** | none built-in ("all permissions by default"); BYO Docker/VM + trust prompt | No in core (`pi-subagents`) | `~/.pi/agent/settings.json` |
|
|
96
|
-
|
|
97
|
-
Learn one and it teaches you nothing about the next, and none of it ports
|
|
98
|
-
across tools. treebox owns the *isolation* layer instead — **one
|
|
99
|
-
worktree-per-branch layout, one operator-owned sandbox, one config file** — and
|
|
100
|
-
launches your agent of choice inside it. Learn treebox once; swap the agent,
|
|
101
|
-
keep the box. Full comparison with citations:
|
|
102
|
-
[Agents & sandboxing](https://seth-peters.github.io/treebox/agents/).
|
|
103
|
-
|
|
104
86
|
## Install
|
|
105
87
|
|
|
106
88
|
```bash
|
|
@@ -112,7 +94,7 @@ instructions if uv is missing — it never installs a package manager behind
|
|
|
112
94
|
your back. Or install directly:
|
|
113
95
|
|
|
114
96
|
```bash
|
|
115
|
-
uv tool install
|
|
97
|
+
uv tool install treebox
|
|
116
98
|
```
|
|
117
99
|
|
|
118
100
|
Host isolation needs only `git` and a logged-in agent CLI (`claude` /
|
|
@@ -123,8 +105,7 @@ requirements and installer overrides.
|
|
|
123
105
|
|
|
124
106
|
## Usage
|
|
125
107
|
|
|
126
|
-
The
|
|
127
|
-
them.
|
|
108
|
+
The worktree lifecycle is five commands.
|
|
128
109
|
|
|
129
110
|
**Check the host.** `doctor` verifies exactly what `create` will need — git,
|
|
130
111
|
agent logins, `.env`, credentials for the required fetch — and prints the fix
|
|
@@ -189,12 +170,32 @@ treebox teardown fix-auth brave-otter --delete-branch
|
|
|
189
170
|
treebox teardown # pick interactively
|
|
190
171
|
```
|
|
191
172
|
|
|
192
|
-
treebox is built to be scripted, including by agents:
|
|
193
|
-
`--json` (data to stdout, diagnostics to stderr, a schema that
|
|
194
|
-
fields within a version), `--dry-run` prints the exact commands
|
|
195
|
-
codes are stable (`0` ok · `
|
|
196
|
-
conflict). Full
|
|
197
|
-
[usage guide](https://seth-peters.github.io/treebox/usage/).
|
|
173
|
+
treebox is built to be scripted, including by agents: the worktree commands and
|
|
174
|
+
`doctor` take `--json` (data to stdout, diagnostics to stderr, a schema that
|
|
175
|
+
only gains fields within a version), `--dry-run` prints the exact commands
|
|
176
|
+
without running them, and exit codes are stable (`0` ok · `1` runtime/doctor
|
|
177
|
+
blocked · `2` usage · `3` not found · `4` auth · `5` conflict). Full
|
|
178
|
+
reference in the [usage guide](https://seth-peters.github.io/treebox/usage/).
|
|
179
|
+
|
|
180
|
+
## Every agent ships its own cage
|
|
181
|
+
|
|
182
|
+
Every coding agent invents its own answer to "run me in parallel" and "don't
|
|
183
|
+
let me touch the wrong thing" — a different config file, a different schema, a
|
|
184
|
+
different word for the same idea:
|
|
185
|
+
|
|
186
|
+
| Agent | Sandbox / permission config | Built-in worktrees | Config lives in |
|
|
187
|
+
| ----- | --------------------------- | ------------------ | --------------- |
|
|
188
|
+
| **Claude Code** | `permissions` allow/ask/deny **+** native OS sandbox (Seatbelt/bubblewrap) **+** dev container | Yes (`--worktree`) | `.claude/settings.json`, `.devcontainer/` |
|
|
189
|
+
| **OpenAI Codex** | `sandbox_mode` × `approval_policy` (Seatbelt / Landlock+seccomp) | No in CLI (app only) | `~/.codex/config.toml`, `[profiles.*]` |
|
|
190
|
+
| **opencode** | `permission` per-tool allow/ask/deny (no OS sandbox) | No (community plugins) | `opencode.json` |
|
|
191
|
+
| **pi** | none built-in ("all permissions by default"); BYO Docker/VM + trust prompt | No in core (`pi-subagents`) | `~/.pi/agent/settings.json` |
|
|
192
|
+
|
|
193
|
+
Learn one and it teaches you nothing about the next, and none of it ports
|
|
194
|
+
across tools. treebox owns the *isolation* layer instead — **one
|
|
195
|
+
named-worktree layout, one operator-owned sandbox, one config file** — and
|
|
196
|
+
launches your agent of choice inside it. Learn treebox once; swap the agent,
|
|
197
|
+
keep the box. Full comparison with citations:
|
|
198
|
+
[Agents & sandboxing](https://seth-peters.github.io/treebox/agents/).
|
|
198
199
|
|
|
199
200
|
## Design
|
|
200
201
|
|
|
@@ -211,14 +212,14 @@ conflict). Full reference in the
|
|
|
211
212
|
- **Credentials go in as scoped copies.** Only the agents' login files are
|
|
212
213
|
copied into a throwaway per-worktree dir — never the live `~/.claude` /
|
|
213
214
|
`~/.codex` — refreshed on every entry so a host logout or a fresh login
|
|
214
|
-
reaches the sandbox next time
|
|
215
|
-
never `ANTHROPIC_API_KEY`.
|
|
215
|
+
reaches the sandbox next time; treebox uses your subscription login.
|
|
216
216
|
|
|
217
217
|
More in [how it works](https://seth-peters.github.io/treebox/how-it-works/).
|
|
218
218
|
|
|
219
219
|
## Configuration
|
|
220
220
|
|
|
221
|
-
Optional, and user-level only (
|
|
221
|
+
Optional, and user-level only (`$TREEBOX_CONFIG`, else
|
|
222
|
+
`$TREEBOX_HOME/config.toml`, default `~/.treebox/config.toml`) — treebox
|
|
222
223
|
never reads config from the target repo:
|
|
223
224
|
|
|
224
225
|
```toml
|
|
@@ -233,44 +234,51 @@ covered in the
|
|
|
233
234
|
|
|
234
235
|
## Customizing isolation
|
|
235
236
|
|
|
236
|
-
`docker` isolation
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
your repo's deps (in docker, setup runs `postCreate`, not the host-mode
|
|
243
|
-
ecosystem auto-detect):
|
|
237
|
+
`docker` isolation builds from a **template you own** — a directory of files
|
|
238
|
+
treebox ships and you edit. treebox renders it beside the worktree so a boxed
|
|
239
|
+
agent can't touch its own cage. Three steps:
|
|
240
|
+
|
|
241
|
+
**1. Copy the template out** — you edit a copy, never the shipped one. Name it
|
|
242
|
+
(here `node`); a `node` box and a `python` box can coexist, one per stack:
|
|
244
243
|
|
|
245
244
|
```bash
|
|
245
|
+
mkdir -p ~/.treebox/templates
|
|
246
246
|
cp -R "$(python -c 'import treebox.assets, pathlib; print(pathlib.Path(treebox.assets.__file__).parent)')/container" \
|
|
247
|
-
~/.
|
|
247
|
+
~/.treebox/templates/node
|
|
248
248
|
```
|
|
249
249
|
|
|
250
|
+
**2. Edit two files.** The shipped image already bundles Node 22, uv, `gh`,
|
|
251
|
+
ripgrep, and the agent CLIs, so most projects touch only these:
|
|
252
|
+
|
|
250
253
|
```dockerfile
|
|
251
|
-
# ~/.
|
|
254
|
+
# ~/.treebox/templates/node/Dockerfile — global tooling
|
|
252
255
|
USER root
|
|
253
256
|
RUN npm install -g pnpm@9 typescript tsx
|
|
254
257
|
USER ${USERNAME}
|
|
255
258
|
```
|
|
256
259
|
|
|
257
260
|
```json
|
|
258
|
-
// ~/.
|
|
261
|
+
// ~/.treebox/templates/node/container.json — your install command
|
|
259
262
|
"postCreate": "if [ -f pnpm-lock.yaml ]; then pnpm install --frozen-lockfile; elif [ -f package-lock.json ]; then npm ci; else npm install; fi"
|
|
260
263
|
```
|
|
261
264
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
265
|
+
(In docker, setup runs `postCreate`, not the host-mode ecosystem auto-detect,
|
|
266
|
+
so a non-Python project wires its install here.)
|
|
267
|
+
|
|
268
|
+
**3. Point treebox at it** — per run with `--isolation docker --template node`,
|
|
269
|
+
or set `template = "node"` in `~/.treebox/config.toml`.
|
|
270
|
+
|
|
271
|
+
Full walkthrough — every file in a template and the `container.json` schema — in
|
|
272
|
+
the [configuration guide](https://seth-peters.github.io/treebox/configuration/#customizing-the-sandbox).
|
|
266
273
|
|
|
267
274
|
## Development
|
|
268
275
|
|
|
269
276
|
```bash
|
|
270
277
|
git clone https://github.com/Seth-Peters/treebox && cd treebox
|
|
271
278
|
uv run treebox ... # run the CLI from the working tree
|
|
272
|
-
uv run --extra dev pre-commit install # lint/format/type hooks (see CONTRIBUTING.md)
|
|
279
|
+
uv run --extra dev pre-commit install # lint/format/strict type-check hooks (see CONTRIBUTING.md)
|
|
273
280
|
uv run --extra dev python -m pytest # unit + integration suite
|
|
281
|
+
uv run --extra dev mypy # strict type check
|
|
274
282
|
./scripts/validate.sh # lint + format + tests + live host-runner smoke
|
|
275
283
|
```
|
|
276
284
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="assets/treebox-logo.png" alt="treebox" width="
|
|
2
|
+
<img src="https://raw.githubusercontent.com/Seth-Peters/treebox/main/assets/treebox-logo.png" alt="treebox logo: a small tree growing inside a glass box" width="300">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
<h1 align="center">treebox</h1>
|
|
5
|
+
<h1 align="center">Spin up worktrees, put them in a box,<br>tear them down - treebox</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<strong>Isolated, ready-to-run git worktrees for
|
|
8
|
+
<strong>Isolated, ready-to-run git worktrees for coding agents.</strong>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
@@ -24,17 +24,19 @@
|
|
|
24
24
|
<a href="https://www.linkedin.com/in/seth-peters/">Seth Peters</a>
|
|
25
25
|
</p>
|
|
26
26
|
|
|
27
|
+
<p align="center">
|
|
28
|
+
<img src="https://raw.githubusercontent.com/Seth-Peters/treebox/main/assets/treebox-demo.gif" alt="treebox lifecycle demo: create, enter, ls, and an interactive teardown" width="900">
|
|
29
|
+
</p>
|
|
30
|
+
|
|
27
31
|
---
|
|
28
32
|
|
|
29
|
-
|
|
30
|
-
`
|
|
33
|
+
`treebox` hands coding agents isolated, ready-to-run git worktrees — one
|
|
34
|
+
directory per worktree name. `treebox create` fetches, cuts a worktree from a
|
|
35
|
+
fresh `origin/<base>`, copies your `.env`, installs dependencies from a shared
|
|
31
36
|
cache, and launches `claude` or `codex` inside. No branch name needed up
|
|
32
|
-
front: the worktree gets a stable name
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
on a laptop or over plain SSH.
|
|
36
|
-
|
|
37
|
-
Built by [Seth Peters](https://www.linkedin.com/in/seth-peters/) as a small, operator-focused layer for AI agent infrastructure: git worktrees, sandbox boundaries, subscription auth, and repeatable developer environments. If that is the kind of problem you are solving, the [docs](https://seth-peters.github.io/treebox/) go deeper on the design tradeoffs — and I'm [on LinkedIn](https://www.linkedin.com/in/seth-peters/) if you want to compare notes.
|
|
37
|
+
front: the worktree gets a stable name and an un-pushable `treebox/<name>`
|
|
38
|
+
placeholder branch the agent renames when the work takes shape. Agents work the same repo
|
|
39
|
+
in parallel without collisions — on a laptop or over plain SSH.
|
|
38
40
|
|
|
39
41
|
Provisioning is identical everywhere; a pluggable **isolation mode** decides
|
|
40
42
|
where the agent runs:
|
|
@@ -44,26 +46,6 @@ where the agent runs:
|
|
|
44
46
|
| `host` (default) | none | the worktree shell |
|
|
45
47
|
| `docker` | sandboxed | a docker container, with your `.env` + caches mounted |
|
|
46
48
|
|
|
47
|
-
## Every agent ships its own cage
|
|
48
|
-
|
|
49
|
-
Every coding agent invents its own answer to "run me in parallel" and "don't
|
|
50
|
-
let me touch the wrong thing" — a different config file, a different schema, a
|
|
51
|
-
different word for the same idea:
|
|
52
|
-
|
|
53
|
-
| Agent | Sandbox / permission config | Built-in worktrees | Config lives in |
|
|
54
|
-
| ----- | --------------------------- | ------------------ | --------------- |
|
|
55
|
-
| **Claude Code** | `permissions` allow/ask/deny **+** native OS sandbox (Seatbelt/bubblewrap) **+** dev container | Yes (`--worktree`) | `.claude/settings.json`, `.devcontainer/` |
|
|
56
|
-
| **OpenAI Codex** | `sandbox_mode` × `approval_policy` (Seatbelt / Landlock+seccomp) | No in CLI (app only) | `~/.codex/config.toml`, `[profiles.*]` |
|
|
57
|
-
| **opencode** | `permission` per-tool allow/ask/deny (no OS sandbox) | No (community plugins) | `opencode.json` |
|
|
58
|
-
| **pi** | none built-in ("all permissions by default"); BYO Docker/VM + trust prompt | No in core (`pi-subagents`) | `~/.pi/agent/settings.json` |
|
|
59
|
-
|
|
60
|
-
Learn one and it teaches you nothing about the next, and none of it ports
|
|
61
|
-
across tools. treebox owns the *isolation* layer instead — **one
|
|
62
|
-
worktree-per-branch layout, one operator-owned sandbox, one config file** — and
|
|
63
|
-
launches your agent of choice inside it. Learn treebox once; swap the agent,
|
|
64
|
-
keep the box. Full comparison with citations:
|
|
65
|
-
[Agents & sandboxing](https://seth-peters.github.io/treebox/agents/).
|
|
66
|
-
|
|
67
49
|
## Install
|
|
68
50
|
|
|
69
51
|
```bash
|
|
@@ -75,7 +57,7 @@ instructions if uv is missing — it never installs a package manager behind
|
|
|
75
57
|
your back. Or install directly:
|
|
76
58
|
|
|
77
59
|
```bash
|
|
78
|
-
uv tool install
|
|
60
|
+
uv tool install treebox
|
|
79
61
|
```
|
|
80
62
|
|
|
81
63
|
Host isolation needs only `git` and a logged-in agent CLI (`claude` /
|
|
@@ -86,8 +68,7 @@ requirements and installer overrides.
|
|
|
86
68
|
|
|
87
69
|
## Usage
|
|
88
70
|
|
|
89
|
-
The
|
|
90
|
-
them.
|
|
71
|
+
The worktree lifecycle is five commands.
|
|
91
72
|
|
|
92
73
|
**Check the host.** `doctor` verifies exactly what `create` will need — git,
|
|
93
74
|
agent logins, `.env`, credentials for the required fetch — and prints the fix
|
|
@@ -152,12 +133,32 @@ treebox teardown fix-auth brave-otter --delete-branch
|
|
|
152
133
|
treebox teardown # pick interactively
|
|
153
134
|
```
|
|
154
135
|
|
|
155
|
-
treebox is built to be scripted, including by agents:
|
|
156
|
-
`--json` (data to stdout, diagnostics to stderr, a schema that
|
|
157
|
-
fields within a version), `--dry-run` prints the exact commands
|
|
158
|
-
codes are stable (`0` ok · `
|
|
159
|
-
conflict). Full
|
|
160
|
-
[usage guide](https://seth-peters.github.io/treebox/usage/).
|
|
136
|
+
treebox is built to be scripted, including by agents: the worktree commands and
|
|
137
|
+
`doctor` take `--json` (data to stdout, diagnostics to stderr, a schema that
|
|
138
|
+
only gains fields within a version), `--dry-run` prints the exact commands
|
|
139
|
+
without running them, and exit codes are stable (`0` ok · `1` runtime/doctor
|
|
140
|
+
blocked · `2` usage · `3` not found · `4` auth · `5` conflict). Full
|
|
141
|
+
reference in the [usage guide](https://seth-peters.github.io/treebox/usage/).
|
|
142
|
+
|
|
143
|
+
## Every agent ships its own cage
|
|
144
|
+
|
|
145
|
+
Every coding agent invents its own answer to "run me in parallel" and "don't
|
|
146
|
+
let me touch the wrong thing" — a different config file, a different schema, a
|
|
147
|
+
different word for the same idea:
|
|
148
|
+
|
|
149
|
+
| Agent | Sandbox / permission config | Built-in worktrees | Config lives in |
|
|
150
|
+
| ----- | --------------------------- | ------------------ | --------------- |
|
|
151
|
+
| **Claude Code** | `permissions` allow/ask/deny **+** native OS sandbox (Seatbelt/bubblewrap) **+** dev container | Yes (`--worktree`) | `.claude/settings.json`, `.devcontainer/` |
|
|
152
|
+
| **OpenAI Codex** | `sandbox_mode` × `approval_policy` (Seatbelt / Landlock+seccomp) | No in CLI (app only) | `~/.codex/config.toml`, `[profiles.*]` |
|
|
153
|
+
| **opencode** | `permission` per-tool allow/ask/deny (no OS sandbox) | No (community plugins) | `opencode.json` |
|
|
154
|
+
| **pi** | none built-in ("all permissions by default"); BYO Docker/VM + trust prompt | No in core (`pi-subagents`) | `~/.pi/agent/settings.json` |
|
|
155
|
+
|
|
156
|
+
Learn one and it teaches you nothing about the next, and none of it ports
|
|
157
|
+
across tools. treebox owns the *isolation* layer instead — **one
|
|
158
|
+
named-worktree layout, one operator-owned sandbox, one config file** — and
|
|
159
|
+
launches your agent of choice inside it. Learn treebox once; swap the agent,
|
|
160
|
+
keep the box. Full comparison with citations:
|
|
161
|
+
[Agents & sandboxing](https://seth-peters.github.io/treebox/agents/).
|
|
161
162
|
|
|
162
163
|
## Design
|
|
163
164
|
|
|
@@ -174,14 +175,14 @@ conflict). Full reference in the
|
|
|
174
175
|
- **Credentials go in as scoped copies.** Only the agents' login files are
|
|
175
176
|
copied into a throwaway per-worktree dir — never the live `~/.claude` /
|
|
176
177
|
`~/.codex` — refreshed on every entry so a host logout or a fresh login
|
|
177
|
-
reaches the sandbox next time
|
|
178
|
-
never `ANTHROPIC_API_KEY`.
|
|
178
|
+
reaches the sandbox next time; treebox uses your subscription login.
|
|
179
179
|
|
|
180
180
|
More in [how it works](https://seth-peters.github.io/treebox/how-it-works/).
|
|
181
181
|
|
|
182
182
|
## Configuration
|
|
183
183
|
|
|
184
|
-
Optional, and user-level only (
|
|
184
|
+
Optional, and user-level only (`$TREEBOX_CONFIG`, else
|
|
185
|
+
`$TREEBOX_HOME/config.toml`, default `~/.treebox/config.toml`) — treebox
|
|
185
186
|
never reads config from the target repo:
|
|
186
187
|
|
|
187
188
|
```toml
|
|
@@ -196,44 +197,51 @@ covered in the
|
|
|
196
197
|
|
|
197
198
|
## Customizing isolation
|
|
198
199
|
|
|
199
|
-
`docker` isolation
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
your repo's deps (in docker, setup runs `postCreate`, not the host-mode
|
|
206
|
-
ecosystem auto-detect):
|
|
200
|
+
`docker` isolation builds from a **template you own** — a directory of files
|
|
201
|
+
treebox ships and you edit. treebox renders it beside the worktree so a boxed
|
|
202
|
+
agent can't touch its own cage. Three steps:
|
|
203
|
+
|
|
204
|
+
**1. Copy the template out** — you edit a copy, never the shipped one. Name it
|
|
205
|
+
(here `node`); a `node` box and a `python` box can coexist, one per stack:
|
|
207
206
|
|
|
208
207
|
```bash
|
|
208
|
+
mkdir -p ~/.treebox/templates
|
|
209
209
|
cp -R "$(python -c 'import treebox.assets, pathlib; print(pathlib.Path(treebox.assets.__file__).parent)')/container" \
|
|
210
|
-
~/.
|
|
210
|
+
~/.treebox/templates/node
|
|
211
211
|
```
|
|
212
212
|
|
|
213
|
+
**2. Edit two files.** The shipped image already bundles Node 22, uv, `gh`,
|
|
214
|
+
ripgrep, and the agent CLIs, so most projects touch only these:
|
|
215
|
+
|
|
213
216
|
```dockerfile
|
|
214
|
-
# ~/.
|
|
217
|
+
# ~/.treebox/templates/node/Dockerfile — global tooling
|
|
215
218
|
USER root
|
|
216
219
|
RUN npm install -g pnpm@9 typescript tsx
|
|
217
220
|
USER ${USERNAME}
|
|
218
221
|
```
|
|
219
222
|
|
|
220
223
|
```json
|
|
221
|
-
// ~/.
|
|
224
|
+
// ~/.treebox/templates/node/container.json — your install command
|
|
222
225
|
"postCreate": "if [ -f pnpm-lock.yaml ]; then pnpm install --frozen-lockfile; elif [ -f package-lock.json ]; then npm ci; else npm install; fi"
|
|
223
226
|
```
|
|
224
227
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
228
|
+
(In docker, setup runs `postCreate`, not the host-mode ecosystem auto-detect,
|
|
229
|
+
so a non-Python project wires its install here.)
|
|
230
|
+
|
|
231
|
+
**3. Point treebox at it** — per run with `--isolation docker --template node`,
|
|
232
|
+
or set `template = "node"` in `~/.treebox/config.toml`.
|
|
233
|
+
|
|
234
|
+
Full walkthrough — every file in a template and the `container.json` schema — in
|
|
235
|
+
the [configuration guide](https://seth-peters.github.io/treebox/configuration/#customizing-the-sandbox).
|
|
229
236
|
|
|
230
237
|
## Development
|
|
231
238
|
|
|
232
239
|
```bash
|
|
233
240
|
git clone https://github.com/Seth-Peters/treebox && cd treebox
|
|
234
241
|
uv run treebox ... # run the CLI from the working tree
|
|
235
|
-
uv run --extra dev pre-commit install # lint/format/type hooks (see CONTRIBUTING.md)
|
|
242
|
+
uv run --extra dev pre-commit install # lint/format/strict type-check hooks (see CONTRIBUTING.md)
|
|
236
243
|
uv run --extra dev python -m pytest # unit + integration suite
|
|
244
|
+
uv run --extra dev mypy # strict type check
|
|
237
245
|
./scripts/validate.sh # lint + format + tests + live host-runner smoke
|
|
238
246
|
```
|
|
239
247
|
|
|
Binary file
|
|
Binary file
|
|
@@ -8,7 +8,7 @@ of words for the same ideas. Learn one and it teaches you nothing about the
|
|
|
8
8
|
next.
|
|
9
9
|
|
|
10
10
|
That fragmentation is treebox's reason to exist. treebox owns the *isolation*
|
|
11
|
-
layer — one worktree
|
|
11
|
+
layer — one named-worktree layout and one operator-owned sandbox — and
|
|
12
12
|
launches your agent of choice inside it. **One config to learn, any agent in
|
|
13
13
|
the box.**
|
|
14
14
|
|
|
@@ -54,8 +54,9 @@ whichever agent you launch:
|
|
|
54
54
|
|
|
55
55
|
---
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
`$TREEBOX_CONFIG`, else `$TREEBOX_HOME/config.toml` (default
|
|
58
|
+
`~/.treebox/config.toml`), picks the isolation mode, harness, base, caches,
|
|
59
|
+
and sandbox template. It's the single source of truth, and it's never read
|
|
59
60
|
from the target repo.
|
|
60
61
|
|
|
61
62
|
- :material-swap-horizontal:{ .lg .middle } **Swap the agent, keep the box**
|