Do Obsidian ao blog com um commit — GitHub Actions, Marmite e Telegram
Introdução
Por muito tempo meu fluxo de escrita era uma bagunça: rascunho no Obsidian, copiar manualmente pro repositório do blog, rodar o build local, fazer deploy na mão. Funcionava, mas qualquer fricção a mais e o post ficava na gaveta por semanas.
A solução foi montar um pipeline que faz tudo isso com um único git push. O Obsidian
continua sendo meu editor — onde escrevo, reviso e organizo — mas agora ele está conectado
diretamente ao repositório do blog. Um commit aciona o GitHub Actions, que roda o
Marmite, gera o site estático e faz deploy.
No final do job, uma mensagem chega no meu Telegram confirmando se deu certo ou errado.
Este post documenta exatamente como montar esse setup do zero.
Visão geral do pipeline
Antes de entrar nos detalhes, vale ter o mapa mental de tudo que vai acontecer:
| Etapa | Ferramenta | O que faz |
|---|---|---|
| Edição | Obsidian | Escrever e revisar posts em Markdown |
| Versionamento | Git + GitHub | Vault como repositório, histórico de alterações |
| Build | GitHub Actions | Roda o Marmite e gera o _site/ |
| Deploy | GitHub Actions | Copia o _site/ para o servidor via rsync |
| Notificação | Telegram Bot | Avisa o resultado do job no celular |
O fluxo completo é: escrevo no Obsidian, dou push, e alguns minutos depois o post está no ar — ou tem uma notificação me avisando o que quebrou.
Configurando o Obsidian como repositório Git
Plugin obsidian-git
O plugin obsidian-git é o que transforma o vault em um repositório gerenciado. Ele faz commit e push automático em intervalos configuráveis, ou manualmente pelo command palette.
Instalação via Community Plugins do Obsidian. Após instalar, as configurações relevantes:
Vault backup interval (minutes): 0 ← desabilita auto-commit
Auto pull interval (minutes): 5 ← puxa mudanças remotas periodicamente
Commit message: vault: {{date}}
Pull updates on startup: true
Prefiro não usar auto-commit. O commit manual pelo Ctrl+P → Git: Commit and push
me força a revisar o que estou mandando.
Estrutura do repositório
O vault inteiro vira o repositório, mas só uma pasta vai pro pipeline do blog:
vault/
├── .obsidian/ ← configurações do Obsidian (no .gitignore do blog)
├── notas/ ← notas pessoais, não publicadas
├── projetos/ ← docs de projetos, não publicadas
└── blog-content/
└── content/
├── media/
│ └── gallery/
├── 2026-04-19-meu-post.md
└── marmite.yaml
O GitHub Actions vai olhar apenas para mudanças em blog-content/content/.
Configurando o Marmite
O Marmite é um gerador de sites estáticos minimalista escrito em Rust. Rápido, sem dependências de Node, binário único — ideal para rodar em CI.
marmite.yaml
O arquivo de configuração fica na raiz do content/:
name : raphazilla.rocks
tagline : notas, projetos e devaneios
url : https://raphazilla.rocks
language : pt-BR
authors :
rapha :
name : Rapha
avatar : media/rapha.jpg
pagination : 10
date_format : "%d/%m/%Y"
extra :
social :
github : raphazilla
mastodon : "@rapha@bolha.us"
Testando localmente
Antes de mandar pro CI, vale validar o build local:
# instala o binário (uma vez)
cargo install marmite
# na pasta blog-content/
marmite content/ _site/ --serve
O site sobe em http://localhost:8000 para revisão.
GitHub Actions — o coração do pipeline
O workflow fica em .github/workflows/deploy.yml na raiz do repositório.
name : Build e Deploy
on :
push :
branches : [ main ]
paths :
- "blog-content/content/**"
jobs :
build-and-deploy :
runs-on : ubuntu-latest
steps :
- name : Checkout
uses : actions/checkout@v4
- name : Instala Marmite
run : |
curl -sSL \
https://github.com/rochacbruno/marmite/releases/latest/download/marmite-x86_64-unknown-linux-gnu.tar.gz \
| tar xz -C /usr/local/bin
- name : Build do site
run : marmite blog-content/content/ _site/
- name : Deploy via rsync
env :
SSH_KEY : ${{ secrets.DEPLOY_SSH_KEY }}
DEPLOY_HOST : ${{ secrets.DEPLOY_HOST }}
DEPLOY_USER : ${{ secrets.DEPLOY_USER }}
DEPLOY_PATH : ${{ secrets.DEPLOY_PATH }}
run : |
echo "$SSH_KEY" > /tmp/deploy_key
chmod 600 /tmp/deploy_key
rsync -avz --delete \
-e "ssh -i /tmp/deploy_key -o StrictHostKeyChecking=no" \
_site/ \
${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_PATH}
- name : Notifica Telegram — sucesso
if : success()
run : |
curl -s -X POST \
"https://api.telegram.org/bot${{ secrets.TELEGRAM_TOKEN }}/sendMessage" \
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
-d text="Blog deployado com sucesso — commit \`${{ github.sha }}\`" \
-d parse_mode="Markdown"
- name : Notifica Telegram — falha
if : failure()
run : |
curl -s -X POST \
"https://api.telegram.org/bot${{ secrets.TELEGRAM_TOKEN }}/sendMessage" \
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
-d text="Falha no deploy do blog — veja em ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
-d parse_mode="Markdown"
Secrets necessários
Todos esses valores ficam em Settings → Secrets and variables → Actions no repositório:
| Secret | Descrição |
|---|---|
DEPLOY_SSH_KEY |
Chave privada SSH para o servidor |
DEPLOY_HOST |
IP ou hostname do servidor |
DEPLOY_USER |
Usuário SSH |
DEPLOY_PATH |
Caminho no servidor, ex: /var/www/blog/ |
TELEGRAM_TOKEN |
Token do bot (obtido com o @BotFather) |
TELEGRAM_CHAT_ID |
ID do seu chat ou grupo |
Configurando o bot do Telegram
Criando o bot
- Abra o Telegram e fale com o @BotFather
- Envie
/newbote siga as instruções - Guarde o token no formato
123456789:ABCdef...
Descobrindo o chat_id
Mande qualquer mensagem pro bot e consulte a API:
curl "https://api.telegram.org/bot<SEU_TOKEN>/getUpdates"
O chat_id aparece no campo message.chat.id do JSON retornado. Para grupos,
é negativo (ex: -1001234567890).
Testando manualmente
curl -s -X POST \
"https://api.telegram.org/bot<TOKEN>/sendMessage" \
-d chat_id="<CHAT_ID>" \
-d text="Teste de notificação"
Se chegou, está funcionando.
Lint antes do push — evitando builds quebrados
Adicionar um hook pre-push no vault evita mandar Markdown com erros que vão quebrar o linter do CI:
# .git/hooks/pre-push
#!/usr/bin/env bash
set -e
echo "Rodando markdownlint..."
markdownlint blog-content/content/**/*.md --config .markdownlint.json
echo "OK — enviando push."
chmod +x .git/hooks/pre-push
O .markdownlint.json reflete as mesmas regras do validate.yml do CI:
{
"MD026" : true ,
"MD034" : true ,
"MD040" : true ,
"MD047" : true ,
"line-length" : { "line_length" : 100 }
}
O fluxo no dia a dia
Com tudo configurado, escrever e publicar ficou assim:
- Abro o Obsidian, crio ou edito um arquivo em
blog-content/content/ - Quando estiver pronto,
Ctrl+P → Git: Commit and push - O GitHub Actions detecta a mudança, roda o build e faz deploy
- Alguns segundos depois, a notificação chega no Telegram
Se eu precisar só salvar rascunhos sem publicar, uso publish: false no frontmatter —
o CI roda o build normalmente, mas o Marmite ignora o arquivo.
Conclusão
O pipeline completo — Obsidian escrevendo, Git versionando, Actions buildando, Marmite gerando e Telegram notificando — eliminou toda a fricção manual que me fazia procrastinar publicações. O custo de publicar um post caiu para zero: é só escrever e fazer push.
O código completo do workflow está no repositório em .github/workflows/deploy.yml. Se tiver dúvidas ou melhorias, abre uma issue por lá. 2026-04-19