Routines no Claude: agente trabalhando sem você

Quer parar de gastar 20 minutos toda segunda resumindo o Focus para o time? Nesta postagem, mostramos como montar uma Routine do Claude Code que, todo início de semana às 10h, lê o boletim publicado pelo BCB, gera um resumo executivo com as três principais revisões e abre um Pull Request no GitHub pronto para você revisar. O passo a passo separa a parte determinística (um GitHub Action que baixa o PDF e extrai o texto) da parte interpretativa (a Routine que escreve o resumo), entregando um template que se adapta para Ata do Copom, RTI, IBC-Br e qualquer outro boletim recorrente.

A rotina que se repete toda segunda

Você é analista de macro e, antes da reunião das 10h, alguém precisa baixar o Focus daquela segunda, ler o boletim, identificar o que mudou em relação à semana anterior e escrever um parágrafo para o Slack ou o e-mail do time. São 20 minutos toda segunda numa tarefa cujo roteiro nunca muda: mesmo site, mesmo PDF, mesma estrutura de variáveis (IPCA, PIB, Selic, câmbio).

Tarefas repetitivas que envolvem texto não estruturado são onde a automação com modelo de linguagem começa a fazer sentido, e a pergunta correta deixa de ser “dá para automatizar?” e passa a ser “com qual ferramenta?”.

Como automatizar isso

O leque de opções é maior do que parece, e cada alternativa cobre um trade-off diferente entre agendamento, capacidade de ler texto livre e dependência da sua presença.

Como Agenda? Lê texto? Precisa de você?
Script + cron (Python, R) só se quebrar
Chatbot no navegador (ChatGPT, Claude.ai) presente, todo dia
n8n / Zapier + LLM configurar visualmente
Routine (Claude Code) revisar PR depois

Script + cron é imbatível quando o dado já vem estruturado por uma API, e chatbot resolve quando o trabalho é pontual. n8n encaixa bem em fluxos que orquestram serviços externos sem código próprio. Routine ganha quando o output precisa virar arquivo versionado no Git e o agente raciocina sobre os arquivos do repositório — o caso de um boletim que entra para revisão antes de chegar ao time.

Determinístico, LLM ou híbrido

Antes de adotar qualquer ferramenta, vale classificar a tarefa em um de três regimes.

Código puro serve quando o dado já vem estruturado: API REST, CSV bem formado, regra que não muda, sem texto livre para interpretar. Um script Python com requests + pandas ou um nó HTTP no n8n resolvem sem precisar de modelo de linguagem.

LLM puro entra quando o trabalho é ler texto livre, seja para resumir um documento, classificar comentários ou redigir um e-mail a partir de bullets. Um chatbot ou um nó Anthropic/OpenAI dentro do n8n cobrem o caso.

Híbrido com código (Routine) aparece quando, além de interpretar texto, você precisa rodar análise, gerar gráfico ou versionar o resultado, com o agente decidindo o próximo passo a cada etapa. É aqui que Routine entra, e o resumo semanal do Focus se encaixa nesse regime.

O que é uma Routine

Uma Routine é uma configuração salva do Claude Code: um prompt, um ou mais repositórios e um conjunto de conectores, empacotados uma vez e executados automaticamente. A execução acontece na infraestrutura em nuvem da Anthropic, então a rotina segue funcionando mesmo com seu notebook desligado.

Em uma frase, é o agente do Claude Code rodando num servidor remoto, no horário que você definir, com acesso ao seu repositório.

Há três formas de criar, todas escrevendo na mesma conta na nuvem. Pelo site claude.ai/code/routines, com formulário completo e suporte aos três tipos de trigger; pelo aplicativo desktop, na seção Routines da barra lateral; ou pelo CLI, com /schedule dentro da pasta do projeto, exigindo um repositório Git conectado.

A feature está em research preview, então limites e comportamento podem mudar. O /schedule no CLI cria apenas trigger do tipo schedule — para os outros tipos, edite a Routine pela web.

Como uma Routine dispara

Existem três formas de iniciar a execução.

