Kodama AI — galeria realtime + agent desktop
Kodama AI
Pipeline: extensão de browser scrapeia TikTok/Instagram → faz upload da mídia pra API → web e desktop mostram em tempo real (card de imagem entra com animação). Mais um app desktop que embute o Claude Agent SDK pra pedir tarefas via OAuth da assinatura.
- Web (público): https://ai.kodama.solutions — galeria realtime (v1: só imagens) + botão Instalar extensão
- API: https://api-ai.kodama.solutions — REST + upload + WebSocket + Swagger em
/docs - Repo: https://github.com/kodama1/kodama-ai (privado)
- Local:
C:\Users\User\kodama-ai(monorepo bun workspacesapps/*) - Deploy: VPS Hermes
187.127.24.217, Docker Compose + nginx nativo + certbot — ver infra/vps-hermes
Arquitetura
Extensão (offscreen) ──POST /api/upload (x-upload-token)──▶ API (Elysia/Bun)
│ grava arquivo em disco (/files/<id>.<ext>)
│ insere row no Postgres (Drizzle)
│ publish "media:new" no tópico WS
▼
Web (Next 16) / Desktop (Tauri) ◀──WS /ws── card novo entra (framer-motion)
Realtime = WebSocket nativo do Bun/Elysia com pub/sub (socket.io NÃO integra limpo em Bun — decisão deliberada). Cliente usa WebSocket puro, sem dep.
Monorepo (apps/)
| App | Stack | Papel |
|---|---|---|
| api | Elysia (Bun), Drizzle, postgres.js, @elysiajs/{cors,static,swagger} | upload multipart (token), GET /api/media, serve /files, WS /ws, /docs. Schema criado no boot (ensureSchema, sem migrate manual) |
| web | Next 16 (standalone), framer-motion, tailwind v4 | galeria masonry dark, card animado (scale+blur+spring), WS live + reconnect, botão Instalar extensão (modal + download /kodama-ai-extension.zip) |
| extension | MV3 puro (sem build) | scraper TikTok/IG → POST /api/upload. Carregar via Load unpacked. Ver apps/extension/README.md |
| desktop | Tauri v2 (Rust) + React/Vite + framer-motion | aba Tarefas (agent console) + aba Galeria (mesma do web) |
| desktop/agent | Bun + @anthropic-ai/claude-agent-sdk |
sidecar: roda tarefa agêntica, stream de mensagens em JSON-lines via stdout |
Desktop — como o agent funciona
- Rust (
src-tauri/src/lib.rs): comandorun_taskfaz spawn debun agent.ts <prompt>injetandoCLAUDE_CODE_OAUTH_TOKEN, e faz stream do stdout pro front via eventoagent-event. Token guardado no Windows Credential Manager (cratekeyring, comandossave_token/has_token/clear_token). - Auth: OAuth da assinatura (
claude setup-token→sk-ant-oat01-…, pool de créditos Agent SDK do Max/Pro). Fallback =ANTHROPIC_API_KEY. Anthropic proíbe "Sign in with Claude" pra terceiros — ok porque é app pessoal. - Tools liberadas (conservador): Read, Glob, Grep, Bash, Edit, Write, WebSearch, WebFetch.
permissionMode: acceptEdits.
Extensão (TikTok & Instagram Downloader)
- Versionada no
main:apps/extension(MV3, reconstruída 2026-06-27 — PR #1 merged). Original (não versionada) ainda emC:\Users\User\tiktok-downloaderno Windows + zipDesktop\tiktok-downloader.zip. - Arquivos:
content.js(extrai mídia do post: TikTok__UNIVERSAL_DATA_FOR_REHYDRATION__photo+video; IG walk no JSON embutido + DOM +og:),offscreen.js(fetch dos bytes +POST /api/upload),background.js(orquestra),popup.html/js(config + captura + progresso),rules.json(DNR reescreve Referer),tools/gen-icons.mjs(ícones sem deps). - Resolve mídia dentro da aba (mesma origem, sessão real) pra furar anti-bot; baixa bytes no offscreen document (host-permission, sem CORS, Referer via DNR) → vira blob local →
chrome.downloads(403 impossível) e POST pra API. - Baixa todo media: vídeo + imagem + carrossel/slideshow (TikTok
/video/e/photo/, IG/p/ /reel/ /tv/). - Popup ⚙: API URL
https://api-ai.kodama.solutions+UPLOAD_TOKEN(emchrome.storage.local). - Distribuição via web:
scripts/zip-extension.mjsempacotaapps/extension→apps/web/public/kodama-ai-extension.zip(commitado); a galeria oferece como download no botão Instalar extensão. Token NÃO é exibido na página pública (só API URL). Rodar o script de novo se a extensão mudar, antes dodocker compose build. - ⚠️ A reconstrução não foi testada contra páginas live — seletores do TikTok/IG mudam muito e podem precisar de calibração; carrossel do IG pode pegar só o slide visível.
Deploy / infra (Hermes)
- Código no VPS:
/home/kodama-ai(NÃO é repo git — transferido viagit archive origin/main | ssh hermes "tar -x -C /home/kodama-ai", preserva.envedata/que são gitignored). Sem GitHub auth no VPS. docker compose up -d --build [web|api]: serviçosdb(postgres 16),api,web. Containerskodama-ai-{db,api,web}-1.- Portas remapeadas: web
127.0.0.1:3015, api127.0.0.1:3016(3000 já é do lunacrm-web). - nginx:
sites-available/{ai,api-ai}.kodama.solutions+ symlink emsites-enabled.client_max_body_size 300m,proxy_buffering off+ upgrade headers (WS). Cloudflare na frente. - TLS: certbot Let's Encrypt nos 2 domínios (auto-renova, expira 2026-09-25).
.envno VPS (/home/kodama-ai/.env, chmod 600):POSTGRES_PASSWORD(openssl),UPLOAD_TOKEN,PUBLIC_FILES_URL,CORS_ORIGIN,NEXT_PUBLIC_API_URL,NEXT_PUBLIC_WS_URL.- Acesso SSH: este Mac (chave
~/.ssh/id_rsa, aliashermes) foi autorizado no VPS em 2026-06-28 —ssh hermesfunciona sem senha. (Aid_ed25519tem passphrase, por isso usa-se aid_rsa.)
Config / secrets
- UPLOAD_TOKEN (extensão ↔ API):
U--Rkh1oT3i40khWb78iE3LGzPMv8M2AmJGwYdmRPsk(no.envdo VPS e no popup da extensão). Baixo impacto: só permite upload de mídia. - OAuth token do agent: gerado por
claude setup-token, guardado no Credential Manager pelo app desktop — nunca em arquivo.
Status (2026-06-28) — LIVE, verificado end-to-end
- ✅ web
200, api/health {"ok":true}, upload→DB→list roundtrip,/filesserve, WS101 Switching Protocols,/docs 200, TLS ativo. - ✅ desktop compila (cargo + tsc/vite) e roda (
bun run tauri dev). - ✅ extensão versionada no
main(PR #1 merged) + botão Instalar extensão no web deployado e live:https://ai.kodama.solutions/kodama-ai-extension.zip→200(16140 bytes), botão presente no HTML. - 🔵 Pendente: testar/calibrar seletores da extensão contra páginas live do TikTok/IG.
Gotchas aprendidos
- socket.io ✗ em Bun → WebSocket nativo Elysia.
- npm quebra no bun workspace (
Cannot read properties of null) → usarbun install/bun run.tauri.confusabun run dev/build. - Tauri precisa Rust + VS C++ Build Tools (instalados via winget; rustup stable-msvc). WebView2 já vem no Win11.
- vite escuta
localhost(IPv6 ::1) — checar saúde por IPv4127.0.0.1dá falso negativo. - Porta 3000 ocupada no Hermes (lunacrm) → kodama usa 3015/3016.
- cargo não no PATH em sessão/processo que não recarregou env após winget → terminal novo resolve, ou prefixar
~/.cargo/bin. - Navegador não instala extensão via JS (inline install removido em 2018) → botão da web só baixa o
.zip+ guia deLoad unpacked. - VPS sem
zip→ o.zipda extensão é commitado no repo (gerado localmente), não gerado no servidor.
Próximos passos
- Testar a extensão contra TikTok/IG live; calibrar seletores (
content.js) se preciso. - Vídeo na galeria (hoje v1 só imagem; schema e upload já guardam vídeo).
- Aprovar tools do agent na UI (em vez de
acceptEditsautomático) + seletor de pasta de trabalho por tarefa. - Sidecar do agent compilado (
bun build --compile) como externalBin do Tauri pra distribuir sem depender de bun/claude instalados. - Deploy do site automatizado (GitHub Actions) em vez de
git archive+docker composemanual.
Relacionado: infra/vps-hermes · projects/mimic/ (também TikTok-driven) · memory/MEMORY