12. /propose: uma página
Depois deste capítulo você consegue transformar uma linha da fila em uma página com o /propose, ler a página como o registro do que o agente entendeu e do que o /apply vai construir, cobrir os buracos dela por conversa antes de existir qualquer código, e dividir uma entrega que não cabe em uma página.
Você sabe que o /propose decide o que os documentos do projeto já respondem, nomeando a fonte na página, e rascunha as linhas de Comportamento com o que precisa falhar e os casos de borda, então o seu trabalho é corrigir a página, não escrevê-la.
Você também consegue explorar um problema que ainda não entende conversando com o agente, antes de existir uma página.
E consegue definir várias linhas em um comando, um subagente para cada, e dizer o que o comando pode deixar que eles decidam sozinhos ou construam.
O problema
Um agente que planeja e constrói no mesmo fôlego toma as decisões no meio da construção, onde você não as vê. O que você não decidiu, ele decide por você, de um jeito plausível, e você encontra o palpite quando um usuário o encontra. A página põe cada decisão onde você consegue lê-la antes de existir qualquer código, e corrigi-la ali custa um turno de conversa.
O que é uma entrega
Todo trabalho em um projeto com o focus-kit é uma entrega: a menor mudança que tem valor, o que outros métodos chamam de tarefa ou item de trabalho.
Ela tem como nome um slug (o nome curto da entrega), palavras minúsculas unidas por hífens, como emprestar-livro, escrito uma vez na linha da fila e usado dali em diante para tudo o que é dela: a página work/<slug>.md, o argumento do /propose <slug> e do /apply <slug>, e a última linha do commit que a fecha.
Uma entrega cabe em uma página.
Se não cabe, o escopo ainda não foi entendido, e são duas entregas.
O que o /propose faz
O /propose <slug> conversa com você até o escopo caber em uma página, e o que os documentos do projeto já respondem, ele não pergunta: o arquivo do comando no kit manda decidir, escrever a decisão na página e nomear o documento de onde ela veio, então, se o documento estiver errado, você corrige uma vez, na revisão, em vez de responder a mesma pergunta duas vezes.
Ele só pergunta onde os documentos deixam mais de uma leitura e nenhum a fecha: primeiro a avaliação dele, em prosa, e a recomendação dele primeiro em cada pergunta.
Para decidir, ele lê antes de perguntar: o docs/00 para o produto e as suas regras, o docs/03 para as palavras que a página precisa usar, o docs/05 para os slots do projeto e o formato da página, o docs/06 para o que vem antes e depois da linha, work/ para as entregas em andamento, e o docs/01 para onde a mudança mora no código.
Em uma linha que já está [?], ele diz o que a linha espera e só segue quando você diz que está resolvido; em uma linha cujo after nomeia uma linha que ainda não está [x], ele diz o mesmo e não começa, e assim em uma linha cujo token tem - primeiro, (-A) ou (--), enquanto uma linha acima dela ainda não está [>] ou além (capítulo 14).
No trunk ele lê essas marcas na fila da pasta onde a sessão roda; com um branch ou um worktree por entrega, a fila do branch principal, onde ele roda e de cujo HEAD parte o worktree da entrega, mostra cada linha como estava até o merge dela, então ele lê a própria linha e cada linha que o seu after nomeia e, quando o seu token espera, toda linha acima dela no branch daquele slug, local ou remoto, com as linhas que só um branch tem, reconciliadas pelo slug, e depois de um git fetch uma linha cujo branch existe está ocupada, mostre o que mostrar a fila do branch principal (capítulo 14).
Em uma linha que ele pode começar, ele primeiro se coloca onde o slot Git do projeto põe a entrega: no trunk, a pasta onde a sessão roda, sem nada a criar; nos outros casos, o branch ou worktree com o nome do slug, com o remoto consultado antes por esse branch, já que um branch que já está lá quer dizer que a linha está ocupada, depois criado, com o seu branch enviado na hora, antes de a página existir, então a linha fica ocupada em todo clone, ou reutilizado quando a definição é retomada, com o rascunho da página deixado para o slug trazido para ele (capítulos 18 e 19).
A primeira edição dele ali marca a linha como [~] na fila, então quem a lê vê uma entrega sendo definida, e fora do trunk a marca e a página vão com o branch da entrega, onde o /apply constrói e o merge as leva.
Com um worktree por entrega a própria sessão não se move: o /propose roda em main/ e escreve a marca e a página no worktree da entrega, que o manual do contêiner deixa uma sessão em main/ editar (capítulo 19).
Só quando a página, work/<slug>.md, está completamente definida, não apenas escrita, a marca vira [>]: uma página escrita enquanto uma questão de escopo ainda está sendo conversada deixa a linha dela [~] (o capítulo 14 diz quando uma página está completa).
Com a página escrita, ele julga o token da linha por ela, o que a página tira das páginas acima e em que arquivos o Contrato mexe, e corrige o token na linha quando ela diz outra coisa, dizendo isso (capítulo 14).
Ele termina mostrando essa linha da fila, [>] emprestar-livro ... para a página abaixo, e pedindo que você leia e questione a página, e depois rode o /apply em uma sessão nova, aberta no worktree da entrega quando há um, cujo caminho ele escreve por extenso.
Quando descobre, enquanto define, que o escopo espera uma resposta que ninguém deu ainda ou outra linha que precisa ser feita antes, ele escreve a página até onde ela vai e marca a linha como [?] no lugar, com · resume: propose e o que ela espera.
Ele nunca escreve, edita nem gera código, migration, teste ou configuração.
O README do kit dá o motivo: "O escopo não cresce durante a implementação porque quem decidiu não está na sala."
O /apply começa em uma sessão nova, com o contexto limpo, aberta no worktree da entrega quando há um (capítulo 13), e a página é tudo o que ele leva desta conversa, então a página precisa guardar tudo de que a construção precisa.
O próprio /propose roda onde você escolhe: na conversa que pediu a mudança, que guarda o que foi dito ali, ou numa sessão nova, que parte dos documentos e do rascunho da página, quando há um (capítulo 11); nos dois casos, o que só a conversa trouxe vai para a página, e você lê e corrige a página na sessão que a escreveu, ou, quando um comando definiu várias linhas, na sessão que o digitou (abaixo), antes do /apply.
A página
O formato é fixado no §3 do docs/05 do projeto e é o mesmo em todo projeto:
- Objetivo. Uma frase: o que o usuário consegue fazer depois.
- Comportamento. Cenários verificáveis na linguagem do usuário, cada um uma ação com uma entrada concreta e o resultado que o usuário vê, incluídos os casos que precisam falhar e os casos de borda; cada linha vira um teste ou uma checagem manual. O
/proposeos rascunha a partir dos documentos, e você os corrige em vez de escrevê-los. - Contrato. Dados, schema, API, formatos de mensagem, ou "nenhum".
- Estados. Vazio, carregando, erro, offline, uma linha cada, ou "os padrões"; só quando há uma tela.
- Referência visual. Onde está o design, e os tamanhos de tela; só quando há uma tela.
- Fora do escopo. O que não entra, com meia linha de motivo cada.
- Pronto quando. Uma lista mecânica: os testes passam, a verificação está verde, o screenshot confere.
Esta é uma página para a biblioteca de empréstimos da Parte I, escrita para este capítulo:
# emprestar-livro
**Objetivo.** Um bibliotecário registra que um membro pegou um exemplar
emprestado, e o sistema recusa quando as regras dizem não.
**Comportamento.**
* Um membro sem livros atrasados pega um exemplar disponível, e o exemplar
aparece como emprestado a ele, com data de devolução 21 dias depois
(docs/03).
* Um membro com um livro atrasado é recusado com "Devolva primeiro os seus
livros atrasados"; nada é registrado.
* Um membro suspenso é recusado com "A sua matrícula está suspensa"; nada
é registrado.
* Dois bibliotecários emprestam o último exemplar no mesmo momento: um
consegue e o outro vê "Este exemplar acabou de ser emprestado a outra
pessoa".
* Um membro cujo único empréstimo vence hoje pega um exemplar disponível:
vencer hoje ainda não é estar em atraso.
**Contrato.**
Tabela `emprestimo`:
* `exemplar_id`, `membro_id`: texto, não nulo.
* `emprestado_em`, `devolver_em`: texto, uma data como `YYYY-MM-DD`, não
nulo.
* `devolvido_em`: texto, uma data como `YYYY-MM-DD`, nulo enquanto o
exemplar está fora.
Índice único em `exemplar_id` onde `devolvido_em` é nulo: um empréstimo
aberto por exemplar, e um exemplar cujo empréstimo foi devolvido pode ser
emprestado de novo.
`emprestar(exemplar, membro, hoje):
Result<Emprestimo, RecusaDeEmprestimo>` com `RecusaDeEmprestimo =
"TemLivrosEmAtraso" | "JaEmprestado" | "MembroSuspenso"`.
**Estados.** Os padrões.
**Referência visual.** A tela de empréstimo no arquivo de design, com 390
e 1280 pixels de largura.
**Fora do escopo.**
* Devolver um exemplar: uma entrega própria, `devolver-livro`, a seguinte
na fila.
* Reservas: não estão no docs/00.
* Multas: o docs/00 as lista como uma decisão em aberto, então ninguém
decide isso aqui.
**Pronto quando.**
* [ ] Os testes unitários de `emprestar` provam a data de devolução 21
dias depois, a recusa de um membro com um livro atrasado e de um membro
suspenso, e que um empréstimo que vence hoje não conta como atraso.
* [ ] Os testes de `emprestimoPedido`, com repositórios falsos, provam
que um empréstimo é salvo e o seu estado é `Emprestado`, e que cada
recusa, incluída `JaEmprestado` vinda de `inserirEmprestimo`, dá
`Recusado` levando essa recusa; para o membro com um livro atrasado e
o suspenso, nada chama `inserirEmprestimo`.
* [ ] O teste do repositório, com as migrações reais, prova que o
primeiro empréstimo aberto de um exemplar é salvo e que um segundo
devolve `JaEmprestado`, e que um exemplar cujo empréstimo foi devolvido
é emprestado de novo.
* [ ] Testes ponta a ponta provam que um exemplar emprestado mostra o
membro e a sua data de devolução, e que cada recusa mostra a sua
mensagem: "Devolva primeiro os seus livros atrasados.", "A sua
matrícula está suspensa." e, com um empréstimo aberto do exemplar já
salvo, "Este exemplar acabou de ser emprestado a outra pessoa."
* [ ] `npm run verify` está verde.
* [ ] A tela de empréstimo confere com o design nas duas larguras.
Leia a página como o relato do agente sobre o que ele entendeu.
Cada linha de Comportamento pode ser conferida; o Contrato é exato; o Fora do escopo nomeia o que alguém poderia ter suposto que estava dentro; o Pronto quando é uma lista que uma máquina ou uma pessoa consegue marcar.
O Pronto quando também diz qual teste do capítulo 5 prova cada linha de Comportamento: as regras nos testes unitários de emprestar, que uma recusa não salva nada nos testes do orquestrador, a disputa pelo último exemplar no teste do repositório, e o que a tela mostra nos testes ponta a ponta.
A disputa é do repositório: dois bibliotecários no mesmo instante só se encontram no banco, e nenhuma função pura os vê.
Cada decisão tirada de um documento o nomeia: os 21 dias vêm do docs/03, e as reservas e as multas do Fora do escopo vêm do docs/00.
O agente rascunhou os casos que precisam falhar e o caso de borda: o Contrato já tinha MembroSuspenso, então um membro suspenso ganha uma linha, e uma regra sobre livros atrasados implica o dia em que um empréstimo vence, que ainda não é atraso.
O Contrato é a única seção que precisa ser exata.
O motivo do kit: "uma tela errada se corrige numa sessão, uma coluna errada é uma migration, e uma regra de acesso errada já vazou".
Uma tela é código que você reescreve; uma coluna guarda dados, e mudá-la exige mover os dados que já estão lá; uma regra de acesso decide quem lê o quê, e uma errada já deixou dados saírem antes que alguém releia a página.
Nenhuma correção posterior desfaz a terceira.
Por isso o Contrato acima dá a cada coluna o seu tipo e se ela pode ser nula, as datas como texto, como o hoje do capítulo 3, e a regra do índice em palavras: ele guarda só os empréstimos abertos.
Leia a página antes do /apply
A página é escrita para ser lida, e as perguntas a fazer são estas:
- Cada linha de Comportamento pode ser conferida, como teste ou à mão?
- O Comportamento inclui o que precisa falhar e os casos de borda?
- O Contrato é exato, até os nomes e os tipos?
- O Fora do escopo nomeia algo que você supôs que estava dentro?
- Cada decisão tirada de um documento o nomeia, e você concorda com ela?
- Você discorda de alguma escolha que o agente fez por conta própria?
- O Pronto quando lista o que faria você dizer "pronto", e nada mais vago?
Você pede cada correção na mesma conversa, ou, para uma página de um comando digitado com vários slugs, na sessão desse comando (abaixo), e o agente escreve a correção: na página, e em qualquer documento que ela toque.
Você não edita a página à mão: o agente sabe qual documento é dono de cada fato, então uma correção que toca o vocabulário ou a fila entra lá também, e a conversa guarda o motivo.
Se o /propose pergunta o que um documento já diz, como quantos dias dura um empréstimo quando o docs/03 diz 21, diga isso na conversa: a resposta pertence à página, com a sua fonte.
Se o Comportamento só tem o caminho feliz, um exemplar disponível emprestado a um membro em dia, peça ao agente os casos que precisam falhar e os casos de borda antes do /apply: uma pessoa que não conhece a ferramenta sendo construída e deixa o resultado esperado para o agente recebe uma solução, só o caminho feliz, que o cliente rejeita.
A ordem é a barata.
Um buraco achado na página custa um turno; achado depois do /apply, custa outro /apply, o comando mais caro, que constrói, testa e prova de novo.
No Ninjobs, a página da entrega que calcula a pontuação de compatibilidade de um candidato descobriu, enquanto era escrita, que a idade aproximada de um candidato já vazava no primeiro nível de privacidade pelas datas das suas experiências; isso virou uma linha para uma entrega posterior, e nenhum código foi escrito além dela.
Os hosts têm o seu próprio jeito de planejar dentro de uma sessão, como o modo de plano (plan mode) do Claude Code, em que "o Claude lê arquivos e propõe um plano, mas não faz nenhuma edição até você aprovar";1 a página é o que sobrevive à sessão: um arquivo no repositório, escrito a partir dos documentos do projeto e com as palavras deles, marcado na fila, lido por uma sessão nova para construí-lo, e guardado em work/done/ com o que aconteceu.
Várias linhas em um comando
O /propose aceita mais de um slug: /propose buscar-catalogo renovar-emprestimo, em duas linhas da biblioteca do capítulo 14, define as duas em um comando.
A sessão que o recebe abre um subagente por slug, um agente que ela lança com uma mensagem, que é uma sessão nova: ele só tem o que essa mensagem e os arquivos do projeto dizem, e roda o arquivo do comando no seu próprio slug, como /propose renovar-emprestimo digitado sozinho rodaria.
Ela abre ao mesmo tempo todo subagente cuja linha os tokens e o after deixam começar, não um depois do outro, e uma linha que ainda espera quando os outros terminam é relatada a você, não esperada (capítulo 14).
No trunk os subagentes dividem a pasta onde a sessão roda, cada um mudando só a sua linha e a sua página; com um worktree por entrega cada um escreve no worktree do seu slug, que ele cria a partir de main/, ou reutiliza quando já existe, como faz um /propose digitado sozinho (capítulo 19).
A própria sessão não edita nada: as marcas, as páginas e os worktrees são trabalho dos subagentes.
Um subagente não consegue perguntar a você: onde perguntaria, ele relata a pergunta com o que você precisa para respondê-la e para; a sessão pergunta a você e manda a sua resposta de volta, para esse subagente onde o host consegue retomá-lo, senão para um novo aberto no slug, que retoma o [~] da linha pela palavra do seu comando.
Você também lê e corrige cada página ali: pede na sessão que digitou o comando, e ela manda a sua correção para um subagente no slug do jeito que manda uma resposta, e corrigir a página e qualquer documento que a correção toque é trabalho desse subagente.
Os comandos mantêm as configurações do capítulo 8 que impedem um host de rodar uma skill por conta própria, o disable-model-invocation no Claude Code e no Copilot CLI e o arquivo ao lado de cada skill no Codex: o comando que você digitou nomeia todos os slugs, e cada subagente tira o seu slug da mensagem que o abre e roda pela sua palavra, então nenhum subagente precisa que uma configuração seja tirada.
Tirar uma delas traria de volta o que ela impede: uma mensagem que só menciona um comando rodando esse comando (capítulo 8), e um agente a quem se pediu uma mudança seguindo para o /propose em vez de parar na linha da fila (capítulo 11).
O seu comando também pode dizer duas coisas.
Decidir sozinho: cada pergunta que um subagente teria feito é respondida pela sua própria recomendação e escrita na página como resposta do agente, a pergunta, a resposta e o porquê, então a sua leitura a encontra entre as escolhas que o agente fez por conta própria (o capítulo 19 mostra essa lista).
Construir também: quando uma página chega a [>], um novo subagente roda o /apply nela, mandado para o caminho do worktree da entrega quando há um, e a página diz que foi construída antes de você a ler; você lê as páginas e os diffs no fim, e cada commit continua sendo seu, uma entrega por vez (capítulo 13).
Construir também abre mão da ordem barata acima: um buraco que a página mostraria em um turno custa, achado no diff, outro /apply.
Quando não cabe
Um escopo que não cabe em uma página são duas entregas: o /propose diz isso, propõe a divisão e escreve só a primeira página, e a segunda vira uma linha na fila, onde ela pertence.
No Ninjobs, a linha única da fila para uma vaga de emprego virou seis entregas em um /propose: a vaga, o empregador, as tags, a oferta, os benefícios e os idiomas, e o ciclo de vida; a página da primeira dizia que ela era o passo um de seis.
Cada uma das seis foi revisada na sua própria página e construída na sua própria sessão.
Quando você ainda não sabe
Alguns escopos não cabem em uma página porque ninguém sabe a resposta ainda: como uma API desconhecida se comporta, ou qual de duas abordagens se sustenta.
Outros métodos chamam o trabalho que descobre isso de spike; aqui ele é uma conversa com o agente, em qualquer sessão, antes de qualquer página.
O agente é um modelo de linguagem com quem você conversa, não um botão que roda um comando fixo, e ele lê os documentos do projeto, então o que ele sugere segue o projeto.
A conversa termina de um de três jeitos: uma linha nova na fila, com um rascunho da página guardando o que a exploração achou quando a linha não o comporta, do qual o /propose parte, nessa conversa ou numa sessão nova (capítulo 11); uma decisão que você aceita, escrita no documento que é dono dela (capítulo 7); ou nada, quando o que você achou deixa o plano como está.
Nos meus projetos isso foi raro, e a conversa sempre bastou, então nenhuma marca, comando ou tipo de entrega foi acrescentado para isso: nenhum nomearia um erro que tivesse pegado, que é o regulador do capítulo 16.
O que o time ganha
A página é a superfície de revisão do time. Um desenvolvedor, um gerente ou o cliente lê uma página na linguagem do docs/03 e sabe o que está para ser construído, o que não está, e o que "pronto" vai significar, antes de existir uma linha de código. No Caso A, o mesmo formato de página levou perguntas ao cliente e documentos para a passagem do projeto, então todo tipo de trabalho foi revisado do mesmo jeito, lendo a sua página (capítulo 21). E quando a construção termina, a mesma página registra o que aconteceu, então a história de uma decisão é um arquivo, com o nome do seu slug, em todo projeto que o time roda.
Pontos-chave
- Uma entrega é a menor mudança com valor, com um slug como nome, e cabe em uma página; se não cabe, são duas.
- O
/proposedecide o que os documentos respondem e nomeia a fonte na página, só pergunta onde eles deixam mais de uma leitura, com a recomendação primeiro, espera como oaftere o token da sua linha dizem, julgando-os, fora do trunk, pelo branch de cada slug, começa no branch ou worktree da entrega, onde o slot Git do projeto põe um, um worktree escrito de uma sessão que fica emmain/, enviando o seu branch no momento em que o cria, a reivindicação da linha, ou no trunk na pasta onde a sessão roda, e marca a linha[~]ali enquanto conversa e[>]quando a página está completamente definida, corrigindo o token pela página, ou[?]quando o escopo espera, nunca escreve código, e termina dando, com um worktree por entrega, o caminho do worktree, onde abre a sessão nova do/apply. /propose a babre um subagente por slug, uma sessão nova rodando o comando na sua própria linha, ao mesmo tempo onde os tokens e oafterdeixam, todos na única pasta no trunk ou cada um no seu worktree; a sessão não edita nada e repassa a você as perguntas de cada subagente e as suas correções a um subagente no slug; os comandos mantêm o que impede um host de rodar um comando por conta própria, odisable-model-invocatione o arquivo do Codex ao lado de cada skill, já que o seu comando nomeia todos os slugs; um comando instruído a decidir sozinho faz cada resposta ser escrita na página como do agente, e um instruído a construir também faz um novo subagente rodar o/applyem cada página[>], que diz que foi construída antes de você a ler.- A página tem um formato fixo e é a superfície de revisão do time, para código e para qualquer outra coisa que caiba em uma página; o Contrato é a única seção exata, porque uma coluna errada é uma migration.
- O
/proposerascunha o Comportamento, incluídos o que precisa falhar e os casos de borda; você lê a página antes do/apply, na sessão que a escreveu ou, para um comando digitado com vários slugs, na sessão desse comando, e a corrige pedindo ao agente, nunca à mão: um buraco na página custa um turno, depois do/applycusta outro/apply. - Quando ninguém sabe a resposta ainda, explore-a conversando com o agente, e termine com uma linha na fila, com um rascunho da página quando a linha não comporta o que você achou, uma decisão escrita onde ela pertence, ou nenhuma das duas; nada novo é preciso para isso.
-
Anthropic, "Common workflows", documentação do Claude Code, seção "Plan before editing", acesso em 2026-09-28. https://code.claude.com/docs/en/common-workflows#plan-before-editing ↩