MÓDULO 2.3

Acabamento e Segurança

Os quatro comandos utilitários que tornam o plugin usável no dia a dia — e o safety pass que garante que nenhum erro vai travar o usuário.

6
Tópicos
50
Minutos
Int.
Nível
🔧
Prático
1

Prompt 06 — Os quatro comandos utilitários

O sexto prompt marca a transição do plugin funcional para o plugin usável. O loop já funciona de ponta a ponta — agora é hora de adicionar os quatro comandos que qualquer pessoa vai chamar no terminal real: /claudex:status, /claudex:doctor, /claudex:cancel e /claudex:rollback.

💡 Conceito Principal

O prompt real (Prompt 06)

# Prompt 06 — Utility commands

> Loop works end-to-end. Now add the four utility commands
  that make it usable in real life.

---

Build:

## `/claudex:status`
plugins/claudex/commands/status.md is a one-liner that runs
bash "${CLAUDE_PLUGIN_ROOT}/scripts/status.sh". Read-only.

scripts/status.sh:
- Find the most recent state file (claudex_find_active_loop).
- Print mode, phase (color-coded: yellow=active, green=done,
  red=cancelled/errored), round, topic, started_at, elapsed,
  decision_signal, interview_used, from_draft.
- Replace lockfile-aliveness check with an "activity" line
  derived from phase.
- For each round's findings file, print a line like:
  round 1   high=2 medium=4 low=1
- Always exit 0. Do not install an ERR trap.

## `/claudex:doctor`
One-liner → doctor.sh. Sections with ✓/✗ checks:
- Shell: bash present, bash 4+ (warn on 3.x)
- Codex CLI: in PATH + codex --version
- Optional: python3 (warn-only)
- State dir: .claude/claudex exists and writable
- Plugin files: collapse 15 files into 1 line on success
- Hook fail-open sanity: hook executable, returns approve on empty state
- Helpers smoke: state-helpers + personas source cleanly
- Loop hygiene: print whether there's a loop on disk and its phase

## `/claudex:cancel` and `/claudex:rollback`
cancel-loop.sh: find active loop, set phase=cancelled, remove
runner/prompt/lock files. Keep state file for audit.

rollback-loop.sh: nuke every state file, lock, runner, prompt,
and findings folder under .claude/claudex/. Keep .claude/claudex/log.
Print count of files removed.

## Interview offer in `/claudex:plan`
Extend plan.md procedure:
- If $ARGUMENTS is empty, ask user for topic, do NOT run start-loop yet
- Without --skip-interview, use AskUserQuestion with two options:
  "Interview me first (Recommended)" / "Just launch the loop"
- On opt-in, ask three questions (scope, constraints, worry list)
- Compose enriched topic with ; separators. Pass with --interviewed.

## Tests
Update smoke-test.sh with sections for started_at_epoch,
interview_used, --skip-interview, --interviewed flags,
/claudex:status output, and "no loops" empty-state path.
Fazer
  • Manter status.sh read-only (nunca muta estado)
  • Usar exit 0 sempre em status e doctor
  • Manter state file após cancel (para auditoria)
  • Colapsar 15 arquivos em 1 linha no doctor (sucesso)
Evitar
  • Instalar ERR trap em status.sh ou doctor.sh
  • Usar lockfile para controle de concorrência (a fase faz isso)
  • Tópico multi-linha no estado YAML (quebra o parser)
  • Deletar o log em rollback (manter para debug)
2

O /claudex:doctor — diagnóstico completo do plugin

Todo sistema de produção precisa de um comando de diagnóstico. O /claudex:doctor não é uma novidade — é uma prática estabelecida (pense em rails doctor, brew doctor). Mas a forma como ele é construído aqui revela muito sobre a filosofia do projeto.

📊 Anatomia do doctor.sh
01
Shell check — bash presente, versão 4+. Warn em 3.x (macOS default).
02
Codex CLI — está no PATH? Se sim, imprime codex --version.
03
Dependências opcionais — python3 é warn-only, não falha.
04
State dir.claude/claudex existe e tem permissão de escrita.
05
Plugin files — 15 arquivos esperados. Em sucesso: 1 linha só. Em falha: lista cada um.
06
Hook fail-open sanity — hook é executável e retorna approve em estado vazio.
07
Helpers smoke — state-helpers e personas carregam limpos; personas são distintas.
08
Loop hygiene — há loop em disco? Em que fase está?
💡 Dica Prática