Trigger Quando dispara Caso típico
Schedule Cron recorrente ou data única no futuro Resumo do Focus toda segunda às 10h
API POST autenticado num endpoint próprio da Routine Alerta do Sentry chama Claude para investigar
GitHub event Eventos do repo (pull_request.openedrelease.published) Revisão automática de PR com checklist do time

Uma mesma Routine pode combinar os três, rodando toda noite, reagindo a cada novo PR e ainda aceitando disparo manual via API. Nesta postagem usamos apenas schedule, mas vale saber que os outros existem.

Anatomia de uma Routine

Toda Routine se decompõe em quatro decisões.

ponto de partida define se a Routine recebe só um prompt (tarefa de texto pura), prompt + repositório pronto (caso do Focus) ou prompt + repositório que o próprio Claude vai escrever do começo.

Os conectores decidem com o que ela conversa. GitHub é obrigatório quando há repositório, e o Environment customizado entra se a rotina precisa de dependências instaladas ou acesso de rede específico. Connectors MCP (Slack, Linear, Drive, Notion, GitHub) cobrem o que estiver fora do repo.

trigger determina quando ela dispara — schedule, API ou GitHub event.

entrega define para onde vai o resultado: PR no GitHub (default quando há repo), e-mail, Slack/Discord/Teams, Notion/Docs/Sheets via connector. Os destinos são combináveis, e você pode abrir PR e postar o mesmo conteúdo no Slack na mesma execução.

Três perguntas ajudam a desenhar uma Routine nova. Tem código no fluxo? Se sim, precisa de repositório e Environment. Roda sozinha ou reage a algo? Sozinha pede schedule; reativa pede API ou GitHub event. Quem precisa ler o resultado? Você sozinho aceita PR ou e-mail; o time inteiro pede Slack ou Notion via connector.

O projeto: resumo semanal do Focus

O Focus é a pesquisa semanal do Banco Central com cerca de 100 instituições financeiras, consolidando expectativas para IPCA, PIB, Selic e câmbio. É publicado toda segunda às 8h30 BRT em bcb.gov.br/publicacoes/focus, e quando segunda é feriado, o BCB publica na terça.

A entrega que vamos automatizar é um markdown com duas seções: um resumo executivo de até 200 palavras, começando pelas medianas-chave (IPCA do ano corrente, Selic fim de ano, PIB, câmbio); e uma lista das três principais revisões da semana, cada uma com hipótese de motivo. O markdown chega como Pull Request no GitHub, e você revisa o diff antes de compartilhar com o time.

Por que duas peças, não uma

A primeira tentativa intuitiva é colocar tudo dentro da própria Routine: baixar o PDF, extrair o texto e resumir. Não funciona, porque o BCB bloqueia IPs de cloud (Anthropic, AWS, GCP) — a Routine roda numa dessas faixas e o download falha.

A saída é separar o pipeline em duas peças, com responsabilidades claras.

A primeira peça é um GitHub Action que roda às 9h15 BRT, baixando o PDF do Focus mais recente e extraindo o texto, para então commitar data/focus_AAAA-MM-DD.{pdf,txt} em main. Roda em IPs do GitHub, que o BCB não bloqueia, sem nenhum LLM no caminho — apenas Python com requests e pdfplumber.

A segunda peça é a Routine do Claude Code que entra às 10h BRT, lê o .txt mais recente, gera o resumo executivo + três revisões e abre PR na branch claude/focus-AAAA-MM-DD. Interpretação de texto livre é o tipo de tarefa que justifica usar um modelo de linguagem em vez de regex.

A folga de 45 minutos entre as duas garante que o .txt já esteja em main quando a Routine começar a procurar.

Estrutura do projeto

meu-projeto/
├── CLAUDE.md                          # briefing que o agente lê a cada execução
├── routine-prompt.md                  # os passos que ele executa toda segunda
├── requirements.txt                   # requests, pdfplumber, pytest
├── pytest.ini                         # configura marker `network`
├── .github/workflows/
│   └── focus-download.yml             # Action que baixa o PDF (9h15 BRT segunda)
├── src/
│   ├── baixar_focus.py                # descobre a data certa e baixa o PDF
│   └── extrair_texto.py               # extrai o texto do PDF e salva como .txt
├── tests/
│   └── test_baixar_focus.py
├── demo.py                            # roda baixar + extrair localmente
└── output/focus/                      # onde a Routine salva o markdown final

