diff --git a/tooling/WORKFLOW.md b/tooling/WORKFLOW.md new file mode 100644 index 0000000..02bb0ec --- /dev/null +++ b/tooling/WORKFLOW.md @@ -0,0 +1,192 @@ +# Dev Orchestrator — AI Workflow Guide + +Workflow de desenvolvimento com IA usando **OpenCode** + **OpenSpec** + **git worktrees**, com orquestração automática do loop dev→QA. + +``` +Você (review specs) → Orquestrador (specs) → Dev Agent (implementa) → QA Agent (revisa) + ↑ │ + └─────────────────── FAIL ──────────────────────────┘ + PASS → merge → archive +``` + +--- + +## Pré-requisitos + +```bash +# Instalar as 2 dependências +npm install -g opencode-ai@latest +npm install -g @fission-ai/openspec@latest + +# Configurar provedor (OpenRouter, Anthropic, etc.) +opencode auth login +``` + +--- + +## Comandos + +| Comando | O que faz | +|---|---| +| `dev-orchestrator init` | Configura o repo com OpenSpec (roda 1x por projeto) | +| `dev-orchestrator spec ` | Cria spec OpenSpec + worktree isolado + preenche spec via IA | +| `dev-orchestrator build ` | Roda dev→QA loop no worktree, merge automático no main se QA passar | +| `dev-orchestrator status` | Visão kanban dos features ativos | +| `dev-orchestrator clean ` | Remove worktree + branch (para features abandonadas) | + +--- + +## Fluxo Completo + +### 1. Inicializar o projeto + +```bash +cd ~/projetos/meu-app +dev-orchestrator init +``` + +Isso cria a pasta `openspec/`, configura o OpenCode, e adiciona `.worktrees/` ao `.gitignore`. + +### 2. Criar spec de uma feature + +```bash +dev-orchestrator spec add-oauth-login +``` + +O que acontece: +1. Cria `openspec/changes/add-oauth-login/` com os templates +2. Cria um **git worktree** isolado em `../.worktrees/add-oauth-login/` no branch `dev-flow/add-oauth-login` +3. Roda `npm install` (ou `pip install`) dentro do worktree +4. Chama o **orquestrador** (OpenCode) que lê o código, preenche os specs, valida + +### 3. Revisar os specs + +```bash +# Ver arquivos gerados +ls openspec/changes/add-oauth-login/ +cat openspec/changes/add-oauth-login/spec.md + +# Validar +openspec validate add-oauth-login --strict +``` + +**Aqui você está no controle.** Revise os specs, ajuste o que quiser. +Só prossiga quando estiver satisfeito. + +### 4. Disparar o build + +```bash +dev-orchestrator build add-oauth-login +``` + +O que acontece: +``` +── Dev Phase (attempt 1/3) ── + → OpenCode implementa no worktree + → Roda testes + +── QA Review ── + → OpenCode revisa: spec compliance, testes, regressões, edge cases + +PASS → merge no main, archive spec, remove worktree +FAIL → volta pro dev (até 3 tentativas) +``` + +Se o QA falhar 3 vezes, o worktree é mantido pra você inspecionar e corrigir manualmente. + +### 5. Ver status de tudo + +```bash +dev-orchestrator status +``` + +Exemplo de output: +``` +# FEATURE COMMITS SPEC WORKTREE +─── ───────────────────────────── ───────── ───────── ────────────── +1. add-oauth-login 3 2/4 ../.worktrees/add-oauth-login/ +2. fix-payment-timeout 1 active ../.worktrees/fix-payment-timeout/ +``` + +--- + +## Estrutura de diretórios + +``` +~/projetos/meu-app/ +├── src/ # código principal +├── openspec/ +│ ├── specs/ # specs arquivados (source of truth) +│ └── changes/ # specs ativos +│ └── add-oauth/ +│ ├── spec.md +│ ├── design.md +│ └── tasks.md +├── .gitignore # inclui .worktrees/ +└── ... + +../.worktrees/ +└── add-oauth/ # worktree isolado + ├── .git # branch: dev-flow/add-oauth + ├── src/ # cópia do código + ├── node_modules/ # instalado localmente + └── ... +``` + +--- + +## FAQ + +### Posso rodar múltiplos features em paralelo? + +Sim. Cada `dev-orchestrator spec` cria um worktree isolado. Rode `build` em terminais separados: + +```bash +# Terminal 1 +dev-orchestrator build add-oauth + +# Terminal 2 +dev-orchestrator build fix-payments +``` + +Worktrees em branches diferentes = zero conflito. O merge no main é o único ponto de serialização. + +### O QA falhou e eu quero corrigir manualmente + +```bash +cd ../.worktrees/fix-payments +# ... faz as correções ... +git add -A && git commit -m "manual fix" +dev-orchestrator build fix-payments # re-dispara do QA +``` + +### Como limpar uma feature abandonada? + +```bash +dev-orchestrator clean fix-abandonada +``` + +Remove o worktree e o branch. O spec em `openspec/changes/` fica — delete manualmente se quiser. + +### Preciso commitar algo no meio do build? + +O Dev Agent já commita a cada tentativa. Se quiser checkpoints extras, faça manualmente no worktree — o script não interfere. + +### O que acontece com `node_modules`? + +Cada worktree tem o seu próprio `node_modules`, instalado durante o `spec`. Sem symlinks, sem compartilhamento — isolamento total. Custa espaço em disco, mas evita qualquer heisenbug de dependência. + +--- + +## Opcional: Kanban com .hive (Swarm Tools) + +Se quiser tracking mais visual, instale o Swarm Tools (leve, sem daemon, sem binário grande): + +```bash +npm install -g opencode-swarm-plugin +swarm setup +``` + +Depois, dentro do OpenCode, use `/hive` pra ver tasks e `/swarm "tarefa"` pra decompor em paralelo. O `.hive/` é uma pasta git-tracked com markdown — nada de banco ou servidor. + +O script `dev-orchestrator` funciona com ou sem Swarm Tools. São independentes. diff --git a/tooling/dev-orchestrator b/tooling/dev-orchestrator new file mode 100755 index 0000000..86d1088 --- /dev/null +++ b/tooling/dev-orchestrator @@ -0,0 +1,277 @@ +#!/usr/bin/env bash +# dev-orchestrator — OpenSpec + OpenCode dev→QA loop with git worktrees +# Zero dependencies beyond git, opencode, openspec. No heavy binaries. +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO="${DEV_FLOW_REPO:-$(pwd)}" +WORKTREE_ROOT="$REPO/../.worktrees" + +# ── helpers ────────────────────────────────────────────────────── + +_wt_path() { echo "$WORKTREE_ROOT/$1"; } +_wt_branch(){ echo "dev-flow/$1"; } + +_die() { echo "✗ $*" >&2; exit 1; } +_ok() { echo "✓ $*"; } + +# Ensure we're inside a git repo with openspec +_guard() { + cd "$REPO" + git rev-parse --show-toplevel >/dev/null 2>&1 || _die "not a git repo: $REPO" + [ -d openspec ] || _die "openspec not initialized. Run: dev-orchestrator init" +} + +# ── commands ───────────────────────────────────────────────────── + +cmd_init() { + cd "$REPO" + git rev-parse --show-toplevel >/dev/null 2>&1 || _die "not a git repo" + + mkdir -p "$WORKTREE_ROOT" + [ -d openspec ] && _ok "openspec already initialized" || { + openspec init --tools opencode --force + _ok "openspec initialized" + } + + grep -qxF '.worktrees/' .gitignore 2>/dev/null || { + echo '.worktrees/' >> .gitignore + _ok "added .worktrees/ to .gitignore" + } + + echo "" + echo "Repo ready. Next: dev-orchestrator spec " +} + +cmd_spec() { + local name="$1" + _guard + + # ── validate name (kebab-case) ── + [[ "$name" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]] || _die "name must be kebab-case: add-oauth, fix-login" + + # ── create OpenSpec change ── + echo "── Creating OpenSpec change: $name ──" + openspec new change "$name" --json 2>/dev/null || { + _die "openspec new change failed. Already exists? Run: dev-orchestrator status" + } + + # ── create worktree ── + local branch="$(_wt_branch "$name")" + local wt="$(_wt_path "$name")" + echo "── Creating worktree: $wt [$branch] ──" + git worktree add -b "$branch" "$wt" HEAD + + # ── install deps in worktree (fully isolated, no symlinks) ── + if [ -f "$wt/package.json" ]; then + echo "── Installing dependencies ──" + (cd "$wt" && npm install --silent 2>&1 | tail -1) || true + fi + if [ -f "$wt/pyproject.toml" ] || [ -f "$wt/setup.py" ]; then + (cd "$wt" && [ -d .venv ] || python3 -m venv .venv && . .venv/bin/activate && pip install -e . -q 2>&1 | tail -1) || true + fi + + # ── orchestrator fills the spec ── + echo "── Orchestrator filling spec ──" + opencode run \ + "You are filling an OpenSpec change for feature: $name. + + STEPS: + 1. Read the codebase structure first (scan src/, lib/, or equivalent). + 2. Read openspec/changes/$name/ — note the template files created. + 3. Read openspec/specs/ for existing specs to avoid conflicts. + 4. For each template file in the change directory, fill it with: + - Clear requirements and acceptance criteria + - Files that need to change + - Dependencies on other modules + - Test plan + 5. Run: openspec validate $name --strict + 6. Fix any validation errors, re-run until clean. + 7. Output a summary: spec files created, key decisions, estimated scope." \ + --workdir "$REPO" + + echo "" + _ok "Spec '$name' ready at openspec/changes/$name/" + echo " Worktree: $wt" + echo " Review the spec, then: dev-orchestrator build $name" +} + +cmd_build() { + local name="$1" + _guard + + local wt="$(_wt_path "$name")" + [ -d "$wt" ] || _die "worktree not found: $wt. Run: dev-orchestrator spec $name" + + local branch="$(_wt_branch "$name")" + local max_retries=3 + + for attempt in $(seq 1 $max_retries); do + echo "" + echo "══════════════════════════════════════════════════" + echo " $name — Dev Phase (attempt $attempt/$max_retries)" + echo "══════════════════════════════════════════════════" + + opencode run \ + "IMPLEMENT the spec at openspec/changes/$name/. + + RULES: + - Read openspec instructions --change $name first + - Implement ALL requirements from the spec + - Write tests for every new code path + - Run the test suite and ensure it passes + - If tests fail, fix them before considering work done + - Commit with message: '$name: implement feature (attempt $attempt)' + - Do NOT modify openspec/ files — only source code and tests" \ + --workdir "$wt" || { + echo "⚠ Dev phase had errors, proceeding to QA anyway..." + } + + # ── QA phase ── + echo "" + echo "──────────────────────────────────────────────────" + echo " $name — QA Review" + echo "──────────────────────────────────────────────────" + + local qa_file="/tmp/dev-orchestrator-qa-$$.txt" + opencode run \ + "QA REVIEW for $name. + + CHECKLIST (answer each with PASS or FAIL): + 1. SPEC COMPLIANCE — Does the code implement everything in openspec/changes/$name/? + 2. TESTS — Do all tests pass? Run them now. + 3. REGRESSIONS — Does any existing test break? Check git diff vs main. + 4. EDGE CASES — Are errors handled? Null/empty inputs? Timeouts? + 5. CODE QUALITY — Clear naming? No debug leftovers? No commented-out code? + + OUTPUT FORMAT (exactly these 2 lines, nothing else): + VERDICT: PASS|FAIL + REASON: " \ + --workdir "$wt" > "$qa_file" 2>&1 + + local verdict + verdict=$(grep '^VERDICT:' "$qa_file" | head -1 | awk -F': ' '{print $2}') + local reason + reason=$(grep '^REASON:' "$qa_file" | head -1 | cut -d' ' -f2-) + + if [ "$verdict" = "PASS" ]; then + echo "" + _ok "QA PASSED — $reason" + + # ── archive + merge ── + cd "$REPO" + echo "── Archiving spec ──" + openspec archive "$name" --yes 2>/dev/null || true + + echo "── Merging to main ──" + local current_branch=$(git branch --show-current) + git merge "$branch" -m "dev-flow: merge $name" 2>/dev/null || { + echo "⚠ Merge conflict. Resolve manually in $wt then run:" + echo " cd $wt && git checkout main && git merge $branch" + return 1 + } + + echo "── Cleaning up worktree ──" + git worktree remove "$wt" 2>/dev/null || true + git branch -d "$branch" 2>/dev/null || true + + echo "" + _ok "$name — BUILD COMPLETE ✓" + rm "$qa_file" + return 0 + fi + + echo "" + echo "✗ QA FAILED — ${reason:-see $qa_file}" + rm "$qa_file" + + if [ "$attempt" -eq "$max_retries" ]; then + _die "$name FAILED after $max_retries attempts. Worktree kept at $wt for manual fix." + fi + echo "↻ Sending back to dev with QA feedback..." + done +} + +cmd_status() { + _guard 2>/dev/null || true + + echo "" + printf "%-4s %-30s %-10s %-10s %-15s\n" "#" "FEATURE" "COMMITS" "SPEC" "WORKTREE" + printf "%-4s %-30s %-10s %-10s %-15s\n" "───" "──────────────────────────────" "──────────" "──────────" "──────────────" + + local n=0 + for wt in "$WORKTREE_ROOT"/*/; do + [ -d "$wt" ] || continue + local name=$(basename "$wt") + local branch="$(_wt_branch "$name")" + local commits="?" + [ -d "$wt/.git" ] && commits=$(cd "$wt" && git rev-list --count "$branch" -- 2>/dev/null || echo "?") + commits="${commits:-0}" + + # spec status + local spec="?" + [ -d "$REPO/openspec/changes/$name" ] && { + spec=$(cd "$REPO" && openspec status --change "$name" --json 2>/dev/null | \ + python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('artifacts_completed','?'),'/',d.get('artifacts_total','?'),sep='')" 2>/dev/null || echo "active") + } + + n=$((n+1)) + printf "%-4s %-30s %-10s %-10s %-15s\n" \ + "$n." "$name" "$commits" "${spec:-active}" "$wt" + done + + if [ "$n" -eq 0 ]; then + echo " (no active features)" + fi + echo "" +} + +cmd_clean() { + local name="$1" + cd "$REPO" + local wt="$(_wt_path "$name")" + local branch="$(_wt_branch "$name")" + + git worktree remove "$wt" 2>/dev/null || true + git branch -D "$branch" 2>/dev/null || true + [ ! -d "$wt" ] && _ok "cleaned $name" || _die "could not remove $wt" +} + +# ── dispatch ───────────────────────────────────────────────────── + +case "${1:-}" in + init) + cmd_init + ;; + spec) + [ $# -ge 2 ] || _die "usage: dev-orchestrator spec " + cmd_spec "$2" + ;; + build) + [ $# -ge 2 ] || _die "usage: dev-orchestrator build " + cmd_build "$2" + ;; + status) + cmd_status + ;; + clean) + [ $# -ge 2 ] || _die "usage: dev-orchestrator clean " + cmd_clean "$2" + ;; + *) + echo "dev-orchestrator — OpenSpec + OpenCode dev→QA loop" + echo "" + echo "commands:" + echo " init Set up repo (run once per project)" + echo " spec Create OpenSpec + worktree + fill spec" + echo " build Dev→QA loop in isolated worktree" + echo " status Kanban view of features in flight" + echo " clean Remove worktree + branch" + echo "" + echo "flow: init → spec → [review] → build → [loop until QA passes]" + echo "" + echo "worktrees live at: ../.worktrees//" + echo "branches named: dev-flow/" + exit 1 + ;; +esac \ No newline at end of file