diff --git a/.agents/shell/worktree.sh b/.agents/shell/worktree.sh
index 9578ac4f..6c3674a2 100644
--- a/.agents/shell/worktree.sh
+++ b/.agents/shell/worktree.sh
@@ -1,23 +1,26 @@
-# worktree — CLI determinístico de worktrees em torno da fila de claim, com um
-# `--go` que realmente troca de diretório.
+# worktree — CLI determinístico de worktrees em torno da fila de claim, com
+# troca de diretório por padrão (e `kill` que volta ao main).
#
# A lógica determinística (fila → branch → worktree) vive em scripts/worktree.mjs;
-# esta função é só a camada de shell que APLICA o `cd
` que o script imprime,
-# porque um processo filho (node) não consegue mudar o cwd do shell que o chamou.
+# esta função é só a camada de shell que APLICA o `cd ` que o script imprime
+# na última linha, porque um processo filho (node) não consegue mudar o cwd do
+# shell que o chamou.
#
# Instalação (uma linha no profile):
# source /.agents/shell/worktree.sh
#
# Uso (terminal interativo):
-# worktree next [--go] cria/reutiliza o worktree da próxima Issue claimável;
-# com --go, cd para dentro dele
-# worktree plan [bag] [--go] cria um worktree de planejamento do /plan-issue
-# DIFERENTE a cada chamada (sessões paralelas): com bag,
-# branch plans/plan-issue- (sufixo -2/-3 se o nome
-# já existir), sem bag o próximo plans/plan-issue-
-# sequencial; com --go, cd para dentro dele
-# worktree kill [--force]
+# worktree next [--stay] cria/reutiliza o worktree da próxima Issue claimável
+# e cd para dentro dele por padrão; --stay não troca
+# worktree plan [bag] [--stay] cria um worktree de planejamento do /plan-issue
+# DIFERENTE a cada chamada (sessões paralelas): com bag,
+# branch plans/plan-issue- (sufixo -2/-3 se o nome
+# já existir), sem bag o próximo plans/plan-issue-
+# sequencial; cd para dentro dele por padrão; --stay não
+# troca
+# worktree kill [--force] destrói o worktree atual e cd para o main por padrão
#
+# `--go` explícito continua aceito como no-op (era o antigo padrão).
# Read-only no GitHub — claim continua sendo `pnpm agent:claim`.
worktree() {
@@ -25,23 +28,22 @@ worktree() {
local root
root="$(cd "$(dirname "$src")/../.." && pwd)"
- local has_go=0
+ local stay=0
local arg
for arg in "$@"; do
- if [ "$arg" = "--go" ]; then
- has_go=1
+ if [ "$arg" = "--stay" ]; then
+ stay=1
fi
done
- if [ "$has_go" -eq 0 ]; then
- node "$root/scripts/worktree.mjs" "$@"
- return $?
- fi
-
local out
out="$(node "$root/scripts/worktree.mjs" "$@")" || return $?
printf '%s\n' "$out"
+ if [ "$stay" -eq 1 ]; then
+ return 0
+ fi
+
local dir
dir="$(printf '%s\n' "$out" | sed -n 's/^cd //p' | tail -n 1)"
if [ -n "$dir" ] && [ -d "$dir" ]; then
diff --git a/.agents/skills/local-database/SKILL.md b/.agents/skills/local-database/SKILL.md
index d905153b..e7ec13c8 100644
--- a/.agents/skills/local-database/SKILL.md
+++ b/.agents/skills/local-database/SKILL.md
@@ -26,7 +26,7 @@ VMs Cloud **não rodam** `docker compose` / `pnpm db:start`. Postgres nativo: `.
## Per-worktree environments (`pnpm worktree next`)
-Parallel agents must not fight over port 3000, the shared `teqo_test`, or a second Postgres container. `pnpm worktree next [--go]` provisions each worktree with a deterministic isolated env:
+Parallel agents must not fight over port 3000, the shared `teqo_test`, or a second Postgres container. `pnpm worktree next [--stay]` provisions each worktree with a deterministic isolated env (`next`/`plan` print `cd ` by default — apply it, or pass `--stay` to suppress; `--go` is still accepted as a no-op):
- `slot` = numeric part of the issue code (`C15` → 15, `B164` → 164; hash fallback without digits; bumped on collision among live worktrees).
- Dev server port `3100+slot`; databases `teqo_wt` (dev) and `teqo_wt_test` (tests), created on the **one shared container** with the full migration chain applied (one-time, ~30 s each).
diff --git a/.agents/skills/worktree-next-issue/SKILL.md b/.agents/skills/worktree-next-issue/SKILL.md
index 9df5d96a..99737873 100644
--- a/.agents/skills/worktree-next-issue/SKILL.md
+++ b/.agents/skills/worktree-next-issue/SKILL.md
@@ -19,8 +19,8 @@ Prepara o ambiente git para a próxima Issue da fila de claim, **sem** tocá-la
A lógica determinística (fila → código+slug → branch → worktree) vive em **`scripts/worktree.mjs`** — fonte única, coberta por `tests/unit/worktree.unit.spec.ts`. Não a reescreva à mão aqui.
```bash
-pnpm worktree next [--go] [--no-migrate] # cria worktree de origin/main + provisiona o ambiente
-pnpm worktree plan [bag] [--go] [--no-migrate] # worktree de PLANEJAMENTO (/plan-issue): um DIFERENTE por invocação
+pnpm worktree next [--stay] [--no-migrate] # cria worktree de origin/main + provisiona o ambiente
+pnpm worktree plan [bag] [--stay] [--no-migrate] # worktree de PLANEJAMENTO (/plan-issue): um DIFERENTE por invocação
pnpm worktree kill [--force] # destrói o worktree atual + remove seus bancos gerados
```
@@ -28,7 +28,7 @@ No opencode, isso é o comando **`/worktree next`** / **`/worktree kill`** (`.op
`plan` é o primo do `next`: worktree de **planejamento** para rodar a skill `/plan-issue` sem ocupar o main. **Cada invocação cria um DIFERENTE** (sessões paralelas): com `bag` opcional → branch `plans/plan-issue-` (sufixo `-2`/`-3` se o nome já estiver vivo); sem `bag` → próximo sequencial `plans/plan-issue-` livre. Não é nomeado por Issue nenhuma — proposital, para um `next` posterior da próxima Issue nunca colidir em branch nem em slot (prefixo minúsculo `plans/…` vs branch `-` sempre uppercase-led). O fluxo desta skill (fila → próxima Issue → implementação) é só `next`.
-No terminal interativo, para `--go` trocar de diretório de verdade, use a função `worktree()` de **`.agents/shell/worktree.sh`** (uma linha de `source` no profile): o script imprime `cd ` e a função o aplica no shell que te chamou — node não consegue mudar o cwd do shell pai.
+**Default-go:** `next` e `plan` imprimem `cd ` na última linha **por padrão**; `--stay` suprime; `--go` explícito continua aceito como no-op. No terminal interativo, use a função `worktree()` de **`.agents/shell/worktree.sh`** (uma linha de `source` no profile) para o `cd` ser aplicado de verdade no shell que te chamou — node não consegue mudar o cwd do shell pai. `kill` também imprime `cd ` no fim (a sessão nunca fica num diretório destruído).
## Fluxo quando invocado como skill (agentes que não têm opencode)
diff --git a/.opencode/commands/worktree.md b/.opencode/commands/worktree.md
index 65e2c97f..8e7527dd 100644
--- a/.opencode/commands/worktree.md
+++ b/.opencode/commands/worktree.md
@@ -1,11 +1,11 @@
---
-description: Cria o worktree da próxima Issue claimável (next [--go]), um worktree novo de planejamento do /plan-issue (plan [bag] [--go]) ou destrói o worktree atual (kill [--force])
+description: Cria o worktree da próxima Issue claimável (next [--stay]), um worktree novo de planejamento do /plan-issue (plan [bag] [--stay]) ou destrói o worktree atual (kill [--force])
---
Rode o script determinístico abaixo (não improvise a lógica) e reporte o resultado de forma concisa.
-- `next [--go]`: cria (ou reutiliza) o worktree da próxima Issue claimável. Com `--go`, o script imprime `cd ` na última linha — aplique-o na sessão de shell atual (`cd `) e reporte o novo diretório.
-- `plan [bag] [--go]`: cria um worktree de planejamento **diferente a cada invocação** (branch `plans/plan-issue-`, ou `plans/plan-issue-` sequencial sem bag; sufixo `-2`/`-3` em colisão) para rodar `/plan-issue` sem ocupar o main; nunca conflita com `next`.
-- `kill [--force]`: destrói o worktree em que você está.
+- `next [--stay]`: cria (ou reutiliza) o worktree da próxima Issue claimável. Por padrão o script imprime `cd ` na última linha — aplique-o na sessão de shell atual (`cd `) e reporte o novo diretório. `--stay` suprime o `cd` (não troque de diretório). `--go` explícito continua aceito como no-op.
+- `plan [bag] [--stay]`: cria um worktree de planejamento **diferente a cada invocação** (branch `plans/plan-issue-`, ou `plans/plan-issue-` sequencial sem bag; sufixo `-2`/`-3` em colisão) para rodar `/plan-issue` sem ocupar o main; nunca conflita com `next`. Mesmo contrato de `cd` do `next`: aplique a última linha `cd ` por padrão; `--stay` suprime.
+- `kill [--force]`: destrói o worktree em que você está e remove seus bancos. O script imprime `cd ` na última linha — aplique-o (`cd `) para a sessão sair do diretório destruído.
!`node scripts/worktree.mjs $ARGUMENTS`
diff --git a/AGENTS.md b/AGENTS.md
index 0a34e2ec..acbe066b 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -34,7 +34,7 @@ These are product/architecture constraints — not a ban on editing existing cod
- `Consent.text` was reconciled from `varchar` to `jsonb` via `20260715_163500_consent_text_to_jsonb` (matching the `richText` field). Any future field-type change is a migration, not a manual DB edit.
- To copy production content locally, use `pnpm db:pull` (`scripts/db-pull.mjs`): it only reads prod, only writes local, and excludes supporter PII (`contact`/`signature`/`subscription` row data).
- `pnpm db:doctor` diagnoses local database connectivity for the dev AND test targets: it names who holds the port, points at exited/crash-looping containers, and flags Postgres containers sharing one data volume (two postmasters on one PGDATA corrupt the WAL — this destroyed the local cluster's checkpoint on 2026-07-25; the canonical setup is ONE compose container on 5432 hosting `teqo` + `teqo_test`). `pnpm dev` runs the same preflight via `guard-dev-db` and refuses to start with a named remedy instead of a later ECONNREFUSED. `db:start`/`db:stop` pin the compose project with `-p teqo`, so they always target that ONE container even from a worktree directory.
-- **Per-worktree environments (`pnpm worktree next`, 2026-08-08):** parallel agents each get a deterministic isolated env — no fighting over port 3000, the shared `teqo_test`, or a second Postgres container. `worktree next [--go]` provisions: a dev-server port `3100+slot` (slot = numeric part of the issue code, hash fallback, bumped on collision among live worktrees), plus dedicated databases `teqo_wt` (dev) and `teqo_wt_test` (tests) created on the shared container with the full migration chain applied; writes `.env.local` + `.env.test.local` (gitignored, marker `# teqo worktree env (generated by pnpm worktree next)`; manual envs are never overwritten) and copies `PAYLOAD_SECRET`/Blob/VAPID from the main repo. `worktree plan [bag] [--go]` (2026-08-08) is the sibling for the `/plan-issue` skill: **each invocation creates a DIFFERENT planning worktree** so parallel `/plan-issue` sessions never share one — branch `plans/plan-issue-` when a `bag` slug is given (suffixed `-2`/`-3` if that name is taken) or the next free sequential `plans/plan-issue-` when not (`PLAN_BRANCH_PREFIX`/`planBranchName`, `scripts/lib/worktree.mjs`); the lowercase `plans/…` prefix deliberately never matches `next`'s uppercase-led `-`, so a later `next` never collides in branch or slot. `kill` drops the worktree's generated databases best-effort. Tests read `.env.test.local` after `.env.test` (vitest.setup.ts / playwright.config.ts / db-doctor / gate-ci mirror the layering), and `assertTestDatabase` accepts `teqo_test` or `teqo__test` on localhost only — still fail-closed on remote. Pure derivation lives in `scripts/lib/worktree-env.mjs` (unit-tested). Without Docker (Cursor Cloud) it degrades to the shared `teqo`/`teqo_test` with a warning.
+- **Per-worktree environments (`pnpm worktree next`, 2026-08-08; default-go 2026-08-10):** parallel agents each get a deterministic isolated env — no fighting over port 3000, the shared `teqo_test`, or a second Postgres container. `worktree next [--stay]` provisions: a dev-server port `3100+slot` (slot = numeric part of the issue code, hash fallback, bumped on collision among live worktrees), plus dedicated databases `teqo_wt` (dev) and `teqo_wt_test` (tests) created on the shared container with the full migration chain applied; writes `.env.local` + `.env.test.local` (gitignored, marker `# teqo worktree env (generated by pnpm worktree next)`; manual envs are never overwritten) and copies `PAYLOAD_SECRET`/Blob/VAPID from the main repo. **`next`/`plan` print `cd ` as the last line BY DEFAULT** — the caller applies it (shell function `worktree()` in `.agents/shell/worktree.sh`, or the `/worktree` opencode command); `--stay` suppresses the cd, `--go` explicit stays accepted as a no-op (it was the old default), and `kill` ends with `cd ` so the shell never sits in a destroyed directory. `worktree plan [bag] [--stay]` (2026-08-08) is the sibling for the `/plan-issue` skill: **each invocation creates a DIFFERENT planning worktree** so parallel `/plan-issue` sessions never share one — branch `plans/plan-issue-` when a `bag` slug is given (suffixed `-2`/`-3` if that name is taken) or the next free sequential `plans/plan-issue-` when not (`PLAN_BRANCH_PREFIX`/`planBranchName`, `scripts/lib/worktree.mjs`); the lowercase `plans/…` prefix deliberately never matches `next`'s uppercase-led `-`, so a later `next` never collides in branch or slot. `kill` drops the worktree's generated databases best-effort. Tests read `.env.test.local` after `.env.test` (vitest.setup.ts / playwright.config.ts / db-doctor / gate-ci mirror the layering), and `assertTestDatabase` accepts `teqo_test` or `teqo__test` on localhost only — still fail-closed on remote. Pure derivation lives in `scripts/lib/worktree-env.mjs` (unit-tested). Without Docker (Cursor Cloud) it degrades to the shared `teqo`/`teqo_test` with a warning.
- To (re)populate news content, `pnpm db:seed:posts` fetches articles live from jorgesolla.com.br into the LOCAL db (same non-local `DATABASE_URL` guard as `pnpm dev`). It writes from a CLI process outside the deployed runtime, so after seeding — or after ANY direct-DB change — you must bust the production `posts` cache via `POST /api/revalidate`. See "Posts & Tags" below.
- To (re)populate the TSE 2022 election baseline, `pnpm db:seed:tse` downloads TSE open data and imports the Bahia scope into the LOCAL db (same guard). Since the 2026-07-23 hardening, elections-tab reads are cached under the `election-tse` tag — after re-seeding a database the deployed app reads, bust it via `POST /api/revalidate?tag=election-tse`. See "Election baseline data (TSE 2022)" below.
diff --git a/docs/CHANGELOG-AGENTS.md b/docs/CHANGELOG-AGENTS.md
index b24bdd86..82397f49 100644
--- a/docs/CHANGELOG-AGENTS.md
+++ b/docs/CHANGELOG-AGENTS.md
@@ -4,6 +4,8 @@ Conteúdo movido do `AGENTS.md` em 2026-07-30 (fatiamento do paradigma de agente
---
+**Recently resolved (2026-08-10):** **OPS24** (Issue #569) — `--go` virou o **padrão** do worktree CLI e `kill` volta ao main: `worktree next`/`plan` imprimem `cd ` na última linha **por padrão** (antes exigiam `--go`); `--stay` suprime; `--go` explícito continua aceito como no-op (não quebra hábito/automação). `kill` troca a mensagem "Volte ao main: cd …" (que nunca casava com o sed `s/^cd //p` da função shell) pela **linha máquina `cd ` como última linha** — depois do drop dos DBs, que rodava antes — e **não aceita `--stay`** (ficar em cwd destruído é exatamente o bug corrigido; `--go` no kill é no-op). Vale nas duas superfícies que aplicam o cd: função `worktree()` de `.agents/shell/worktree.sh` (agora sempre captura/applica, `--stay` retorna cedo) e comando `/worktree` do opencode (agente aplica o `cd` da última linha sempre, exceto `--stay`). Docs: header/uso do script, AGENTS.md ("Per-worktree environments"), skills `worktree-next-issue`/`local-database`. Sem migration/dados/access; derivação pura (`worktree-env.mjs`/`worktree.mjs` libs) intocada. Intenção [`worktree-go-default-e-kill-volta-ao-main.md`](plans/worktree-go-default-e-kill-volta-ao-main.md); impl [`worktree-go-default-e-kill-volta-ao-main-impl.md`](plans/worktree-go-default-e-kill-volta-ao-main-impl.md).
+
**Recently resolved (2026-08-10):** **B192** (Issue #533) — o Sollinha encerra respostas factuais com **follow-ups sugeridos como chips** (2–3, no mesmo slot dos chips de abertura do B191, acima do input; tocar envia como mensagem do usuário; substituídos a cada resposta; somem durante o streaming; mobile limita a 2). **Uma única chamada ao modelo:** o prompt (`systemPrompt.ts`) instrui encerrar com o bloco estável `**Sugestões de continuação:**` + lista markdown (só perguntas respondíveis pelas próprias tools, leader sem sugestão eleitoral — B180; bloco = instrução de interface, nunca citar em prosa) e o cliente extrai. **Contrato em fonte única:** `src/lib/sollinhaFollowUpSuggestions.ts` — `SOLLINHA_FOLLOW_UP_MARKER` (interpolado no prompt) + `splitSollinhaFollowUpBlock` (última ocorrência vence; body sempre mascarado do marcador em diante; itens `-/*/1./1)` aceitos, bold e duplicados limpos, teto 3; **fail-closed: <2 itens ou linha não-lista → sem chips**, resposta normal). UI: strip no render de todo text part assistant **antes** do markdown/links (bloco nunca pisca como prosa; mensagens antigas restauradas via B188 continuam mascaradas e os chips renascem por derivação); slot B191 estendido (catálogo vazio → follow-ups); tipo compartilhado renomeado `SollinhaOpeningQuestion → SollinhaChatChip`. **Strip defensivo no servidor:** `route.ts` remove o bloco das mensagens assistant ao reconverter para o modelo (próximo turno sem eco nem custo de contexto). Unit (16 casos do split) + e2e novo `campaignAiChatFollowUps.e2e.spec.ts` (wire format v7 como o mock do B187; bolha sem o bloco, chips, substituição, fail-closed, cap mobile). Sem migration/access/Consent/schema/endpoint novo. Intenção [`sollinha-follow-ups-respostas.md`](plans/sollinha-follow-ups-respostas.md); impl [`sollinha-follow-ups-respostas-impl.md`](plans/sollinha-follow-ups-respostas-impl.md).
**Recently resolved (2026-08-10):** **OPS23** (Issue #566) — a Action OPS18 (`plan-issue-ready-on-main-merge.yml`) falhava **sempre** no primeiro disparo real (PR #563, run 31381977772): o job roda `actions/setup-node@v5` sem `pnpm/action-setup` e o script é plain Node — com `package-manager-cache: true` (default do v5), o setup-node resolve o `packageManager` do package.json (`pnpm@10.11.0`) e procura o executável pnpm → `Unable to locate executable file: pnpm`, promote nunca rodava. Correção: `package-manager-cache: false` no setup-node (precedente exato dos jobs plain-Node: cooldown do `ci.yml`, `vercel-promote.yml`, `archive-cursor-agent.yml`; `pnpm/action-setup@v6` rejeitado — só existe onde há `pnpm install`). Varredura dos 21 usos de setup-node: `plan-issue-ready` era o único com o bug latente. Validação funcional = próximo merge de PR com `Related #N` (trigger `closed+merged→main` só dispara em merge real). Impl [`ops23-action-promote-related-setup-node-impl.md`](plans/ops23-action-promote-related-setup-node-impl.md).
diff --git a/docs/plans/worktree-go-default-e-kill-volta-ao-main-impl.md b/docs/plans/worktree-go-default-e-kill-volta-ao-main-impl.md
new file mode 100644
index 00000000..8b6070e7
--- /dev/null
+++ b/docs/plans/worktree-go-default-e-kill-volta-ao-main-impl.md
@@ -0,0 +1,78 @@
+# Impl: Worktree CLI: `--go` vira o padrão (escape `--stay`) e `kill` volta ao main
+
+Status: aprovado
+Atualizado em: 2026-08-10
+Issue: #569
+Intenção: docs/plans/worktree-go-default-e-kill-volta-ao-main.md
+Appetite restante: ~0,5 dia eng (herdado — mudança pequena, 7 arquivos de texto/CLI)
+
+## Leitura da intenção
+
+- **Outcome:** `worktree next`/`plan` sem flags aplicam o `cd` (hoje exigem `--go`); `--stay` suprime; `--go` vira no-op; `worktree kill` termina no main repo (cwd nunca num diretório destruído). Vale nas duas superfícies que aplicam o cd: função `worktree()` do shell e comando `/worktree` do opencode.
+- **O que NÃO negociar:** lógica determinística de branch/slot/provisionamento intacta; `kill` não ganha `--stay` (decidido no gate: kill sempre volta ao main); nada de detectar terminal vs opencode no script (o script só imprime o `cd`; quem aplica decide).
+- **O que reavaliar:** a hipótese da intenção manda "`cmdKill` imprime `cd ` no mesmo formato máquina". Verifiquei o formato real: `next`/`plan` imprimem `cd ` na ÚLTIMA linha; `kill` hoje imprime `Volte ao main: cd ${mainRoot}` — linha que **não** casa com o sed `s/^cd //p` da função shell, por isso nada aplica. A correção é substituir a mensagem humana pela linha máquina (o contexto "Worktree destruído:" já diz o que aconteceu), não acrescentar as duas. Ajuste extra: a linha máquina do `kill` precisa ser a última do output — hoje o `dropWorktreeDatabases` (best-effort, imprime `[worktree] banco removido: …`) roda DEPOIS do print. O sed usa `tail -n 1` de linhas que casam `^cd `, então funcionaria mesmo assim, mas o contrato "última linha" fica limpo movendo o print para depois dos drops.
+
+## Abordagem recomendada
+
+```mermaid
+flowchart LR
+ A[worktree next/plan] --> B[flags: --stay suprime, --go no-op]
+ A2[kill] --> B2[sempre imprime cd mainRoot como última linha]
+ B --> C[worktree.mjs imprime cd dir por default]
+ B2 --> C
+ C --> D[worktree.sh: aplica cd por default; --stay não aplica]
+ C --> E[/worktree opencode: agente aplica cd sempre]
+ D --> F[terminal termina no worktree / no main]
+```
+
+**Opções consideradas:** A | B | C
+**Recomendação:** A — inversão do flag na origem (script), com shell e opencode command consumindo a mesma linha máquina.
+**Rejeitadas:**
+
+- **B — inverter só na função shell** (shell decide aplicar por default e passa `--stay` ao script): deixaria o opencode command e consumidores diretos do script com a semântica velha; a superfície `/worktree` também precisa do default-go. Rejeitada por inconsistência.
+- **C — detectar "terminal vs opencode" no script** (ex.: env `WORKTREE_TERMINAL`): anti-goal explícito da intenção; o contrato continua sendo "script imprime `cd`; quem aplica decide". Rejeitada.
+- **D — `kill --stay`** (ficar no cwd morto): anti-goal de produto (é exatamente o bug que se corrige). Rejeitada — `kill` com `--stay` morre com mensagem clara.
+
+### Componentes / mudanças
+
+- **`scripts/worktree.mjs`**:
+ - Header (docblock, linhas 5-34) e bloco de uso (`pnpm worktree` sem args, linhas 486-504): `next [--stay]`, `plan [bag] [--stay]`, `kill [--force]`; nota de que `--go` segue aceito como no-op.
+ - `cmdNext(go, skipMigrate)` / `cmdPlan(go, skipMigrate, bag)`: parâmetro `go` → `stay`; `if (go) console.log(\`cd ${dir}\`)`vira`if (!stay) console.log(\`cd ${dir}\`)` (linhas 329 e 400).
+ - `cmdKill(force)`: troca `Volte ao main: cd ${mainRoot}` por `cd ${mainRoot}` como **última** linha (depois de `await dropWorktreeDatabases`); `flags.go` no kill vira no-op aceito (consistente com o novo status do flag); `flags.stay` no kill → `die('--stay não se aplica a kill — ele sempre volta ao main')`.
+ - Dispatch (linhas 508-514): `cmdNext(Boolean(flags.stay), …)`, `cmdPlan(Boolean(flags.stay), …)`, `kill` valida `--stay`.
+- **`.agents/shell/worktree.sh`**: a função sempre captura o output e aplica o `cd` da linha máquina; `--stay` detectado nos args → repassa ao script e **não** aplica cd (retorno 0 após imprimir). Remove o ramo `has_go` (o `--go` nem precisa ser tratado — vira default). Funciona para `next`/`plan`/`kill` com o mesmo sed.
+- **`.opencode/commands/worktree.md`**: frontmatter + corpo — `next [--stay]`, `plan [bag] [--stay]`, `kill [--force]`; o agente aplica o `cd ` da última linha **sempre** (default), suprimido só com `--stay`; `kill` também aplica o `cd `.
+- **`AGENTS.md`** (seção "Per-worktree environments"): `worktree next [--go]` → `worktree next [--stay]`, `worktree plan [bag] [--go]` → `[bag] [--stay]`, `kill` volta ao main; nota `--go` no-op.
+- **`.agents/skills/worktree-next-issue/SKILL.md`**: linhas de uso (`next [--go]` → `[--stay]`) e a nota sobre a função `worktree()` (agora default).
+- **`.agents/skills/local-database/SKILL.md`**: menção `pnpm worktree next [--go]` → `[--stay]`.
+- **`docs/CHANGELOG-AGENTS.md`**: entrada curta da entrega (padrão OPS17+).
+- **Migration:** sem migration (nenhum schema).
+- **Access / Consent:** N/A — CLI de dev fora do runtime.
+- **UI:** Impeccable A — N/A (sem superfície de usuário de produto).
+
+## Fases verificáveis
+
+1. **Script** — `scripts/worktree.mjs` (flags + kill line) + shell function + opencode command + docs (AGENTS.md, skills, CHANGELOG). Verificação manual de contrato: `node scripts/worktree.mjs` sem args mostra o uso novo; `next --stay`/`--go`/sem flag imprimem/omitem a linha `cd` (a fila pode estar vazia → testar via `cmdPlan` que não depende da fila, ou pela mensagem de `die` da fila vazia — o que importa é o contrato de flags não quebrar).
+2. **Verificação real do kill** (a única parte que toca estado real): criar worktree de teste barato não é viável nesta sessão (kill precisa estar DENTRO de um worktree e destrói DBs) — o contrato do kill fica coberto pelo mesmo formato de linha `cd ` e pela lógica simples de print; validar o caminho feliz com um worktree de planejamento descartável se o ambiente permitir.
+3. **Gates** — `pnpm gate:fast` (lint + typecheck + unit); `pnpm push` (gate completo: format/knip/cycles/test/build) — este item é scripts/docs puro, sem testes de domínio novos.
+
+## Rabbit holes / Não escopo (engenharia)
+
+- Não adicionar um helper "puro" para a linha `cd ` com unit test — a derivação não muda, o contrato é uma template string de 1 linha já pinada por 3 usos no mesmo arquivo; testes unitários do `cmdNext` exigiriam mock de git/pg que não existe no repo (as duas libs puras já são cobertas).
+- Não tocar `scripts/lib/worktree-env.mjs` / `worktree.mjs` (derivação pura) — nenhuma mudança de branch/slot/provisionamento.
+- Não criar "vários escapes" (`--no-go`, `--here`…) — a intenção pinou `--stay` como o único.
+- Não alterar o marker `GENERATED_ENV_MARKER` (pinado por teste de unidade).
+- OPS26 (abrir opencode no go) e OPS27 (`worktree new`) são itens próprios — esta entrega só muda a semântica de flags; OPS26 já nasce sobre o default-go.
+
+## Riscos e mitigação
+
+- **Quebrar automação/scripts que dependem da ausência do cd sem `--go`** — mitigação: `--go` continua aceito como no-op e o formato da linha máquina é idêntico ao de hoje; quem não quer o cd usa `--stay` (novo) — documentado nas duas superfícies.
+- **`kill` imprimir a linha máquina antes do drop dos DBs** — mitigação: print movido para depois de `dropWorktreeDatabases`; a linha é a última do output (contrato do sed `tail -n 1`).
+- **Shell function: perda do streaming de output** (antes, sem `--go`, o node imprimia direto; agora sempre captura e reimprime) — mitigação: comportamento idêntico ao do `--go` de hoje (já capturava); `printf '%s\n' "$out"` preserva o texto; o `|| return $?` preserva o exit code do script.
+- **`kill --stay` ambíguo** — mitigação: die com mensagem clara (mesmo padrão do `--go` antigo), nunca silêncio.
+
+## Aceite de engenharia
+
+- [ ] Aceite de produto da intenção ainda coberto (default-go nas duas superfícies; `--stay`; kill volta ao main; `--go` no-op)
+- [ ] Invariantes AGENTS/engineering-standards (nenhuma mudança em branch/slot/provisionamento; docs atualizadas)
+- [ ] Testes de domínio previstos (unit/int): sem mudança de access/write paths — `pnpm test:unit` existente verde; verificação manual do contrato de flags/linha `cd`
diff --git a/scripts/worktree.mjs b/scripts/worktree.mjs
index bfa26884..84cd8288 100644
--- a/scripts/worktree.mjs
+++ b/scripts/worktree.mjs
@@ -2,14 +2,16 @@
* `pnpm worktree` — worktree management determinístico em torno da fila de
* claim do projeto (mesma fila de `agent:claim` / agent pool).
*
- * pnpm worktree next [--go] [--no-migrate]
+ * pnpm worktree next [--stay] [--no-migrate]
* cria worktree a partir de origin/main para a
* próxima Issue claimável; branch `-`.
- * Com `--go`, imprime `cd ` no fim — node
+ * Por padrão imprime `cd ` no fim — node
* não muda o cwd do shell pai; o shell chamador
* aplica (opencode/CDP usa o opencode command;
* terminal interativo: função `worktree()` em
* `.agents/shell/worktree.sh`, sourced no profile).
+ * `--stay` suprime a linha `cd`; `--go` explícito
+ * continua aceito como no-op (era o antigo padrão).
* Também PROVISIONA o ambiente isolado do worktree:
* porta do dev server + bancos próprios derivados
* deterministicamente do branch (ver
@@ -17,7 +19,7 @@
* paralelo não disputarem porta 3000 nem o
* `teqo_test` compartilhado. `--no-migrate` pula a
* aplicação das migrations nos bancos novos.
- * pnpm worktree plan [bag] [--go] [--no-migrate]
+ * pnpm worktree plan [bag] [--stay] [--no-migrate]
* cria um worktree de PLANEJAMENTO novo para rodar
* a skill /plan-issue sem ocupar o main — cada
* invocação cria UM DIFERENTE, para sessões de
@@ -30,7 +32,11 @@
* Mesmo provisionamento isolado do `next`.
* pnpm worktree kill [--force] destrói o worktree em que o shell atual está
* (recusa worktree sujo sem `--force`) e remove os
- * bancos gerados do worktree (best-effort)
+ * bancos gerados do worktree (best-effort); por
+ * padrão termina imprimindo `cd ` para o
+ * shell voltar ao worktree principal — o cwd nunca
+ * fica num diretório destruído (não aceita
+ * `--stay`; `--go` é no-op)
*
* Read-only no GitHub: `next` NUNCA claima (claim = `pnpm agent:claim`).
* Dir raiz: `~/.cursor/worktrees/teqo/` (mesma casa dos worktrees do Cursor).
@@ -280,7 +286,7 @@ const provision = async ({ dir, branch, issue, env, skipMigrate, mainRoot, purpo
runMigrate(dir, testUrl, payloadSecret)
}
-const cmdNext = async (go, skipMigrate) => {
+const cmdNext = async (stay, skipMigrate) => {
const pick = nextClaimableIssue()
if (!pick) {
die('Fila vazia — nada `ready` desbloqueado. Rode `pnpm agent:status` para ver a fila.')
@@ -326,7 +332,7 @@ const cmdNext = async (go, skipMigrate) => {
console.log(` banco dev: postgresql://teqo:teqo@localhost:5432/${env.devDatabase}`)
console.log(` banco test: postgresql://teqo:teqo@localhost:5432/${env.testDatabase}`)
- if (go) console.log(`cd ${dir}`)
+ if (!stay) console.log(`cd ${dir}`)
}
/**
@@ -340,7 +346,7 @@ const cmdNext = async (go, skipMigrate) => {
* worktree — parallel `/plan-issue` sessions never share one. Same isolated
* env provisioning as `next`.
*/
-const cmdPlan = async (go, skipMigrate, bag) => {
+const cmdPlan = async (stay, skipMigrate, bag) => {
git(['fetch', 'origin'])
const entries = parseWorktreeList(git(['worktree', 'list', '--porcelain']))
@@ -397,7 +403,7 @@ const cmdPlan = async (go, skipMigrate, bag) => {
console.log(` banco dev: postgresql://teqo:teqo@localhost:5432/${env.devDatabase}`)
console.log(` banco test: postgresql://teqo:teqo@localhost:5432/${env.testDatabase}`)
- if (go) console.log(`cd ${dir}`)
+ if (!stay) console.log(`cd ${dir}`)
}
/** Generated database names referenced by a worktree's own env files. */
@@ -475,9 +481,10 @@ const cmdKill = async (force) => {
console.log(`Worktree destruído: ${top}`)
console.log(` branch removido: ${branch ?? '(detached — nada a remover)'}`)
- console.log(`Volte ao main: cd ${mainRoot}`)
await dropWorktreeDatabases(databaseNames)
+
+ console.log(`cd ${mainRoot}`)
}
const { flags, positional } = parseArgs(process.argv.slice(2), new Set())
@@ -485,31 +492,33 @@ const subcommand = positional[0]
if (!subcommand) {
console.log(
- 'Uso: pnpm worktree next [--go] [--no-migrate] | plan [bag] [--go] [--no-migrate] | kill [--force]',
+ 'Uso: pnpm worktree next [--stay] [--no-migrate] | plan [bag] [--stay] [--no-migrate] | kill [--force]',
)
- console.log(' next [--go] [--no-migrate]')
+ console.log(' next [--stay] [--no-migrate]')
console.log(' cria worktree da próxima Issue claimável (branch -) e provisiona o')
console.log(' ambiente isolado: porta de dev + bancos próprios (determinístico do branch);')
- console.log(' com --go imprime `cd ` no fim (quem aplica o cd: opencode command, ou a')
- console.log(' função `worktree()` de .agents/shell/worktree.sh); --no-migrate pula migrations')
- console.log(`\n plan [bag] [--go] [--no-migrate]`)
+ console.log(' por padrão imprime `cd ` no fim (quem aplica o cd: opencode command, ou a')
+ console.log(' função `worktree()` de .agents/shell/worktree.sh); --stay suprime o cd; --go')
+ console.log(' explícito continua aceito como no-op; --no-migrate pula migrations')
+ console.log(`\n plan [bag] [--stay] [--no-migrate]`)
console.log(
' cria um worktree de planejamento DIFERENTE a cada invocação (sessões /plan-issue',
)
console.log(' paralelas): com bag, branch plans/plan-issue- (sufixo -2/-3 se o nome já')
console.log(' existir); sem bag, o próximo plans/plan-issue- sequencial livre; o prefixo')
console.log(' minúsculo plans/… nunca colide com o branch - de `next`')
- console.log(' kill [--force] destrói o worktree em que você está (recusa sujo sem --force) e')
- console.log(' remove os bancos gerados do worktree (best-effort)')
+ console.log(' kill [--force] destrói o worktree em que você está (recusa sujo sem --force),')
+ console.log(' remove os bancos gerados do worktree (best-effort) e imprime')
+ console.log(' `cd ` no fim — o shell sempre volta ao worktree principal')
process.exit(1)
}
try {
- if (subcommand === 'next') await cmdNext(Boolean(flags.go), Boolean(flags['no-migrate']))
+ if (subcommand === 'next') await cmdNext(Boolean(flags.stay), Boolean(flags['no-migrate']))
else if (subcommand === 'plan')
- await cmdPlan(Boolean(flags.go), Boolean(flags['no-migrate']), positional[1])
+ await cmdPlan(Boolean(flags.stay), Boolean(flags['no-migrate']), positional[1])
else if (subcommand === 'kill') {
- if (flags.go) die('`--go` só faz sentido com `next`.')
+ if (flags.stay) die('`--stay` não se aplica a `kill` — ele sempre volta ao main.')
await cmdKill(Boolean(flags.force))
} else die(`subcomando desconhecido: ${subcommand} (esperado: next | plan | kill)`)
} catch (error) {