Rode bash plugins/claudex/scripts/doctor.sh dentro de um repositório vazio antes de qualquer deploy. Se o doctor sai 0, o plugin não depende de estado residual da máquina de desenvolvimento — ele é genuinamente portável.

⚠️ Atenção

Assim como o status.sh, o doctor.sh não instala ERR trap. A função claudex_find_active_loop retorna não-zero legitimamente quando não há loops — e um ERR trap transformaria isso num erro assustador na tela do usuário.

3

A entrevista de planejamento antes do loop

Uma das adições mais sutis do Prompt 06 é a entrevista interativa no /claudex:plan. Em vez de aceitar um tópico cru e disparar o loop imediatamente, o Claude pode primeiro fazer três perguntas estruturadas para enriquecer o contexto de revisão.

💡 Como funciona a entrevista
1
Se $ARGUMENTS está vazio, o Claude pede o tópico. Ainda não inicia o loop.
2
Sem a flag --skip-interview, usa AskUserQuestion com duas opções: "Interview me first (Recommended)" vs. "Just launch the loop".
3
No opt-in, mais três perguntas: escopo, restrições e lista de preocupações — com opções contextualizadas ao tópico.
4
As respostas são compostas em um único tópico enriquecido com separadores ; (tópicos multi-linha quebram o YAML do state file). O start-loop recebe a flag --interviewed e registra interview_used: true.
🎯 Por que isso importa

A entrevista resolve um problema real: quando você diz "revise meu auth module", o Claude não sabe se você quer focar em performance, segurança ou legibilidade. Três perguntas estruturadas antes do loop produzem resultados muito mais úteis — e o campo interview_used: true no estado permite auditar depois se a entrevista foi feita.

4

Prompt 07 — O safety pass: auditando cada caminho de erro

O sétimo e último prompt não adiciona novas features. Ele stess-testa cada caminho de erro e garante que o usuário nunca vai ficar preso. Este é o safety pass — a auditoria sistemática das seis primitivas de segurança definidas no SPEC.

💡 O prompt real (Prompt 07)
# Prompt 07 — Safety pass

> Last prompt. Stress-test every error path and make sure
  the user is never trapped.

---

Read SPEC.md's "Six safety primitives" section. The hook should
already have most of these. This pass verifies them and adds
the missing ones.

## Audit checklist

Walk every code path and confirm:

1. ERR trap. First line of stop-hook.sh after helper definitions
   installs a trap that returns approve on any error and exits 0.
   Confirm no path that mutates state runs before the trap.

2. Atomic writes. Every state mutation goes through
   claudex_state_write or claudex_state_set_field (tmp + rename).
   No direct > redirects to state files anywhere. Grep to confirm.

3. CAS phase transitions. Every phase field write uses
   claudex_phase_transition, NOT claudex_state_set_field "phase".
   Exception: deliberate "force" sites like cancel-loop.sh.
   Document which sites are which in code comments.

4. Lockfile + PID liveness. claudex_lock_is_active does kill -0.
   The lockfile is informational only — it doesn't gate concurrency
   (phase does). Don't load-bear the lock for anything important.

5. Stale loop sweeper. Runs on every start-loop.sh invocation
   BEFORE the concurrency check. Old completed loops kept on disk
   for audit are not swept; only files older than CLAUDEX_STALE_MINUTES.

6. cwd validation. Hook reads repo_root from state and fails open
   if pwd != repo_root.

## New tests
tests/synthetic-e2e.sh — Real Codex calls. Spins up a throwaway
repo at /tmp/claudex_synthetic, runs through one full plan-mode
round end-to-end. Asserts: start-loop produces valid review_id,
hook BLOCKs with run-runner instructions when PLAN.md is present,
runner exits 0 with non-empty output, mark-done.sh + final hook
produces approve and cleans up lockfile, back-to-back loops work.

## README and SAFETY docs
README.md at repo root + plugins/claudex/docs/SAFETY.md.
docs/ARCHITECTURE.md (loop lifecycle deep dive).
docs/V2_DESIGN.md (auto-apply-with-branch-isolation, deferred to v2).

## Final test sweep
bash plugins/claudex/tests/platform-validation.sh
bash plugins/claudex/tests/smoke-test.sh
bash plugins/claudex/tests/synthetic-e2e.sh   # se Codex configurado