Os scripts Python rodam no GitHub Action, não na Routine, cuidando só da parte determinística (baixar e extrair). O resumo em si é gerado pelo próprio agente Claude Code que executa a Routine, lendo o .txt que o Action commitou em main.

Etapas até a Routine rodar sozinha

São seis etapas, na ordem em que precisam acontecer. Pré-requisitos: Python 3.12+, GitHub CLI autenticado (gh auth login), Claude Code instalado, conta na Anthropic com acesso a Routines e um repositório no GitHub onde o bot do Claude possa abrir PR.

Estrutura local

mkdir -p meu-projeto && cd meu-projeto
mkdir -p src tests data output/focus .github/workflows
touch CLAUDE.md routine-prompt.md requirements.txt demo.py

requirements.txt:

requests
pdfplumber
pytest

O CLAUDE.md do projeto

CLAUDE.md é o briefing permanente, lido pelo agente no início de toda execução. Coloque ali objetivo, fonte, convenções de arquivo e branch, e regras inegociáveis (nunca inventar número, nunca dar push direto em main).

# Resumo Focus — Routine semanal

## Objetivo

Toda segunda-feira, baixar o boletim Focus do BCB em PDF, gerar resumo
executivo + análise das três principais revisões da semana, abrir PR com
o markdown pronto.

## Fonte

- Página: https://www.bcb.gov.br/publicacoes/focus
- PDF: https://www.bcb.gov.br/content/focus/focus/R{AAAAMMDD}.pdf

## Convenções

- Saída: `output/focus/focus_AAAA-MM-DD.md` (nunca sobrescreve)
- Branch: `claude/focus-AAAA-MM-DD`
- Push direto em `main` é proibido

## Regras

- Nunca inventar número. Toda mediana citada deve estar no PDF.
- Citação literal entre aspas é preferível quando o boletim traz
  número-chave atualizado.
- Quando segunda é feriado, o script retrocede dia a dia até 7 dias antes
  de desistir.

O script de download

Este script roda dentro do GitHub Action, e não na Routine, porque o BCB bloqueia IPs de cloud da Anthropic. Como o Focus às vezes empurra para terça em feriado, o script parte da última segunda e recua dia a dia até encontrar um PDF válido.

from __future__ import annotations
import sys
from datetime import date, timedelta
from pathlib import Path
import requests

URL = "https://www.bcb.gov.br/content/focus/focus/R{ymd}.pdf"
UA = "Mozilla/5.0 (compatible; routine-focus/1.0)"


def ultima_segunda(hoje: date) -> date:
    return hoje - timedelta(days=(hoje.weekday() or 7))


def baixar(dest: Path) -> tuple[date, Path]:
    dest.mkdir(parents=True, exist_ok=True)
    candidato = ultima_segunda(date.today())
    for _ in range(7):
        ymd = candidato.strftime("%Y%m%d")
        url = URL.format(ymd=ymd)
        resp = requests.get(url, headers={"User-Agent": UA}, timeout=30)
        if resp.status_code == 200 and resp.content[:4] == b"%PDF":
            arq = dest / f"focus_{candidato}.pdf"
            arq.write_bytes(resp.content)
            return candidato, arq
        candidato -= timedelta(days=1)
    raise RuntimeError("Nenhum PDF do Focus nos últimos 7 dias.")


def main() -> int:
    dest = Path(__file__).parent.parent / "data"
    data_pub, arq = baixar(dest)
    print(f"Focus de {data_pub} salvo em {arq} ({arq.stat().st_size // 1024} KB)")
    return 0


if __name__ == "__main__":
    sys.exit(main())

A função ultima_segunda usa o truque hoje.weekday() or 7 para que, quando hoje é segunda (weekday() == 0), o resultado seja a segunda anterior — caso contrário, retornaria o próprio dia, antes do boletim daquela manhã estar publicado.

O script de extração de texto

Segunda etapa do Action: abre o PDF com pdfplumber, concatena o texto das páginas e salva como .txt ao lado do PDF. Nenhuma chamada de LLM acontece aqui, e é esse material que a Routine lerá 45 minutos depois.

from __future__ import annotations
import argparse, sys
from pathlib import Path

ROOT = Path(__file__).parent.parent
DATA = ROOT / "data"


def extrair(pdf_path: Path) -> Path:
    import pdfplumber
    with pdfplumber.open(pdf_path) as pdf:
        texto = "\n".join(p.extract_text() or "" for p in pdf.pages)
    txt = pdf_path.with_suffix(".txt")
    txt.write_text(texto, encoding="utf-8")
    return txt


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--pdf", type=Path, help="caminho do PDF (default: último em data/)")
    args = parser.parse_args()

    if args.pdf:
        pdf = args.pdf
    else:
        candidatos = sorted(DATA.glob("focus_*.pdf"))
        if not candidatos:
            print("Nenhum PDF em data/. Rode src/baixar_focus.py primeiro.", file=sys.stderr)
            return 1
        pdf = candidatos[-1]

    txt = extrair(pdf)
    print(f"Texto salvo em {txt}")
    return 0


if __name__ == "__main__":
    sys.exit(main())

Validar localmente antes de agendar

Antes de agendar qualquer coisa, confirme que o pipeline determinístico funciona na sua máquina. Como o resumo é trabalho do agente da Routine, localmente você só valida baixar + extrair.

python3 -m pip install -r requirements.txt
python3 demo.py --abrir

Saída esperada:

[1/2] PDF baixado: focus_2026-05-18.pdf (768 KB)
[2/2] Texto extraído: data/focus_2026-05-18.txt

Abra o .txt e confira que ele traz as tabelas de IPCA, Selic, PIB e câmbio com os marcadores ▲▼ de revisão — é esse material que o agente lerá na Routine.

Subir o repositório

git init -b main
git add .
git commit -m "Projeto inicial: Routine Focus"
gh repo create resumo-focus --private --source=. --remote=origin --push

Em Settings → Actions → General do repositório, marque Allow all actions and reusable workflows e, em Workflow permissionsRead and write permissions. Sem isso, o Action não consegue commitar o .txt de volta em main e a Routine não consegue abrir PR.

Workflow do GitHub Action

Este workflow é a outra ponta do pipeline: toda segunda às 9h15 BRT (12h15 UTC) ele baixa o PDF, extrai o texto e commita ambos em main. O workflow_dispatch permite disparar manualmente pela aba Actions, o que ajuda no primeiro teste.

.github/workflows/focus-download.yml:

name: Focus — Download e Extração

on:
  schedule:
    # Toda segunda-feira às 12:15 UTC = 09:15 BRT (UTC-3)
    - cron: '15 12 * * 1'
  workflow_dispatch:

jobs:
  baixar:
    runs-on: ubuntu-latest
    permissions:
      contents: write

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Instalar dependências
        run: pip install -r requirements.txt

      - name: Baixar PDF do Focus
        run: python src/baixar_focus.py

      - name: Extrair texto do PDF
        run: python src/extrair_texto.py

      - name: Commit dos arquivos gerados
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add data/focus_*.pdf data/focus_*.txt
          if git diff --cached --quiet; then
            echo "Nenhum arquivo novo — Focus já estava em data/."
          else
            DATE=$(ls data/focus_*.txt | sort | tail -1 | grep -oP '\d{4}-\d{2}-\d{2}')
            git commit -m "data: Focus ${DATE} — PDF e texto extraído"
            git push
          fi

Em Actions → Focus — Download e Extração → Run workflow, dispare a primeira execução manual e confira que data/focus_AAAA-MM-DD.{pdf,txt} aparece commitado em main.

Conectores GitHub: App + MCP

A Routine precisa de dois acessos ao GitHub, que não são a mesma coisa.

GitHub App é instalado em github.com/apps/claude, selecionando o repositório resumo-focus, e autoriza a Anthropic a clonar e ler o repo. O MCP do GitHub é adicionado durante o /schedule, no campo MCP connectors, e é obrigatório, porque é por ele que a Routine cria a branch claude/focus-*, commita o markdown e abre o PR. Sem MCP, a Routine não tem ferramenta para entregar.

Se o conector visual não estiver disponível na criação da Routine, adicione manualmente via URL do servidor MCP: https://api.githubcopilot.com/mcp.

O routine-prompt.md

Este é o prompt que a Routine executa a cada disparo. Estruture em passos numerados com regras explícitas de aborto, porque o agente roda sem você — cenários de falha precisam estar escritos, não implícitos.

Você está executando a Routine de resumo semanal do Focus.

O download do PDF e a extração do texto já foram feitos por um GitHub
Action mais cedo (segunda 9h15 BRT). Os arquivos
`data/focus_AAAA-MM-DD.{pdf,txt}` já estão commitados em `main` quando
a Routine inicia. Sua tarefa é ler o `.txt` mais recente, gerar o
resumo executivo e abrir um PR.

## Passos

1. **Localize o `.txt` mais recente.** Liste `data/focus_*.txt` e pegue
   o de data mais alta. Se não houver nenhum, pare sem abrir PR — o
   Action não rodou.

2. **Verifique frescor.** Extraia a data do nome e compare com hoje:
   - 0 a 3 dias: está fresco, siga.
   - 4 a 7 dias: marque o PR como `[REVISAR]`.
   - Mais de 7 dias: pare sem abrir PR.

3. **Sanity check do texto.** Confirme: pelo menos 2 000 caracteres e
   presença das palavras `IPCA`, `Selic`, `PIB`. Se falhar, o layout do
   PDF pode ter mudado — pare sem abrir PR.

4. **Leia o texto** e gere markdown com:
   - **Resumo executivo** em até 200 palavras, em prosa corrida.
     Comece pelas medianas das principais variáveis (IPCA do ano,
     Selic fim de ano, PIB, câmbio). Cite literalmente entre aspas
     quando houver número-chave.
   - **Três principais revisões da semana** em bullets:
     `- **Variável (ano):** anterior → atual. *Hipótese:* motivo.`
   - Nunca invente número. Se não houver hipótese sólida, escreva
     "sem hipótese clara — pode ser ruído amostral".

5. **Salve** em `output/focus/focus_AAAA-MM-DD.md` com cabeçalho YAML
   (`data`, `fonte`).

6. **Inspecione** o markdown gerado: medianas batem com o `.txt`, ao
   menos uma citação literal entre aspas, hipóteses plausíveis.

7. **Abra o PR.** Branch `claude/focus-AAAA-MM-DD` a partir de `main`,
   commit `"Focus AAAA-MM-DD: resumo semanal"`, título do PR
   `"Focus — AAAA-MM-DD"`.

8. **Corpo do PR:** o markdown inteiro + link para o PDF original no
   site do BCB.

## Falhas

Em qualquer cenário abaixo, pare sem abrir PR. O motivo aparece no
transcript da Routine.

- Nenhum `.txt` em `data/` (Action não rodou).
- `.txt` com mais de 7 dias (Action quebrado).
- Sanity check do texto falhou (mudança de layout do PDF).

Nunca dê push direto em `main`. Nunca invente número.

Criar a Routine com /schedule

Abra o Claude Code local na pasta do projeto e rode /schedule. Preencha:

Campo Valor
Nome resumo-focus
Repositório analisemacro/resumo-focus (com allow_unrestricted_git_push: true)
Prompt cole o conteúdo de routine-prompt.md
Trigger (cron) 0 13 * * 1
Modelo claude-sonnet-4-6
MCP connectors github

O cron 0 13 * * 1 é segunda às 13h UTC, ou 10h BRT, 45 minutos depois do Action das 9h15 BRT. Essa folga garante que o .txt já esteja em main quando a Routine começar.

A branch claude/ e por que ela existe

Por padrão, a Routine só consegue dar push em branches prefixadas com claude/, como proteção contra sobrescrever a main por engano. Na prática, o PR que chega no repositório vem de uma branch tipo claude/focus-2026-05-18, e você revisa o diff e dá merge normalmente.

Para liberar push em qualquer branch, marque Allow unrestricted branch pushes na edição da Routine. Para a maioria dos casos, manter o default é mais seguro.

Primeiro disparo

Pela web (claude.ai/code/routines → sua Routine → Run now) ou pelo CLI (/schedule run resumo-focus), dispare a primeira execução manual e acompanhe o transcript: a Routine clona o repo, lista data/focus_*.txt, lê o mais recente, faz o sanity check, gera o markdown em output/focus/focus_AAAA-MM-DD.md, cria a branch claude/focus-AAAA-MM-DD, commita e abre o PR.

Você recebe a notificação do GitHub com o PR, abre, revisa o diff e faz merge se estiver correto. A partir da segunda seguinte, tudo roda sozinho às 10h.

O primeiro disparo é onde você ajusta o prompt: se o resumo veio sem citação literal, reforce no routine-prompt.md; se a hipótese sobre uma revisão soou inventada, adicione um exemplo do que considera hipótese aceitável. Cada erro vira uma linha nova no prompt, e em duas ou três semanas a Routine estabiliza.

Onde entregar o resumo

O markdown chega como PR no GitHub, mas o time precisa ler o resumo onde já trabalha. A Routine pode postar o mesmo texto em vários destinos no fim do prompt, bastando acrescentar um passo extra que dispara um webhook ou usa um connector já autorizado na sua conta.

Destino Quando usar
Slack / Discord Time trabalha em chat; histórico fica no canal
E-mail corporativo Escalação formal; arquivo pessoal
Teams / Mattermost Corporativo com plataforma própria
Google Docs / Sheets Auditoria e histórico fora do git
Notion Knowledge base integrado

Mantenha o PR como ponto de revisão obrigatório, e o destino externo recebe apenas o que você aprovou no merge — isso preserva o controle editorial sem perder velocidade de distribuição.

Observabilidade

Uma Routine que trabalha sem supervisão precisa deixar rastro. O transcript da execução fica em claude.ai/code/routines e mostra cada chamada de ferramenta com input e output, o histórico de PRs aparece em gh pr list --author "@claude" com toda semana publicada, e os logs do Action ficam na aba Actions do repositório, com retenção padrão de 30 dias.

Configure notificação por e-mail quando o Action falhar (Settings → Notifications no GitHub), porque sem isso você só percebe o problema na segunda em que o PR não chegar.

Quando a Routine não basta

A Routine automatiza o fluxo, mas não substitui você na interpretação econômica de fundo — o resumo cita “mediana do IPCA subiu para 4,5%”, e quem decide se é ruído ou mudança de regime continua sendo o analista. Decisões editoriais finais passam pelo seu merge, e mudanças de escopo (o boletim virar nota de política monetária) pedem reescrita do prompt, já que a Routine não se reinventa sozinha.

Reaproveitando o padrão

O padrão Action determinístico baixa + Routine interpretativa resume + PR para revisão serve, com pequenas trocas, para outros boletins.

Produto Ajustes mínimos
Ata do Copom Trocar URL e cron (8 reuniões ao ano em vez de semanal)
Relatório Trimestral de Inflação Trocar fonte e expandir o prompt para gráficos comparativos
Boletim Macro Fiscal (STN) Trocar fonte; manter o resto
Release IBC-Br Action baixa o XLS; Routine compara mês contra mês

A primeira Routine custa o tempo de entender os conectores, a branch claude/ e o ciclo Action → Routine → PR; a segunda custa metade, porque a arquitetura já está resolvida. Trate o projeto do Focus como template.

Compartilhe esse artigo

Facebook
Twitter
LinkedIn
WhatsApp
Telegram
Email
Print
Análise Macro © 2011 / 2026

comercial@analisemacro.com.br – Rua Visconde de Pirajá, 414, Sala 718
Ipanema, Rio de Janeiro – RJ – CEP: 22410-002

como podemos ajudar?

Preencha os seus dados abaixo e fale conosco no WhatsApp