🍴 Fork setup one-time
Layout obrigatório de remotes: origin aponta pro seu fork,
upstream aponta pro tinyhumansai/openhuman (fetch-only). Push direto no upstream polui branches
e fura code review.
# Layout esperado origin git@github.com:<your-username>/openhuman.git # push aqui upstream git@github.com:tinyhumansai/openhuman.git # fetch-only # Se clonou direto do upstream, conserte uma vez: $ git remote rename origin upstream $ git remote add origin git@github.com:<your-username>/openhuman.git $ git fetch upstream # Verifique $ git remote -v
💡 Por quê
Push direto pro upstream cria branches no repo principal, polui a UI do GitHub e bypassa o code review (qualquer maintainer pode acabar mergeando sua branch sem PR). Tratando upstream como leitura, você força o fluxo limpo: fork → PR → review.
🌳 Nunca escreva em main
Antes de qualquer mudança de código, crie uma feature branch a partir do upstream atualizado. Main fica limpa e só avança via merge.
# Workflow padrão antes de qualquer feature $ git fetch upstream $ git checkout -b feat/cron-jobs-export upstream/main # Trabalho, commits, etc. $ git add -p && git commit -m "feat(cron): add JSON export" # Quando precisar atualizar com main recente: $ git fetch upstream $ git rebase upstream/main
✓ Padrão saudável
- ✓Branch atômica por feature
- ✓Nome descritivo (
feat/...,fix/...) - ✓Rebase sobre upstream/main quando necessário
- ✓main local sempre limpa
✗ Receita de dor
- ✗Commit direto em main local
- ✗Misturar 3 features na mesma branch
- ✗Branch baseada em fork/main (defasada)
- ✗
git reset --hardsem entender o estado
🚀 Push e PR: cuidado com --head
Push pra origin, abre PR contra tinyhumansai/openhuman:main usando
--head <seu-user>:<branch>. O --head resolve ambiguidade quando a mesma branch existe em
múltiplos remotes.
# Push pra seu fork $ git push origin feat/cron-jobs-export # PR via gh CLI (recomendado) $ gh pr create \ --repo tinyhumansai/openhuman \ --base main \ --head <seu-user>:feat/cron-jobs-export \ --title "feat(cron): JSON export for scheduled jobs" \ --body-file PR_BODY.md
📋 Templates do repo
- •
.github/ISSUE_TEMPLATE/feature.md— pedido de feature - •
.github/ISSUE_TEMPLATE/bug.md— bug report - •
.github/PULL_REQUEST_TEMPLATE.md— corpo do PR
Siga os templates verbatim. AI-authored também — não improvise as seções, apenas preencha.
🎯 Boa estrutura de PR
- • Título: conventional commits (
feat(cron): ...,fix(memory): ...) - • Resumo: o que muda e por quê (não como)
- • Tests: liste o que foi adicionado / atualizado
- • Screenshots/GIFs: para mudanças de UI
- • Breaking changes: seção dedicada se houver
🪝 Pre-push hook (Husky)
Husky roda pnpm rust:check automaticamente antes de cada push. Falha rápida =
feedback rápido = menos tempo desperdiçado com CI quebrado.
# Ciclo local antes de pushar $ pnpm format # Prettier + cargo fmt $ pnpm lint # ESLint --cache $ pnpm typecheck # tsc --noEmit (alias: pnpm compile) $ pnpm rust:check # cargo check no Tauri shell $ pnpm test # Vitest $ pnpm test:rust # cargo + mock # Push (hook roda automaticamente) $ git push origin feat/cron-jobs-export
⚠️ Quando usar --no-verify
Apenas quando o hook falha em código não relacionado ao seu PR — ex: main atual já está quebrada por motivo alheio.
- • Se falha no seu código → conserte, não pule.
- • Se falha em código pré-existente → use
--no-verify+ mencione no corpo do PR. - • Nunca pule hook como atalho preguiçoso. CI vai pegar e PR vai voltar.
💡 Otimização
Configure seu editor pra rodar Prettier on-save e ESLint inline. A maior parte do que o hook checa já estará verde quando você for pushar.
🌍 i18n parity: 12 locales, sem exceção
Toda string visível ao usuário em app/src/** passa por useT(). Chave nova vai
em en.ts e no chunk correspondente en-N.ts e na mesma posição em
todos os 12 locales. CI bloqueia merge se faltar qualquer chave.
🗂️ Estrutura de chunks
Source of truth são os chunks em app/src/lib/i18n/chunks/:
- •
en.ts+en-1.ts,en-2.ts, ...,en-5.ts - •
pt-1.ts...pt-5.ts,es-1.ts...es-5.ts, etc.
Locales obrigatórios: ar, bn, de, es, fr, hi, id, it, ko, pt, ru, zh-CN.
Use o valor em inglês como placeholder nos outros locales — tradutores corrigem depois. O importante é a chave existir.
✓ Padrão correto
const t = useT();
<button label={t('cron.export.button')}>
Chave registrada em en.ts, en-3.ts, e em todos os <loc>-3.ts.
✗ Bloqueia CI
<button label="Export JSON"> <button aria-label="Exportar">
Hard-coded em JSX, label=, placeholder=, aria-label=. Não passa lint nem revisão.
# Roda o gate localmente antes de pushar $ pnpm i18n:check # Listará exatamente quais chaves faltam em quais locales
🔍 Exceções permitidas
Logs de debug dev-only, identificadores de código (slug, URL, sentinel), valores técnicos que nunca aparecem ao usuário. Quando em dúvida, traduza.
✅ CI checks: rode antes, mergee depois
Conhecer os gates de CI = não ter PR vermelho por surpresa. Tudo que CI checa, você pode rodar local. A diferença é só tempo de feedback.
Format + Lint
Prettier, ESLint, cargo fmt --check
Local: pnpm format:check && pnpm lint
Typecheck
tsc --noEmit + cargo check
Local: pnpm typecheck && pnpm rust:check
Testes (3 níveis)
Vitest, cargo + mock, WDIO
Local: pnpm test && pnpm test:rust
Coverage gate (≥80% diff)
.github/workflows/coverage.yml
Local: pnpm test:coverage e abra app/coverage/lcov-report/index.html
i18n parity
Chaves consistentes em todos os locales
Local: pnpm i18n:check
⏱️ Cheat sheet pre-PR
pnpm format && pnpm lint && pnpm typecheck \ && pnpm rust:check && pnpm i18n:check \ && pnpm test && pnpm test:rust \ && pnpm test:coverage
Tudo verde aqui = altíssima chance de CI verde também.
🎓 Resumo do Módulo
Próxima Trilha:
Trilha 6 — Troubleshooting & Dicas (erros comuns, debug, recovery)