MÓDULO 2.1

O Blueprint: Arquitetura Antes do Código

📚

Tópicos

7

⏱️

Minutos

50

🎯

Nível

Intermediário

🧠

Tipo

Conceitual

1

A Filosofia do Build Incremental

Por que um prompt de cada vez muda tudo

A abordagem mais comum para construir sistemas complexos com Claude é despejar uma especificação enorme em um único prompt e torcer para que tudo funcione. O Claudex foi construído de forma radicalmente diferente: sete prompts incrementais, cada um verificado antes do próximo. Essa não é uma escolha de estilo — é uma exigência das garantias de sistema que o Claudex precisa oferecer.

💡 Conceito Principal

Cada layer não verificada é onde um bug se esconde

Quando você empilha código não testado sobre código não testado, a falha final pode ter origem em qualquer camada. Builds incrementais criam "fronteiras de verificação" — você só avança quando a camada atual está funcionando. No Claudex: os state files precisam funcionar antes de você ligar o hook neles. O hook precisa falhar aberto antes de escrever mensagens de BLOCK para o usuário.

📊 A Sequência dos 7 Prompts
01Esqueleto do plugin + slash commands + hook fail-open
02Máquina de estados — state files atômicos, CAS, helpers
03Stop hook lifecycle real — BLOCK/APPROVE por fase
04Extração de findings + rotação de personas por rodada
05Fase de sumarização — o loop não termina em silêncio
06Comandos utilitários: status, doctor, cancel, rollback
07Safety pass — ERR trap, lockfile, sweeper, validação de cwd

Fazer

  • Verificar cada prompt antes de continuar
  • Ter o SPEC.md aberto como referência constante
  • Testar isoladamente cada nova camada
  • Construir o estado antes de construir o comportamento

Evitar

  • Passar toda a spec em um único prompt gigante
  • Avançar sem confirmar que o passo anterior funciona
  • Misturar responsabilidades em um único passo
  • Depurar múltiplas camadas simultaneamente
2

O SPEC.md: O Blueprint Antes do Código

Arquitetura em texto como referência viva

Antes de um único arquivo de código ser escrito, o Claudex tinha um SPEC.md completo. Não um documento de requisitos corporativo — um blueprint técnico de página única que Claude pode consultar a qualquer momento durante o build. É a diferença entre construir com um mapa e construir com esperança.

💡 Conceito Principal

O SPEC.md é a fonte de verdade, não o código

O SPEC define: o que o sistema faz, as garantias hard que nunca podem ser violadas, os ciclos de vida completos de cada modo, a estrutura dos state files com cada campo e tipo, os canais de comunicação entre componentes, as primitivas de segurança e as variáveis de ambiente configuráveis. Tudo em uma página que cabe na janela de contexto.

Ciclo de Vida

drafting → reviewing → summarizing → done, com tabela por fase indicando quem age e o que o hook faz

State File

Cada campo definido: tipo, notas, valores possíveis. review_id com regex. review_id como padrão YYYYMMDD-HHMMSS-xxxxxx

File Tree

Estrutura completa de diretórios com cada arquivo nomeado e sua responsabilidade

Dica Prática

Mantenha o SPEC.md aberto em outra aba enquanto faz o build. Cada prompt de construção começa com "Read SPEC.md if it's in this folder; that's the source of truth." Isso ancora Claude no blueprint mesmo quando o contexto da conversa cresce.

3

As 6 Garantias de Segurança do Sistema

Invariantes inegociáveis que o sistema nunca viola

O SPEC.md define seis primitivas de segurança que precisam ser verdadeiras em todo momento do ciclo de vida do Claudex. Elas não são features — são restrições do design. Violá-las significa que o sistema pode travar o usuário, corromper estado ou criar loops infinitos silenciosos.

1

ERR Trap Fail-Open

A primeira linha ativa do hook instala trap '... approve; exit 0' ERR. Qualquer erro não tratado retorna approve. O usuário NUNCA fica preso.

2

Escritas Atômicas de Estado

Toda mutação vai via tmp + rename. Arquivos nunca ficam parcialmente escritos. Um crash no meio de uma escrita não corrompe o estado.

3

CAS em Transições de Fase

Compare-And-Swap: claudex_phase_transition só escreve se a fase atual corresponde ao from esperado. Impede duas paths de avançar o mesmo loop simultaneamente.

4

Lockfile + Liveness de PID

O PID armazenado pode ser testado com kill -0. Detecta se o processo pai ainda está vivo.

5

Sweeper de Loops Stale

find -mmin +15 remove loops abandonados em cada invocação de start-loop.sh. Configurável via CLAUDEX_STALE_MINUTES.

6

Validação de cwd

O estado armazena repo_root. O hook falha aberto se pwd != repo_root. O hook pode ter sido disparado em um projeto diferente do onde o loop começou.

⚠️ Atenção

Essas seis garantias foram identificadas no SPEC antes do primeiro prompt ser escrito. Não foram descobertas durante o desenvolvimento. Sistemas de segurança precisam ser planejados como restrições, não adicionados como features posteriores.

4

Prompt 01 — Esqueleto do Plugin

Estrutura e fail-open hook — o primeiro passo verificável

O primeiro prompt não constrói lógica real. Ele constrói o esqueleto: os manifestos, os comandos placeholder e, mais importante, um hook que falha aberto por padrão. A meta é verificar que o plugin carrega no Claude Code antes de adicionar qualquer lógica substantiva.

💡 O Que o Prompt 01 Constrói
  • Manifesto do marketplace em .claude-plugin/marketplace.json
  • Manifesto do plugin em plugins/claudex/.claude-plugin/plugin.json
  • 6 arquivos de slash command com frontmatter YAML (placeholder)
  • hooks.json registrando o Stop hook com timeout 60s
  • stop-hook.sh com ERR trap fail-open e stub incondicional
  • tests/platform-validation.sh com assertions coloridas

O Prompt Real (Cole no Claude Code)

01_scaffold.md
I want to build a Claude Code plugin called `claudex`. Read `SPEC.md`
if it's in this folder; that's the source of truth.

For this first pass, just scaffold the layout. No real logic yet.
I want to verify the plugin loads in Claude Code before we wire up
anything substantive.

Build:

1. The marketplace manifest at `.claude-plugin/marketplace.json` and
   the plugin manifest at `plugins/claudex/.claude-plugin/plugin.json`.
   Author name `promptadvisers`. Description matches the spec.

2. Six slash command files under `plugins/claudex/commands/`:
   `plan.md`, `review.md`, `status.md`, `doctor.md`, `cancel.md`,
   `rollback.md`. Each one for now is a placeholder that just `echo`s
   "TODO" so I can confirm the commands surface in Claude Code's
   slash-command list. Use proper YAML frontmatter (`description`,
   `allowed-tools: Bash`).

3. `plugins/claudex/hooks/hooks.json` registering a `Stop` hook that
   calls `${CLAUDE_PLUGIN_ROOT}/hooks/stop-hook.sh` with a 60s timeout
   and a `statusMessage`.

4. `plugins/claudex/hooks/stop-hook.sh`. **Critical**: this is
   fail-open everywhere from day one. Install an `ERR` trap that prints
   `{"decision":"approve"}` on any unhandled error and exits 0. The
   default body for now: read stdin, log "no logic yet", print approve.
   The user must NEVER get trapped because the hook crashed.

5. `plugins/claudex/tests/platform-validation.sh`. A simple bash test
   that asserts the hook is executable, returns valid JSON when fed `{}`
   on stdin, and fail-opens on garbage input. Print colored ✓/✗ per
   check. Exit non-zero on any failure.

Don't write any state-machine code yet. That's the next prompt. Just
the skeleton + the unconditional fail-open hook.

Once you're done, run `bash plugins/claudex/tests/platform-validation.sh`
and tell me what it says.
Dica Prática

O teste de plataforma no final não é opcional. Antes de avançar para o Prompt 02, você precisa ver todas as assertions passando. "Parece certo" não é uma fronteira de verificação válida.

5

Por Que "Falhar Aberto" é Inegociável

Hooks nunca podem bloquear o trabalho do usuário

Um Stop hook que retorna BLOCK diz ao Claude Code: "não deixe o usuário encerrar este turno ainda". Se esse hook crashar silenciosamente, sem retornar nada, o Claude Code pode ficar esperando indefinidamente. A filosofia fail-open significa: em caso de dúvida, deixar passar. Um loop que termina cedo demais é ruim. Um usuário preso em um loop que nunca termina é inaceitável.

💡 Conceito Principal

O ERR trap como primeira linha ativa

A primeira coisa que o stop-hook.sh faz é instalar um trap global de erro. Não na segunda linha. Não depois das importações. A primeira linha.

trap 'echo "{\"decision\":\"approve\"}" ; exit 0' ERR
🔍 Por Que Isso Importa na Prática
  • O hook roda em cada fim de turno do Claude. Uma falha de script em qualquer sessão de trabalho normal travaria o usuário.
  • Dependências externas podem estar ausentes (python3, um arquivo de estado corrompido). O fail-open absorve esses casos.
  • Durante o desenvolvimento, bugs no hook são inevitáveis. Sem fail-open, cada bug bloquearia a sessão do desenvolvedor.

O que acontece quando o hook recebe entrada inesperada

1

Hook recebe JSON malformado no stdin

2

Qualquer comando shell falha → ERR trap dispara automaticamente

3

Trap imprime {"decision":"approve"} no stdout

4

Claude Code recebe approve, usuário nunca percebe o problema

6

Prompt 02 — A Máquina de Estados

Gerenciando sessões do loop com state files atômicos

O segundo prompt introduz o coração do Claudex: a máquina de estados. Cada loop de planejamento é rastreado em um arquivo .state YAML-ish isolado. O prompt constrói os helpers de baixo nível que todo o resto do sistema usa — e os testa em isolamento completo antes de qualquer hook lifecycle ser escrito.

🔍 O Que o Prompt 02 Constrói
claudex_new_review_id — gera IDs únicos YYYYMMDD-HHMMSS-xxxxxx
claudex_validate_review_id — regex estrito, rejeita path traversal
claudex_state_write — escrita atômica via tmp + rename
claudex_state_read_field — grep do valor YAML-ish
claudex_state_set_field — sed in-place + bumpa last_updated_at
claudex_phase_transition — CAS: só escreve se fase atual bate
claudex_sweep_stale — remove loops com +15min sem atividade
claudex_find_active_loop — retorna o loop mais recente por mtime

O Prompt Real (Cole no Claude Code)

02_state_machine.md
We need the state machine before we wire the hook lifecycle. Claudex
tracks each loop in a YAML-ish file under
`.claude/claudex/<review_id>.state`. Per-loop, never shared. See
`SPEC.md` for the full field list.

Build:

1. `plugins/claudex/scripts/state-helpers.sh`. Sourceable. Exposes:
   - `claudex_new_review_id` — generates `YYYYMMDD-HHMMSS-XXXXXX`
     (six lowercase hex chars at the end).
   - `claudex_validate_review_id <id>` — strict regex check; returns 0/1.
   - `claudex_state_write <file> <content>` — atomic. Write to
     `${file}.tmp.$$` then `mv -f`. Never partial files.
   - `claudex_state_read_field <file> <field>` — grep the YAML-ish value.
   - `claudex_state_set_field <file> <field> <value>` — sed in place via
     tmp + rename. Also bumps `last_updated_at` to now (UTC ISO 8601).
     Don't recursively bump itself when you ARE setting `last_updated_at`.
   - `claudex_phase_transition <file> <from_phase> <to_phase>` —
     compare-and-swap. Only writes if current phase matches `from`.
     Updates `last_updated_at` in the same write. Returns 0/1.
   - `claudex_lock_write <file>` — writes `$$`.
   - `claudex_lock_is_active <file>` — `kill -0` on the stored PID.
   - `claudex_sweep_stale` — `find -mmin +$CLAUDEX_STALE_MINUTES`
     (default 15) on `*.state` files; remove the state file plus its
     `.lock`, `-runner.sh`, `-prompt.txt`, and per-review subfolder.
   - `claudex_find_active_loop` — print path to the most-recent state
     file (by mtime) or return 1 if none.

2. `plugins/claudex/scripts/start-loop.sh`. Called by `/claudex:plan`
   and `/claudex:review`. Behavior:
   - Parse flags before the topic: `--rounds N`, `--from-draft`,
     `--skip-interview`, `--interviewed`. Reject `--rounds 0` and
     non-integers with a clear error. Reject `--from-draft` if `PLAN.md`
     is missing.
   - Refuse to start if any existing state file has phase NOT in
     `{done, cancelled, errored}`. Phase-based concurrency, NOT
     file-presence.
   - Sweep stale loops first (`claudex_sweep_stale`).
   - Generate a `review_id`, write the initial state file atomically,
     write a lockfile.
   - Print initial instructions to stdout.

