Skip to main content
Glama
README.md
# worktree-manager

CLI para gerenciar **git worktrees por produto**: várias tasks em paralelo, com config YAML reutilizável, cópia de arquivos/dependências e workspace Cursor/VS Code gerado automaticamente.

Binário: **`wt`** · MCP: **`wt-mcp`** · Python 3.11+

---

## Índice

- [Para quem é](#para-quem-é)
- [Como funciona](#como-funciona)
- [Instalação](#instalação)
- [Início rápido](#início-rápido)
- [Fluxos de trabalho](#fluxos-de-trabalho)
- [Comandos](#comandos)
- [Configuração](#configuração)
- [Estado](#estado)
- [MCP para agentes](#mcp-para-agentes)
- [Vários produtos](#vários-produtos)
- [Documentação](#documentação)
- [Desenvolvimento](#desenvolvimento)

---

## Para quem é

Útil quando você:

- Mantém **mais de um repositório** por produto (ex.: API + web, backend + mobile)
- Cria uma pasta por **task/ticket** com worktrees git isoladas
- Quer reaproveitar arquivos locais (`.env`, `launch.json`, `node_modules`, etc.)
- Abre tudo num **`.code-workspace`** com pastas extras (docs, utilitários, specs)

Não é um wrapper genérico de `git worktree` para um único repo solto — o foco é o **workspace de produto** com N projetos.

---

## Como funciona

```text
Pasta do produto/
├── api/                           ← repositório git
├── web/                           ← repositório git
├── docs/                          ← pasta extra no workspace
└── .worktree-manager/              ← pasta do manager
    ├── config.yml                 ← config (versionável)
    ├── state.yml                  ← estado local (não versionar)
    └── worktrees/
        └── TASK-123/
            ├── api/               ← worktree
            ├── web/               ← worktree
            └── TASK-123.code-workspace
```

Dois caminhos para criar tasks:

1. **Em etapas** — `create` (pasta + workspace + estado) e depois `add` projeto a projeto  
2. **Preset** — `create --preset …` encadeia create + vários adds

A **branch de trabalho** default é o nome da task (`--branch` sobrescreve; no preset, `--branch proj=b` por projeto).  
A **base de origem** é por projeto (`default_base` no YAML, com override via `--base`).

> Execute os comandos na **pasta base do produto** (pai de `.worktree-manager/`) **ou** dentro de `.worktree-manager/`.  
> Outro produto = outra pasta = outro `init`.

---

## Instalação

### Desenvolvimento (recomendado hoje)

```bash
git clone <url-deste-repo> worktree-manager
cd worktree-manager

uv venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
uv pip install -e ".[dev]"

wt --version
```

Alternativa com pip:

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
```

Deixe o venv ativo (ou exponha `wt` no `PATH`) para usar em qualquer pasta de produto.

---

## Início rápido

### 1. Entre na pasta do produto

```bash
cd ~/projetos/meu-produto
```

Estrutura mínima esperada: repositórios git lado a lado (ex.: `api/`, `web/`).

### 2. Inicialize a config

```bash
wt init
```

O assistente pergunta:

1. Nome do produto  
2. Loop de projetos: **path → nome (default: basename) → default base**

Cria `.worktree-manager/config.yml` (worktrees em `.worktree-manager/worktrees/`).  
Depois edite `copy`, `workspace_folders` e `presets`, ou use `wt projects add`.

### 3. Complete o YAML (exemplo)

```yaml
name: meu-produto
root: .
worktrees_dir: worktrees
workspace_file: "{task}.code-workspace"

workspace_folders:
  - path: docs

projects:
  api:
    path: api
    default_base: main
    copy:
      - from: .env.local
        to: .env.local
  web:
    path: web
    default_base: main
    copy:
      - from: node_modules
        to: node_modules
        strategy: rsync

presets:
  backend: [api]
  frontend: [web]
  fullstack: [api, web]
```

Veja o schema completo em [docs/configuracao.md](docs/configuracao.md) e exemplos em [docs/exemplos/](docs/exemplos/).

### 4. Crie uma task

**Rápido (preset):**

```bash
wt create TASK-123 --preset fullstack --open
# ou com branches explícitas:
wt create TASK-123 --preset fullstack --branch feature/TASK-123 --open
```

**Em etapas:**

```bash
wt create TASK-123
wt add TASK-123 api
wt add TASK-123 web --base develop
wt open TASK-123
```

### 5. Gerencie

```bash
wt list
wt status TASK-123
wt sync TASK-123
wt doctor
wt doctor --fix
wt prune
wt remove TASK-123 --force
```

---

## Fluxos de trabalho

### Só um projeto da stack

```bash
wt create TASK-10 --preset backend
```

### Começar parcial e evoluir

```bash
wt create TASK-11
wt add TASK-11 api --branch feature/TASK-11
# ... trabalhar só na API ...
wt add TASK-11 web --branch feature/TASK-11
```

### Branches e bases diferentes por projeto no mesmo preset

```bash
wt create TASK-12 \
  --preset fullstack \
  --branch api=feature/TASK-12-api \
  --branch web=feature/TASK-12-ui \
  --base api=main \
  --base web=develop
```

### Simular antes de executar

```bash
wt create TASK-13 --preset fullstack --dry-run
wt add TASK-13 api --dry-run
wt remove TASK-13 --force --dry-run
wt sync TASK-13 --dry-run
```

### Remover um projeto sem apagar a task

```bash
wt remove TASK-12 web --force
```

### Remover tudo (e opcionalmente a branch local)

```bash
wt remove TASK-12 --force --delete-branch
```

---

## Comandos

| Comando | Descrição |
|---|---|
| `wt init` | Cria `.worktree-manager/config.yml` |
| `wt create <task>` | Cria task vazia (pasta + workspace + estado) |
| `wt create <task> --preset <nome>` | Create + adds do preset |
| `wt add <task> <project> [--branch <b>] [--base <b>]` | Adiciona projeto à task (branch default = task) |
| `wt remove <task> [project] --force` | Remove projeto da task ou a task inteira |
| `wt list` | Lista tasks do estado |
| `wt projects list` | Lista projetos do `config.yml` |
| `wt projects add <path> [--name] [--base]` | Adiciona projeto à config (nome default = basename) |
| `wt projects remove <nome> --force` | Remove projeto da config |
| `wt status <task>` | `git status` dos projetos da task |
| `wt sync <task> [project]` | Fetch + rebase/merge na base registrada |
| `wt open <task>` | Abre o `.code-workspace` (Cursor/VS Code) |
| `wt doctor [--fix]` | Diagnóstico; `--fix` tenta corrigir |
| `wt prune` | Limpa órfãos e ghosts |
| `wt help [comando]` | Ajuda detalhada |
| `wt --help` / `wt --version` | Ajuda curta e versão |

Opções úteis:

| Opção | Onde | Efeito |
|---|---|---|
| `--branch` | `add`, `create --preset` | Branch de trabalho (default: nome da task) |
| `--branch proj=b` | `create --preset` | Branch por projeto (repetível) |
| `--base` | `add` | Base de origem (senão usa `default_base`) |
| `--base proj=branch` | `create --preset` | Override de base por projeto |
| `--strategy` | `sync` | `rebase` (default) ou `merge` |
| `--open` | `create` | Abre o workspace ao terminar |
| `--delete-branch` | `remove` | Apaga a branch local criada |
| `--dry-run` | `create`, `add`, `remove`, `sync`, `doctor --fix`, `prune` | Mostra o plano sem alterar nada |
| `--force` | `remove`, `sync` | Confirma remoção / permite dirty no sync |

Referência detalhada: [docs/comandos.md](docs/comandos.md).

---

## Configuração

Arquivo: **`.worktree-manager/config.yml`**.

| Campo | Obrigatório | Default | Descrição |
|---|---|---|---|
| `name` | sim | — | Nome do produto |
| `root` | não | `.` | Raiz relativa ao produto (pai de `.worktree-manager/`) |
| `worktrees_dir` | não | `worktrees` | Pasta das tasks (relativa a `.worktree-manager/`) |
| `workspace_file` | não | `{task}.code-workspace` | Nome do workspace gerado |
| `workspace_folders` | não | `[]` | Pastas extras no workspace |
| `projects.<id>.path` | sim | — | Path do repositório (relativo à raiz do produto) |
| `projects.<id>.default_base` | sim | — | Branch de origem padrão |
| `projects.<id>.copy` | não | `[]` | Arquivos/pastas a copiar no `add` |
| `projects.<id>.copy[].strategy` | não | `rsync` | `rsync` \| `copy` \| `skip` |
| `presets` | não | `{}` | Nome → lista de ids de projeto |

**Não existem** `allowed_bases` nem pattern automático de branch.

Guia completo do schema, `init` e estado: [docs/configuracao.md](docs/configuracao.md).

---

## Estado

Arquivo local: **`.worktree-manager/state.yml`**.

| | Config | Estado |
|---|---|---|
| Responde | O que *pode* ser feito | O que *já existe* |
| Versionar? | Sim (`config.yml` é útil no time) | **Não** |
| Quem escreve | `init` + edição humana | Só o CLI |

Sugestão de `.gitignore` no produto:

```gitignore
.worktree-manager/state.yml
```

O `wt doctor` compara estado, pastas em disco e `git worktree list` (órfãos, drift de branch, worktrees fantasma, etc.).  
`wt doctor --fix` e `wt prune` corrigem o que for seguro; `wt sync` atualiza as branches da task com a base.

---

## MCP para agentes

O servidor **`wt-mcp`** expõe as mesmas operações da CLI via [Model Context Protocol](https://modelcontextprotocol.io/) (stdio), para agentes Cursor (e outros clientes MCP) criarem/listarem/sincronizarem tasks sem parsear stdout.

Pré-requisito: pacote instalado (`uv tool install --editable .` ou `uv pip install -e .`) e `wt-mcp` no `PATH` (`which wt-mcp`).

### Adicionar no Cursor

1. Abra **Cursor Settings → MCP** (ou edite o JSON de MCP).
2. Inclua o servidor abaixo.
3. Salve e confirme que `worktree-manager` aparece como conectado (tools disponíveis no chat/agente).

**Global** (`~/.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "worktree-manager": {
      "command": "wt-mcp",
      "args": []
    }
  }
}
```

**Só neste repo** (`.cursor/mcp.json` na raiz do projeto):

```json
{
  "mcpServers": {
    "worktree-manager": {
      "command": "wt-mcp",
      "args": []
    }
  }
}
```

Se `wt-mcp` não estiver no `PATH`, use o caminho absoluto do venv:

```json
{
  "mcpServers": {
    "worktree-manager": {
      "command": "/caminho/para/worktree-manager/.venv/bin/wt-mcp",
      "args": []
    }
  }
}
```

### Uso pelo agente

- Passe **`product_root`** (path absoluto da pasta do produto) quando o cwd do agente não for o produto.
- Respostas: `{ "ok": true, "data": … }` ou `{ "ok": false, "error": { "kind", "message" } }`.
- Ações destrutivas (`remove`, `prune`, `doctor` com `fix`) exigem **`confirm=true`** (ou `dry_run=true` para simular).

| Tool | Equivale a |
|---|---|
| `resolve_product` / `list_tasks` / `list_projects` | inventário |
| `create_task` / `create_with_preset` / `add_project` | `wt create` / `--preset` / `wt add` |
| `remove` | `wt remove … --force` |
| `status` / `sync` | `wt status` / `wt sync` |
| `doctor` / `prune` | `wt doctor [--fix]` / `wt prune` |
| `workspace_path` / `open_workspace` | path do workspace / `wt open` |

Skill opcional (orquestra MCP ou CLI): [`.cursor/skills/worktree-manager/`](.cursor/skills/worktree-manager/).  
Detalhes e contrato de erro: [docs/mcp.md](docs/mcp.md).

---

## Vários produtos

Cada produto tem sua própria pasta `.worktree-manager/`:

```text
ProdutoA/
├── api/
└── .worktree-manager/
    ├── config.yml
    └── worktrees/

ProdutoB/
├── backend/
├── mobile/
└── .worktree-manager/
    ├── config.yml
    └── worktrees/
```

```bash
cd ~/projetos/ProdutoA && wt init
cd ~/projetos/ProdutoB && wt init
```

---

## Documentação

| Documento | Conteúdo |
|---|---|
| **[README.md](README.md)** | Porta de entrada (este arquivo) |
| [docs/configuracao.md](docs/configuracao.md) | Schema YAML, init, estado |
| [docs/comandos.md](docs/comandos.md) | Referência detalhada dos comandos |
| [docs/mcp.md](docs/mcp.md) | Servidor MCP (`wt-mcp`) para agentes |
| [docs/exemplos/](docs/exemplos/) | YAMLs de exemplo (genérico + casos) |
| [docs/migracao-clinic.md](docs/migracao-clinic.md) | Caso: migrar script legado Clinic → `wt` |
| [docs/plano-desenvolvimento.md](docs/plano-desenvolvimento.md) | Histórico de fases / backlog interno |

Exemplos prontos para copiar:

```bash
# stack API + web (genérico)
mkdir -p /caminho/do/produto/worktree-manager
cp docs/exemplos/api-web.yml /caminho/do/produto/.worktree-manager/config.yml

# caso Clinic (referência)
mkdir -p /caminho/do/Clinic/worktree-manager
cp docs/exemplos/clinic.yml /caminho/do/Clinic/.worktree-manager/config.yml
```

Skill opcional do Cursor (orquestra MCP/`wt`, sem reimplementar lógica):  
[`.cursor/skills/worktree-manager/`](.cursor/skills/worktree-manager/)

---

## Desenvolvimento

```bash
source .venv/bin/activate
uv pip install -e ".[dev]"
pytest
wt --help
wt-mcp   # sobe o servidor MCP em stdio (usado pelo Cursor)
```

Layout do pacote:

```text
src/worktree_manager/
├── cli/           # comandos Typer
├── config/        # load/validate/write YAML
├── state/         # estado local
├── git/           # operações git
├── workspace/     # geração .code-workspace
├── mcp/           # servidor MCP (wt-mcp)
├── copyops.py     # cópias declarativas
└── services.py    # create/add/remove/sync/doctor/prune
```

Plano e backlog: [docs/plano-desenvolvimento.md](docs/plano-desenvolvimento.md).

---

## Licença

MIT (ver `pyproject.toml`).

TDQS

B3.2/5.0

Scored across 13 tools

Disambiguation4/5

Most tools have clear, distinct purposes: listing, creating, syncing, removing, and diagnosing. Minor overlap exists between create_task and create_with_preset, and between remove and add_project, but descriptions clarify the differences.

Naming Consistency3/5

Names mix styles: some are verb_noun (list_tasks, create_task), while others are bare verbs (sync, remove, status, prune) or noun-ish (workspace_path, open_workspace). This inconsistency makes it less predictable, though still readable.

Tool Count5/5

With 13 tools, the server is well-scoped for managing development tasks and projects. Each tool addresses a distinct need without being overwhelming.

Completeness4/5

The tool surface covers core lifecycle operations: create, list, resolve, add, remove, sync, status, and maintenance. Minor gaps exist (e.g., no explicit update/rename task), but the set is sufficient for the domain.

Maintenance

ActivitySlowing
ResponsivenessNo issues