Você realmente precisa do WordPress? Migre seu blog para S3 + CloudFront com o Claude em menos de uma hora

Traduzido do original em espanhol. Ler em espanhol

WordPress, Drupal, Joomla — são plataformas maduras e resolvem muitos casos. E sim, para um site com usuários, formulários, e-commerce ou uma equipe editorial, continuam fazendo sentido. Mas se tudo o que você faz é publicar artigos, você está pagando caro por algo que não usa: PHP, um banco de dados, plugins que precisam de patch e um painel de admin exposto na internet.

A alternativa é velha e sem graça: HTML estático em um bucket do S3, servido pelo CloudFront. O que mudou é o custo da migração. Com o Claude Code, a migração completa — conteúdo, infraestrutura em stage e prod, pipelines — me levou entre 30 e 50 minutos.

Como referência: estimo que um senior dev que conhece AWS, fazendo o mesmo à mão para um site de 50 posts, leve de 3 a 5 dias de trabalho — umas 20 a 35 horas. A maior parte não é a infra, e sim converter e limpar o conteúdo post por post e replicar o theme. Se ele já tiver a infra em Terraform ou CDK, cai para um dia e meio ou dois. Continua sendo outra escala.

Aqui vai o passo a passo, com os detalhes técnicos e — sobretudo — o modelo de segurança.

Una ingeniera frente a un monitor que muestra un panel de migración de un sitio web legacy a uno moderno, con un chip de IA en el centro


Você precisa de um CMS? Os trade-offs

Antes de migrar, vale ser honesto sobre o que você perde e o que ganha.

O que você ganha:

  • Superfície de ataque quase nula — não há PHP, nem banco de dados, nem /wp-admin. Nada é executado do lado do servidor, então não há nada para explorar.
  • Zero manutenção — chega de updates de core, de plugins e de theme. Um site estático de cinco anos atrás continua funcionando igual.
  • Custo — para um blog pequeno, centavos por mês. O CloudFront tem um free tier de 1 TB de transferência mensal.
  • Performance — tudo sai do edge do CloudFront. Não há render por request.
  • Versionamento de verdade — o site inteiro vive no Git. Cada mudança tem histórico, review e rollback.

O que você perde:

  • Comentários — resolve-se com um serviço externo (Giscus, por exemplo) ou eles são removidos. Eu os removi.
  • Formulários — você precisa de um endpoint à parte (Lambda, Formspree). Adiciona uma peça móvel.
  • Busca — só do lado do cliente (Pagefind, Lunr). Funciona bem até alguns milhares de posts.
  • O editor visual — você escreve em Markdown. Se isso não é para você, mais abaixo mostro como o Claude resolve essa parte.

Se a lista do que você perde não dói, continue lendo.


A arquitetura

O design final é simples:

  • GitHub repo — o conteúdo em Markdown e o gerador de site estático (uso Astro).
  • GitHub Actions — um pipeline que faz o build e publica em stage a cada push para main, e em prod depois de uma aprovação manual.
  • S3 — dois buckets privados, um por ambiente. Sem website hosting, sem acesso público.
  • CloudFront — uma distribuição por ambiente, com Origin Access Control (OAC) para ler do bucket, certificado do ACM e uma CloudFront Function para as URLs.
  • IAM — duas identidades diferentes, com permissões diferentes: uma temporária para o Claude fazer a migração e um role por ambiente para o pipeline, via OIDC.

O modelo de segurança, antes de mexer em qualquer coisa

A ideia original era dar ao Claude uma access key, criar o repo, criar os pipelines e pronto. Funciona. Mas ao revisar aparecem três problemas, e eu os corrigi antes de começar:

  • O Claude não pode ter permissões de IAM. Se o user do Claude pode criar roles e policies, pode se conceder qualquer permissão — é escalação de privilégios por design. O OIDC provider e os roles do pipeline são criados por você.
  • O pipeline não usa access keys. Nada de AWS_ACCESS_KEY_ID nos GitHub Secrets. O GitHub Actions se autentica na AWS com OIDC e recebe credenciais temporárias, e a trust policy restringe qual repo e qual ambiente pode assumir cada role.
  • O Claude não pode modificar o pipeline. Se o agente pode editar .github/workflows/, pode mudar para onde se publica e com quais permissões. Os workflows são commitados por você, e o token do Claude não tem permissão para mexer neles.

A regra que aplico: o agente opera dentro dos limites; nunca define os limites.


Passo a passo

1. Crie o IAM user para o Claude

No console do IAM, crie um user sem acesso ao console — por exemplo claude-migration. Atribua a ele esta policy inline. Substitua mi-blog pelo prefixo dos seus buckets:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SiteBucketsOnly",
      "Effect": "Allow",
      "Action": [
        "s3:CreateBucket",
        "s3:PutBucketPolicy",
        "s3:GetBucketPolicy",
        "s3:PutBucketPublicAccessBlock",
        "s3:GetBucketPublicAccessBlock",
        "s3:PutBucketOwnershipControls",
        "s3:PutEncryptionConfiguration",
        "s3:ListBucket",
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Resource": [
        "arn:aws:s3:::mi-blog-*",
        "arn:aws:s3:::mi-blog-*/*"
      ]
    },
    {
      "Sid": "CloudFront",
      "Effect": "Allow",
      "Action": [
        "cloudfront:CreateDistribution",
        "cloudfront:UpdateDistribution",
        "cloudfront:GetDistribution",
        "cloudfront:GetDistributionConfig",
        "cloudfront:ListDistributions",
        "cloudfront:CreateOriginAccessControl",
        "cloudfront:GetOriginAccessControl",
        "cloudfront:ListOriginAccessControls",
        "cloudfront:CreateFunction",
        "cloudfront:UpdateFunction",
        "cloudfront:DescribeFunction",
        "cloudfront:TestFunction",
        "cloudfront:PublishFunction",
        "cloudfront:CreateResponseHeadersPolicy",
        "cloudfront:ListResponseHeadersPolicies",
        "cloudfront:ListCachePolicies",
        "cloudfront:CreateInvalidation",
        "cloudfront:GetInvalidation"
      ],
      "Resource": "*"
    },
    {
      "Sid": "Certificates",
      "Effect": "Allow",
      "Action": [
        "acm:RequestCertificate",
        "acm:DescribeCertificate",
        "acm:ListCertificates"
      ],
      "Resource": "*"
    }
  ]
}

Três coisas a notar:

  • O S3 está restrito por ARN — o Claude só pode mexer em buckets que comecem com o seu prefixo. Não há s3:DeleteBucket: apagar um bucket é uma decisão sua.
  • O CloudFront usa "Resource": "*" — a criação de distribuições não admite restrição por recurso. É o ponto mais amplo da policy, e é o motivo pelo qual a key só existe durante a migração.
  • Não há nenhuma ação de IAM. De propósito.

Se durante a migração aparecer um AccessDenied, o Claude vai dizer qual ação está faltando. Adicione só ela. Não coloque cloudfront:* para destravar.

Crie a access key do user e configure-a em um profile próprio, não no default:

aws configure --profile claude-migration
export AWS_PROFILE=claude-migration
aws sts get-caller-identity

Nunca cole a key no chat com o Claude. O agente usa o profile; não precisa ver o segredo.

2. Crie o repo e limite o que o Claude pode fazer

Crie o repo no GitHub (privado, mesmo que o site seja público — não é preciso expor drafts). Depois gere um fine-grained personal access token:

  • Repository access — só este repo.
  • Contents — read and write.
  • Pull requests — read and write.
  • Workflows — sem acesso. Assim o Claude não consegue fazer push de mudanças em .github/workflows/.
  • Expiration — 7 dias.

Do lado do Claude Code, adicione um .claude/settings.json no repo com regras de permissões:

{
  "permissions": {
    "deny": [
      "Read(~/.aws/**)",
      "Bash(aws iam:*)",
      "Bash(aws s3 rb:*)"
    ],
    "ask": [
      "Bash(aws cloudfront create-distribution:*)",
      "Bash(aws cloudfront update-distribution:*)",
      "Bash(aws s3 sync:*)",
      "Bash(git push:*)"
    ]
  }
}

Lembre-se de que esta é uma segunda camada, não a principal. Um deny sobre Read não impede um cat pelo Bash. O controle real é a policy de IAM do passo anterior. As regras do Claude Code servem para que as operações importantes passem pela sua aprovação.

3. Migre o conteúdo: o Claude lê o WordPress via MCP

