From 729703cee218372ff6afdb6952493514c643e07a Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Tue, 15 Sep 2026 07:05:26 -0300 Subject: [PATCH] =?UTF-8?q?docs(plan):=20OPS108=20+=20OPS109=20+=20OPS110?= =?UTF-8?q?=20=E2=80=94=20modo=20--auto=20nas=20skills,=20painel=20TUI=20d?= =?UTF-8?q?e=20issues=20e=20sess=C3=B5es=20de=20agente=20persistentes=20(R?= =?UTF-8?q?elated=20#1018,=20#1020,=20#1019)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/plans/ops108-modo-autonomo-por-flag.md | 88 ++++ ...09-painel-issues-no-terminal-ui-draft.html | 401 ++++++++++++++++++ .../plans/ops109-painel-issues-no-terminal.md | 114 +++++ docs/plans/ops110-attach-detach-runs-agent.md | 93 ++++ 4 files changed, 696 insertions(+) create mode 100644 docs/plans/ops108-modo-autonomo-por-flag.md create mode 100644 docs/plans/ops109-painel-issues-no-terminal-ui-draft.html create mode 100644 docs/plans/ops109-painel-issues-no-terminal.md create mode 100644 docs/plans/ops110-attach-detach-runs-agent.md diff --git a/docs/plans/ops108-modo-autonomo-por-flag.md b/docs/plans/ops108-modo-autonomo-por-flag.md new file mode 100644 index 00000000..3dfaa7cd --- /dev/null +++ b/docs/plans/ops108-modo-autonomo-por-flag.md @@ -0,0 +1,88 @@ +# OPS108 — Modo autônomo por flag nas skills plan-issue e work-issue + +Status: rascunho +Atualizado em: 2026-09-15 +Issue: #1018 +Priority: P2 +Impeccable: A — N/A (arquivos de skills/comandos; sem UI de produto) +Rascunho UI: N/A — sem UI +Appetite: ~0,5–1 dia eng; uma flag com semântica única nas duas skills + comandos +Responsável: — + +## Intenção + +> "Possibilidade de rodar as skills `plan-issue` e `work-issue` de forma autônoma, passando flag que sinaliza que o agente não precisa esperar por confirmação do plano, e pode auto-aprovar o que ele próprio recomendar." + +Hoje os dois fluxos param por definição: `plan-issue` fecha o lote num GATE que exige confirmação explícita antes de qualquer Issue/PR; `work-issue` escreve o plano de implementação e para até confirmação explícita antes de codar. Isso é o comportamento certo para colaborar, mas o dono do processo quer também poder **disparar os dois sem supervisão quando ele escolher** — deixar o agente seguir, auto-aprovar a própria recomendação e entregar (Issue registrada / execução até PR), reservando ao humano só o que o repo já exige (CI, auto-merge no servidor, aprovação de produção). + +O pedido não é remover os gates — é tornar a pausa **opt-out por invocação**, com a flag explícita carregando a intenção. Sem flag, nada muda. + +## Persona e fluxo + +- **Persona / contexto:** o operador do paradigma (hoje o `fsolla`), de mesa, disparando um lote de ideias ou uma Issue já claimada quando não quer acompanhar passo a passo. +- **Job principal:** iniciar o fluxo e voltar depois com ele concluído até onde o repo permite — Issue registrada ou PR de entrega aberto. +- **Fluxo desejado:** invoca com a flag → o agente explora, escreve o plano, aprova a própria recomendação e segue (registro + PR no plan-issue; execução até PR no work-issue) → o humano revisa o resultado no fim, e só é interrompido antes se um invariante duro aparecer. +- **Anti-goals de produto:** não virar o default (autonomia é opt-in por invocação); não criar skill gêmea nem segundo fluxo; não mexer no contrato de claim, no pool dormente nem no launch de worktree; não auto-aprovar produção nem qualquer gate que o repo trata como humano. + +## Objetivo e aceite + +- Com a flag, `plan-issue` conduz o lote do overview até o registro (Issues + PR dos planos) **sem** esperar confirmação humana; sem a flag, o GATE atual permanece idêntico. +- Com a flag, `work-issue` cria/apresenta o plano de implementação, o marca como aprovado e executa até o PR **sem** pausa; sem a flag, a pausa atual permanece idêntica. +- **Pode auto-aprovar (recomendação do próprio agente, dentro do que a skill já decide):** conteúdo e fatiamento dos planos, prioridade, dependências, abordagem técnica, cortes de escopo já previstos nas skills e os literais de dados que o próprio plano recomenda (registrados como assumidos, para validação posterior). +- **Continua parando (invariantes duros do repo, valem mesmo com a flag):** Consent/LGPD fail-closed, migração de schema, contrato de URL público, shapes públicos e produção (aprovação humana do environment). Divergência material de produto → o agente para e reporta: no `work-issue` a Issue vira `blocked` (precedente do fluxo autônomo); no `plan-issue` o item não é registrado e fica fora do lote até decisão humana. +- Flag ausente ou desconhecida → comportamento atual preservado (fail-safe de compatibilidade). +- O claim continua sendo contrato do ambiente: o modo autônomo do `work-issue` não claima Issue nenhuma. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — **Dados: N/A**: sem superfície de dados de campanha; o item muda só o fluxo das skills e dos comandos que as invocam. +- **Decisões desbloqueadas:** N/A — nenhuma decisão de campanha depende disso. +- **Forma:** N/A — nada a apresentar. + +## Dados da decisão (literais) + +- Flag única `--auto` nas duas skills (decidido no gate 2026-09-15). Ela remove a pausa das skills; nunca os invariantes duros. Atenção: o `--auto` do CLI do opencode é outro conceito (auto-aprovar permissões de ferramenta) — a skill deve deixar a distinção explícita no texto. +- Sem a flag, os dois GATEs atuais permanecem exatamente como estão (pausa explícita). +- Lista fechada de auto-aprovação: planos/fatiamento, prioridade, dependências, abordagem técnica, cortes já permitidos pelas skills, literais recomendados pelo próprio plano. +- Lista fechada de parada dura: Consent/LGPD fail-closed, migração de schema, contrato de URL público, shapes públicos, produção; divergência material de produto. +- Escopo: as duas skills + os dois comandos que as invocam; claim, pool e launch de worktree intocados. +- ID reservado **OPS108**; kind **chore**; sem UI (Impeccable A). + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** os dois documentos de skill (`plan-issue` e `work-issue`) e os dois comandos que as invocam (`.opencode/commands/`) — a flag tende a viajar no texto já repassado hoje (o único flag documentado hoje é `--issue `); os comandos ganham só a menção que a torna descobrível. +- **Precedente a olhar:** `agent-work-issue` (fluxo autônomo de ponta a ponta; único freio = divergência material de produto → `blocked`) e `engineering-audit` (modo primário autônomo; humano é gate final). `docs/plans/engineering-audit-v2-impl.md:41` lista o que fica fora da noite por construção — mesma lista de parada dura. +- **Risco de acoplamento:** editar o dono, não twinar (nada de skill nova). O claim é do ambiente (`worktree next`/`pnpm agent:claim`) e não pode ser puxado para a skill; `agent-work-issue` continua sendo o contrato do pool dormente. + +## Dependências + +- Nenhuma dura. Soft (fora deste item): o launch de worktree hoje monta `/work-issue --issue ` no prompt — um dia pode carregar a flag junto, mas isso é mudança de outro dono. + +## Fora de escopo + +- Mudar o contrato de claim, o pool dormente ou o launch de worktree (dependência futura citada acima). +- Tornar autonomia o default ou ter modo autônomo implícito por heurística. +- Um terceiro fluxo/skill gêmeo; espelhos `.claude/`/`.cursor/`. +- Auto-aprovar CI, auto-merge ou produção: os gates de servidor continuam como estão. +- Consolidar `agent-work-issue` com `work-issue --auto` (pergunta em aberto abaixo). + +## Rabbit holes de produto + +- **"Já que existe flag, deixa ligado sempre."** Autonomia silenciosa remove os gates de colaboração que protegem o lote em construção. **Corte neste item:** opt-in por invocação; sem flag, pausa idêntica à de hoje. +- **"A flag pula tudo, inclusive o que o repo trava."** Um modo que atravessa Consent/migração/URL/produção vira bypass de LGPD e de banco. **Corte neste item:** a lista de parada dura nunca é afetada pela flag. +- **"Faz uma skill só para autônomo."** Twin do mesmo fluxo cria drift entre dois donos. **Corte neste item:** a própria skill ganha o modo; nenhum fluxo paralelo. + +## Questões em aberto (produto) + +- **No `plan-issue` autônomo, divergência material de produto achada na exploração: registra bloqueada ou deixa fora?** **Opções:** A) não registra e reporta no resumo final (itens restantes seguem) · B) registra `blocked` com o motivo. **Recomendação:** A — preserva a regra "nada no tracker antes do gate" e mantém o item barato de retomar; a Issue nasce quando o humano decidir. _(assumido — validar)_ +- **`work-issue --auto` vira o mesmo que `agent-work-issue`?** **Opções:** A) mantê-los separados neste item (contrato do pool vs. sessão humana) · B) consolidar num só. **Recomendação:** A agora; a convivência fica documentada e a consolidação é item futuro se os dois divergirem. _(assumido — validar)_ + +## Referências + +- GitHub Issue #1018 +- `.agents/skills/plan-issue/SKILL.md` — ciclo, "nada no tracker antes do gate", Passo 4 (GATE) e Passo 5 (registro) +- `.agents/skills/work-issue/SKILL.md` — Passo 3 (impl plan + GATE humano) e o "Proibido" que preserva claim/CI +- `.opencode/commands/plan-issue.md` e `.opencode/commands/work-issue.md` — wrappers que repassam `$ARGUMENTS` +- `.agents/skills/agent-work-issue/SKILL.md` — precedente autônomo (impl plan `aprovado`; divergência → `blocked`) +- `.agents/skills/engineering-audit/SKILL.md` — modo autônomo com humano como gate final +- `docs/plans/engineering-audit-v2-impl.md` (l.41) e `docs/AGENT-OPS.md` — o que o repo mantém humano por construção diff --git a/docs/plans/ops109-painel-issues-no-terminal-ui-draft.html b/docs/plans/ops109-painel-issues-no-terminal-ui-draft.html new file mode 100644 index 00000000..fab808b1 --- /dev/null +++ b/docs/plans/ops109-painel-issues-no-terminal-ui-draft.html @@ -0,0 +1,401 @@ + + + + + + + UI draft — OPS109 · Painel de issues e planos no terminal + + +
+

+ UI draft — Painel de issues e planos no terminal (OPS109) +

+

+ O mantenedor abre a TUI no terminal (mesa ou SSH do laptop/celular): lista de issues com + estado, prioridade e o que esperam dele; detalhe com plano de intenção e de implementação e + o status de cada um; leitor de markdown renderizado. Do detalhe também abre o rascunho UI no + browser da máquina e anexa à sessão do agente que está rodando aquela issue. Read-only sobre + tracker e planos. +

+

+ Cena estática — sem interação, sem dados reais. Cinza = estrutura · acento + sky = seleção/foco · cores de estado = leitura funcional · + barras cinza = conteúdo não especificado. +

+ + + + +
+

+ Cena 1 · desktop (~100 colunas) — lista com filtro por estado +

+
+
+
+ teqo · issues + | + repo fsolla/teqo + última sync: 14:32 +
+
+ 1 todas (43) + 2 em andamento (3) + 3 aguardando (12) + 4 concluídas (28) +
+
+ estado + id + título + plano + prio +
+
+
+ ● em andamento + C163 + Título de exemplo da issue em curso + impl em execução + P1 +
+
+
+
+ ◌ aguardando + OPS000 + Título de exemplo aguardando aprovação + intenção: aguardando + P2 +
+
+
+
+ ■ travada + B000 + Título de exemplo com dependência aberta + depends OPS111 + P2 +
+
+
+
+ ○ pronta + C000 + Título de exemplo pronto para claim + intenção: aprovado + P2 +
+
+
+
+ ✓ concluída + OPS097 + Título de exemplo já entregue + impl entregue + P2 +
+
+
+
+ ○ pronta + OPS000 + Título de exemplo sem plano ligado + sem plano + P3 +
+
+
+ ↑↓ navegar + enter abrir + 1-4 filtrar + / buscar + r recarregar + q sair +
+
+
+
+ + + + +
+

+ Cena 2 · desktop — detalhe da issue: resumo + planos e status +

+
+
+
+ OPS000 — Título de exemplo aguardando aprovação + ◌ aguardando +
+
+ Issue #0000 · prio + P2 · kind + feature · depends + — · + github.com/fsolla/teqo/issues/0000 +
+
+

resumo

+

+ Duas linhas de exemplo do resumo de produto, na voz do humano que pediu o item. Sem + números reais e sem promessa que o plano não faça. +

+
+
+

planos

+
+ ✓ intenção + · + docs/plans/ops000-exemplo.md + · + aprovado (gate humano 2026-09-10) + · + enter abre +
+
+ ◌ implementação + · + docs/plans/ops000-exemplo-impl.md + · + aguardando aprovação + · + enter abre +
+
+
+

ações

+
+ w + abrir rascunho UI no browser + · + docs/plans/ops000-exemplo-ui-draft.html +
+
+ s + abrir sessão do agente + · + run ativo + · + worktree do exemplo +
+
+
+ esc voltar + enter abrir plano + w rascunho UI + s sessão do agente + o abrir no GitHub +
+
+
+
+ + + + +
+

+ Cena 3 · desktop — leitor de plano: markdown renderizado no terminal +

+
+
+
+ docs/plans/ops000-exemplo-impl.md + Status: aprovado + 64% · ↑↓ rolar +
+
+

# Impl: OPS000 — Título de exemplo

+

+ Parágrafo de exemplo com negrito e + alguma decisão de implementação já tomada — o leitor de terminal precisa distinguir + hierarquia sem browser. +

+

## Fases verificáveis

+

1. Tracer bullet — esqueleto navegável

+

2. UI — encaixe na tela existente

+

3. Gates — pnpm gate:fast, push

+

## Alternativas rejeitadas

+
+ | Opção | Por + que caiu | +
+
+ |-------------|--------------------------------| +
+
+ | A | exemplo + de motivo | +
+
+ | B | exemplo + de motivo | +
+

```text

+

fluxo de exemplo → outcome

+

```

+

+ > citação de exemplo do plano +

+
+
+ ↑↓ rolar + pgup/pgdn página + esc voltar à issue +
+
+
+
+ + + + +
+

+ Cena 4 · estados críticos — sem token (erro claro), filtro vazio e sem ações +

+
+
+
+ teqo · issues +
+
+

erro: GITHUB_TOKEN não definido no ambiente.

+

Nada foi alterado. Defina o token e rode de novo:

+

GITHUB_TOKEN=… pnpm issues:tui

+
+
+ r tentar de novo + q sair +
+
+
+
+ teqo · issues · aguardando +
+
+

Nenhuma issue aguardando aprovação no momento.

+

+ 1 ver todas · + 2 em andamento · + 4 concluídas +

+
+
+ 1-4 trocar filtro + q sair +
+
+
+
+ teqo · issues · ações +
+
+

sessão do agente: nenhuma ativa.

+

+ O painel não inicia run — dispare pelo worktree/skill. +

+

rascunho UI: não tem (classe A).

+

Um caminho longo de exemplo é impresso no lugar.

+
+
+ esc voltar + q sair +
+
+
+
+ + + + +
+

+ Cena 5 · celular (~390px) — terminal estreito: lista e leitor +

+
+
+
+ teqo · issues +
+
+ todas + andam. + aguard. + feitas +
+
+

● em andamento · C163 · P1

+

Título de exemplo da issue em curv…

+

s abrir sessão (run ativo)

+
+
+

◌ aguardando · OPS000 · P2

+

Título de exemplo aguardando aprovaç…

+
+
+

■ travada · B000 · P2

+

Título de exemplo com dependência ab…

+
+
+

✓ concluída · OPS097 · P2

+

Título de exemplo já entregue

+
+
+ ↑↓ mover + enter abrir + q sair +
+
+
+
+

ops000-exemplo-impl.md

+

Status: aprovado · 64%

+
+
+

# Impl: OPS000 —

+

Título de exemplo

+

Parágrafo de exemplo com

+

negrito e decisão já tomada.

+

## Fases verificáveis

+

1. Tracer bullet — esqueleto

+

2. UI — encaixe na tela

+

3. Gates — gate:fast

+

## Alternativas

+

A · exemplo de motivo

+

B · exemplo de motivo

+
+
+ ↑↓ rolar + esc voltar +
+
+
+
+
+ + diff --git a/docs/plans/ops109-painel-issues-no-terminal.md b/docs/plans/ops109-painel-issues-no-terminal.md new file mode 100644 index 00000000..4f9e68a8 --- /dev/null +++ b/docs/plans/ops109-painel-issues-no-terminal.md @@ -0,0 +1,114 @@ +# OPS109 — Painel de issues e planos no terminal (via SSH) + +Status: rascunho +Atualizado em: 2026-09-15 +Issue: #1020 +Priority: P2 +Impeccable: C — fluxo novo (ferramenta de terminal; sem UI de produto) +Rascunho UI: docs/plans/ops109-painel-issues-no-terminal-ui-draft.html +Appetite: ~1–2 dias eng +Responsável: — + +## Intenção + +> _"Ferramenta local (TUI preferida) para visualizar o andamento de cada issue — em andamento / concluídas / aguardando —, abrir os planos de intenção e de implementação e ver se estão aprovados ou aguardando aprovação. Tem que funcionar via SSH de outro dispositivo (laptop/celular); exibir os planos (markdown) estilizados para leitura fácil."_ + +Hoje o andamento se lê em pedaços: `pnpm issue all` dá contadores e lista, `pnpm agent:status` dá fila e grafo, mas **nenhum** dos dois lê os planos — para saber se o plano de intenção ou o impl está aprovado é preciso abrir o arquivo no editor ou o GitHub no browser. Fora da mesa (laptop/celular via SSH), isso vira atrito: o mantenedor quer responder "o que anda, o que espera aprovação, o que travou, o que vem depois" em segundos, e ler o plano sem trocar de contexto. Prioridade **P2**: ferramenta de operação, sem incidente ou bloqueio de produto. + +No gate, o humano somou duas ações à ferramenta: abrir os rascunhos UI do item no browser padrão da máquina e abrir a sessão do agente que está rodando aquela issue. + +## Persona e fluxo + +- **Persona / contexto:** o próprio mantenedor (fsolla), navegando de laptop/celular via SSH ou na mesa; pressa de conferir o estado antes de decidir o próximo passo. +- **Job principal:** saber em segundos o que está em andamento, o que espera aprovação, o que travou e o que a próxima Issue fará — e ler o plano sem sair do terminal. +- **Fluxo desejado:** abre o painel no terminal do dispositivo → lista de issues com estado/prioridade/kind e a ação pendente → filtra por estado (em andamento / concluídas / aguardando) → seleciona uma issue → vê o resumo e, para cada plano (intenção e impl), o link e o status (aprovado / aguardando aprovação) → abre o markdown renderizado (títulos, listas, tabelas, código, negrito) → se a issue tiver rascunho UI, abre o `.html` no browser padrão da máquina → se houver run de agente ativo para a issue, abre a sessão dele (attach) → rola e volta → sai. +- **Anti-goals de produto:** read-only sobre tracker e planos (não claima, não relabela, não edita Issue/plano; abrir no browser e anexar à sessão são navegação local, não escrita); não é web/server/browser de produto; não cria segunda fonte de verdade nem duplica `agent:status`; não inicia run novo (o abrir-sessão só anexa a um run existente); sem dashboard de vaidade — cada painel responde a uma decisão do operador. + +### Esboço de fluxo (B/C/D) + +```text +[SSH] → [lista: issues × estado/prio/kind/ação] → [filtro por estado] + → [issue: resumo + planos (intenção/impl) + status] → [markdown renderizado] + → [rascunho UI: abre no browser da máquina] → [sessão do agente: attach] + → [rolar / voltar] → [sair] +cenários: issue sem plano · impl não criado · sem rascunho UI · sem sessão ativa · + sem browser/display · terminal estreito · sem token/sem rede (erro claro) +``` + +### Rascunho UI (B/C/D) + +- Rascunho UI (gate): `docs/plans/ops109-painel-issues-no-terminal-ui-draft.html` — mock do terminal com cenas estáticas (lista, detalhe com planos + ações de rascunho UI e sessão, leitor de markdown, vazio/sem token, terminal estreito). + +## Objetivo e aceite + +- O painel lista as issues rastreáveis com estado, prioridade e kind, mais a ação que esperam do operador (ex.: "aguardando aprovação", "em andamento", "travada"). +- Filtrar por estado responde "em andamento / concluídas / aguardando" sem sair do painel. +- Issue selecionada mostra o plano de intenção e o de implementação, cada um com link e status legível de relance ("aprovado" vs "aguardando aprovação"); "sem plano" e "impl ainda não criado" se explicam sozinhos, com o link do GitHub como saída. +- Markdown do plano abre renderizado para leitura (títulos, listas, tabelas, código, negrito), com rolagem e volta. +- Issue com rascunho UI (`docs/plans/-ui-draft.html`) abre o arquivo no browser padrão da máquina; sem browser/display (SSH puro), imprime o caminho para abrir manualmente — nunca falha em silêncio. Sem rascunho, a ação se explica (é classe A / não tem UI). +- Issue com run de agente ativo mostra isso na lista e no detalhe e abre a sessão existente (attach); sem run, o estado diz "nenhuma sessão ativa" — o painel não inicia run. Depende do OPS110. +- Terminal estreito (celular) continua utilizável; token ausente ou rede fora vira mensagem clara — nunca stack trace/crash. +- Guardrail: read-only sobre tracker e planos de ponta a ponta; a fonte é a mesma camada de leitura de Issues usada por `pnpm issue`/`pnpm agent:status`. + +## Dados (intenção) + +- **Vou apresentar dados?** Sim, superfície neste item — o painel é a apresentação. +- **Decisões desbloqueadas:** + - Mantenedor escolhe a próxima Issue a trabalhar vendo estado + prioridade + o que vem na fila. + - Mantenedor vê o que está travado e decide o que destravar. + - Mantenedor vê se um plano (intenção ou impl) espera aprovação e decide aprovar ou não. + - Mantenedor revisa o rascunho UI da issue e decide se interfere no run em andamento — sem sair do painel. +- **Forma:** _adiada ao plano de implementação_ — restrições de produto: leitura de relance na lista, detalhe só sob seleção; sem métricas agregadas de vaidade. + +## Dados da decisão (literais) + +- Labels de estado da Issue: `ready`, `in-progress`, `blocked`, `done`, `in-prod`. +- Outros labels lidos: `prio:P0`, `prio:P1`, `prio:P2`, `prio:P3`, `kind:*`, `needs:*`. +- Status de plano (linha `Status:` dos `docs/plans/*.md` e `*-impl.md`): `rascunho`, `registrado`, `aprovado` (às vezes com sufixo `(gate humano )`), `em execução`, `executado`, `entregue`, `blocked`. +- Link do plano no body da Issue: ``Plano: [`docs/plans/.md`](docs/plans/.md)``. +- Back-links: o plano de intenção tem `Issue: #N`; o `-impl.md` tem `Intenção: docs/plans/.md`. +- Rascunho UI é arquivo irmão do plano: `docs/plans/-ui-draft.html`. +- Sessão do agente da Issue: quem define como descobrir/endereçar é o OPS110 (dependência dura) — aqui só se consome; "nenhuma sessão ativa" é estado de primeira classe. +- Leitura de produto (assumida): `aprovado*` = aprovado; `rascunho`/`registrado`/`blocked` = aguardando; `em execução`/`executado`/`entregue` = já andou — valor cru do `Status:` sempre visível. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** scripts top-level (`scripts/*.mjs`) com exposição em `package.json` no padrão de `issue`/`agent:status`; leitura de Issues em `scripts/lib/github-api.mjs` (`listIssues`, exige `GITHUB_TOKEN`), parse de frontmatter/labels/grafo em `scripts/lib/agent-forgejo.mjs` (`parseFrontmatter`, `labelNames`, `issuesById`) e extração do path do plano em `scripts/lib/agent-pool-prompt.mjs` (`extractPlanPath`). Nenhuma lib TUI instalada hoje (Node 24 ESM). +- **Precedente a olhar:** `scripts/issue.mjs` (flags, `dieAgent`, saída compacta), `scripts/agent-status.mjs` (contadores/fila) e `docs/AGENT-OPS.md` (tabela de comandos e labels). +- **Risco de acoplamento:** reusar a camada de leitura existente (sem cache paralelo), read-only sobre tracker/planos, render de markdown de terminal (`react-markdown`/`remark-gfm` são de browser e não servem), sem servidor web — precisa funcionar num terminal SSH comum. Abrir o rascunho UI depende do browser da máquina (hipótese: `xdg-open`/`open`; sem display, imprimir o caminho); abrir a sessão depende do mecanismo do OPS110 (dependência dura, sem twinar). + +## Dependências + +- **OPS110 (dura)** — abrir a sessão do agente só existe depois que o run persistente/endereçável do OPS110 existir; até lá o painel mostra "nenhuma sessão ativa". +- Nenhuma outra. + +## Fora de escopo + +- Escrita no tracker/planos (claim/relabel/close/comentar/editar plano) — destino: comandos existentes. +- Iniciar run novo pelo painel — o abrir-sessão só anexa a um run existente; disparar run fica para o fluxo normal (worktree/skill). +- Servidor web, browser de produto, app mobile, `tmux` obrigatório — o terminal SSH puro é o contrato; o browser local só é chamado para exibir o rascunho `.html`. +- Notificações, watch/daemon em background, histórico/analytics — destino: outro item, se pedido. +- Gráficos de time/burndown — vaidade sem decisão nomeável. +- Substituir `pnpm issue`/`pnpm agent:status` — eles continuam. + +## Rabbit holes de produto + +- **"Já que lista issues, claima daqui."** Escrita puxa lock/labels e quebra o contrato read-only. **Corte neste item:** só visualizar. +- **"Já que renderiza markdown, edita o plano."** Editor concorrente é outro produto. **Corte neste item:** leitura e navegação. +- **"Expõe com ttyd/wetty no navegador do celular."** Traz servidor, porta e auth — o pedido é SSH. **Corte neste item:** roda no terminal do cliente. +- **"Cacheia local pra economizar token."** Vira segunda fonte que envelhece. **Corte neste item:** sempre a camada existente. + +## Questões em aberto (produto) + +- **Issue sem plano ou com impl não criado — como representar?** **Opções:** A) estado explícito "sem plano"/"impl não criado" + link do GitHub | B) omitir a seção. **Recomendação:** A — nunca célula vazia. _(assumido — validar no gate)_ +- **"Aguardando aprovação" inclui `em execução`?** **Opções:** A) não, só `rascunho`/`registrado`/`blocked` | B) todo status não-`aprovado`. **Recomendação:** A. _(assumido)_ +- **Onde o painel roda?** **Opções:** A) na máquina do repo (com `GITHUB_TOKEN`) acessada por SSH | B) homeserver. **Recomendação:** A — o token já vive lá e nada novo é hospedado. _(assumido)_ +- **Sem browser/display (SSH puro) ao abrir o rascunho UI?** **Opções:** A) imprimir o caminho para abrir manualmente | B) só avisar que falhou. **Recomendação:** A — o caminho colado no terminal do cliente resolve. _(assumido)_ + +## Referências + +- GitHub Issue #1020 +- Rascunho UI (gate): `docs/plans/ops109-painel-issues-no-terminal-ui-draft.html` +- `docs/plans/ops110-attach-detach-runs-agent.md` — de onde vem a sessão endereçável (dependência dura) +- `scripts/lib/github-api.mjs`, `scripts/lib/agent-forgejo.mjs`, `scripts/lib/agent-pool-prompt.mjs` (`extractPlanPath`), `scripts/issue.mjs`, `scripts/agent-status.mjs` — pistas de leitura, não contrato +- `docs/AGENT-OPS.md` (comandos e labels) e `AGENTS.md` (convenções de scripts/CI) diff --git a/docs/plans/ops110-attach-detach-runs-agent.md b/docs/plans/ops110-attach-detach-runs-agent.md new file mode 100644 index 00000000..5c00bb67 --- /dev/null +++ b/docs/plans/ops110-attach-detach-runs-agent.md @@ -0,0 +1,93 @@ +# OPS110 — Acompanhar runs longos de agente por attach/detach, sem manter terminal aberto + +Status: rascunho +Atualizado em: 2026-09-15 +Issue: #1019 +Priority: P2 +Impeccable: A — N/A (ferramenta/ops; sem UI de produto) +Rascunho UI: N/A — sem UI +Appetite: ~1–2 dias eng +Responsável: — + +## Intenção + +Hoje cada run de agente exige presença: o opencode roda no terminal do workstation e, se o TUI fechar (ou a sessão SSH cair), o run para. O fsolla quer largar um `/work-issue` ou `/plan-issue` longo no workstation e ir embora — almoço, reunião, fim de expediente — acompanhando do laptop ou do celular, entrando e saindo da sessão quantas vezes quiser enquanto o agente trabalha. + +Não é um pedido de "rodar agentes em background" solto: é o mesmo run de hoje, com o ciclo de vida desacoplado do terminal que o observa. O que os agentes fazem não muda; muda como o humano os acompanha. O painel de Issues (OPS109) também quer abrir a sessão do run daquela Issue — para isso este item precisa deixar a sessão **endereçável**, não só persistente. + +## Persona e fluxo + +- **Persona / contexto:** fsolla no workstation, com worktrees de agente ativos; longe dele, no laptop ou celular, por SSH ou rede confiável. Não quer vigiar em tempo real — quer poder espiar, sair e voltar. +- **Job principal:** iniciar um run longo, desconectar, e (re)entrar na sessão de outro dispositivo quando quiser, sem interromper o agente. +- **Fluxo desejado:** + 1. Dispara o run do jeito que já dispara hoje (worktree + skill, ex. `/work-issue`). + 2. Fecha o terminal do workstation ou perde o SSH; o agente continua trabalhando. + 3. Do laptop ou celular, entra na sessão existente e vê o histórico/estado do agente; acompanha ou digita se quiser. + 4. Sai de novo — quantas vezes quiser — sem matar o run. + 5. Quando decidir encerrar, encerra de forma explícita, nunca por acidente ao fechar o cliente. +- **Anti-goals de produto:** + - Não vira pool/supervisor de agentes (o pool morreu na OPS65; não ressuscitar). + - Não automatiza produção nem cria caminho que burle gates humanos (PR/CI/approval). + - Não cria um segundo jeito de iniciar sessão que ignore o worktree/claim vigente. + - Não exige terminal aberto no workstation nem processo pendurado em SSH. + - Não abre porta pública na internet. + +## Objetivo e aceite + +- O run continua trabalhando quando nenhum cliente está olhando (nenhum terminal/SSH aberto no workstation). +- (Re)entrar na sessão de outro dispositivo retoma exatamente onde estava — mesma sessão, mesmo worktree, mesmo histórico. +- Sair do cliente nunca é o mesmo que encerrar o run; encerrar é ato explícito. +- Nada novo escutando além do loopback sem credencial: se alguma superfície passar de `127.0.0.1`, exige autenticação e só em rede confiável (SSH/tailnet) — fail-closed sem credencial. +- O worktree/branch em que o agente roda continua sendo o contrato de ambiente; não há nova forma de claim nem de sessão órfã. +- A sessão de um run é endereçável a partir da Issue/worktree (dá para saber como chegar nela sem adivinhar) — pré-requisito do "abrir a sessão do agente" do painel OPS109. + +## Dados (intenção) + +- **Vou apresentar dados?** Não. +- **Decisões desbloqueadas:** N/A. +- **Forma:** N/A — `Dados: N/A` — ferramenta/ops de operação de agentes; sem métrica, gráfico ou dado eleitoral/de contato envolvido. + +## Dados da decisão (literais) + +- Se algo escutar além do loopback, a credencial é a do próprio opencode por ambiente: `OPENCODE_SERVER_PASSWORD` (e `OPENCODE_SERVER_USERNAME`); valores reais vivem fora do repo (workstation), nunca commitados — sem credencial, a superfície responde 401. +- "Loopback" aqui é `127.0.0.1`, o default atual do modo servidor do opencode 1.18.31. +- Os nomes acima são o contrato disponível hoje; porta, host de bind, paths de log/socket e nome de serviço são hipóteses do plano de implementação, não de contrato de produto. +- O painel OPS109 consome este endereçamento (abrir a sessão da Issue); o artefato/mecanismo concreto de descoberta é decisão do plano de implementação — sem mapa paralelo. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `scripts/lib/worktree.mjs` (diretiva `launch`, ~207–233) e `.agents/shell/worktree.sh` (~104–112, executa o launch); documentação em `docs/AGENT-OPS.md` e `AGENTS.md`. +- **Duas direções citáveis, sem escolha aqui:** (a) servidor nativo persistente do opencode (`opencode serve`, dono da sessão) com cliente `opencode attach ` de qualquer dispositivo (replay/`--continue`); ou (b) multiplexador de terminal mantendo o TUI vivo entre anexações. A forma é decisão do plano de implementação; o aceite de produto é o mesmo. +- **Precedente a olhar:** OPS106 `scripts/auto-unblock.mjs` (spawn destacado + log + flock) mostra o padrão local de processo que sobrevive ao invocador, embora não seja sessão interativa; OPS40 `scripts/dev.mjs` mostra wrapper de CLI passando flags. +- **Risco de acoplamento:** o launch atual nasce da shell function e depende do `cd`/worktree — qualquer modo destacado precisa preservar worktree/branch e não duplicar a porta de entrada; o painel OPS109 consome o mesmo endereçamento (sem mapa paralelo). Expor bind além do loopback é o risco nº 1: a workstation não tem IP tailnet documentado (só o homeserver) e o repo não tem precedente de acesso remoto a ela. + +## Dependências + +- Nenhuma dura. Depende de capacidades já presentes no opencode instalado (servidor + attach). O OPS109 (painel) depende deste item para abrir a sessão da Issue — o endereçamento da sessão é aceite daqui. + +## Fora de escopo + +- Multi-usuário ou servir agentes para terceiros. +- Web UI como produto — se útil na implementação, é meio, não aceite. +- Notificações/push de progresso, painel de frota de runs, métricas de agentes. +- Mudanças no fluxo de claim/worktree ou nos gates de PR/deploy. + +## Rabbit holes de produto + +- **"Já que tem servidor, vira painel de frota".** Se alguém "só completar": status de todos os runs, iniciar/parar agentes, retomar por lista. **Corte neste item:** uma sessão, um worktree, attach/detach — nada de orquestração. +- **"Expõe na tailnet e pronto".** Se alguém "só completar": bind aberto sem auth "porque a rede é confiável". **Corte neste item:** qualquer superfície além do loopback exige credencial, fail-closed. +- **"Persistência própria de sessão".** Se alguém "só completar": banco/daemon próprio guardando estado do run. **Corte neste item:** usar o que o opencode já persiste; nada de um segundo dono da sessão. + +## Questões em aberto (produto) + +- **Servidor nativo vs multiplexador?** **Opções:** A servidor persistente + `attach` | B multiplexador de terminal mantendo o TUI | C os dois. **Recomendação:** deixa ao impl plan decidir; produto só exige o mesmo aceite (run sobrevive sem cliente, reattach exato, encerramento explícito, auth fora do loopback). _(assumido — validar com produto)_ +- **De onde se acompanha no celular?** **Opções:** A SSH/TUI no terminal do celular | B navegador (web UI) | C só laptop por enquanto. **Recomendação:** A — reaproveita a superfície TUI já validada; B adiciona escopo de UI que o aceite não exige. + +## Referências + +- GitHub Issue #1019 +- `scripts/lib/worktree.mjs` (diretiva `launch`) e `.agents/shell/worktree.sh` (execução do launch) — de onde o run nasce hoje +- `scripts/auto-unblock.mjs` — precedente OPS106 de processo local destacado +- `docs/AGENT-OPS.md` — operação de agentes paralelos; `AGENTS.md` — convenções do repo +- `docs/ops/teqo-1313-deploy.md` — topologia de rede (homeserver × workstation) +- opencode 1.18.31 instalado: `opencode serve`, `opencode attach`, `opencode run --attach` e `opencode web` (help local)