swarm — spec técnica (OpenClaw)
Swarm — Spec técnica (OpenClaw)
Implementação do ecossistema de agentes como deployment OpenClaw always-on. Estruturada pra quebrar em Linear issues. Ver context.md pra visão geral e dashboard.md pra arquitetura do dashboard.
0. Monorepo
Tudo num repo só: github.com/kodama1/swarm (private).
swarm/
├── infra/
│ ├── docker-compose.yml # swarm-db (postgres 5433) + dashboard
│ ├── Caddyfile.snippet # swarm.kodama.solutions
│ └── .env.example
├── db/
│ ├── schema.sql # tabelas + seed
│ └── migrations/ # alterações futuras
├── openclaw/
│ ├── workspace/ # SOUL, AGENTS, USER, MEMORY, HEARTBEAT
│ └── skills/ # scout, master, creator-*, distributor-*, analytics, treasurer
├── dashboard/ # Astro + React islands + SSE + OAuth
└── README.md
OpenClaw aponta o workspace pra openclaw/workspace/ (symlink ou config) e as skills pra openclaw/skills/.
1. Modelo de execução OpenClaw
OpenClaw = Gateway (WebSocket, always-on, 127.0.0.1:18789 loopback) + workspace files (definem quem o agente é) + skills (o que ele sabe fazer) + HEARTBEAT/cron (quando age sozinho) + memory (o que lembra).
Mapeamento do swarm:
| Conceito swarm | Implementação OpenClaw |
|---|---|
| Identidade do operador | SOUL.md + IDENTITY.md |
| Hard rules / business context | AGENTS.md (carregado em todo system prompt) |
| Perfil do dono (Eu/Kodama1) | USER.md |
| Estado curado / aprendizados | MEMORY.md + memory/YYYY-MM-DD.md |
| Ciclos autônomos (scout, analytics, treasurer) | HEARTBEAT.md + cron jobs via openclaw cron add |
| Roles (Scout, Creator, Distributor, Treasurer) | Skills (openclaw/skills/<role>-<playbook>/SKILL.md) |
| Paralelismo entre playbooks | Sub-agents com --session isolated |
| Estado estruturado (produtos, métricas) | Postgres (Docker) acessado via skill ou Postgres MCP |
| Human-in-loop + monitoramento | Dashboard (canal primário) + Telegram (só alerta crítico) |
Golden rule do OpenClaw: o agente é tão bom quanto o prompt que ele constrói, e tu controla cada arquivo que entra nesse prompt. Os workspace files são o produto.
2. Workspace files
Localização: openclaw/workspace/ no repo (montado em ~/.openclaw/workspace-swarm/ na VPS via symlink).
SOUL.md (personalidade do operador)
Operador econômico frio, orientado a dados, sem apego a produtos. Pensa em portfolio, não em ideias individuais. Mata sem dó produtos que não vendem. Celebra aprendizado, não esforço. [Escrever completo na implementação.]
AGENTS.md (regras — carregado SEMPRE)
Contém as 7 hard rules do context.md em forma operacional + contexto de negócio + como usar cada skill. Este é o arquivo mais crítico. Exemplo de regra operacional:
## Disclosure obrigatório Etsy
Ao publicar QUALQUER produto na Etsy via skill distributor-etsy:
- SEMPRE selecionar categoria "Designed by a seller" (nunca "Made by")
- SEMPRE incluir no final da descrição: "This design was created with AI assistance."
- Se a skill não confirmar disclosure aplicado, ABORTAR publicação e logar erro.
## Aprovação humana via dashboard
Ações que exigem aprovação (nova conta, preço +50%, payout > R$100, qualquer irreversível):
- Gravar row em `approvals` (skill, action, payload).
- BLOQUEAR: fazer polling em approvals.decision até != null.
- NUNCA executar a ação antes de approvals.decision = 'approved'.
- Se pendente > 24h, inserir row em `alerts` (severity=critical) → dispara Telegram.
USER.md
Eu / Kodama1, preferências de comunicação (pt-BR), como aprovar ações (dashboard, não Telegram), tolerância a risco.
MEMORY.md
Estado curado sempre em contexto: playbooks ativos e status, aprendizados acumulados (ex: "nicho X saturado, não tentar de novo"), métricas-chave da semana. Atualizado pelo Treasurer e pela rotina de memória diária.
HEARTBEAT.md (ciclos autônomos — lido a cada 30min)
## A cada 6 horas
- Rodar skill scout: buscar nichos novos em Pinterest, Reddit, Etsy trending, Google Trends.
Validar fit-score por playbook. Salvar em Postgres (niches).
Emitir agent_events (started/completed).
## Todo dia às 09:00 (America/Sao_Paulo)
- Rodar ciclo master: pegar niches validados, decidir quais viram produto em qual playbook
conforme budget disponível. Spawnar sub-agent creator do playbook escolhido.
## Todo dia às 05:00
- Rodar skill analytics: puxar métricas das 3 plataformas, upsert em metrics_daily.
## Toda segunda às 10:00
- Rodar skill treasurer: avaliar cada produto vs kill window. Decidir kill/double-down/boost.
Logar em treasurer_log. Atualizar MEMORY.md com aprendizados.
Gravar resumo semanal em treasurer_log; dashboard exibe. Só alerta Telegram se crítico.
## A cada 30min (health)
- Verificar Gateway liveness, Postgres writable, último ciclo scout < 7h atrás.
Emitir agent_events. Se algo quebrado, tentar restart e inserir alert (critical) → Telegram.
⚠️ HEARTBEAT tem até 30min de delay (checado a cada 30min). Pra timing preciso usar openclaw cron add --cron "..." que roda dentro do Gateway. Confirmar qual usar por ciclo na implementação.
Toda skill emite agent_events (started/completed/failed) pro dashboard mostrar atividade em tempo real via SSE.
3. Skills
Cada role vira uma skill em openclaw/skills/<name>/SKILL.md. Estrutura: metadata + instruções + tools requeridas.
| Skill | Função | Tools que usa |
|---|---|---|
scout |
Caça e valida nichos | Pinterest API, Reddit API, Google Trends, Etsy trending, Postgres write |
master |
Decide o que produzir onde | Postgres read/write, spawn sub-agent |
creator-etsy |
Gera designs + mockup | Imagen 3 API, Printify API, Postgres write |
creator-gumroad |
Monta Notion template | Notion API ou template gen, screenshot, Postgres write |
creator-kdp |
Redige mini-ebook + cover | Claude (nativo), EPUB gen, Imagen 3, Postgres write |
distributor-etsy |
Publica com disclosure | Etsy API v3, Postgres update — disclosure hardcoded |
distributor-gumroad |
Publica + draft tweet | Gumroad API/Playwright, Postgres update |
distributor-kdp |
Upload via browser | Playwright, Postgres update |
analytics |
Coleta métricas | Etsy/Gumroad/KDP read, Postgres write |
treasurer |
Kill/double-down/budget | Postgres read/write, dashboard (approvals/alerts), MEMORY.md write |
Lógica do skill treasurer (central)
para cada playbook ativo:
para cada produto live:
age_days = today - created_at
sales_30d = sum(sales últimos 30d)
revenue_30d = sum(revenue últimos 30d)
se age_days >= kill_window e sales_30d == 0: → kill (status=killed)
senão se age_days >= 7 e sales_30d >= 2: → double_down (spawn creator, variação do nicho)
senão se sales_30d >= 5 e revenue_30d > custo: → boost_ads (grava em approvals, espera humano no dashboard)
senão: → hold
logar em treasurer_log com snapshot
se budget_gasto_mes >= monthly_budget: → pause_playbook
atualizar MEMORY.md com top performers e nichos a evitar
gravar resumo semanal (treasurer_log) — dashboard exibe; alerta Telegram só se crítico
4. Schema Postgres
Container Postgres dedicado na VPS (NÃO o do LunaCRM/Evolution — isolado, porta 5433). SQL completo em db/schema.sql. Tabelas:
create table playbooks (
id text primary key, -- etsy_pod | gumroad_notion | kdp_ebooks
name text not null,
status text not null default 'active', -- active | paused | killed
monthly_budget_brl numeric not null,
kill_window_days int not null,
config jsonb default '{}',
created_at timestamptz default now(),
updated_at timestamptz default now()
);
create table niches (
id uuid primary key default gen_random_uuid(),
keyword text not null,
source text not null, -- etsy_trending | pinterest | reddit | gtrends
fit_etsy_pod numeric default 0,
fit_gumroad_notion numeric default 0,
fit_kdp_ebooks numeric default 0,
validation_data jsonb default '{}',
status text not null default 'pending', -- pending | validated | rejected | used
created_at timestamptz default now()
);
create index niches_status_idx on niches(status);
create table products (
id uuid primary key default gen_random_uuid(),
playbook_id text references playbooks(id) not null,
niche_id uuid references niches(id),
title text not null,
description text,
listing_url text,
external_id text,
status text not null default 'draft', -- draft | live | archived | killed
cost_brl numeric default 0,
price_brl numeric,
assets_urls jsonb default '[]',
created_at timestamptz default now(),
killed_at timestamptz
);
create index products_playbook_status_idx on products(playbook_id, status);
create table metrics_daily (
product_id uuid references products(id) on delete cascade,
date date not null,
views int default 0,
sales int default 0,
revenue_brl numeric default 0,
ad_spend_brl numeric default 0,
fetched_at timestamptz default now(),
primary key (product_id, date)
);
create table treasurer_log (
id uuid primary key default gen_random_uuid(),
product_id uuid references products(id),
playbook_id text references playbooks(id),
decision text not null, -- kill | hold | double_down | boost_ads | pause_playbook | weekly_summary
reason text not null,
metrics_snapshot jsonb,
decided_at timestamptz default now()
);
-- ----- Dashboard / human-in-loop (substitui aprovação por Telegram) -----
create table approvals (
id uuid primary key default gen_random_uuid(),
skill text not null, -- treasurer | distributor-etsy | ...
action text not null, -- boost_ads | open_account | price_change | payout | ...
payload jsonb not null, -- contexto factual pro humano decidir
requested_at timestamptz default now(),
decided_at timestamptz,
decided_by text,
decision text -- approved | rejected | timeout
);
create index approvals_pending_idx on approvals(decided_at) where decided_at is null;
create table agent_events (
id bigserial primary key,
skill text not null,
event_type text not null, -- started | completed | failed
payload jsonb,
ts timestamptz default now()
);
create index agent_events_ts_idx on agent_events(ts desc);
create table alerts (
id uuid primary key default gen_random_uuid(),
severity text not null, -- critical | warning | info
source text not null,
message text not null,
payload jsonb,
created_at timestamptz default now(),
acknowledged_at timestamptz
);
create index alerts_unack_idx on alerts(created_at desc) where acknowledged_at is null;
insert into playbooks (id, name, monthly_budget_brl, kill_window_days) values
('etsy_pod', 'Etsy POD via Printify', 200, 21),
('gumroad_notion', 'Gumroad Notion Templates', 150, 14),
('kdp_ebooks', 'Amazon KDP Mini-ebooks', 150, 45);
Acesso pelas skills: via Postgres MCP server plugado no OpenClaw (preferível) ou via script com connection string nos secrets. O dashboard lê as mesmas tabelas via Drizzle.
5. Setup VPS (Hermes — 187.127.24.217)
Pré-requisitos: Node.js 22+, Docker (já tem), confirmar recursos pós-upgrade (free -h, nproc, df -h).
/home/swarm/ # clone do repo kodama1/swarm
├── infra/docker-compose.yml # swarm-db + dashboard
├── openclaw/workspace/ # symlink → ~/.openclaw/workspace-swarm
└── ...
Containers (infra/docker-compose.yml)
services:
swarm-db:
image: postgres:17-alpine
restart: unless-stopped
ports: ["127.0.0.1:5433:5432"]
environment:
- POSTGRES_USER=swarm
- POSTGRES_PASSWORD=${SWARM_DB_PASS}
- POSTGRES_DB=swarm
volumes:
- ./pgdata:/var/lib/postgresql/data
deploy:
resources:
limits:
memory: 512M
dashboard:
build: ../dashboard
restart: unless-stopped
ports: ["127.0.0.1:4321:4321"]
environment:
- DATABASE_URL=postgres://swarm:${SWARM_DB_PASS}@swarm-db:5432/swarm
- VAULT_OAUTH_BASE=https://vault.kodama.solutions
- PUBLIC_BASE_URL=https://swarm.kodama.solutions
- GATEWAY_WS=ws://host.docker.internal:18789
- TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
- TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID}
depends_on: [swarm-db]
deploy:
resources:
limits:
memory: 512M
OpenClaw (gateway always-on via systemd)
npm install -g openclaw # confirmar nome exato do pacote na doc
openclaw setup --workspace /home/swarm/openclaw/workspace
# openclaw.json: modelo (Claude), secrets (Anthropic key, API keys),
# cron.enabled=true. Telegram só pra alertas (não aprovação).
# systemd: Restart=always, MemoryMax=1G (proteger LunaCRM)
systemctl enable --now openclaw-swarm
⚠️ Cron só roda se o Gateway estiver vivo continuamente. systemd Restart=always obrigatório.
Caddy (infra/Caddyfile.snippet)
swarm.kodama.solutions {
reverse_proxy 127.0.0.1:4321
}
Telegram (SÓ alertas críticos)
Bot no @BotFather, token no .env. Worker do dashboard escuta alerts (severity=critical) e dá push. NÃO há aprovação via Telegram — aprovação é no dashboard. Telegram só diz "abre o dashboard, tem X pendente".
6. APIs e contas externas
| Serviço | Custo | Pra |
|---|---|---|
| Anthropic API | pay-per-use | Cognição (custo principal) |
| Google AI Studio (Imagen 3) | ~$0.04/img | Creator Etsy + covers KDP |
| Etsy Open API v3 | grátis (aprovação necessária — SOLICITAR JÁ) | Distributor Etsy |
| Printify API | free | Mockups + fulfillment |
| Gumroad | free | Distributor (API leitura; criação via web) |
| Amazon KDP | free | Distributor (Playwright) |
| Pinterest / Reddit API | free c/ limite | Scout |
| Telegram Bot | free | Alertas críticos |
| vault SSO (OAuth) | — | Auth do dashboard |
| Sentry | free tier | Observability |
7. Cronograma (3 semanas)
Semana 1 — OpenClaw vivo + 1 playbook (Gumroad) + dashboard base
KOD-XXXSetup Postgres do swarm (docker-compose, schema SQL, seed)KOD-XXXInstalar OpenClaw na Hermes, systemd service, confirmar gateway always-onKOD-XXXEscrever workspace files: SOUL.md, AGENTS.md (com 7 hard rules), USER.md, MEMORY.md, HEARTBEAT.mdKOD-XXXPlugar Postgres MCP + secrets (Anthropic, Gumroad, Pinterest)KOD-XXXEscrever skillscout(MVP: Pinterest + Reddit)KOD-XXXEscrever skillcreator-gumroad+distributor-gumroadKOD-XXXEscrever skillanalytics(MVP: Gumroad) +treasurer(lógica completa)KOD-XXXDashboard base: Astro scaffold, OAuth vault SSO, overview + agents + approvals + SSE de agent_eventsKOD-XXXSmoke test: deixar rodar 48h, validar produtos criados + métricas + sem derrubar LunaCRM + dashboard mostrando atividade
Sucesso: Gateway estável 48h, 3+ produtos Gumroad criados autonomamente, ciclos rodando, dashboard mostrando agentes em tempo real, approval flow funcionando.
Semana 2 — Etsy POD + KDP + dashboard completo
KOD-XXXSolicitar Etsy API (cedo!) + setup PrintifyKOD-XXXSkillscreator-etsy(Imagen+Printify) +distributor-etsy(disclosure hardcoded)KOD-XXXDecidir KDP: Playwright vs alternativa com APIKOD-XXXSkillscreator-kdp+distributor-kdp+ skill PlaywrightKOD-XXXAmpliarscout(Etsy trending) eanalytics(3 plataformas)KOD-XXXAmpliarmasterpra rotear entre 3 playbooks por fit + budgetKOD-XXXDashboard: rotas playbooks/products/niches/treasurer + telegram critical bridge
Semana 3 — Loop de aprendizado + observability
KOD-XXXTreasurer escreve aprendizados no MEMORY.md (nichos a evitar, padrões vencedores)KOD-XXXFeedback MEMORY.md → scout (não repetir nichos mortos)KOD-XXXSentry + alertas críticos via Telegram (API falha 3x, budget estourado, gateway down)KOD-XXXSub-agents isolados pros 3 playbooks rodarem em paralelo (--session isolated)KOD-XXXRunbook de troubleshooting + revisão de custo real de API vs projeção
8. Decisões pendentes
- KDP automation: Playwright (frágil, ToS-cinza) vs Kobo/Apple Books/Smashwords (têm API).
- Gumroad criação: API permite? Senão Playwright vs pivot Lemon Squeezy.
- Estado: Postgres local (Docker) — DECIDIDO: Postgres local, tudo self-hosted.
- Repo:
monorepo vs standalone— DECIDIDO: monorepo únicokodama1/swarm(infra + openclaw + dashboard). - VPS: coabitar com LunaCRM (com limites) vs separada. Começar coabitando, separar quando houver receita.
- Nome final —
swarmé placeholder. - Pacote OpenClaw exato + comando gateway — confirmar na doc oficial (docs.openclaw.ai) antes de instalar.
- Skills via MCP vs scripts — Postgres/APIs como MCP servers plugados, ou scripts chamados pelas skills?
9. Riscos conhecidos
| Risco | Impacto | Mitigação |
|---|---|---|
| Gateway cai → ciclos param | Alto | systemd Restart=always + health check 30min + alerta Telegram + dashboard mostra gateway down |
| Swarm derruba LunaCRM | Alto | Limites de memória (Postgres 512M, dashboard 512M, gateway 1G), monitorar |
| Etsy ban por disclosure errado | Alto | Disclosure hardcoded no AGENTS.md + skill aborta se não confirmar |
| KDP/Gumroad Playwright frágil | Médio | Health check + fallback manual via dashboard |
| Custo Claude API 24/7 explode | Alto | Frequência conservadora + Haiku pra tasks leves + prompt caching + cap monitorado pelo treasurer |
| Treasurer mata bom produto | Médio | Window conservador + resumo semanal no dashboard + boost_ads exige aprovação humana |
| Mercado saturado (receita=0) | Alto | Hipótese a validar. 50 listings sem venda em 60d → pivotar nichos |
10. Glossário
- Workspace files — markdown que define o agente (SOUL, AGENTS, USER, MEMORY, HEARTBEAT)
- Gateway — processo always-on do OpenClaw; cron roda dentro dele
- HEARTBEAT — agendamento em linguagem natural, checado a cada 30min
- Skill — capacidade do agente (SKILL.md com instruções + tools)
- Sub-agent — sessão isolada spawned pra paralelizar (1 por playbook)
- Playbook — vertical produto+plataforma
- Kill window — dias sem venda → produto arquivado
- Fit score — 0-1, casamento nicho×playbook
- Approval — ação que exige decisão humana no dashboard antes de executar
- agent_events — stream de atividade das skills, consumido pelo dashboard via SSE