Aqui não há export, nem XML, nem scripts de conversão. Instalo o plugin AI Engine (da Meow Apps) no WordPress, que expõe um MCP server, e conecto o Claude diretamente ao site. O Claude lê todos os posts, categorias e tags, baixa as imagens e monta o site novo. Tudo é feito pelo Claude.

Para autenticar uso OAuth, não um Bearer Token estático. A diferença importa:

  • Não há segredo compartilhado — não há um token para copiar, colar em um comando e que acabe no histórico do shell ou em um arquivo de config.
  • Identidade real — cada autorização fica vinculada a um usuário do WordPress, com login normal e uma tela de consentimento que mostra qual app pede acesso e com qual papel.
  • Revogação em um clique — o painel Connected Apps do AI Engine lista cada autorização ativa.

No WordPress, AI Engine → Settings → MCP: ative o MCP server. Com OAuth não é preciso definir Bearer Token — o AI Engine publica os endpoints de discovery (/.well-known/oauth-*) e o cliente se registra sozinho via Dynamic Client Registration. A partir do repo:

claude mcp add --transport http wp-origen https://mi-sitio.com/wp-json/mcp/v1/http

Depois, dentro do Claude Code, rode /mcp, escolha wp-origen e Authenticate. O browser abre, você faz login no WordPress e aprova. O token fica no armazenamento seguro do Claude Code, não em um arquivo do repo.

E aqui está a distinção mais ignorada: com OAuth, o Claude tem as permissões do usuário com que você faz login. Se você aprova como admin, o Claude é admin — pode apagar posts, mudar settings, instalar plugins se o grupo estiver exposto. OAuth melhora a autenticação; não reduz a autorização. Por isso:

  • Crie um usuário dedicado — por exemplo claude-migracion, com o papel mais baixo que permita ler o que você precisa. Não aprove com sua conta de admin.
  • Exponha só o necessário — na tela do MCP, deixe ativo só o grupo WordPress (posts, media, taxonomias). Plugins, Themes e Dynamic REST, desligados.
  • Revise o WAF — algumas hospedagens bloqueiam os POST para /wp-json/mcp/v1/oauth/register e o registro falha. Se isso acontecer, é preciso liberar /.well-known/oauth-* e /wp-json/mcp/v1/*.

Se a sua versão do AI Engine exige um usuário admin para o MCP, o trade-off muda: um Bearer Token com access level Read-Only é restringido do lado do servidor, e aí pode ser a opção mais segura das duas. Verifique antes de escolher.

Como segunda camada, bloqueie as tools de escrita do lado do Claude Code. Adicione ao .claude/settings.json:

{
  "permissions": {
    "deny": [
      "mcp__wp-origen__wp_create_post",
      "mcp__wp-origen__wp_update_post",
      "mcp__wp-origen__wp_delete_post",
      "mcp__wp-origen__wp_upload_media",
      "mcp__wp-origen__wp_update_option"
    ]
  }
}

Os nomes exatos das tools dependem da versão do plugin — com /mcp você vê a lista. Bloqueie tudo o que escreve. O Claude só precisa das tools de leitura.

Com o MCP conectado, o prompt:

Conectate al MCP wp-origen y migrá el sitio a Astro en este repo.

- Leé todos los posts publicados, con sus categorías, tags y excerpt.
- Convertí cada post a Markdown en una content collection, con front
  matter: title, date, slug, categories, tags, description.
- Mantené exactamente las mismas URLs que en WordPress.
- Bajá todas las imágenes referenciadas (incluida la featured image)
  a public/images/ y reescribí las rutas.
- Convertí los shortcodes y bloques de Gutenberg a HTML limpio.
- Ignorá comentarios, drafts y páginas de sistema.
- No escribas nada en WordPress: sólo lectura.
- Antes de escribir código, armá un plan en PLAN.md y esperá mi OK.

Revise o plano. Com cuidado. O que mais quebra nesta etapa são as URLs: se mudarem, você perde o SEO acumulado e todos os links externos. No Astro, a rota é definida pela estrutura de src/pages/ — por exemplo src/pages/[year]/[month]/[slug].astro se o seu WordPress usa /%year%/%monthnum%/%postname%/. Se a estrutura coincidir, não há redirects para manter.

Deixe o build.format do Astro em directory (o padrão): ele gera /mi-post/index.html, que é o que depois a CloudFront Function do passo 4 resolve. E crie src/pages/404.astro — o build o transforma em 404.html.

Para visualizar localmente:

npm run dev

E aqui há um risco que costuma passar despercebido: o conteúdo que o Claude está lendo é untrusted (não confiável). Posts antigos, HTML colado de outros sites, um comentário de spam que passou. Um texto com instruções escondidas é um vetor de prompt injection — e com um MCP que pode escrever no seu site ao vivo, o dano possível já não é só local. Por isso as tools de escrita vão em deny, não em ask, e por isso as permissões da AWS são mínimas.

A alternativa sem MCP é o export nativo (Tools → Export, formato WXR) mais uma cópia de wp-content/uploads. Não mexe no site ao vivo, mas cabe a você baixar e organizar os arquivos. Para um site com poucos posts, o MCP é bem mais rápido.

4. Peça ao Claude a infraestrutura

Com o site fazendo build localmente, peça ao Claude que crie a infra para stage e prod. Isto é o que precisa ficar pronto, e o que vale verificar:

  • Buckets privados — Block Public Access ativado nas quatro flags, sem static website hosting. O CloudFront lê pelo endpoint REST do bucket, não pelo de website.
  • Origin Access Control — não o legacy OAI. O bucket só aceita s3:GetObject a partir daquela distribuição específica.
  • Certificado ACM em us-east-1 — o CloudFront só aceita certificados dessa região, não importa onde estejam os buckets. A validação é por DNS.
  • Response headers policy — HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy. A managed policy SecurityHeadersPolicy cobre o básico.
  • TLS mínimo — TLSv1.2_2021 e redirect de HTTP para HTTPS.

A bucket policy que deve ficar em prod:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCloudFrontOAC",
      "Effect": "Allow",
      "Principal": { "Service": "cloudfront.amazonaws.com" },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::mi-blog-prod/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::ACCOUNT_ID:distribution/DISTRIBUTION_ID"
        }
      }
    }
  ]
}

5. Conecte o GitHub à AWS via OIDC (isto é com você)

Este é o passo que não delego ao Claude, porque exige permissões de IAM. Primeiro, o identity provider (uma vez por conta):

aws iam create-open-id-connect-provider \
  --url https://token.actions.githubusercontent.com \
  --client-id-list sts.amazonaws.com

Depois, um role por ambiente. A trust policy do role de prod:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
          "token.actions.githubusercontent.com:sub": "repo:TU_USUARIO/TU_REPO:environment:production"
        }
      }
    }
  ]
}

A condição sobre sub é a que garante “só este repo pode publicar”. E vai um passo além: só um job rodando no environment production desse repo pode assumir o role. Use StringEquals, não StringLike com wildcards — um repo:TU_USUARIO/* abre o acesso a todos os seus repos.

O role de stage é idêntico, com environment:staging e apontando para o bucket de stage.

As permissões do role de prod — só o que o deploy precisa:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::mi-blog-prod"
    },
    {
      "Effect": "Allow",
      "Action": ["s3:PutObject", "s3:DeleteObject", "s3:GetObject"],
      "Resource": "arn:aws:s3:::mi-blog-prod/*"
    },
    {
      "Effect": "Allow",
      "Action": "cloudfront:CreateInvalidation",
      "Resource": "arn:aws:cloudfront::ACCOUNT_ID:distribution/DISTRIBUTION_ID"
    }
  ]
}

Aqui CreateInvalidation admite restrição por ARN. O pipeline pode publicar em um bucket e invalidar uma distribuição. Nada mais.

6. Os pipelines de stage e prod

No repo, Settings → Environments, crie dois environments:

  • staging — deployment branch: só main. Variáveis: AWS_ROLE_ARN, BUCKET, DISTRIBUTION_ID, SITE_URL.
  • production — deployment branch: só main, required reviewer: você. As mesmas variáveis, com os valores de prod.

São variáveis, não secrets. Um role ARN não é um segredo — sem o token OIDC do seu repo, ele não serve para nada.

O workflow, em .github/workflows/deploy.yml, tem três jobs:

  • check — roda em cada PR. Instala as dependências com npm ci e faz o build. Não pede credenciais da AWS.
  • deploy-stage — roda em cada push para main, no environment staging. Faz o build, assume o role de stage via OIDC, sobe o site com aws s3 sync --delete e invalida o cache do CloudFront.
  • deploy-prod — depende de stage e roda no environment production. Os mesmos passos, com o role e as variáveis de prod.

Dois detalhes que fazem a diferença: a permissão id-token: write é declarada só nos jobs de deploy, não no nível do workflow, e os três jobs leem tudo das variáveis do environment — o mesmo código publica em stage ou em prod conforme onde roda.

O fluxo fica assim: um PR só faz o build — sem credenciais da AWS, então um PR malicioso não consegue publicar nada. Um merge em main publica em stage automaticamente. Prod fica esperando a sua aprovação na aba Actions. Você aprova, e publica.

Sobre a invalidação: /* conta como um único path, e os primeiros 1.000 paths por mês são gratuitos. Para um blog, invalidar tudo a cada deploy é a opção mais simples e não custa nada.

Fazer o build duas vezes (uma por ambiente) é proposital: a URL do site muda, e o Astro a embute no HTML — canonical, sitemap, RSS. Em astro.config.mjs:

export default defineConfig({
  site: process.env.SITE_URL,
  build: { format: 'directory' },
});

No pipeline, SITE_URL vem da variável do environment. O custo são alguns segundos a mais de build.

7. Proteja o pipeline

O pipeline agora é o único caminho para prod. Isso o torna o ativo a proteger:

  • Branch protection em main — PR obrigatório, status check check verde, sem force push.
  • CODEOWNERS sobre .github/ — qualquer mudança nos workflows exige o seu review.
  • Required reviewer em production — já configurado no passo anterior. É o último controle humano antes de publicar.

8. Cutover

Com prod publicado e verificado na URL do CloudFront (dxxxx.cloudfront.net):

  1. Baixe o TTL do registro DNS para 300 segundos, um dia antes.
  2. Aponte o domínio para a distribuição: um alias record no Route 53, ou um CNAME no seu provedor (para o apex, use ALIAS/ANAME se ele suportar).
  3. Verifique se as URLs antigas respondem. Um script simples que percorra o sitemap do WordPress e compare os códigos HTTP é suficiente.
  4. Mantenha o WordPress desligado — não apagado — por algumas semanas, caso apareça algo que tenha escapado.

9. Feche tudo o que você abriu para a migração

Primeiro, a key da AWS:

aws iam update-access-key \
  --user-name claude-migration \
  --access-key-id AKIAXXXXXXXXXXXXXXXX \
  --status Inactive

E remova-a de ~/.aws/credentials. Uma key inativa em disco continua sendo uma key esperando que alguém a reative.

Minha recomendação, na verdade, é ir um passo além: apagá-la. Quando precisar, você cria uma nova — leva dez segundos e garante que nenhuma key antiga fique esquecida. Revogue também o token do GitHub, ou deixe-o expirar.

Depois, o MCP. Se o WordPress continuar online durante o período de transição, revogue a autorização em Connected Apps, desative o MCP no AI Engine e apague o usuário claude-migracion. Se o plugin estava só para a migração, desinstale-o. E do lado do Claude Code:

claude mcp remove wp-origen

Um MCP com permissões de escrita sobre um site que você não usa mais é exatamente o tipo de coisa que é esquecida e fica aberta.


O Claude é o seu editor “visual”

Aqui está o que convence quem não quer saber de Markdown nem de Git. O painel do WordPress desaparece, e o editor passa a ser uma conversa. Você abre o Claude Code no repo e diz:

Creá un post nuevo. Este es mi draft:

[tu texto, bla bla]

Categoría Tecnología.
Levantá npm run dev para que lo revise.
Cuando te dé el OK, creá una branch, commiteá y abrí un PR.

Você revisa em localhost:4321, pede ajustes — “encurte a intro”, “mova a imagem para baixo do primeiro parágrafo”, “mude o título” — e aprova. O Claude abre o PR, o check passa, você faz o merge, stage se atualiza sozinho, você aprova prod. Pronto.

Para isso não são necessárias credenciais da AWS. O Claude só precisa do token do GitHub — o deploy é feito pelo pipeline. É a configuração que deixo de forma permanente.

Um skill com as regras do seu blog

O prompt acima funciona, mas deixa muito por conta do que o Claude inferir dos posts existentes. A forma de fixar isso é um skill: um arquivo com as regras de como um post deve ser, que o Claude carrega toda vez que você pede um. É o que um editor faz — conhecer o manual de estilo sem que você precise repeti-lo.

Ele vive no repo, em .claude/skills/nuevo-post/SKILL.md:

---
name: nuevo-post
description: Crea o edita posts del blog. Usar siempre que se pida
  escribir, corregir o publicar un post.
---

# Nuevo post

## Front matter (obligatorio)
- title, date (ISO), slug en kebab-case, description (máx. 160 caracteres)
- categories: sólo Tecnología, Seguridad o AI
- tags: entre 2 y 5

## Estilo
- Español, primera persona, frases cortas.
- Términos técnicos en inglés, sin traducir.
- Apertura con el problema, no con una definición.
- Un H2 por sección. Nada de H1 en el cuerpo.

## Imágenes
- En public/images/[slug]/, formato webp, máx. 1600px de ancho.
- alt obligatorio y descriptivo.
- La principal va debajo de la intro.

## Flujo
1. Crear el archivo en src/content/blog/[slug].md como draft: true.
2. Levantar npm run dev y pasar la URL local.
3. Aplicar los cambios que pida.
4. Con el OK: draft: false, branch post/[slug], commit y PR.
   Nunca pushear directo a main.

Com o skill, o prompt se reduz a “crie um post com este draft”. O resto — formato, imagens, categorias, o fluxo até o PR — já está definido.


A validação de segurança, resumida

Estes são os riscos que revisei, e como fica cada um:

  • Access key de longa duração — mitigado. Só existe durante a migração, em um profile separado, e é apagada depois. Risco residual: a janela da migração, menos de uma hora.
  • Escalação de privilégios via IAM — eliminado. O user do Claude não tem nenhuma ação de IAM; os roles do pipeline são criados por você.
  • Policy do CloudFront com Resource: * — aceito. É uma limitação da API. Durante a migração, o Claude poderia modificar outras distribuições da conta. Se você tem outras distribuições em produção, faça a migração em uma conta separada do AWS Organizations.
  • Credenciais no GitHub — eliminado. OIDC com credenciais temporárias, sem secrets.
  • Outro repo publicando no seu bucket — eliminado. A trust policy exige repo e environment exatos.
  • Agente modificando o pipeline — mitigado. O token não tem permissão de Workflows, e o CODEOWNERS exige o seu review.
  • Prompt injection a partir do conteúdo importado — mitigado, não eliminado. O blast radius é limitado pelas permissões, e os comandos sensíveis exigem a sua aprovação.
  • Bucket exposto — eliminado. Block Public Access, sem website hosting, OAC vinculado a uma distribuição.
  • s3 sync --delete apagando demais — aceito. Se um build sair vazio, ele apaga o site. Ative o versioning no bucket de prod: você recupera qualquer versão anterior por centavos.
  • MCP com escrita sobre o WordPress ao vivo — mitigado. OAuth com um usuário dedicado de papel baixo, só o grupo WordPress exposto, tools de escrita em deny, e autorização revogada e MCP desligado ao terminar. Risco residual: o endpoint fica exposto na internet enquanto está ativo, e as permissões reais são as do papel do usuário.
  • Supply chain — mitigado. Actions fixadas por SHA, npm ci com lockfile commitado.

Menos de uma hora? Depende

Para um blog de algumas dezenas de posts, sim. Esses 30–50 minutos são tempo meu revisando e aprovando; boa parte não é trabalho do Claude, e sim espera: a validação do certificado ACM, o deploy inicial do CloudFront (vários minutos) e a propagação do DNS. Se o site tem centenas de posts com shortcodes custom de plugins, some tempo de revisão — a conversão vai precisar de mais de uma iteração.

Esta é uma forma de fazer. Os componentes são intercambiáveis — Astro por Hugo, AI Engine pelo export nativo, GitHub Actions por outro CI, Route 53 pelo seu DNS atual. O que eu não mudaria é o modelo de permissões: o agente com o mínimo e por tempo limitado, o pipeline sem keys e um humano aprovando o que chega a prod.

Maximiliano Díaz Doglia

AI Platform Engineer & Full-Stack Developer
Building Enterprise Integrations & Automations