009 — Blog AI-first auto-publish coordenado via SQLite kanban (board commitado no git)
Status: Aceita (2026-06-03)
Contexto
Section titled “Contexto”Blog PT-BR é vetor #1 de growth (CEO #9 + docs/SEO.md). Bootstrap = sem time editorial. SEO.md já cravou pillars (8), clusters (25+), cadência (20-30 backlog pré-launch + 2/sem). Falta decidir production model + coordenação de pipeline (multiple agents/workers fazendo partes do fluxo: gerar draft, fact-check, publish, indexar pra RAG, extrair insights do agent, agregar FAQ).
Tradeoff conhecido: AI puro auto-publish escala (custo near-zero, 20+ posts/sem possível) mas tem risco Google Helpful Content Update (penalty se conteúdo for genérico). Híbrido (human-led pillars + AI clusters) seria mais seguro mas exige tempo de founder que não tem.
Coordenação entre workers (writer, judge, publisher, indexer, extractor, aggregator) precisa primitivo simples: sem servidor, sem ORM, sem queue infra (Redis/SQS overkill MVP), sem race condition entre workers.
Decisão
Section titled “Decisão”1. Production model: AI-first auto-publish com guardrails EEAT obrigatórios.
LLM gera draft → LLM judge fact-checa → publisher publica direto, sem human gate por default. Guardrails non-negotiable:
- EEAT schema agressivo:
Article.authorreal (founder bio),datePublished/dateModified,reviewedBy(humano nominal),Organization.foundingDate. Schema.orgArticle+FAQPage+HowToconforme post type. - Originalidade via dados próprios: cada cluster post precisa citar pelo menos uma stat do agent (anonimized, k-anonymity ≥ 50). Sem stat → judge mata. Pillars podem ser evergreen sem stat (são human-reviewed inicialmente).
- Fact-check judge gate: LLM-judge segundo (modelo diferente do writer, ou prompt adversarial) valida números, claims, ausência de hallucination de produto. Falha →
killedcomreason. Aprovação parcial →review(queue manual). - GSC kill switch: queda > 20% impressions/semana em pillar =
config.auto_publish_enabled = false. Publisher worker checa antes de cada claim. - Pillars stay human-led MVP: 8 pillars do SEO.md são moat. AI puro só clusters + refresh. Pillars entram via
enqueue source='backlog' pillar=<x>com human draft já no payload; pipeline pula direto prareview.
2. Coordenação: SQLite kanban commitado no git (content/board.sqlite).
Sem servidor, sem queue, sem ORM. Workers (qualquer agente — Claude session, cron shell, founder manual) interagem via bash + sqlite3 CLI conforme content/README.md. Estado é uma tabela items com FSM backlog → drafting → fact-check → review → publishing → published → archived | killed. Audit trail em transitions. Claim atômico via UPDATE ... WHERE id=(SELECT ... LIMIT 1) RETURNING. Lease TTL (300s default) + requeue-stale recovery.
Board commitado pra: (a) source of truth durável sem infra, (b) qualquer agente em qualquer máquina pulla trabalho com git pull && sqlite3 ..., (c) audit/lead-time queryable, (d) merge conflict raro (binário, mas regenerável).
Consequências
Section titled “Consequências”Positivas:
- Custo de blog tende a zero (LLM API + Astro build hosting). Cabe em bootstrap.
- Escala destravada: add worker = nada de config. Pull-based.
- Audit trail nativo via
transitionstable. Lead time + throughput queryable. Já alinha com## Lead time trackingdo AGENTS.md (tags git pra scenarios + queries SQL pra blog). - Sem servidor de queue = sem ops overhead. SQLite + git já no stack.
- Workers stateless. Crash = lease expira, próximo pega.
- ContentBoard fica fora do domínio TypeScript: zero código aplicação MVP. Promove pra TS aggregate (
content/context) quando aparecer caso pra integrar com agent tools (ex: agent loga em board via TS).
Negativas/risks:
- Google Helpful Content penalty é risco real. Mitigação via guardrails acima. Não há plano B além de migrar pra híbrido (pillars human-led já é primeiro passo). Acompanha via GSC monitoring + kill switch.
- Brand risk: post AI ruim publicado = brand hit. Judge gate + sample manual review (founder olha 10% random/semana) mitiga.
- Binary diff no git:
board.sqlitepolui diff. Aceitável pra MVP (commit batched, schema.sql é a verdade legível). Quando virar dor, dump.sqlopcional commitado em paralelo. - Single-writer SQLite: workers no mesmo host serializam writes. OK pra MVP (low contention, workers rápidos). Distribuído real → migrar pra Postgres + adapter TS (port
ContentBoardjá no design implícito do README). - Multi-host setup só via git pull: dois workers em hosts diferentes pulando trabalho simultaneamente precisam coordenar via pull/push. MVP = single-host (laptop founder ou 1 VPS).
RETURNINGexige SQLite 3.35+: macOS default e brew OK. CI Docker base precisa conferir.
Alternativas (consideradas, rejeitadas)
Section titled “Alternativas (consideradas, rejeitadas)”- AI + human editor (recommended pelo Claude inicial): mais seguro mas exige tempo founder = 30min/post × 50 posts = 25h. Bootstrap não tem. Adia pra pós-tração.
- AI puro sem guardrails: máximo risco penalty, brand hit. Rejeitado.
- Human-led pillars + AI cluster (híbrido full): meio-caminho. Cluster AI puro ficou OK (decidido); pillars human-led já caem nessa categoria por exceção. Híbrido por tier é o que se materializou na prática.
- Redis/SQS/Postgres queue: ops overhead. Sem time SRE bootstrap. SQLite + git resolvem MVP.
- Files no git (markdown com frontmatter
status: drafting): race condition entre workers, sem atomicidade, conflict de merge constante. Rejeitado. - GitHub Issues / Projects como kanban: dependência externa, API rate limits, sem queryable analytics local, perde se mudar de host. Rejeitado.
- Aggregate TS
ContentItem+ portContentBoard+ adapter Sqlite (proposta inicial): over-engineering pra MVP que não tem código de aplicação tocando o board ainda. Workers atuais são bash/cron/Claude session. Promove a TS quando agent precisar logar/ler do board via tool — port + adapter encaixam no padrão 007/012.
Referências
Section titled “Referências”content/README.md— recipes bash + TL;DR wrappers + git workflow + gotchascontent/schema.sql— DDL completacontent/board.sqlite— board inicializada (commitada)scripts/board.sh— CLI wrapper (subcommands: enqueue/claim/release/kill/requeue-stale/list/status/wip/throughput/inspect/pause/resume/help)scripts/workers/— 6 workers bash que pullam do board: writer (backlog→fact-check), judge (fact-check→review|killed, EEAT validator enforça dataStat em clusters), publisher (publishing→published, frontmatter patch, respeita kill switch), indexer (flag embedded:true), insights-extractor (cron, pillars vazios), faq-aggregator (cron, PT-BR intents).LLM_CMDenv swap mock→realapps/landing/src/content.config.ts— schema estendido comstatus/pillar/cluster/source/boardItemId/dataStat/reviewedBy/authorBio(Astro = content truth)apps/docs/.../cmo/content-calendar.mdx— CMO dashboard (snapshot vivo do board)docs/SEO.md— pillars/clusters/cadência (pre-existe; produção model section vai ganhar update apontando aqui)docs/CEO.md#9 — blog/waitlist primeiro move- ADR 005 — Astro content collection é destino dos posts publicados
- ADR 006 — anonymous-first; blog CTA → wa.me direct (sem email)
- ADR 007 — wa.me CTA do blog é conversão final
- ADR 008 — voz mel aplica a posts via system prompt do writer worker
- Google Search Central — Helpful Content Update — origem do risco penalty
- Schema.org Article — EEAT markup obrigatório