# Cadernos · LLM + agentes
URL: /docs/cadernos

Curadoria dos escritos do blog dev·magic que importam pra quem mexe com Claude Code, agentes, e WhatsApp+LLM. Atalho pra encontrar o que já foi resolvido.





Os escritos longos vivem em [fonsecagabriel.com.br/blog](https://fonsecagabriel.com.br/blog). Esta página é o índice que eu queria ter quando começo um projeto novo.

<Callout type="info">
  Cada bullet abaixo é a frase que faz cê abrir o post — não o resumo do post. Se nada engancha, pula. Se enganchou, clica.
</Callout>

## Claude Code · mecânica interna [#claude-code--mecânica-interna]

Quatro escritos sobre como Claude Code realmente funciona quando cê encara a sério, não em demo.

<Cards>
  <Card title="№ 001 · Hooks que injetam contexto" description="UserPromptSubmit, PreToolUse e PostToolUse formam a tríade que injeta memória, bloqueia tool call e redacta secret — sem você repetir no prompt." href="https://fonsecagabriel.com.br/blog/hooks-injetam-contexto/" />

  <Card title="№ 002 · Configuration drift" description="47 linhas em permissions.allow, 31 são band-aid e cê esqueceu pra que serve metade. Três canais, três usos, fim do ciclo." href="https://fonsecagabriel.com.br/blog/configuration-drift-settings-muleta/" />

  <Card title="№ 005 · Statusline que mede rate-limit ETA" description="Burn-rate sampling de 30min com three-tier severity. Saber quanto tempo cê ainda tem antes do limit te derrubar — antes do limit te derrubar." href="https://fonsecagabriel.com.br/blog/statusline-rate-limit-eta/" />

  <Card title="№ 003 · BRIEF contract" description="CLAUDE.md inteiro vira metralhadora pra subagent. JSON imutável com scope + success criteria + forbidden paths resolve sem narrar." href="https://fonsecagabriel.com.br/blog/brief-contract-contexto-sem-leak/" />
</Cards>

### Por que estes quatro andam juntos [#por-que-estes-quatro-andam-juntos]

`settings.json`, hooks, statusline e BRIEF são as quatro alavancas que decidem se a sessão vai render ou virar manicômio. Ordem de leitura recomendada quando configurando perfil novo: **001 → 002 → 003 → 005**.

## Orquestração de agentes em paralelo [#orquestração-de-agentes-em-paralelo]

Quando 1 Claude vira 9 panes simultâneos, o problema deixa de ser prompt e vira coordenação.

<Cards>
  <Card title="№ 006 · Pane-dispatch vence fila" description="9 worktrees simultâneos via tmux send-keys + JSONL + BRIEF. Sem broker, sem fila, sem cerimônia." href="https://fonsecagabriel.com.br/blog/pane-dispatch-vs-fila/" />

  <Card title="№ 009 · Agente que planeja mas não executa" description="Cinco sintomas do agent que confunde TodoList com produto. Três correções que param o ciclo." href="https://fonsecagabriel.com.br/blog/agente-planeja-nao-executa/" />
</Cards>

### Cinco sintomas do agent travado (resumo do № 009) [#cinco-sintomas-do-agent-travado-resumo-do--009]

1. "primeiro vou…" sem nada commitado
2. TodoList que cresce, código que não move
3. "implement the X" sem `run + verify`
4. "let me know if you want me to proceed"
5. Crash silencioso pós-edit

Se três bateram na sua sessão atual, [abre o post](https://fonsecagabriel.com.br/blog/agente-planeja-nao-executa/) — os três consertos estão lá.

## WhatsApp + LLM no Brasil real [#whatsapp--llm-no-brasil-real]

LLM pra cliente brasileiro = áudio + Evolution API + agente decidindo. Dois escritos sobre o que escalou de fato.

<Cards>
  <Card title="№ 008 · Evolution API · 5.000 mensagens" description="Por que Evolution venceu Baileys. Multi-tenant com 2 instâncias via MCP custom. Onde o WhatsApp ainda dói no Brasil." href="https://fonsecagabriel.com.br/blog/evolution-api-cinco-mil-mensagens/" />

  <Card title="№ 004 · Áudio WhatsApp → ação em 3 passos" description="Whisper LOCAL + Evolution webhook + pydantic-ai. Cliente manda áudio, máquina escuta, sem cloud, sem latência." href="https://fonsecagabriel.com.br/blog/audio-whatsapp-vira-acao-whisper/" />
</Cards>

## Bonus · diário [#bonus--diário]

<Cards>
  <Card title="№ 010 · Notas da madrugada: produtizando MktOS" description="3am, terceira xícara. O que vira produto, o que continua serviço. Decisão de uma noite que talvez muda no dia seguinte." href="https://fonsecagabriel.com.br/blog/notas-madrugada-produtizando-mktos/" />

  <Card title="№ 007 · Caderno aberto" description="Primeiro escrito. Manifesto do que o caderno é e do que não é." href="https://fonsecagabriel.com.br/blog/hello-astro/" />
</Cards>

## Como esta página foi feita [#como-esta-página-foi-feita]

Curadoria honesta: nada de IA-resumindo-IA. Cada one-liner foi escrito olhando o título + meta + estrutura H2 de cada post (`curl https://fonsecagabriel.com.br/blog/<slug>/`). Se o post mudar de ângulo, esta página precisa atualizar — fonte da verdade é o blog, não esta página.

Pra agent que quer indexar tudo: prefira [`/llms-full.txt`](/llms-full.txt) — corpus inteiro, single fetch, zero HTML chrome.


# Fumadocs vs Nextra
URL: /docs/fumadocs-vs-nextra

Bake-off lendo o source de ambos. Quem entrega melhor pra humanos e pra agentes LLM.





Comparo as duas frameworks lendo o repositório de cada uma, não o marketing.

<Callout type="info" title="TL;DR">
  **Fumadocs** se você precisa que **agentes LLM consumam suas docs** ou se você **não está casado com Next.js**.
  **Nextra** se você é 100% Next.js, quer um tema polido por default, e ChatGPT/Claude jump-out fora-da-caixa.
</Callout>

## Quem usar quando [#quem-usar-quando]

<Cards>
  <Card title="Use Fumadocs se…" description="Você documenta um SDK / API que será scrapeado por agentes; quer `llms.txt` nativo; usa TanStack Start, React Router, Waku, Vite; precisa renderizar OpenAPI; quer i18n robusta." />

  <Card title="Use Nextra se…" description="Tudo é Next.js App Router e vai continuar sendo; tempo até a primeira página importa mais que extensibilidade; o leitor é humano que vai abrir no ChatGPT/Claude manualmente." />
</Cards>

## Matriz [#matriz]

| Dimensão                  | Fumadocs                                                                       | Nextra                                   |   Vence   |
| ------------------------- | ------------------------------------------------------------------------------ | ---------------------------------------- | :-------: |
| Frameworks                | Next, TanStack Start, React Router, Waku, Vite                                 | Next.js ≥14                              |  🟧 Fuma  |
| `llms.txt` nativo         | Sim (`core/src/source/llms.ts`, `remark-llms`)                                 | Não                                      |  🟧 Fuma  |
| Copy-as-Markdown UI       | `MarkdownCopyButton` em todos os layouts                                       | `CopyPage` com ChatGPT/Claude deep-links | ⚖️ Empate |
| OpenAPI → MDX             | `fumadocs-openapi@10.8` codegen                                                | Não em core                              |  🟧 Fuma  |
| Fontes de conteúdo        | MDX, MD, content-collections, Obsidian, Sanity, BaseHub, Python, GitHub remote | MDX, GitHub remote                       |  🟧 Fuma  |
| Subpath exports           | \~50 paths em `fumadocs-core` (ESM only)                                       | 4 paths em `nextra`                      |  🟧 Fuma  |
| Tempo até primeira página | Maior (escolher framework + UI + content)                                      | Menor (`nextra` + theme + go)            | 🟦 Nextra |
| Tema default polido       | 3 layouts (docs, notebook, flux) — precisa escolher                            | 1 tema, opinado, brilhante               | 🟦 Nextra |
| Exemplos no repo          | **25**                                                                         | **4**                                    |  🟧 Fuma  |

## Arquitetura [#arquitetura]

<Tabs items="['Fumadocs', 'Nextra']">
  <Tab value="Fumadocs">
    **Headless + adapter por framework.** `fumadocs-core` não sabe nada sobre Next — sabe sobre *docs*. Cada framework é um arquivo de adapter.

    ```
    packages/core/src/framework/
      ├ next.tsx        ← Next.js adapter
      ├ react-router.tsx
      ├ tanstack.tsx
      └ waku.tsx
    ```

    UI separada em `base-ui` (Tailwind puro) ou `radix-ui` (Tailwind + Radix). Você compõe.
  </Tab>

  <Tab value="Nextra">
    **Stack acoplada a Next.js App Router.** O pacote `nextra` é o compilador + page-map; os temas (`nextra-theme-docs`, `nextra-theme-blog`) são opinions completas. Você instala, pluga `next.config.mjs`, e ganha um site.

    ```
    packages/
      ├ nextra/              ← compile + page-map + loader
      ├ nextra-theme-docs/   ← single happy path
      └ nextra-theme-blog/
    ```

    Quase nada pra decidir. Quase nada pra trocar.
  </Tab>
</Tabs>

## LLM / Code-agent friendliness [#llm--code-agent-friendliness]

Dois leitores hoje: humano e máquina. A framework decide quão bem a máquina come.

### Score [#score]

| Critério                                | Peso | Fumadocs |  Nextra |
| --------------------------------------- | ---: | -------: | ------: |
| `llms.txt` / flat-markdown endpoint     |  25% |   **10** |       4 |
| Markdown raw alcançável por URL         |  15% |    **9** |       6 |
| AI provider deep-link UI                |  10% |        6 |  **10** |
| Subpath imports tipados pra code agents |  20% |   **10** |       7 |
| Page-map estável pra crawl              |  15% |        8 |   **9** |
| Baixa carga cognitiva pra codegen       |  15% |        7 |   **9** |
| **Total ponderado**                     |      |  **9.0** | **7.0** |

### Como cada uma alimenta o agente [#como-cada-uma-alimenta-o-agente]

<Tabs items="['Fumadocs', 'Nextra']">
  <Tab value="Fumadocs">
    ```
    agent  ─GET /llms-full.txt─►  site
    agent  ◄─whole tree as markdown─  site
            (1 fetch, zero HTML noise)
    ```

    `/llms.txt/*path` reescrito automaticamente a partir de `/docs/*path.mdx` (`core/test/negotiation.test.ts:39`). Markdown raw servido como rota de primeira classe.
  </Tab>

  <Tab value="Nextra">
    ```
    agent  ─GET /docs/api/auth─►  site
    agent  ◄─full HTML w/ theme chrome─  site
    agent  strip nav · extract main · repeat
    ```

    OU: humano clica **Copy Page** → **Open in Claude** → cola conteúdo. Funciona, mas o agente precisa do humano no meio.
  </Tab>
</Tabs>

<Callout title="Nuance" type="warn">
  Nextra não impede `llms.txt` — só não vem pronto. Você escreve um route handler em `app/llms.txt/route.ts` que lê seu page-map e concatena os MDX. Custa \~30 linhas. Mas é seu problema, não da framework.
</Callout>

## Gotchas reais (de quem deployou) [#gotchas-reais-de-quem-deployou]

<Accordions>
  <Accordion title="Next 16 standalone + Dockerfile precisa de public/">
    Se você usa `output: 'standalone'` e o seu projeto não tem `public/`, o `COPY --from=builder /app/public ./public` no Dockerfile quebra com `not found`. Crie `public/.gitkeep` mesmo que nunca vá usar.
  </Accordion>

  <Accordion title="Healthcheck path do kamal-proxy">
    Default é `/`. Fumadocs com `baseUrl: '/docs'` retorna 404 em `/`. Resultado: container "unhealthy", deploy aborta em 30s. Fix: ou adiciona `app/page.tsx` que faz `redirect('/docs')`, ou seta `proxy.healthcheck.path: /docs` no `deploy.yml`.
  </Accordion>

  <Accordion title="Versões workspace nos examples">
    Os exemplos no repo do fumadocs usam `"fumadocs-core": "workspace:*"`. Se você copiar um example, troque pelas versões npm reais (`^16.8.11` etc) antes de `pnpm install`, ou ele tenta resolver o workspace e quebra.
  </Accordion>

  <Accordion title="Nextra é Next ≥14, mas teme upgrades">
    Nextra 4 trava Next ≥14 e exige App Router. Se você herdou um projeto com Pages Router, ou é migração antes ou nada.
  </Accordion>
</Accordions>

## Conclusão pragmática [#conclusão-pragmática]

<Callout title="Recomendação" type="info">
  Padrão pra projetos novos onde docs servem **humano + agente**: **Fumadocs**. O custo extra de composição se paga no `llms.txt` nativo + OpenAPI + escape route de framework.

  Padrão pra projetos onde docs servem **humano dentro de uma stack 100% Next**: **Nextra**. Você ganha o tempo de volta no tema default e perde pouco (`llms.txt` é 30 linhas de route handler).
</Callout>

## Source lido [#source-lido]

Repositórios clonados via `opensrc`, lidos diretamente:

* `github.com/fuma-nama/fumadocs@dev`
  * `packages/core/package.json` (v16.8.11)
  * `packages/core/src/source/llms.ts:101,107`
  * `packages/core/src/mdx-plugins/remark-llms.ts:58`
  * `packages/core/test/negotiation.test.ts:39-47`
  * `packages/core/src/framework/{next,tanstack,react-router,waku}.tsx`
  * `packages/{base-ui,radix-ui}/src/layouts/shared/page-actions.tsx:59`
  * `packages/openapi/package.json` (v10.8.5)
* `github.com/shuding/nextra@main`
  * `packages/nextra/package.json` (v4.6.4 · `"next": ">=14"`)
  * `packages/nextra-theme-docs/src/components/copy-page.tsx`
  * `packages/nextra-theme-docs/src/mdx-components/wrapper.client.tsx:47-48`
  * `packages/nextra/src/server/{compile,page-map,locales}`


# docs.fonsecagabriel
URL: /docs

Personal docs hub · fumadocs on Kamal v2 · Contabo VPS





Notas, comparações, e ADRs do que rodo em produção em `*.fonsecagabriel.com.br`.

Stack desta página: **fumadocs 16.8** + Next 16 standalone + Docker multistage, deployado via **Kamal v2** com kamal-proxy + LE HTTP-01.

<Cards>
  <Card title="Cadernos · LLM + agentes" description="Índice dos escritos do blog dev·magic sobre Claude Code, orquestração, e WhatsApp+LLM." href="/docs/cadernos" />

  <Card title="Fumadocs vs Nextra" description="Bake-off lendo o source de ambos. Quem é amigável a agentes LLM." href="/docs/fumadocs-vs-nextra" />
</Cards>

## Como esta página foi feita [#como-esta-página-foi-feita]

<Files>
  <Folder name="docs-fonsecagabriel">
    <File name="Dockerfile" />

    <File name="next.config.mjs" />

    <Folder name="config">
      <File name="deploy.yml" />
    </Folder>

    <Folder name=".kamal">
      <File name="secrets" />
    </Folder>

    <Folder name="content/docs">
      <File name="index.mdx" />

      <File name="fumadocs-vs-nextra.mdx" />
    </Folder>
  </Folder>
</Files>

3 commits, 1 healthcheck bug, \~4min do `git init` ao `200 OK` em HTTPS.