If platform + smoke pass, the plugin is shippable.

As seis primitivas de segurança

1 — ERR trap

Primeira linha do stop-hook.sh instala trap que retorna approve em qualquer erro. Nenhum usuário fica bloqueado por crash do hook.

2 — Atomic writes

Toda mutação de estado usa tmp + rename. Zero redirects diretos > em arquivos de estado.

3 — CAS phase transitions

Compare-And-Swap em toda transição de fase. Exceção documentada: cancel-loop.sh força override deliberadamente.

4 — Lockfile + PID liveness

Lock é informacional. A fase controla concorrência. kill -0 verifica liveness do PID.

5 — Stale loop sweeper

Roda no início de cada start-loop.sh. Remove apenas loops mais velhos que CLAUDEX_STALE_MINUTES — loops completos ficam para auditoria.

6 — cwd validation

Hook lê repo_root do estado e falha aberto (approve) se o diretório atual não bater. Previne revisão do repositório errado.

5

Os três níveis de teste: platform, smoke e e2e sintético

O Claudex não tem testes de unidade clássicos — tem três scripts de shell que verificam o sistema em camadas crescentes de integração. Essa é uma escolha deliberada: cada camada pode ser executada independentemente, e a última (synthetic e2e) é opcional porque custa tokens reais.

Pirâmide de testes do Claudex

L1
platform-validation.sh

Verifica que o ambiente tem o que o plugin precisa: bash 4+, Codex no PATH, status.sh e doctor.sh rodam sem crash em estado vazio. Zero dependências de estado.

Custo: zero tokens
L2
smoke-test.sh

Verifica o estado produzido por start-loop: campos started_at_epoch e interview_used presentes, flags --skip-interview e --interviewed funcionando, /claudex:status imprimindo review_id e fase corretamente.

Custo: zero tokens (mock Codex)
L3
synthetic-e2e.sh

Cria um repositório throwaway em /tmp/claudex_synthetic, roda um ciclo completo com codex exec real, e verifica todas as asserções do fluxo fim-a-fim.

Custo: ~25-30k tokens (opcional)
📋 O que o synthetic-e2e verifica
  • start-loop produz output e cria um review_id válido
  • O hook BLOQUEIA com instruções run-runner quando PLAN.md está presente
  • O runner script tem o heredoc PROMPTEOF com aspas (previne expansão shell)
  • O runner sai 0, produz output não-vazio, não bate em erros de terminal ou auth
  • mark-done.sh + hook final produzem approve e limpam o lockfile
  • Um segundo start-loop aceita novo loop (back-to-back funciona)
6

Como shipar o plugin e o que vem na v2

Com platform + smoke passando, o plugin é shippable. O synthetic e2e confirma integração com o Codex real — mas não é pré-requisito para o sign-off de nível de unidade. E já há um design documentado para a v2.

🚀 Documentação gerada no Prompt 07
README.md

O que o loop faz em inglês simples, quem é o público-alvo, exemplo de terminal.

SAFETY.md

O que o Claudex faz e NÃO faz, arquivos que toca, expectativa de custo (~25-30k tokens/round, ~75-90k para 3 rounds padrão).

ARCHITECTURE.md

Deep dive no ciclo de vida do loop — como as fases se encadeiam, quando o hook intervém.

V2_DESIGN.md

Auto-apply com branch isolation — o design que foi deliberadamente adiado para a v2. Documentado, não implementado.

🎯 O critério de shippable

O SPEC define "shippable" como: platform-validation passa E smoke-test passa. O synthetic e2e confirma integração real com o Codex (e custa tokens), mas não é required para o sign-off. Isso é uma decisão de produto — separa o "funciona tecnicamente" do "funciona no mundo real".

🔮 O que vem na v2

A v1 é read-only por design — o Claudex revisa e sugere, mas nunca aplica automaticamente. A v2 documenta o design de auto-apply com branch isolation:

  • Cada round cria uma branch isolada automaticamente
  • O Codex aplica as sugestões de alta severidade sem intervenção manual
  • A branch é aberta como PR para revisão humana — o plugin nunca merge sozinho
  • Rollback automático se qualquer teste falhar após aplicação

Resumo do Módulo 2.3

Os dois últimos prompts transformam o plugin funcional em produto shippable: