🗄️ State machine em _install-state.json
O ficheiro ~/.claude/skills/_install-state.json é a fonte da verdade. Tudo o que vês em /install-status, no gate, e no /doctor vem daqui.
As 6 fases
- 1. prereqs — Node, Python, Git, Claude Code validados
- 2. sinapsis-engine — Sinapsis copiado para ~/.claude
- 3. context-files — soul.md, me.md, decisions-log.md criados
- 4. operator-state — operator-state.json inicializado
- 5. welcome-completed — welcome-quick-win passou (gera 1 entregável)
- 6. deep-dive-completed — entrevista 22-25 dimensões (deferrable)
Os 5 estados possíveis
💡 5 required + 1 deferrable
As primeiras 5 fases são required: true (instalação só está "pronta" quando todas done). A 6ª (deep-dive) é deferrable — podes saltá-la no início e fazer mais tarde com /deep-dive.
⛔ Hook SessionStart (_install-gate.sh)
Script em ~/.claude/skills/_install-gate.sh. Corre antes de cada sessão começar. Lê o state file; se há fases required pendentes, injeta aviso ao modelo via additionalContext.
Anatomia do hook
#!/usr/bin/env bash
# ~/.claude/skills/_install-gate.sh
# SessionStart hook — fail-open if anything breaks
set +e # never crash the session
STATE_FILE="$HOME/.claude/skills/_install-state.json"
[[ ! -f "$STATE_FILE" ]] && exit 0 # no state → no gate
# Parse state via node (fallback to no-op if node missing)
command -v node >/dev/null 2>&1 || exit 0
PENDING=$(node -e "
const s = require('$STATE_FILE');
const pending = Object.entries(s.phases)
.filter(([k,v]) => v.required && v.status !== 'done')
.map(([k]) => k);
console.log(JSON.stringify(pending));
")
[[ "$PENDING" == "[]" ]] && exit 0 # all done
# Emit additionalContext for the model
cat <<EOF
{"additionalContext": "INSTALLATION INCOMPLETE. Pending: $PENDING.
Do NOT respond to user requests. Tell them to run /install."}
EOF
🛡️ Fail-open
Se o hook crashar (script com bug, node em falta, JSON inválido), a sessão continua normalmente. Princípio: o gate nunca bloqueia o utilizador por erro nosso. Pior caso = sem aviso, melhor caso = aviso correto.
📥 additionalContext JSON injetado ao modelo
O hook devolve JSON com chave additionalContext. O Claude Code injeta isto no contexto da sessão antes de qualquer mensagem do utilizador. O modelo lê isto com prioridade.
📊 Fluxo de uma sessão
- Utilizador abre Claude Code no repo
- Claude Code corre todos os hooks SessionStart (incluindo o gate)
- Gate lê state file, vê que
welcome-completed: pending - Gate emite
{"additionalContext": "INSTALLATION INCOMPLETE..."} - Claude recebe o additionalContext + qualquer mensagem que o utilizador escreva
- Claude prioriza o additionalContext → responde "vamos primeiro completar instalação"
💡 Por que isto funciona
É enforcement estrutural, não confiança no modelo. Sem o additionalContext, o Claude poderia "esquecer" e responder direto. Com ele, é praticamente impossível porque vê o aviso antes da tua mensagem.
📊 Comandos /install e /install-status
Duas peças diferentes com responsabilidades claras: /install age, /install-status só observa.
/install (orquestrador)
- • Lê state, identifica próxima fase pendente
- • Executa fases conversacionais (welcome, deep-dive)
- • Pede para correres bash em fases técnicas
- • Aceita
--resume(default) e--force-reinstall - • Atualiza state após cada fase
/install-status (dashboard)
- • Read-only — não toca em nada
- • Mostra estado das 6 fases em tabela visual
- • Indica próxima ação sugerida
- • Reporta drift entre state e disco
- • Útil para "estou bloqueado?" sem risco
🎯 Fases técnicas vs conversacionais
Técnicas (prereqs, sinapsis-engine, context-files, operator-state) → instalador bash. Conversacionais (welcome-completed, deep-dive-completed) → entrevista dentro do Claude Code. /install sabe qual chamar em cada fase.
🩺 /doctor + validação profunda
O /doctor invoca a skill health-check. Não é só test -f <ficheiro> — faz validação real do conteúdo.
O que valida realmente
- • JSON parseable:
_install-state.json,operator-state.json,settings.json - • Hooks executáveis:
_install-gate.shtem permissão +x - • Conteúdo >100 chars:
soul.md,me.mdnão estão vazios - • Estrutura de pastas:
brand-context/voice/,context/existem - • Settings registado: hook em
~/.claude/settings.json - • Skills válidas: cada SKILL.md tem frontmatter parseável
Output 🟢🟡🔴
🟢 OK State file valid (6 phases) 🟢 OK Sinapsis hooks executable 🟡 WARN brand-context/voice/voice-profile.md empty (12 chars) 🟢 OK All 23 skills have valid frontmatter 🔴 FAIL install-gate hook NOT registered in settings.json Suggested fixes: 1. Run /deep-dive to populate voice-profile.md 2. Run bash scripts/install.sh --resume to re-register hook
💡 Auto-fix com confirmação
Para problemas comuns, /doctor propõe o comando exato para corrigir. Não executa automaticamente — pede confirmação. Tu mantens o controlo.
🌊 Drift detection
Drift = state diz uma coisa, disco diz outra. O /doctor cruza os dois e apanha incoerências que de outro modo passariam despercebidas.
Cenários de drift comuns
State diz context-files: done mas context/me.md tem 0 bytes (apagaste sem querer).
→ /doctor reverte state para pending e sugere /install --resume.
Sync entre 2 máquinas correu mal — state da máquina A diz done mas a máquina B não tem os ficheiros.
→ /doctor deteta na máquina B, propõe reinstalar a fase em falta.
Mudaste de versão do OS (git pull) e novo install adicionou fase nova — state antigo não a tem.
→ /doctor injeta a fase nova como pending sem perder as done existentes.
🔍 Quando correr /doctor
- • Após git pull (sobretudo se houve mudanças em scripts/ ou .claude/)
- • Quando trocas de máquina ou sincronizas via cloud
- • Antes de começar trabalho importante (rápido sanity check)
- • Quando algo se comporta de forma estranha sem motivo claro
💡 Filosofia
State file é hipótese, disco é facto. Quando divergem, o disco ganha. /doctor ajusta o state para refletir a realidade, e propõe ações para reconciliar.
✅ Resumo do Módulo
Próxima Trilha:
Trilha 3 — Brand Context: voice profile com 3 registos, ICP, positioning. A peça que faz outputs soarem a TI.