3. Extend `plugins/claudex/tests/platform-validation.sh` with sections
   that exercise every helper: id generation, validation rejecting bad
   formats including `../../../etc/passwd`, atomic write round-trip,
   CAS valid + stale, sweeper, lockfile alive vs dead PID,
   active-loop finder.

Hook lifecycle stays a fail-open stub for now. We're just verifying
the state machine in isolation.

Run `bash plugins/claudex/tests/platform-validation.sh` and tell me
what passes.
Dica Prática

Note que o Prompt 02 explicitamente diz "Hook lifecycle stays a fail-open stub for now". A máquina de estados é testada completamente em isolamento. Isso é intencional: você não pode testar corretamente o lifecycle do hook se os helpers que ele usa ainda não foram verificados.

7

Escrita Atômica e CAS: Estado que Nunca Corrompe

Os dois padrões que tornam o estado confiável em qualquer condição

Dois padrões de engenharia clássicos aparecem repetidamente no Claudex: escrita atômica via tmp + rename e transições de fase via Compare-And-Swap. Juntos, eles garantem que o estado nunca fica em um estado intermediário inconsistente, mesmo que o processo seja interrompido no meio de uma operação.

Escrita Atômica (tmp + rename)

# Errado: escrita direta pode ser parcial
echo "$content" > "$state_file"

# Certo: tmp + rename é atômico no mesmo fs
tmp="${state_file}.tmp.$$"
echo "$content" > "$tmp"
mv -f "$tmp" "$state_file"

O mv no mesmo filesystem é uma operação atômica do kernel. Ou o arquivo antigo existe, ou o novo existe. Nunca um arquivo vazio ou parcialmente escrito.

CAS — Compare-And-Swap

# claudex_phase_transition <file> <from> <to>
# Só escreve se a fase atual == from_phase
current=$(claudex_state_read_field "$f" phase)
if [[ "$current" != "$from_phase" ]]; then
  return 1  # outro processo já avançou
fi
# Escreve nova fase atomicamente
claudex_state_set_field "$f" phase "$to_phase"

Impede duas invocações do hook de avançar o mesmo loop simultaneamente. Sem CAS, dois BLOCKs concorrentes poderiam criar estados inconsistentes.

🔍 Por Que Isso Não é Óbvio

Claude Code pode disparar o Stop hook múltiplas vezes em rápida sucessão se o usuário encerrar o turno enquanto o hook ainda está processando. Sem CAS, dois disparos simultâneos do hook poderiam ambos ler phase=drafting, ambos escrever a transição para reviewing, e criar dois runners para a mesma rodada. Com CAS, o segundo disparo encontra phase=reviewing e retorna 1 sem escrever.

Dica Prática

Esses dois padrões — tmp+rename e CAS — aparecem em sistemas de banco de dados, sistemas operacionais e sistemas distribuídos há décadas. Aplicá-los em shell script não é over-engineering: é reconhecer que o Claudex é um sistema concorrente com estado compartilhado que precisa das mesmas garantias.

Resumo do Módulo 2.1

O que você aprendeu

  • Por que builds incrementais com fronteiras de verificação produzem sistemas mais confiáveis
  • Como o SPEC.md funciona como blueprint e fonte de verdade durante o build
  • As 6 primitivas de segurança que o sistema nunca viola
  • O Prompt 01: esqueleto do plugin com fail-open hook desde o início
  • Por que fail-open é inegociável em qualquer hook de sistema
  • O Prompt 02: máquina de estados com helpers testados em isolamento
  • Escrita atômica (tmp+rename) e CAS como garantias de consistência de estado

Próximos passos

No Módulo 2.2, você vai ver o Prompt 03 — onde o hook recebe seu lifecycle real, aprendendo a orquestrar as transições de fase, gerar runner scripts para o Codex e fazer o loop se tornar verdadeiramente autônomo.

Também verá o Prompt 04 (extração de findings para economia de tokens) e o Prompt 05 (fase de sumarização para que o loop não termine em silêncio).