- README réécrit (anglais) : setup, quick start, usage, accès Tailscale, flags CLI, sécurité, comparatif, section développement - .gitignore réorganisé par sections (ajout *.tgz, coverage, .claude, .remember, CLAUDE.md) - CLAUDE.md retiré du suivi git (reste local, non publié) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
162 lines
9.5 KiB
Markdown
162 lines
9.5 KiB
Markdown
# Arboretum
|
|
|
|
> A self-hosted web dashboard for your git worktrees and the Claude Code sessions running on them — from any device.
|
|
|
|
**Status: MVP.** The worktree-first dashboard, session discovery & resume, multi-repo worktree lifecycle, live session states, the web terminal, and mobile supervision (installable PWA, Web Push when a session needs you, approve/deny without opening a terminal) are implemented and tested.
|
|
|
|
---
|
|
|
|
## The problem
|
|
|
|
Working with AI coding agents changed how we use git: one feature = one worktree = one Claude Code session, several of them in parallel. But the tooling didn't follow:
|
|
|
|
- `git worktree list` across multiple repos is a chore, worktrees pile up, each needs its `node_modules` and `.env`.
|
|
- Claude Code sessions are scattered: some running in terminals, some resumable from history, with no consolidated view of *which one is waiting for your input*.
|
|
- When you step away from your desk, a session blocked on a permission prompt stays blocked.
|
|
|
|
## What Arboretum does
|
|
|
|
A single Node.js daemon you run on your dev machine (`npx git-arboretum`), serving a web UI usable from your desktop, phone or tablet:
|
|
|
|
- **Worktree-first, multi-repo dashboard** — every worktree of every registered repo, with its git state (branch, ahead/behind, dirty files) *and* the state of its Claude Code session (busy / waiting for input / idle / resumable).
|
|
- **Full worktree lifecycle** — create (with per-repo post-create hooks: `npm ci`, copy `.env`…), adopt worktrees created by hand, delete with guardrails, prune orphans.
|
|
- **Session discovery & resume** — sessions you launched in your own terminal show up automatically; resume dead ones, observe or fork live ones. Never corrupts a live session.
|
|
- **Web terminal** — full xterm.js terminal to every managed session, surviving browser disconnects.
|
|
- **Supervision from your phone** — installable PWA with push notifications when a session needs you; approve/deny a prompt without opening a terminal.
|
|
|
|
---
|
|
|
|
## Requirements
|
|
|
|
- **Node.js ≥ 22.16** — required, not just recommended. Arboretum persists state with `node:sqlite` (`DatabaseSync`), which is native and stable only from this version. (`.nvmrc` pins `22`.)
|
|
- **The `claude` CLI** on your `PATH` if you want Arboretum to launch and manage Claude Code sessions. Arboretum wraps the interactive CLI you already use — install and authenticate it as usual.
|
|
- A **git** repository (or several) you want to manage.
|
|
|
|
## Quick start
|
|
|
|
### Run it (recommended)
|
|
|
|
```bash
|
|
npx git-arboretum
|
|
```
|
|
|
|
On first start, Arboretum prints a one-time **access token** and the URL to open:
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────────────┐
|
|
│ First start — your access token (shown once, store it safely): │
|
|
└──────────────────────────────────────────────────────────────────┘
|
|
|
|
<your-token-here>
|
|
|
|
Login at: http://127.0.0.1:7317/
|
|
```
|
|
|
|
Open the URL, paste the token to log in, and you're in. The token is stored **hashed** — it is shown only once, so save it somewhere safe (a password manager). You can manage tokens later from **Settings**.
|
|
|
|
### Run from source
|
|
|
|
```bash
|
|
git clone https://git.lidge.fr/johanleroy/arboretum.git
|
|
cd arboretum
|
|
nvm use # or ensure Node ≥ 22.16
|
|
npm install
|
|
npm run build # builds shared → server → web (order matters)
|
|
node packages/server/dist/index.js
|
|
```
|
|
|
|
## Using Arboretum
|
|
|
|
1. **Add a repository.** From the dashboard, register a local git repo by its path. Optionally configure **post-create hooks** (e.g. `npm ci`, `cp ../.env .env`) that run automatically every time you create a new worktree for that repo.
|
|
2. **Create or adopt worktrees.** Spin up a new worktree + branch in one click (hooks run for you), or adopt a worktree you created by hand. Each worktree shows its branch, ahead/behind, and dirty-file count.
|
|
3. **Start or resume a session.** Launch a Claude Code session on a worktree, or resume one that was started in your terminal — Arboretum discovers existing sessions automatically and always resumes them in their original working directory.
|
|
4. **Watch the live states.** Each session reports whether it's *busy*, *waiting for your input*, or *idle*. Open the **web terminal** to interact directly; it survives browser disconnects (closing the tab does not kill the session).
|
|
5. **Supervise from your phone.** Install the PWA, and when a session flips to *waiting* you get a push notification. Approve or deny the prompt straight from the notification UI — no terminal required.
|
|
|
|
## Remote access from your phone
|
|
|
|
Arboretum binds to `127.0.0.1` by default and **refuses** to bind to a non-loopback address without an explicit override. The recommended (and safe) way to reach it from other devices is **[Tailscale Serve](https://tailscale.com/kb/1242/tailscale-serve)** — valid HTTPS, tailnet identity, no open ports:
|
|
|
|
```bash
|
|
# Expose the local daemon over HTTPS inside your tailnet
|
|
tailscale serve --bg 7317
|
|
```
|
|
|
|
Then start Arboretum allowing your tailnet origin (the strict Origin check needs to know about it):
|
|
|
|
```bash
|
|
npx git-arboretum --allow-origin https://<machine>.<tailnet>.ts.net
|
|
```
|
|
|
|
Open `https://<machine>.<tailnet>.ts.net` from any device on your tailnet. **Web Push requires HTTPS**, so Tailscale Serve (or another HTTPS front) is also what enables mobile notifications. On **iOS**, install the app to your home screen first, then allow notifications.
|
|
|
|
> ⚠️ A web terminal is remote code execution **by design**. Never expose Arboretum directly to the public internet.
|
|
|
|
## Configuration
|
|
|
|
All options are CLI flags:
|
|
|
|
| Flag | Default | Description |
|
|
|---|---|---|
|
|
| `--port <n>` | `7317` | Port to listen on. |
|
|
| `--bind <addr>` | `127.0.0.1` | Bind address. Non-loopback is refused unless `--i-know-this-exposes-a-terminal` is set. |
|
|
| `--allow-origin <url>` | — | Additional allowed `Origin` (repeatable). Needed for Tailscale/HTTPS access. |
|
|
| `--db <path>` | `<data>/arboretum.db` | SQLite database path. |
|
|
| `--vapid-contact <mailto/url>` | `mailto:arboretum@localhost` | VAPID contact subject for Web Push. |
|
|
| `--print-token` | `false` | Hint about token re-printing (tokens are hashed and cannot be re-shown). |
|
|
| `--i-know-this-exposes-a-terminal` | `false` | Acknowledge binding to a non-loopback address. **Avoid** — prefer Tailscale Serve. |
|
|
|
|
State (the SQLite database) lives in `$XDG_DATA_HOME/arboretum` (default `~/.local/share/arboretum`).
|
|
|
|
## Security model
|
|
|
|
A web terminal is remote code execution *by design*. Arboretum's guardrails are structural:
|
|
|
|
- Binds to `127.0.0.1` by default; refuses non-loopback binds without an explicit flag.
|
|
- Authenticates **every** `/api/**` request **and** every `/ws` upgrade with revocable tokens, and applies a **strict `Origin` check** (the `SameSite=Strict` cookie does not cover WebSocket upgrades — this is the anti cross-site hijacking guard).
|
|
- Tokens are stored **hashed** (sha256) and compared in constant time; the bootstrap token is shown only once. The session cookie is an HMAC-signed payload. Login is rate-limited with exponential backoff.
|
|
|
|
The recommended way to reach Arboretum from other devices is Tailscale Serve (valid HTTPS, tailnet identity, no open ports). Never expose it directly to the internet.
|
|
|
|
## What makes it different
|
|
|
|
| | Arboretum | GitKraken Agent Mode / Conductor / Nimbalyst | Happy / CloudCLI | Anthropic Remote Control |
|
|
|---|---|---|---|---|
|
|
| Web UI, any device | ✅ | ❌ desktop apps | ✅ | ✅ |
|
|
| Visual worktree management (multi-repo) | ✅ | ✅ (single repo, desktop) | ❌ | ❌ |
|
|
| Discovers & resumes *existing* terminal sessions | ✅ | ❌ | partial | ❌ |
|
|
| 100% self-hosted — zero traffic through third-party servers | ✅ | ✅ | relay server | ❌ relayed through Anthropic |
|
|
| Linux-first | ✅ | varies | ✅ | Desktop app has no Linux build |
|
|
| Open source | MIT | ❌ / partial | MIT / AGPL | ❌ |
|
|
|
|
Anthropic's Remote Control is great at piloting *one* session from your phone. Arboretum is the layer it doesn't provide: the consolidated, self-hosted board of all your worktrees and sessions across all your repos.
|
|
|
|
## A note on Claude usage
|
|
|
|
Arboretum wraps the **interactive** Claude Code CLI in a PTY — the same thing you run in your terminal, displayed in your browser. It does not use the Agent SDK or headless mode. Anthropic's usage policies around programmatic use may evolve; Arboretum will track CLI releases and document any impact transparently.
|
|
|
|
## Development
|
|
|
|
Arboretum is an npm-workspaces monorepo: `@arboretum/shared` (WS/REST protocol, source of truth), `git-arboretum` (the Fastify daemon, the published package), and `@arboretum/web` (the Vue 3 SPA).
|
|
|
|
```bash
|
|
npm run build # build shared → server → web (order matters)
|
|
npm run typecheck # tsc -b shared + server
|
|
npm test # vitest across packages
|
|
npm run dev:server # daemon in watch mode
|
|
npm run dev:web # Vite dev server (proxies /api and /ws to the daemon on :7317)
|
|
```
|
|
|
|
End-to-end acceptance scripts (run `npm run build` first):
|
|
|
|
```bash
|
|
node packages/server/scripts/acceptance-p1.mjs # core: daemon + real WS client
|
|
node packages/server/scripts/acceptance-p2.mjs # session discovery & resume
|
|
node packages/server/scripts/acceptance-p3.mjs # worktrees & session correlation
|
|
node packages/server/scripts/acceptance-p4.mjs # Web Push + WS `answer` command
|
|
```
|
|
|
|
## License
|
|
|
|
MIT — see [LICENSE](LICENSE).
|