CH 08 · Modelo Mental da Árvore de Plugins: Tudo é um Plugin
Objetivo do Capítulo
O CH 02 disse "tudo é um plugin"; este capítulo transforma isso em um modelo mental que você pode levar consigo: o que é um dsh em execução, por que cada parte pode ser trocada e por que a frase "troque um Provider, troque o produto" realmente se sustenta.
Uma Frase para Embasar: Um dsh em Execução = uma Árvore de Plugins
O documento oficial de arquitetura coloca assim: um dsh em execução é uma árvore de plugins, composta por camadas ordenadas na inicialização. Divida em três camadas para memorizar, e toda a arquitetura se sustenta:
Lendo o diagrama de cima para baixo, a lógica é: ① Primeiro escolha um Profile → ② Empilhe as camadas de plugins em ordem → ③ Todas as camadas rodam no mesmo kernel Cordis. Os três pontos correspondentes:
- A camada inferior é o kernel Cordis: um contexto compartilhado que permite aos plugins injetar serviços, transmitir eventos e montar efeitos.
- No meio fica a própria árvore de plugins: vários plugins empilhados em uma árvore, cada um fazendo uma coisa específica.
- A camada superior é o Profile: ele não adiciona novas capacidades, apenas decide "como essa árvore é" — web, headless ou sua própria combinação personalizada (abordado na próxima seção).
Cordis: O Framework que Move Tudo
O dsh roda sobre um framework de plugins chamado Cordis (o README oficial diz explicitamente "powered by Cordis"). O Cordis tem apenas três convenções centrais:
- Plugins injetam serviços em um contexto compartilhado. Quer adicionar uma capacidade? Escreva um plugin e registre-o.
- Plugins transmitem eventos tipados. Outros escutam esses eventos para se coordenar, sem precisar importá-los diretamente.
- O registro de plugins é um efeito reversível — quando um plugin é descarregado, o que ele registrou é revertido automaticamente, sem deixar bagunça.
A parte mais importante é a última — é por isso que "tudo é um plugin" pode se sustentar: o dsh não tem núcleo privilegiado para modificar. O adaptador de modelo é um plugin, o registro de ferramentas é um plugin, o log de sessão é um plugin, até mesmo o loop principal do agent é um plugin. O jeito de estender o dsh é "pendurar um plugin ao lado", não "ir editar algum arquivo núcleo". Isso torna seu custo de mudança extremamente baixo: se você não consegue mudar, troque; se não consegue trocar, adicione um.
Em que isso difere dos demais? Coloque lado a lado os dois Agents de CLI mais usados, a diferença salta aos olhos:
| Comparação | Abordagem de extensão | Você consegue tocar no "esqueleto"? |
|---|---|---|
| Claude Code | Ferramentas podem ser estendidas (MCP, skills), mas modelo e loop principal não podem ser trocados | Semiaberto: ferramentas podem ser adicionadas, mas adaptação de modelo, sessão, loop do agent estão soldados, e o modelo está preso ao seu próprio ecossistema |
| Codex | Ferramentas podem ser estendidas, mas modelo e loop principal não podem ser trocados | Semiaberto: ferramentas podem ser adicionadas, mas adaptação de modelo, sessão, loop do agent estão soldados, e o modelo está preso ao seu próprio ecossistema |
| dsh | Pendure um plugin ao lado, altere a configuração para trocar | Totalmente aberto: até mesmo log de sessão, loop do agent, adaptador de modelo são plugins, sem núcleo privilegiado |
Resumo em uma frase: o "esqueleto" do Claude Code e do Codex está soldado; o "esqueleto" do dsh também é um plugin. É por isso que você pode plugar qualquer modelo (a comparação com o Codex no CH 06 é o exemplo), e pode trocar a sessão por sua própria implementação — o esqueleto em si é substituível, o único limite é se você quer mudar.
Veja uma Árvore Real com --dump-config
Dizer a teoria dez vezes não vale uma olhada real. No CH 05 você rodou dsh --profile headless --dump-config uma vez; o que é impresso é uma longa árvore de plugins @deepseek-ai/dsh-* — llm (modelo), session (sessão), credentials (chaves), session-persistence-jsonl (persistência de sessão)... esses plugins cada um lida com sua parte, empilhados juntos em um dsh executável.
A equipe oficial lista claramente os plugins centrais; cada um corresponde a um "grande galho" em uma árvore:
| Plugin central | O que ele trata |
|---|---|
core/session | Log de sessão append-only (tudo que o modelo vê é registrado) |
core/system-prompt | Como o system prompt é montado, como os schemas de ferramentas são empacotados |
core/tools | Registro de ferramentas e pipeline de execução controlada |
core/agent | Interface do Agent e registro ao vivo |
core/agent-loop | Driver padrão do loop "request → chamada de ferramenta" |
llm/llm | Vocabulário de mensagens e streaming + costura do adaptador de modelo |
Observe "costura" na última linha — esse é o próximo conceito-chave.
Profile e Bundle: Como os Plugins se Combinam em um "Modo"
Plugin = um prato (arroz com ovo frito, sopa da casa, acompanhamento); bundle = um conjunto de refeição (arroz, prato principal, talheres pré-empacotados); profile = o cardápio (lista quais pratos, em que ordem); a wok na cozinha dos fundos é o kernel Cordis da próxima seção.
O que uma árvore é composta é decidido pelo Profile — pense nele como o cardápio na sua mão:
- Profile é uma combinação nomeada, armazenada no diretório do Harness. Ele lista quais Bundles empilhar, quais plugins extras instalar e também mantém seu próprio
cordis.patch.yml. O cardápio não cozinha pratos, ele apenas diz "o que tem nessa refeição": a fábrica oficial entrega os cardswebeheadlessprontos para usar; os "quatro modos de execução" do CH 02 são quatro presets diferentes de combinação de plugins por baixo, equivalentes a mais alguns cards. - Bundle é um formato de distribuição para "um grupo de plugins + a configuração que eles montam", equivalente a um conjunto de refeição pré-empacotado:
dsh-baseé a primeira camada para todo profile (fundação: modelo, ferramentas, persistência, sandbox, aprovação, configurações, chaves, telemetria);web-appadiciona "ambiente de comer no local" ao conjunto base (interface de navegador);headlessadiciona "pra viagem" (linha de comando one-shot, sem servidor).
Primeiro um ponto fácil de confundir: Profile não é um plugin. Um plugin é "algo que faz trabalho" (um prato); Profile é apenas "o cardápio" (apenas faz pedidos, não cozinha). Escolher "Modo mínimo" não instala nenhum plugin novo — ele apenas troca a árvore de plugins por uma combinação mais minimalista — cardápio diferente, mesma cozinha.
O empilhamento de plugins tem uma ordem estrita (oficial), como a cozinha preparando pelo cardápio, e anotações posteriores podem sobrescrever as anteriores:
Cada bundle (na ordem listada no profile) ← conjunto de refeição primeiro
→ cordis.patch.yml próprio do profile ← anotações no cardápio
→ nível de diretório do Harness ← requisitos padrão do chefe
→ overlay --patch da linha de comando ← anotações extras temporárias, o último venceCada camada pode sobrescrever a anterior — os patches localizam uma linha pelo id, substituem sua configuração inteira ou inserem uma nova linha. Então o --patch do CH 05 não é "um furo a mais", é modificar abertamente essa árvore: qualquer linha impressa por --dump-config pode ser substituída pelo seu próprio patch.
Construir seu próprio Profile não significa escrever código do zero — a essência é "copiar um cardápio e modificá-lo":
- Quer menos que web? → Copie a configuração web e remova o que não quer ("comer no local, mas sem sopa");
- Quer mais que headless (por exemplo, montar por padrão um plugin de ferramenta que você escreveu)? → Copie headless e adicione uma linha à sua lista de bundles ("pra viagem, mais um acompanhamento que você trouxe");
- O mais leve é não mudar o cardápio, apenas adicionar anotações: para instalar um plugin em um profile existente, use
dsh plugin --profile <nome> add <pacote>("adicione um acompanhamento ao cardápio existente"), para sobreposição temporária, use--patch("nesta refeição: troque a sopa por Sprite") — já vimos ambos no CH 05.
Enfileire o processo de carregamento em uma linha do tempo única, e tudo antes se encaixa:
- Na inicialização, o dsh primeiro lê o Profile que você escolheu — é um manifesto de carregamento, dizendo "em que ordem empilhar quais camadas";
- Carregue camada por camada na ordem do manifesto: primeiro camada 1 base (dsh-base), depois camada 2 adição (web-app / headless / seus plugins), finalmente camada 3 sobreposição (cordis.patch.yml +
--patch) — quanto mais tarde carregar, mais pode sobrescrever o anterior; - Todas as camadas se instalam no mesmo kernel Cordis, onde injetam serviços e se comunicam.
Uma frase de fechamento: Profile = ordem dos pedidos na inicialização; árvore de plugins = pratos instalados nessa ordem; Cordis = a wok usada para instalar os pratos.
Eventos e Costuras de Capacidade: Como os Plugins Conversam
Plugins não se importam uns com os outros; eles se coordenam por meio de duas coisas:
Eventos são pontos de extensão, em três domínios:
- Eventos de sessão: fatos persistentes, anexados ao log e transmitidos, sobrevivendo a reinicializações (ex.: "esta mensagem foi enviada").
- Eventos de Agent (
agent/*): carregam o Agent ao vivo, usados para observar ou interceptar trabalho em execução (ex.: "interceptar antes desta step começar"). - Eventos de Capability (
fs/*,tools/*,telemetry/*): anexam políticas e adaptadores a uma costura sem mudar o loop principal.
Costura de capacidade é uma capacidade substituível; ela tem três papéis fixos:
- Service Definition: declara como a interface se parece;
- Service Provider: de fato a implementa;
- Consumer: a usa (geralmente ferramentas que o modelo chama).
Por que "trocar um Provider, troca o produto"? Porque os providers de sistema de arquivos e subprocesso compartilham o mesmo "mundo de execução" — aponte-os para um sandbox remoto, e Bash, PTY, LSP se movem junto com eles, sem precisar escrever um conjunto separado para cada capacidade. O mesmo vale para o adaptador de modelo: qualquer adaptador registrado em ctx.llm é o modelo que todo o produto usa; nada mais precisa mudar.
O Modelo Mental em Uma Frase
Se você só pode levar três frases, lembre-se destas três (junto com o restaurante pequeno acima):
- O dsh não tem núcleo — cada parte é um plugin, incluindo ele mesmo; adicione um prato ao lado, tire um e ele se reverte automaticamente.
- O Profile decide como a árvore é — web / headless / custom são todos "cards" diferentes da mesma árvore; não funciona, apenas pede.
- Eventos e costuras são a interface de colaboração dos plugins — monte e funciona, tire e se reverte, então troque ou adicione à vontade; troque um Provider, troque o produto.
O que você aprendeu neste capítulo
- [ ] Afirmar que "um dsh em execução = uma árvore de plugins" e que ela é composta por camadas ordenadas
- [ ] Afirmar as três convenções centrais do Cordis (injeção de serviço / eventos / efeitos reversíveis), e por que não há núcleo privilegiado
- [ ] Reconhecer plugins centrais (llm / session / credentials / tools, etc.) na saída de
--dump-config - [ ] Explicar a relação entre Profile e Bundle, e a ordem de camadas do empilhamento de plugins
- [ ] Usar a analogia do "pedido" para explicar a relação entre plugin / bundle / profile, e saber que construir seu próprio profile é "copiar um cardápio e modificar", enquanto
plugin add/--patché a modificação mais leve - [ ] Nomear os três papéis de uma costura de capacidade (Definition / Provider / Consumer), e explicar por que "trocar um Provider, troca o produto"
