<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://thiagopanini.github.io/panlabs-docs/blog</id>
    <title>Blog do panlabs</title>
    <updated>2026-09-07T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://thiagopanini.github.io/panlabs-docs/blog"/>
    <subtitle>Artigos assinados e datados sobre tecnologia, publicados por conta própria.</subtitle>
    <rights>© 2026 panlabs</rights>
    <entry>
        <title type="html"><![CDATA[O modelo de desenvolvimento com IA das skills do Matt Pocock]]></title>
        <id>https://thiagopanini.github.io/panlabs-docs/blog/desenvolvimento-com-skills-do-matt-pocock</id>
        <link href="https://thiagopanini.github.io/panlabs-docs/blog/desenvolvimento-com-skills-do-matt-pocock"/>
        <updated>2026-09-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Como um conjunto de vinte e cinco skills transforma conversa em issue, issue em ticket e ticket em pull request, demonstrado no repositório deste site.]]></summary>
        <content type="html"><![CDATA[<p>Faz um tempo que eu parei de pedir para um agente "implementar" alguma coisa
a partir de uma conversa solta. O fluxo hoje é outro: eu converso até a
decisão ficar de pé, publico a decisão numa issue, fatio a issue em tickets e
só então solto um agente por ticket. O agente não decide nada grande, e eu
não escrevo quase nenhum código.</p>
<p>Esse fluxo não é invenção minha. Ele vem de um conjunto de skills escrito pelo
Matt Pocock, e este acervo inteiro é construído com ele. A demonstração deste
artigo é o próprio blog que você está lendo: ele nasceu por esse caminho, e a
spec, os tickets e os pull requests estão abertos no GitHub.</p>
<div class="callout_hLSU calloutNote_r2HB" data-pd-component="callout" data-pd-variant="note"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.25" class="icon_o5kb iconSm_tpIB" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="sm" focusable="false" aria-hidden="true"><path d="M13 21h8M15 5l4 4M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"></path></svg><div class="calloutContent_OaNL"><p>Tudo aqui foi lido do conjunto instalado na minha máquina, em
<code>~/.claude/skills/</code>. Nenhum <code>SKILL.md</code> dele escreve o endereço público de onde
o conjunto veio, então esse endereço não aparece neste artigo. Para reproduzir,
instale o conjunto e leia os arquivos, que foi o que eu fiz para escrever isto.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="uma-skill-é-uma-pasta-com-instruções">Uma skill é uma pasta com instruções<a href="https://thiagopanini.github.io/panlabs-docs/blog/desenvolvimento-com-skills-do-matt-pocock#uma-skill-%C3%A9-uma-pasta-com-instru%C3%A7%C3%B5es" class="hash-link" aria-label="Link direto para Uma skill é uma pasta com instruções" title="Link direto para Uma skill é uma pasta com instruções" translate="no">​</a></h2>
<p>Mecanicamente, uma skill é uma pasta com um arquivo <code>SKILL.md</code> dentro. O front
matter carrega <code>name</code> e <code>description</code>, e o corpo é prosa que o agente passa a
seguir quando a skill entra em jogo. Algumas trazem arquivos irmãos que o corpo
aponta e o agente só abre quando precisa, como o <code>tests.md</code> e o <code>mocking.md</code> da
<code>tdd</code>.</p>
<p>Você invoca uma skill digitando <code>/nome</code>. E vale entender uma distinção que o
conjunto leva a sério: nem toda skill pode ser invocada pelo agente.</p>
<p>Onze das vinte e cinco não têm restrição, e o agente alcança sozinho quando a
situação pede. São as que funcionam como referência viva, como a <code>grilling</code>, a
<code>tdd</code> e a <code>code-review</code>.</p>
<p>As outras catorze carregam <code>disable-model-invocation: true</code> no front matter, e
só rodam se você digitar: <code>to-spec</code>, <code>to-tickets</code>, <code>implement</code>, <code>triage</code>,
<code>wayfinder</code> e <code>handoff</code> estão todas nessa lista. Não é detalhe de
configuração, é a arquitetura da coisa. Publicar uma spec, cortar tickets e
abrir um pull request têm consequência fora da conversa, e o conjunto decidiu
que começam por uma tecla sua.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-que-o-agente-apura-e-o-que-você-decide">O que o agente apura, e o que você decide<a href="https://thiagopanini.github.io/panlabs-docs/blog/desenvolvimento-com-skills-do-matt-pocock#o-que-o-agente-apura-e-o-que-voc%C3%AA-decide" class="hash-link" aria-label="Link direto para O que o agente apura, e o que você decide" title="Link direto para O que o agente apura, e o que você decide" translate="no">​</a></h2>
<p>A divisão de trabalho está escrita na <code>grilling</code>, e é a frase que mais mudou o
meu jeito de trabalhar:</p>
<blockquote>
<p>Finding facts is your job, never the user's. [...] The decisions are the
user's.</p>
</blockquote>
<p>Traduzindo: o agente nunca deve perguntar quantos registros o índice de busca
tem ou se o plugin aceita determinada opção. Ele vai lá e mede, despachando um
subagente quando o fato está longe. O que ele pergunta é o que só você pode
responder, e pergunta com uma recomendação em cima.</p>
<p>A segunda peça é onde a decisão fica guardada. Uma conversa some quando a
janela de contexto fecha. Uma issue não. Por isso quase toda skill lê ou
escreve no issue tracker, e é ele, não o histórico do chat, que funciona como
memória do trabalho.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-instalação-e-o-setup-uma-vez-por-repositório">A instalação e o setup, uma vez por repositório<a href="https://thiagopanini.github.io/panlabs-docs/blog/desenvolvimento-com-skills-do-matt-pocock#a-instala%C3%A7%C3%A3o-e-o-setup-uma-vez-por-reposit%C3%B3rio" class="hash-link" aria-label="Link direto para A instalação e o setup, uma vez por repositório" title="Link direto para A instalação e o setup, uma vez por repositório" translate="no">​</a></h2>
<p>Instalar é pôr as pastas onde o agente procura por skill. Aqui elas estão em
<code>~/.claude/skills/</code>, a pasta do usuário, então valem em qualquer repositório
da máquina. A própria <code>setup-matt-pocock-skills</code> conta com isso: ela decide se
pula a pergunta dos labels checando se existe uma pasta <code>triage</code> ao lado da
dela.</p>
<p>O setup roda uma vez por repositório, e não é um script determinístico:
explora, apresenta o que achou, confirma com você e só então escreve.</p>
<p>A exploração é conhecida: <code>git remote -v</code>, a existência de <code>AGENTS.md</code> e
<code>CLAUDE.md</code>, um <code>CONTEXT.md</code> na raiz, <code>docs/adr/</code>, e sinais de monorepo. Depois
vêm até três perguntas, cada uma já com a resposta recomendada na frente. A
skill pula a que a exploração já resolveu:</p>
<ol class="steps_o1RM" data-pd-component="steps"><li class="step_Hrf0"><span class="stepMarker__39S"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.25" class="icon_o5kb iconSm_tpIB" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="sm" focusable="false" aria-hidden="true"><path d="M22 12h-6l-2 3h-4l-2-3H2"></path><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11"></path></svg></span><div class="stepBody_uc8z"><p class="stepTitle_AUEf" data-pd-part="title">Onde as issues vivem</p><p>GitHub pela CLI <code>gh</code>, GitLab pela <code>glab</code>, markdown local em <code>.scratch/</code>,
ou um tracker descrito por você em um parágrafo.</p></div></li><li class="step_Hrf0"><span class="stepMarker__39S"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.25" class="icon_o5kb iconSm_tpIB" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="sm" focusable="false" aria-hidden="true"><path d="M13 5h8M13 12h8M13 19h8M3 17l2 2 4-4M3 7l2 2 4-4"></path></svg></span><div class="stepBody_uc8z"><p class="stepTitle_AUEf" data-pd-part="title">O vocabulário de triagem</p><p>Os cinco papéis canônicos são <code>needs-triage</code>, <code>needs-info</code>,
<code>ready-for-agent</code>, <code>ready-for-human</code> e <code>wontfix</code>. Você mantém os nomes ou
mapeia para os labels do seu tracker.</p></div></li><li class="step_Hrf0"><span class="stepMarker__39S"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.25" class="icon_o5kb iconSm_tpIB" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="sm" focusable="false" aria-hidden="true"><path d="M12 5v16M20.001 19A2 2 0 0 0 22 17V5a2 2 0 0 0-1.999-2L16 3.002A5 5 0 0 0 12 5a5 5 0 0 0-4-2H4a2 2 0 0 0-2 2v12a2 2 0 0 0 1.999 2H8a5 5 0 0 1 4 2 5 5 0 0 1 4-2z"></path></svg></span><div class="stepBody_uc8z"><p class="stepTitle_AUEf" data-pd-part="title">Onde a documentação de domínio mora</p><p>Contexto único, com um <code>CONTEXT.md</code> e <code>docs/adr/</code> na raiz, é o padrão.
Multi-contexto só entra em jogo se a exploração achou monorepo.</p></div></li></ol>
<p>No fim ela escreve <code>docs/agents/issue-tracker.md</code>, <code>docs/agents/domain.md</code> e
<code>docs/agents/triage-labels.md</code>, mais um bloco <code>## Agent skills</code> no <code>CLAUDE.md</code>
ou no <code>AGENTS.md</code>, o que já existir.</p>
<p>Aqui as respostas foram GitHub pela <code>gh</code>, vocabulário canônico sem apelido
nenhum, e contexto único. É por isso que um agente que chega neste repositório
sabe, sem perguntar, o que "publicar no issue tracker" quer dizer. O arquivo
sai do modelo que a própria skill carrega, um por tracker:</p>
<div class="codeGroup_uzWV" data-pd-component="code-group"><div class="theme-tabs-container tabs-container tabList__CuJ"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_LNqP tabs__item--active">GitHub</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">GitLab</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_Ymn6"><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:var(--pd-code-fg);--prism-background-color:var(--pd-surface-code)"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:var(--pd-code-fg);background-color:var(--pd-surface-code)"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:var(--pd-code-fg)"><span class="token plain">gh issue create </span><span class="token parameter variable" style="color:var(--pd-code-parameter)">--title</span><span class="token plain"> </span><span class="token string" style="color:var(--pd-code-string)">"..."</span><span class="token plain"> </span><span class="token parameter variable" style="color:var(--pd-code-parameter)">--body</span><span class="token plain"> </span><span class="token string" style="color:var(--pd-code-string)">"..."</span><br></div></code></pre></div></div></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:var(--pd-code-fg);--prism-background-color:var(--pd-surface-code)"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:var(--pd-code-fg);background-color:var(--pd-surface-code)"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:var(--pd-code-fg)"><span class="token plain">glab issue create </span><span class="token parameter variable" style="color:var(--pd-code-parameter)">--title</span><span class="token plain"> </span><span class="token string" style="color:var(--pd-code-string)">"..."</span><span class="token plain"> </span><span class="token parameter variable" style="color:var(--pd-code-parameter)">--description</span><span class="token plain"> </span><span class="token string" style="color:var(--pd-code-string)">"..."</span><br></div></code></pre></div></div></div></div></div></div>
<p>O arquivo é seu depois de escrito: aqui o corpo multi-linha passou a ir por
<code>--body-file</code>, no lugar do heredoc do modelo.</p>
<div class="callout_hLSU calloutTip_uRX1" data-pd-component="callout" data-pd-variant="tip"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon_o5kb iconMd_CfRO" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="md" focusable="false" aria-hidden="true"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5M9 18h6M10 22h4"></path></svg><div class="calloutContent_OaNL"><p>Este repositório tem um quarto arquivo em <code>docs/agents/</code>, o <code>workflow.md</code>, que
a skill não escreve. Ele começa avisando isso, e diz que se contradisser uma
skill, a skill ganha.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-pipeline-etapa-a-etapa">O pipeline, etapa a etapa<a href="https://thiagopanini.github.io/panlabs-docs/blog/desenvolvimento-com-skills-do-matt-pocock#o-pipeline-etapa-a-etapa" class="hash-link" aria-label="Link direto para O pipeline, etapa a etapa" title="Link direto para O pipeline, etapa a etapa" translate="no">​</a></h2>
<p>O caminho que quase todo trabalho percorre tem seis paradas. A demonstração é
real: cada link abre o artefato correspondente deste repositório.</p>
<ol class="steps_o1RM" data-pd-component="steps"><li class="step_Hrf0"><span class="stepMarker__39S"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.25" class="icon_o5kb iconSm_tpIB" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="sm" focusable="false" aria-hidden="true"><path d="M16 10a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 14.286V4a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2zM20 9a2 2 0 0 1 2 2v10.286a.71.71 0 0 1-1.212.502l-2.202-2.202A2 2 0 0 0 17.172 19H10a2 2 0 0 1-2-2v-1"></path></svg></span><div class="stepBody_uc8z"><p class="stepTitle_AUEf" data-pd-part="title">Grilling: a conversa que fecha as decisões</p><p>Duas portas levam ao mesmo lugar. <code>/grill-with-docs</code> roda junto com a
<code>domain-modeling</code> e deixa rastro no glossário e nos ADRs; <code>/grill-me</code> é a
mesma entrevista sem rastro.</p><p>Ela acontece em <strong>rodadas</strong>. O agente monta uma árvore de decisões e
pergunta de uma vez toda a <strong>fronteira</strong>, as decisões cujos pré-requisitos
já estão resolvidos. Cada pergunta sai numerada, com a recomendação do
agente logo abaixo:</p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:var(--pd-code-fg);--prism-background-color:var(--pd-surface-code)"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:var(--pd-code-fg);background-color:var(--pd-surface-code)"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:var(--pd-code-fg)"><span class="token plain">❓ **Q1** - **&lt;título da pergunta&gt;**: &lt;corpo da pergunta&gt;</span><br></div><div class="token-line" style="color:var(--pd-code-fg)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:var(--pd-code-fg)"><span class="token plain">➡️ &lt;a resposta que o agente recomenda&gt;</span><br></div></code></pre></div></div><p>Isso muda a sua participação: você não escreve a decisão, ratifica ou
veta. Dá para responder uma rodada inteira com "sigo as recomendações,
exceto a 3 e a 15". A sessão termina quando a fronteira esvazia, e o agente
não age até você confirmar.</p></div></li><li class="step_Hrf0"><span class="stepMarker__39S"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.25" class="icon_o5kb iconSm_tpIB" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="sm" focusable="false" aria-hidden="true"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"></path><path d="M14 2v5a1 1 0 0 0 1 1h5M10 9H8M16 13H8M16 17H8"></path></svg></span><div class="stepBody_uc8z"><p class="stepTitle_AUEf" data-pd-part="title">/to-spec: a conversa vira uma issue</p><p>A <code>to-spec</code> não entrevista ninguém: ela sintetiza o que já está na
conversa. Antes de escrever, esboça as <strong>costuras</strong> onde a feature vai ser
testada, prefere costura existente a costura nova, e confere com você.</p><p>A spec sai num formato fixo, de Problem Statement a Further Notes, e é
publicada como issue com o label <code>ready-for-agent</code>. As decisões de
implementação não citam caminho de arquivo nem trecho de código, porque
esses envelhecem rápido.</p><p>A spec deste blog é a issue <a href="https://github.com/ThiagoPanini/panlabs-docs/issues/194" target="_blank" rel="noopener noreferrer" class="">O Blog nasce como quinta aba, e não é uma
instância de docs</a>,
com dezessete subdecisões numeradas, uma por pergunta que a rodada de
grilling fechou. A da landing deste site, já encerrada, é a issue <a href="https://github.com/ThiagoPanini/panlabs-docs/issues/191" target="_blank" rel="noopener noreferrer" class="">A landing
volta, e a raiz deixa de ser um
salto</a>.</p></div></li><li class="step_Hrf0"><span class="stepMarker__39S"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.25" class="icon_o5kb iconSm_tpIB" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="sm" focusable="false" aria-hidden="true"><circle cx="6" cy="6" r="3"></circle><path d="M8.12 8.12 12 12M20 4 8.12 15.88"></path><circle cx="6" cy="18" r="3"></circle><path d="M14.8 14.8 20 20"></path></svg></span><div class="stepBody_uc8z"><p class="stepTitle_AUEf" data-pd-part="title">/to-tickets: a spec vira fatias verticais</p><p>Uma spec inteira não cabe numa sessão. A <code>to-tickets</code> corta em <strong>tracer
bullets</strong>: cada fatia atravessa todas as camadas, é demonstrável sozinha, e
cabe numa janela de contexto nova. Fatia horizontal, de uma camada só, é o
que ela evita.</p><p>Cada ticket declara as arestas de bloqueio. A skill mostra a proposta
numerada, pergunta se a granularidade e as arestas estão certas, e itera
até você aprovar. Só então publica, em ordem de dependência. Aqui a
fronteira aparece na interface do GitHub sem convenção de texto nenhuma.</p><p>Foi assim que a spec do blog virou quatro tickets: <a href="https://github.com/ThiagoPanini/panlabs-docs/issues/195" target="_blank" rel="noopener noreferrer" class="">o blog
nasce</a>, sem
bloqueio, e depois <a href="https://github.com/ThiagoPanini/panlabs-docs/issues/196" target="_blank" rel="noopener noreferrer" class="">as páginas
próprias</a>, <a href="https://github.com/ThiagoPanini/panlabs-docs/issues/197" target="_blank" rel="noopener noreferrer" class="">busca
e <code>llms.txt</code></a> e
<a href="https://github.com/ThiagoPanini/panlabs-docs/issues/198" target="_blank" rel="noopener noreferrer" class="">este artigo que você está
lendo</a>, os três
bloqueados apenas pelo primeiro.</p><p>Ligar as arestas é um segundo passe, por um motivo mecânico: uma issue
precisa existir para ser referenciada. A <code>to-tickets</code> só manda usar a
relação nativa do tracker; quem carrega o comando é o arquivo que o setup
escreveu, e ele pede o <code>id</code> interno da issue, nunca o número:</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:var(--pd-code-fg);--prism-background-color:var(--pd-surface-code)"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:var(--pd-code-fg);background-color:var(--pd-surface-code)"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:var(--pd-code-fg)"><span class="token plain">gh api </span><span class="token parameter variable" style="color:var(--pd-code-parameter)">--method</span><span class="token plain"> POST </span><span class="token punctuation" style="color:var(--pd-code-operator)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:var(--pd-code-fg)"><span class="token plain">  repos/</span><span class="token operator" style="color:var(--pd-code-operator)">&lt;</span><span class="token plain">owner</span><span class="token operator" style="color:var(--pd-code-operator)">&gt;</span><span class="token plain">/</span><span class="token operator" style="color:var(--pd-code-operator)">&lt;</span><span class="token plain">repo</span><span class="token operator" style="color:var(--pd-code-operator)">&gt;</span><span class="token plain">/issues/</span><span class="token operator" style="color:var(--pd-code-operator)">&lt;</span><span class="token plain">filho</span><span class="token operator" style="color:var(--pd-code-operator)">&gt;</span><span class="token plain">/dependencies/blocked_by </span><span class="token punctuation" style="color:var(--pd-code-operator)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:var(--pd-code-fg)"><span class="token plain">  </span><span class="token parameter variable" style="color:var(--pd-code-parameter)">-F</span><span class="token plain"> </span><span class="token assign-left variable" style="color:var(--pd-code-parameter)">issue_id</span><span class="token operator" style="color:var(--pd-code-operator)">=</span><span class="token operator" style="color:var(--pd-code-operator)">&lt;</span><span class="token plain">id-do-bloqueador</span><span class="token operator" style="color:var(--pd-code-operator)">&gt;</span><br></div></code></pre></div></div></div></li><li class="step_Hrf0"><span class="stepMarker__39S"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.25" class="icon_o5kb iconSm_tpIB" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="sm" focusable="false" aria-hidden="true"><path d="m15 12-9.373 9.373a1 1 0 0 1-3.001-3L12 9M18 15l4-4"></path><path d="m21.5 11.5-1.914-1.914A2 2 0 0 1 19 8.172v-.344a2 2 0 0 0-.586-1.414l-1.657-1.657A6 6 0 0 0 12.516 3H9l1.243 1.243A6 6 0 0 1 12 8.485V10l2 2h1.172a2 2 0 0 1 1.414.586L18.5 14.5"></path></svg></span><div class="stepBody_uc8z"><p class="stepTitle_AUEf" data-pd-part="title">/implement: o ticket vira código</p><p>O arquivo da <code>implement</code> tem quinze linhas, e cabe nelas o ciclo inteiro.
Implemente o que o ticket descreve, use <code>/tdd</code> nas costuras já combinadas,
rode a checagem de tipos com frequência e a suíte inteira no fim, chame
<code>/code-review</code> e faça o commit.</p><p>A <code>tdd</code> que ela dirige tem três regras de laço: vermelho antes de verde,
uma fatia por vez, e refatoração pertence à revisão. E uma que vale ler
devagar: <strong>nenhum teste é escrito numa costura que você não combinou
antes</strong>. É o que faz o esforço cair no caminho crítico em vez de cair em
toda borda.</p><p>O resto é convenção deste repositório, não da skill: worktree antes da
primeira edição, <code>npm run build</code> antes do primeiro push, pull request em
rascunho e merge automático no verde.</p></div></li><li class="step_Hrf0"><span class="stepMarker__39S"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.25" class="icon_o5kb iconSm_tpIB" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="sm" focusable="false" aria-hidden="true"><path d="m8 11 2 2 4-4"></path><circle cx="11" cy="11" r="8"></circle><path d="m21 21-4.3-4.3"></path></svg></span><div class="stepBody_uc8z"><p class="stepTitle_AUEf" data-pd-part="title">/code-review: dois eixos que não se contaminam</p><p>A revisão roda contra um ponto fixo que você escolhe e dispara <strong>dois
subagentes em paralelo</strong>.</p><p>O eixo <strong>Standards</strong> pergunta se o código segue os padrões documentados do
repositório, mais uma linha de base de doze cheiros do Fowler, tratados
como julgamento e nunca como violação dura.</p><p>O eixo <strong>Spec</strong> pergunta outra coisa: o diff faz o que a issue de origem
pediu? Ele procura requisito faltando, comportamento que ninguém pediu, e
requisito que parece implementado mas está errado.</p><p>Os dois relatórios aparecem lado a lado e <strong>não são fundidos nem
reordenados</strong>: código que segue todo padrão e implementa a coisa errada
passa num eixo e falha no outro.</p><p>O ticket das páginas próprias deste blog rendeu o exemplo: no celular, o
sumário tinha virado ausente em vez de recolhido. O build estava verde e o
código seguia todo padrão da casa, então nada em Standards teria como
apontar aquilo. O que a issue pedia era recolhido, e essa é a única
pergunta que o eixo Spec faz.</p></div></li><li class="step_Hrf0"><span class="stepMarker__39S"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.25" class="icon_o5kb iconSm_tpIB" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="sm" focusable="false" aria-hidden="true"><path d="M4 22V4a1 1 0 0 1 .4-.8A6 6 0 0 1 8 2c3 0 5 2 7.333 2q2 0 3.067-.8A1 1 0 0 1 20 4v10a1 1 0 0 1-.4.8A6 6 0 0 1 16 16c-3 0-5-2-8-2a6 6 0 0 0-4 1.528"></path></svg></span><div class="stepBody_uc8z"><p class="stepTitle_AUEf" data-pd-part="title">/triage e /handoff: as duas saídas</p><p>A <code>triage</code> move issues por uma máquina de estados de dois papéis de
categoria e cinco de estado. Ela vale para o que chega de fora, e só para
isso: ticket que a <code>to-tickets</code> produziu já nasce pronto para agente.</p><p>A <code>handoff</code> é para quando a sessão acaba antes do trabalho. Ela compacta a
conversa num markdown fora do repositório, com uma seção de skills
sugeridas. A instrução mais importante dela é o que não fazer: não duplicar
o que já está numa spec, numa issue ou num commit.</p></div></li></ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="quando-a-ideia-não-cabe-numa-sessão">Quando a ideia não cabe numa sessão<a href="https://thiagopanini.github.io/panlabs-docs/blog/desenvolvimento-com-skills-do-matt-pocock#quando-a-ideia-n%C3%A3o-cabe-numa-sess%C3%A3o" class="hash-link" aria-label="Link direto para Quando a ideia não cabe numa sessão" title="Link direto para Quando a ideia não cabe numa sessão" translate="no">​</a></h2>
<div class="theme-tabs-container tabs-container tabList__CuJ"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_LNqP tabs__item--active">/grill-with-docs</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">/wayfinder</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_Ymn6"><p>A porta de toda ideia que cabe inteira numa sessão, e a que eu uso em quase
tudo. O que ela cobra é higiene de contexto: grilling, spec e tickets numa
janela só, sem compactar nem limpar no meio, para que os três construam sobre o
mesmo raciocínio. Cada <code>/implement</code> depois começa do zero, lendo só o ticket.</p></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""><p>Para o esforço grande demais, em que o caminho até o destino ainda não é
visível. Ela carta um <strong>mapa</strong> no issue tracker e pendura nele <strong>tickets de
decisão</strong>, um por pergunta que precisa fechar antes de alguém construir.</p><p>O que ainda não dá para especificar fica numa seção de névoa de guerra, e
gradua em ticket conforme as decisões anteriores fecham. Quando a névoa acaba,
o mapa não constrói: ele entrega em <code>/to-spec</code>.</p></div></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="as-skills-de-apoio-e-quando-usar-cada-uma">As skills de apoio, e quando usar cada uma<a href="https://thiagopanini.github.io/panlabs-docs/blog/desenvolvimento-com-skills-do-matt-pocock#as-skills-de-apoio-e-quando-usar-cada-uma" class="hash-link" aria-label="Link direto para As skills de apoio, e quando usar cada uma" title="Link direto para As skills de apoio, e quando usar cada uma" translate="no">​</a></h2>
<p>O pipeline acima não usa o conjunto inteiro. As que sobram existem para
situações específicas, e a <code>ask-matt</code> é o roteador que diz qual delas serve.</p>
<div class="table_Giu3" data-pd-component="table" role="region" tabindex="0" aria-label="Tabela"><table><thead><tr><th>Skill</th><th>Quando usar</th><th>O que sai</th></tr></thead><tbody><tr><td><code>/ask-matt</code></td><td>Você não lembra qual skill serve</td><td>O caminho pelas skills, com os desvios</td></tr><tr><td><code>/wayfinder</code></td><td>Esforço grande demais para uma sessão</td><td>Um mapa de tickets de decisão no tracker</td></tr><tr><td><code>/prototype</code></td><td>A pergunta de desenho não fecha no papel</td><td>Código descartável, num branch fora da main</td></tr><tr><td><code>/research</code></td><td>Falta um fato de fora do diretório</td><td>Um markdown com fonte primária citada</td></tr><tr><td><code>/domain-modeling</code></td><td>Um termo do domínio está frouxo</td><td>Glossário afiado, e ADR quando merece</td></tr><tr><td><code>/codebase-design</code></td><td>A forma do módulo está em jogo</td><td>Vocabulário de módulo, costura e profundidade</td></tr><tr><td><code>/diagnosing-bugs</code></td><td>O bug resiste ao primeiro olhar</td><td>Um laço de feedback vermelho, depois a causa</td></tr><tr><td><code>/improve-codebase-architecture</code></td><td>Sobrou tempo para cuidar da casa</td><td>Relatório visual de oportunidades</td></tr><tr><td><code>/resolving-merge-conflicts</code></td><td>Você já está no meio do conflito</td><td>Cada pedaço resolvido por intenção</td></tr><tr><td><code>/to-questionnaire</code></td><td>O que falta está na cabeça de outra pessoa</td><td>Um questionário para ela preencher</td></tr><tr><td><code>/wizard</code></td><td>O passo só um humano pode dar</td><td>Um script bash interativo, estágio a estágio</td></tr><tr><td><code>/writing-for-agents</code></td><td>Você vai escrever para um agente ler</td><td>Regras de ponteiro, hierarquia e poda</td></tr><tr><td><code>/teach</code></td><td>Você quer aprender um assunto ao longo do tempo</td><td>Um workspace de lições e registros</td></tr><tr><td><code>/wait-what</code></td><td>A última mensagem não desceu</td><td>A mesma ideia, redita em inglês técnico simples</td></tr></tbody></table></div>
<p>Duas delas mudam mais o resultado do que o nome sugere.</p>
<p>A <code>diagnosing-bugs</code> recusa hipótese antes do laço. A fase 1 dela é construir um
comando que já <strong>fica vermelho neste bug</strong>. Se você se pegar lendo código para
montar teoria antes desse comando existir, pare.</p>
<p>A <code>writing-for-agents</code> trata da <strong>palavra-guia</strong>, um termo que o modelo já traz
do pré-treino e que ancora um comportamento inteiro em um token só. É por isso
que a <code>diagnosing-bugs</code> fala em laço vermelho em vez de "um laço em que você
confia": troca um portão vago por um estado observável.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-que-muda-no-dia-a-dia">O que muda no dia a dia<a href="https://thiagopanini.github.io/panlabs-docs/blog/desenvolvimento-com-skills-do-matt-pocock#o-que-muda-no-dia-a-dia" class="hash-link" aria-label="Link direto para O que muda no dia a dia" title="Link direto para O que muda no dia a dia" translate="no">​</a></h2>
<p>As rodadas ficam curtas. Eu respondo cinco a quinze perguntas numeradas, quase
sempre ratificando, e a sessão anda sozinha por horas.</p>
<p>A decisão fica escrita. Quando eu esqueço por que o blog não tem página de
autor, a resposta não está na minha memória nem no chat: está numa subdecisão
numerada da issue da spec.</p>
<p>O paralelismo é de verdade. Como cada ticket cabe numa sessão nova e as arestas
de bloqueio são explícitas, mais de uma sessão pega tickets diferentes ao mesmo
tempo. A condição para não quebrar é isolamento: cada sessão entra num worktree
próprio antes da primeira edição.</p>
<div class="callout_hLSU calloutWarning_PylE" data-pd-component="callout" data-pd-variant="warning"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon_o5kb iconMd_CfRO" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="md" focusable="false" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3M12 9v4M12 17h.01"></path></svg><div class="calloutContent_OaNL"><p>Isolamento não é exclusividade de subagente. Duas sessões de topo no mesmo
clone se atropelam do mesmo jeito, e <code>git stash</code> sem pathspec varre tudo que
está sujo na árvore, inclusive o que não é seu.</p></div></div>
<p>O portão fica claro. A CI aqui tem um passo só, <code>npm run build</code>, e é ele que
decide se o pull request entra. Não existe régua, varredura nem hook de commit,
e o que sobrou de regra de escrita está em prosa no <code>AGENTS.md</code> e nos arquivos
de regra ao lado dele.</p>
<p>E o mais desconfortável: você lê muito mais do que escreve. Julgar uma
recomendação, conferir uma medição e vetar uma decisão ruim é trabalho de
leitura, e quem espera pensar menos vai se frustrar.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="lições-deste-acervo">Lições deste acervo<a href="https://thiagopanini.github.io/panlabs-docs/blog/desenvolvimento-com-skills-do-matt-pocock#li%C3%A7%C3%B5es-deste-acervo" class="hash-link" aria-label="Link direto para Lições deste acervo" title="Link direto para Lições deste acervo" translate="no">​</a></h2>
<p>Nada aqui vem da skill. São coisas que este repositório aprendeu apanhando, e
que ficaram escritas para não serem aprendidas de novo.</p>
<ol class="steps_o1RM" data-pd-component="steps"><li class="step_Hrf0"><span class="stepMarker__39S"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.25" class="icon_o5kb iconSm_tpIB" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="sm" focusable="false" aria-hidden="true"><path d="M12 13v8M12 3v3M18.172 6a2 2 0 0 1 1.414.586l2.06 2.06a1.207 1.207 0 0 1 0 1.708l-2.06 2.06a2 2 0 0 1-1.414.586H4a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"></path></svg></span><div class="stepBody_uc8z"><p class="stepTitle_AUEf" data-pd-part="title">A convenção em português não fecha a issue</p><p>O corpo do commit é escrito em português, e uma frase como "Fecha #198" não
dispara automatismo nenhum do GitHub. Sem o trailer <code>Closes #198</code> em
inglês, a issue continua aberta depois do merge.</p></div></li><li class="step_Hrf0"><span class="stepMarker__39S"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.25" class="icon_o5kb iconSm_tpIB" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="sm" focusable="false" aria-hidden="true"><path d="M16 3h5v5M8 3H3v5"></path><path d="M12 22v-8.3a4 4 0 0 0-1.172-2.872L3 3M15 9l6-6"></path></svg></span><div class="stepBody_uc8z"><p class="stepTitle_AUEf" data-pd-part="title">Merge sem apagar a branch</p><p><code>gh pr merge --auto --squash</code>, e nunca com <code>--delete-branch</code>. A flag troca
o checkout local para a <code>main</code>, que pode estar ocupada por outro worktree.
No dia em que estiver, o comando falha na etapa local <strong>depois</strong> de o merge
já ter acontecido no GitHub.</p></div></li><li class="step_Hrf0"><span class="stepMarker__39S"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.25" class="icon_o5kb iconSm_tpIB" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="sm" focusable="false" aria-hidden="true"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"></path><path d="m9 12 2 2 4-4"></path></svg></span><div class="stepBody_uc8z"><p class="stepTitle_AUEf" data-pd-part="title">Duas runs vermelhas pela mesma causa, e para</p><p>Sem teto, um agente queima a sessão inteira consertando em laço. Duas
falhas pelo mesmo motivo dizem que a premissa está errada, não que falta
mais uma tentativa.</p></div></li><li class="step_Hrf0"><span class="stepMarker__39S"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.25" class="icon_o5kb iconSm_tpIB" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="sm" focusable="false" aria-hidden="true"><path d="M6 18h8M3 22h18M14 22a7 7 0 1 0 0-14h-1M9 14h2M9 12a2 2 0 0 1-2-2V6h6v4a2 2 0 0 1-2 2ZM12 6V3a1 1 0 0 0-1-1H9a1 1 0 0 0-1 1v3"></path></svg></span><div class="stepBody_uc8z"><p class="stepTitle_AUEf" data-pd-part="title">O servidor de desenvolvimento mente sobre link quebrado</p><p><code>onBrokenLinks: 'throw'</code> não roda em <code>docusaurus start</code>, que devolve 200
para qualquer rota. Link quebrado só aparece no build, e é por isso que o
build vem antes do primeiro push.</p></div></li></ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="por-onde-começar">Por onde começar<a href="https://thiagopanini.github.io/panlabs-docs/blog/desenvolvimento-com-skills-do-matt-pocock#por-onde-come%C3%A7ar" class="hash-link" aria-label="Link direto para Por onde começar" title="Link direto para Por onde começar" translate="no">​</a></h2>
<p>O menor caminho completo é este: instale o conjunto, rode
<code>/setup-matt-pocock-skills</code> uma vez, e leve uma ideia pequena por
<code>/grill-with-docs</code>, <code>/to-spec</code>, <code>/to-tickets</code> e <code>/implement</code>, sem pular a
revisão no fim. A ideia pequena importa: a mecânica se aprende mais rápido num
assunto cuja spec cabe numa tela.</p>
<div class="cardGroup_Ddak" data-pd-component="card-group"><a class="card_isyu" data-pd-component="card" href="https://thiagopanini.github.io/panlabs-docs/blog/por-que-este-acervo-ganhou-um-blog"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.75" class="icon_o5kb iconLg_f6dh" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="lg" focusable="false" aria-hidden="true"><path d="M15 18h-5M18 14h-8M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2"></path><rect width="8" height="4" x="10" y="6" rx="1"></rect></svg><span class="cardTitle_MzpW" data-pd-part="title">Por que este acervo ganhou um blog</span><p>A nota curta que abriu a quinta aba, escrita no ticket anterior a este.</p></a><a href="https://www.aihero.dev/ai-coding-dictionary/smart-zone" target="_blank" rel="noopener noreferrer" class="card_isyu" data-pd-component="card"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.75" class="icon_o5kb iconLg_f6dh" viewBox="0 0 24 24" data-pd-component="icon" data-pd-variant="lg" focusable="false" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><path d="m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z"></path></svg><span class="cardTitle_MzpW" data-pd-part="title">Smart zone</span><p>O verbete que a <code>ask-matt</code> linka para nomear até onde uma sessão ainda
raciocina com nitidez, e que a higiene de contexto respeita.</p></a></div>]]></content>
        <author>
            <name>Thiago Panini</name>
            <uri>https://github.com/ThiagoPanini</uri>
        </author>
        <category label="IA" term="IA"/>
        <category label="Claude Code" term="Claude Code"/>
        <category label="Skills" term="Skills"/>
        <category label="panlabs-docs" term="panlabs-docs"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Por que este acervo ganhou um blog]]></title>
        <id>https://thiagopanini.github.io/panlabs-docs/blog/por-que-este-acervo-ganhou-um-blog</id>
        <link href="https://thiagopanini.github.io/panlabs-docs/blog/por-que-este-acervo-ganhou-um-blog"/>
        <updated>2026-09-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A lacuna que as quatro abas de documentação não cobriam, e a decisão que abriu a quinta.]]></summary>
        <content type="html"><![CDATA[<p>As quatro abas deste site são a mesma coisa, no fundo: documentação,
organizada por eixo, escrita em "você mais imperativo", sem autor e sem
data. Isso serve bem a <code>Ferramentas</code>, a <code>Jornadas</code>, a <code>Procedimentos</code> e a
<code>Times</code>, mas deixa de fora um tipo de texto que eu queria escrever: uma
novidade que vale comentar, uma nota sobre um tema do dia a dia. Um texto
assim não é uma jornada nem um procedimento, e forçá-lo dentro de uma dessas
abas seria mentir sobre o que ele é.</p>
<p>O sintoma já estava no código antes de eu decidir nada: o plugin de blog do
Docusaurus vinha desligado, com um comentário dizendo que nenhum consumidor
tinha pedido um. Este artigo é esse consumidor.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-que-este-ticket-abriu">O que este ticket abriu<a href="https://thiagopanini.github.io/panlabs-docs/blog/por-que-este-acervo-ganhou-um-blog#o-que-este-ticket-abriu" class="hash-link" aria-label="Link direto para O que este ticket abriu" title="Link direto para O que este ticket abriu" translate="no">​</a></h2>
<p>O Blog entrou como a quinta aba, por último na faixa, e não como mais uma
instância de documentação: é o plugin oficial de blog, que já vinha junto do
preset instalado, então nenhuma dependência nova entrou no projeto. Cada
artigo mora numa pasta própria, com o título só no front matter, nunca como
<code># título</code> no corpo. Cada um carrega pelo menos uma tag de assunto, de um
catálogo fechado, e a primeira delas é a que aparece em destaque na
listagem.</p>
<p>A regra de voz da documentação, "você mais imperativo, zero primeira
pessoa", não alcança o blog. Aqui a voz é minha, artigo a artigo, e este
texto mistura primeira e terceira pessoa por escolha, não por descuido. O
que não muda é o zero travessão: essa regra vale em qualquer texto publicado
deste site, blog incluído.</p>
<p>As páginas ainda são as padrão do tema Docusaurus enquanto escrevo isto. Um
próximo ticket troca a cara delas por componentes deste próprio repositório,
sem nenhum swizzle: todo componente de blog do tema é território <code>unsafe</code>
para essa técnica, e o orçamento disso aqui é zero.</p>]]></content>
        <author>
            <name>Thiago Panini</name>
            <uri>https://github.com/ThiagoPanini</uri>
        </author>
        <category label="Software" term="Software"/>
        <category label="panlabs-docs" term="panlabs-docs"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[A versão 0.31.0 do overpower troca clone por endereço]]></title>
        <id>https://thiagopanini.github.io/panlabs-docs/blog/overpower-0-31-fonte-vira-endereco</id>
        <link href="https://thiagopanini.github.io/panlabs-docs/blog/overpower-0-31-fonte-vira-endereco"/>
        <updated>2026-09-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[O que muda quando uma receita de servidor MCP passa a declarar a fonte do próprio código, em vez de instalar a partir de um clone.]]></summary>
        <content type="html"><![CDATA[<p>Uso o <code>overpower</code> para instalar skill, servidor MCP e receita a partir de um
catálogo declarado, e a versão 0.31.0 mudou uma peça que eu não esperava:
como uma receita aponta para um servidor com código próprio.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-que-era-antes">O que era antes<a href="https://thiagopanini.github.io/panlabs-docs/blog/overpower-0-31-fonte-vira-endereco#o-que-era-antes" class="hash-link" aria-label="Link direto para O que era antes" title="Link direto para O que era antes" translate="no">​</a></h2>
<p>Uma receita cujo servidor tinha código próprio dependia de um clone. O
<code>overpower</code> mantinha esse clone em <code>~/.overpower/mcp/</code>, um diretório por
receita, escopo de máquina por natureza: o clone vivia ali, e o arquivo de
configuração escrito para cada projeto apontava para ele.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-que-muda-na-0310">O que muda na 0.31.0<a href="https://thiagopanini.github.io/panlabs-docs/blog/overpower-0-31-fonte-vira-endereco#o-que-muda-na-0310" class="hash-link" aria-label="Link direto para O que muda na 0.31.0" title="Link direto para O que muda na 0.31.0" translate="no">​</a></h2>
<p>Agora a receita declara <code>source:</code>, com quatro chaves: <code>git</code>, <code>ref</code>, <code>runner</code>
e <code>entrypoint</code>. O <code>overpower</code> monta a linha do runner a partir delas, com o
<code>server.args</code> da receita aposto no fim, e não clona nada. O
<code>~/.overpower/mcp/</code> deixou de existir, e é por isso que uma receita com fonte
volta a instalar em escopo de projeto: o arquivo que cada máquina escreve sai
idêntico, porque não depende mais de um clone local.</p>
<p>O <code>ref</code> é obrigatório, e o <code>runner</code> é vocabulário fechado: só <code>uvx</code> ou <code>npx</code>,
recusados por nome fora dessas duas opções. <code>transport</code>, <code>server.command</code> e a
precondição de runner passaram a <strong>derivados</strong>: declarar qualquer um deles ao
lado de <code>source:</code> também é recusa por nome, porque os dois jeitos de
descrever o mesmo servidor deixariam de concordar em algum momento.</p>
<p>O <code>source:</code> antigo, com a chave <code>url</code>, e o token de substituição que ele
usava pararam de ser lidos. <strong>Sem janela de compatibilidade</strong>: uma receita
escrita no formato anterior falha, nomeando o que precisa mudar.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-que-isso-resolve-no-dia-a-dia">O que isso resolve no dia a dia<a href="https://thiagopanini.github.io/panlabs-docs/blog/overpower-0-31-fonte-vira-endereco#o-que-isso-resolve-no-dia-a-dia" class="hash-link" aria-label="Link direto para O que isso resolve no dia a dia" title="Link direto para O que isso resolve no dia a dia" translate="no">​</a></h2>
<p>O <code>doctor</code> perdeu as duas conferências que existiam para o clone e ganhou
uma no lugar: re-roda a precondição do runner contra o <code>PATH</code>, offline. E o
<code>list --from</code> passou a mostrar a origem e a ref na linha do servidor, o que
antes exigia abrir o arquivo da receita para saber.</p>
<p>O registro completo, com todas as versões, está no
<a class="" href="https://thiagopanini.github.io/panlabs-docs/ferramentas/bibliotecas/overpower/referencia/changelog">changelog do overpower</a>.</p>]]></content>
        <author>
            <name>Thiago Panini</name>
            <uri>https://github.com/ThiagoPanini</uri>
        </author>
        <category label="IA" term="IA"/>
        <category label="overpower" term="overpower"/>
    </entry>
</feed>