Diary of a lazy developer
Tech posts from my projects. Each post lives in its project repo as POST.it.md and POST.en.md, and gets published here automatically by a GitHub Action.
- Theme: leonids (Jekyll)
- Automation: publish.yml
- Sources: sources.yml
Prerequisites
- Docker and Docker Compose
ghCLI (optional, for manual workflow trigger)
Publishing
Posts are collected from source repos and published to the blog, then cross-posted to social platforms.

EN posts go directly to dev.to (as draft) and Mastodon; Buffer queues them for LinkedIn, Twitter/X and Threads, where you review and approve before publishing.

Scheduled publishing (every Saturday at 6:00 UTC) is currently disabled; trigger manually.
To trigger it manually:
- Go to Actions > Publish posts
- Click “Run workflow” > “Run workflow”
Or from CLI:
gh workflow run publish.yml
To test the whole run without creating any post or draft, use dry-run (the steps still query the APIs and dedup, but log only):
gh workflow run publish.yml -f dry_run=true
The “Run workflow” dialog also exposes a “Dry run” checkbox for the same purpose.
Cross-posting
All secrets go in repo Settings > Secrets and variables > Actions > New repository secret.
dev.to (draft)
- On dev.to: Settings > Extensions > DEV Community API Keys > Generate API Key
- Secret:
DEV_TO_API_KEY
Mastodon (public post with image)
- On mastodon.social: Settings > Development > New Application > select read, write and profile
- Copy the token:
MASTODON_ACCESS_TOKEN
Buffer (LinkedIn, Twitter, Threads queue with review)
- Create a free account on buffer.com and connect LinkedIn, Twitter/X and Threads
- On buffer.com: My Organization (bottom left) > Apps & Integrations > API (beta) > + New Key
- Secret:
BUFFER_ACCESS_TOKEN
Post frontmatter
Each post in a source repo has this frontmatter:
---
title: "Docker on EC2 with Terraform"
date: 2026-04-10
categories: [devops]
tags: [terraform, docker, aws, ec2]
repo: bilardi/aws-docker-host
social_summary: "I wrote my first article in the #DiaryOfALazyDeveloper series 🚀\n\n..."
---
| Field | Required | Used by |
|---|---|---|
| title | yes | blog, all social |
| date | yes | blog URL |
| categories | yes | blog |
| tags | yes | blog, social hashtags |
| repo | yes | collect-posts.sh |
| social_summary | no | EN posts only. Used by Mastodon, Buffer (LinkedIn/Threads). If missing, title is used. Twitter always uses title (280 char limit). Must be under 500 characters including link and hashtags (Mastodon/Threads limit). Buffer counts in UTF-16 code units: emoji above BMP (e.g. 🚀, 🔮, 😄) count as 2 characters each. |
#DiaryOfALazyDeveloper is added automatically on all social posts.
Project structure
_layouts/ # leonids theme: page templates
_includes/ # leonids theme: reusable HTML partials
_sass/ # leonids theme: SCSS stylesheets
css/ # leonids theme: compiled CSS
js/ # leonids theme: JavaScript
_posts/ # generated by GitHub Action (gitignored)
img/ # diagrams and favicon
.github/workflows/
publish.yml # GitHub Action: collect + commit, then parse and cross-post via github-actions-publish scripts
collect-posts.sh # clones source repos, copies POST files
scripts/
parse-diary.py # builds posts.json (intermediate format) from _posts/*.en.md
parse-diary.sh # wrapper for parse-diary.py
social.yml # config: hashtag, site_url, channels (parser: diary)
sources.yml # list of repos to scan for POST.it.md / POST.en.md
docker-compose.yml # local Jekyll server
_config.yml # Jekyll configuration
Development
docker compose up
If something is not updated,
rm -rf _site .jekyll-cache .jekyll-metadata
touch .jekyll-metadata; chmod 777 .jekyll-metadata
touch Gemfile.lock; chmod 777 Gemfile.lock
docker compose up
Not commit (there are also in the .gitignore file)
- _site
- .jekyll-cache
- .jekyll-metadata
- Gemfile.lock
- posts.json
Linting the parser
scripts/parse-diary.py is a single helper script (no pyproject.toml). Lint and format on demand with ruff:
uvx ruff format scripts/parse-diary.py
uvx ruff check --select E,F,I,B,UP,ANN --ignore E501 scripts/parse-diary.py
Same lightweight setup as github-actions-publish: ANN enforces type annotations (PEP 484), docstrings follow PEP 257 by hand, line length is left to the formatter.
Run the parser tests:
bash tests/test-parse-diary.sh
Blog post
License
This repo is released under the MIT license. See LICENSE for details.