wt-mcp
# 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
Scored across 13 tools
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.
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.
With 13 tools, the server is well-scoped for managing development tasks and projects. Each tool addresses a distinct need without being overwhelming.
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.